Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ jobs:
- name: Checkout development family sources outside runtime Cargo scope
env:
GH_TOKEN: ${{ github.token }}
run: node scripts/checkout-family-sources.mjs --development --parent "$GITHUB_WORKSPACE/.."
DEVELOPMENT_REF: ${{ github.head_ref || github.ref_name }}
run: >-
node scripts/checkout-family-sources.mjs
--development
--development-ref "$DEVELOPMENT_REF"
--parent "$GITHUB_WORKSPACE/.."
- uses: dtolnay/rust-toolchain@1.95
with: { targets: "wasm32-unknown-unknown,wasm32-wasip1" }
- uses: jetli/wasm-pack-action@v0.4.0
Expand All @@ -43,7 +48,7 @@ jobs:
- name: Install build tool and local interop type package
run: >-
npm install --ignore-scripts --no-save node-gyp@13.0.1
../vinary-tree-interop/bindings/javascript
"@vinary-tree/vinary-tree-interop@file:../vinary-tree-interop/bindings/javascript"
- name: Build and test integrated backends
env:
VINARY_TREE_INTEROP_ROOT: ${{ github.workspace }}/../vinary-tree-interop
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
shell: bash
run: >-
npm install --ignore-scripts --no-save node-gyp@13.0.1
../vinary-tree-interop/bindings/javascript
"@vinary-tree/vinary-tree-interop@file:../vinary-tree-interop/bindings/javascript"
- name: Build relocatable SDK and native addon
shell: bash
env:
Expand Down Expand Up @@ -109,7 +109,9 @@ jobs:
with: { version: v0.13.1 }
- run: bash .github/setup-binaryen.sh
- name: Install local interop type package
run: npm install --ignore-scripts --no-save ../vinary-tree-interop/bindings/javascript
run: >-
npm install --ignore-scripts --no-save
"@vinary-tree/vinary-tree-interop@file:../vinary-tree-interop/bindings/javascript"
- name: Build and test both WebAssembly hosts
env:
VINARY_TREE_INTEROP_ROOT: ${{ github.workspace }}/../vinary-tree-interop
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# C8 property tests install fast-check into an isolated package so npm never has
# to resolve the unpublished @vinary-tree/interop sibling. The lockfile is
# to resolve the unpublished @vinary-tree/vinary-tree-interop sibling. The lockfile is
# committed for reproducibility; the installed tree is not.
test-property/node_modules/
node_modules/
Expand Down
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Vinary Tree JavaScript runtime

`@vinary-tree/vinary-tree` is the single-instance JavaScript runtime for
`@vinary-tree/javascript-runtime` is the single-instance JavaScript runtime for
libdictenstein, liblevenshtein, lling-llang, and duallity. It lets their
project-specific facades exchange retained dictionaries and weighted
finite-state transducers (WFSTs) without copying or loading incompatible native
runtimes.

| Release property | Value |
|---|---|
| Candidate | `4.0.0-rc.4` |
| Candidate | `4.0.0-rc.5` |
| npm dist-tag | `next` |
| Node | 22.14 or newer |
| Backends | Native N-API, browser WebAssembly, Node WASI |
Expand All @@ -17,12 +17,12 @@ runtimes.
## Install the release candidate

```sh
npm install @vinary-tree/vinary-tree@next
npm install @vinary-tree/javascript-runtime@next
```

Use the package root for Node's native backend,
`@vinary-tree/vinary-tree/wasm` in a browser, or
`@vinary-tree/vinary-tree/wasi` when Node/WASI filesystem preopens are needed.
`@vinary-tree/javascript-runtime/wasm` in a browser, or
`@vinary-tree/javascript-runtime/wasi` when Node/WASI filesystem preopens are needed.
Applications normally install a project facade rather than importing the
shared runtime directly.

Expand All @@ -32,7 +32,7 @@ Dictionaries follow the synchronous `Map` vocabulary while retaining explicit
native lifetime control:

```js
import { libdictenstein, liblevenshtein } from "@vinary-tree/vinary-tree";
import { libdictenstein, liblevenshtein } from "@vinary-tree/javascript-runtime";

using dictionary = libdictenstein.dynamicDawg("unicode");
dictionary.set("cat", 1n).set("cot", 2n).set("cut", null);
Expand Down Expand Up @@ -60,9 +60,9 @@ Garbage collection is exceptional-path containment, not resource scheduling.

| Import | Backend | Intended host |
|---|---|---|
| `@vinary-tree/vinary-tree` | Prebuilt N-API addon | Node services and tools |
| `@vinary-tree/vinary-tree/wasm` | `wasm-bindgen` module | Browsers and web workers |
| `@vinary-tree/vinary-tree/wasi` | Explicit WASI linear-memory ABI | Node with preopened persistent storage |
| `@vinary-tree/javascript-runtime` | Prebuilt N-API addon | Node services and tools |
| `@vinary-tree/javascript-runtime/wasm` | `wasm-bindgen` module | Browsers and web workers |
| `@vinary-tree/javascript-runtime/wasi` | Explicit WASI linear-memory ABI | Node with preopened persistent storage |

All three expose the same snapshot, collection, query, and WFST semantics.
Resources carry an immutable runtime identity; passing a resource between
Expand Down Expand Up @@ -93,6 +93,7 @@ directories.
- [Architecture and invariants](docs/architecture.md)
- [Testing strategy and property models](docs/testing.md)
- [Release order, platform matrix, and rollback](docs/releasing.md)
- [npm coordinate migration and compatibility](docs/npm-coordinate-migration.md)
- [History-preserving extraction provenance](docs/extraction-provenance.md)

The project-specific packages own their idiomatic user APIs. This repository
Expand Down
18 changes: 9 additions & 9 deletions docs/diagrams/release-dependency-graph.puml
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ skinparam backgroundColor #FAFAFA
skinparam shadowing false
skinparam ArrowColor #455A64
skinparam defaultFontName DejaVu Sans
title Immutable 4.0.0-rc.4 JavaScript release dependency graph
title Immutable 4.0.0-rc.5 JavaScript release dependency graph

rectangle "llattice\n0.1.0" as lattice #ECEFF1
rectangle "vinary-tree-interop\n4.0.0-rc.4" as interop #FFF59D
rectangle "libdictenstein\n4.0.0-rc.4" as dict #C8E6C9
rectangle "liblevenshtein\n4.0.0-rc.4" as lev #C8E6C9
rectangle "lling-llang\n4.0.0-rc.4" as lling #C8E6C9
rectangle "duallity\n4.0.0-rc.4" as dual #C8E6C9
rectangle "@vinary-tree/vinary-tree-interop\n4.0.0-rc.5 · npm next" as interop #FFF59D
rectangle "libdictenstein\n4.0.0-rc.5" as dict #C8E6C9
rectangle "liblevenshtein\n4.0.0-rc.5" as lev #C8E6C9
rectangle "lling-llang\n4.0.0-rc.5" as lling #C8E6C9
rectangle "duallity\n4.0.0-rc.5" as dual #C8E6C9
rectangle "platform native prebuilds\n+ browser WASM + WASI" as artifacts #B2DFDB
rectangle "@vinary-tree/vinary-tree\n4.0.0-rc.4 · npm next" as runtime #80CBC4
rectangle "project npm facades\n4.0.0-rc.4 · npm next" as facades #C5CAE9
rectangle "liblevenshtein compatibility facade\n4.0.0-rc.4 · npm next" as legacy #FFCCBC
rectangle "@vinary-tree/javascript-runtime\n4.0.0-rc.5 · npm next" as runtime #80CBC4
rectangle "project npm facades\n4.0.0-rc.5 · npm next" as facades #C5CAE9
rectangle "liblevenshtein compatibility facade\n4.0.0-rc.5 · npm next" as legacy #FFCCBC

lattice --> dict
interop --> dict
Expand Down
2 changes: 1 addition & 1 deletion docs/diagrams/release-dependency-graph.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions docs/diagrams/runtime-architecture.puml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ package "Project facades" #E8EAF6 {
component "@vinary-tree/duallity" as dualFacade #C5CAE9
}

package "@vinary-tree/vinary-tree 4.0.0-rc.4" #E0F2F1 {
package "@vinary-tree/javascript-runtime 4.0.0-rc.5" #E0F2F1 {
component "Runtime identity\n(resource compatibility gate)" as identity #80CBC4
component "Node N-API" as napi #B2DFDB
component "Browser WASM" as wasm #B2DFDB
Expand All @@ -26,7 +26,7 @@ package "@vinary-tree/vinary-tree 4.0.0-rc.4" #E0F2F1 {
component "liblevenshtein" as lev #C8E6C9
component "lling-llang" as lling #C8E6C9
component "duallity" as dual #C8E6C9
component "vinary-tree-interop\nretained resources" as interop #FFF59D
component "@vinary-tree/vinary-tree-interop\nretained resources" as interop #FFF59D
}
}

Expand Down
2 changes: 1 addition & 1 deletion docs/diagrams/runtime-architecture.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
78 changes: 78 additions & 0 deletions docs/npm-coordinate-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# npm coordinate migration for the JavaScript runtime

## Canonical public identity

The standalone runtime repository publishes
`@vinary-tree/javascript-runtime`. The name states what the package is and
matches the source repository; it is not a family-wide umbrella package. The
runtime hosts native N-API, browser WebAssembly (WASM), and WebAssembly System
Interface (WASI) backends for the project-specific facades.

RC4 was published under `@vinary-tree/vinary-tree`. That coordinate is an
immutable historical publication mistake. It does not rename the Vinary Tree
project, and it must not appear in new manifests, imports, examples, or release
graphs.

| Role | Coordinate | Policy from RC5 onward |
|---|---|---|
| Canonical shared runtime | `@vinary-tree/javascript-runtime` | Publish and consume directly. |
| Canonical resource contracts | `@vinary-tree/vinary-tree-interop` | Exact RC dependency of the runtime. |
| Legacy RC4 runtime | `@vinary-tree/vinary-tree` | Preserve immutable bytes; deprecate only after canonical public-install verification. |

## Single source of truth

[`release/version.json`](../release/version.json) owns
`coordinates.npmPackage`, the private property-test package name, the RC
version, and exact upstream versions and source tags. The synchronizer derives
package manifests from those fields and rejects legacy, malformed, or drifted
coordinates. In particular, it rejects an accidental concatenation such as
`@vinary-tree/javascript-runtime-interop`; the runtime and interop package are
two independent coordinates joined by an exact dependency edge.

## Safe migration algorithm

The following literate procedure distinguishes immutable artifacts from
mutable registry pointers:

```text
build native, WASM, and WASI artifacts from the exact RC5 source graph
pack the canonical runtime and inspect its package name and dependency keys
publish canonical RC5 with provenance under the `next` dist-tag
install from the public registry in an empty project
exercise all three backends and cross-project retained-resource handoff
promote canonical `latest` only after the full train passes
deprecate the legacy coordinate with a canonical replacement message
read back package metadata and dist-tags without local workspace overlays
```

If verification fails, leave the immutable version in place, keep or restore
the previous distribution tag, correct the source, and issue the next unused
candidate. Never overwrite a version or silently redirect module resolution.

## Consumer migration

Applications should normally install a project facade. Direct runtime users
replace both the package and any backend subpath:

```sh
npm install @vinary-tree/javascript-runtime@next
```

```js
import runtime from "@vinary-tree/javascript-runtime";
import wasmRuntime from "@vinary-tree/javascript-runtime/wasm";
import wasiRuntime from "@vinary-tree/javascript-runtime/wasi";
```

The runtime's public semantics do not change: one package instance owns the
runtime identity, and resources from another instance are rejected before
native dispatch.

## Trust boundary

The package is published through npm's repository-bound trusted publisher and
the protected `npm` environment. Public read-back must match the expected
repository, exact tag, version, coordinate, dependency coordinate, and
provenance before distribution tags or deprecations are changed. Authentication
material must never be written into package metadata, generated artifacts,
logs, or documentation.
70 changes: 38 additions & 32 deletions docs/releasing.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Releasing `@vinary-tree/vinary-tree`
# Releasing `@vinary-tree/javascript-runtime`

The runtime is a downstream assembly artifact. It must never publish before
the exact Rust crates and shared interop package it consumes are publicly
Expand All @@ -9,11 +9,14 @@ resolvable.
## Release identity

`release/version.json` is authoritative. For this train, every Rust and npm
coordinate is `4.0.0-rc.4`, and npm publication uses the `next` distribution
coordinate is `4.0.0-rc.5`, and npm publication uses the `next` distribution
tag. npm's first-publication behavior assigned `latest` to the inert `0.0.0`
bootstrap reservation. After the OIDC-published runtime passes installed
native, WASM, and WASI smoke tests, retarget the new scoped package's `latest`
pointer to `4.0.0-rc.4`, remove `bootstrap`, and deprecate `0.0.0`.
pointer to `4.0.0-rc.5`, remove `bootstrap`, and deprecate `0.0.0`.
The [npm coordinate migration](npm-coordinate-migration.md) records the exact
identity correction and the compatibility policy for the immutable RC4
artifacts.

The runtime's exact Rust requirements deliberately reject a mixed family. The
development overlay changes only source location; it does not relax versions.
Expand All @@ -24,33 +27,10 @@ lockfile. Every component lock must remain byte-for-byte unchanged.

## Exact-tag workflow protocol

Pushing the annotated tag creates only the immutable source ref. Release
Pushing the annotated `v4.0.0-rc.5` tag creates only the immutable source ref. Release
validation and publication are explicit manual dispatches so the complete
cross-project tag graph and public prerequisites can be established first.

The canonical tag predates protected GitHub-release approval. Append-only
corrective source `v4.0.0-rc.4-release.1` added those authority boundaries.
Its validate-only matrix exposed a separate topology defect: family repositories
were cloned beneath the runtime checkout, so owner-crate Cargo builds inherited
the runtime's `[patch.crates-io]` overlay and rejected their otherwise unchanged
lockfiles. No package-registry job ran.

Append-only corrective source `v4.0.0-rc.4-release.2` fixes the topology and
records every family checkout in `release/version.json` as an exact immutable
tag. Native, browser-WASM, WASI, and development integration jobs now place
family owners beside the runtime checkout. Both the checkout helper and local
layout validation reject nested owner roots. Package identity remains
`4.0.0-rc.4`; neither prior tag is moved.

The exact-source gate then exposed a malformed CRLF blob in interop's Windows
Gradle launcher: a fresh checkout of the otherwise exact tag appeared locally
modified after Git applied the declared `text eol=crlf` filter. Interop
corrective source `v4.0.0-rc.4-release.3` stores canonical LF object data and
retains CRLF checkout semantics. Runtime corrective source
`v4.0.0-rc.4-release.3` changes only the immutable source map to consume that
interop correction. It preserves the package version, platform topology, and
all other owner refs from runtime release.2.

The release workflow has two fail-closed modes. `validate-only` builds all six
native prebuilds plus browser WebAssembly and WASI, assembles the npm tarball,
verifies its contents, and creates the checksummed GitHub prerelease. `npm`
Expand All @@ -60,12 +40,12 @@ environment.
```bash
gh workflow run release.yml \
--repo vinary-tree/javascript-runtime \
--ref v4.0.0-rc.4-release.3 \
--ref v4.0.0-rc.5 \
-f registry=validate-only

gh workflow run release.yml \
--repo vinary-tree/javascript-runtime \
--ref v4.0.0-rc.4-release.3 \
--ref v4.0.0-rc.5 \
-f registry=npm
```

Expand All @@ -79,20 +59,46 @@ The `github-release` environment has the same required reviewer and `v*` tag
policy as npm but stores no secret; it gates only the job-scoped
`GITHUB_TOKEN` used to create the checksummed prerelease.

### RC4 historical source record

The RC4 canonical tag predated protected GitHub-release approval. Append-only
corrective source `v4.0.0-rc.4-release.1` added those authority boundaries.
Its validate-only matrix exposed a separate topology defect: family repositories
were cloned beneath the runtime checkout, so owner-crate Cargo builds inherited
the runtime's `[patch.crates-io]` overlay and rejected their otherwise unchanged
lockfiles. No package-registry job ran.

Append-only corrective source `v4.0.0-rc.4-release.2` fixed the topology and
recorded every family checkout in `release/version.json` as an exact immutable
tag. Native, browser-WASM, WASI, and development integration jobs place family
owners beside the runtime checkout. Both the checkout helper and local layout
validation reject nested owner roots. RC4 package identity remained immutable;
neither prior tag was moved.

The exact-source gate then exposed a malformed CRLF blob in interop's Windows
Gradle launcher: a fresh checkout of the otherwise exact tag appeared locally
modified after Git applied the declared `text eol=crlf` filter. Interop
corrective source `v4.0.0-rc.4-release.3` stores canonical LF object data and
retains CRLF checkout semantics. Runtime corrective source
`v4.0.0-rc.4-release.3` changed only the immutable source map to consume that
interop correction. It preserved the package version, platform topology, and
all other owner refs from runtime release.2.

## Required order

1. Publish independent leaf crate `llattice` at its own `0.1.0` version if the
registry does not already contain the required release.
2. Publish `vinary-tree-interop` and verify installation from each supported
registry coordinate.
3. Publish `libdictenstein`, `liblevenshtein`, `lling-llang`, and `duallity`
crates at `4.0.0-rc.4` in dependency order.
crates at `4.0.0-rc.5` in dependency order.
4. Build the runtime's native prebuild matrix from the exact component tags in
`release/version.json`; build browser WASM and WASI from the same source map.
5. Merge the platform artifacts, run package-content and installed-tarball
smoke tests, then publish `@vinary-tree/vinary-tree@4.0.0-rc.4` with `next`.
smoke tests, then publish `@vinary-tree/javascript-runtime@4.0.0-rc.5` with
`next`.
6. Publish project-specific npm facades against that exact runtime.
7. Publish the unscoped `liblevenshtein@4.0.0-rc.4` compatibility facade with
7. Publish the unscoped `liblevenshtein@4.0.0-rc.5` compatibility facade with
`next`; do not change the legacy `latest` tag.

## Native platform matrix
Expand Down
2 changes: 1 addition & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference lib="esnext.disposable" />

import type { DictionaryResource, RuntimeIdentity, UnitDomain } from "@vinary-tree/interop";
import type { DictionaryResource, RuntimeIdentity, UnitDomain } from "@vinary-tree/vinary-tree-interop";

export type Algorithm = "standard" | "transposition" | "merge-and-split" | "damerau-levenshtein";
export type QueryOrder = "traversal" | "distance-then-term";
Expand Down
2 changes: 1 addition & 1 deletion native.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ try {
ffi = require(addon);
} catch (cause) {
throw new Error(
`@vinary-tree/vinary-tree has no usable native addon for ${platform}; `
`@vinary-tree/javascript-runtime has no usable native addon for ${platform}; `
+ "install a supported prebuilt package or build the addon from source",
{ cause },
);
Expand Down
2 changes: 1 addition & 1 deletion native.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ try {
ffi = require(fileURLToPath(addon));
} catch (cause) {
throw new Error(
`@vinary-tree/vinary-tree has no usable native addon for ${platform}; `
`@vinary-tree/javascript-runtime has no usable native addon for ${platform}; `
+ "install a supported prebuilt package or build the addon from source",
{ cause },
);
Expand Down
Loading
Loading