Liking cljdoc? Tell your friends :D

Vinary Tree 4.0.0-rc.1 release ledger

Release date: 2026-08-24
Canonical tag: v4.0.0-rc.1
Policy: coordinated release runbook
State: in progress; append-only until every intended coordinate is either published and independently verified or explicitly recorded as deferred.

Scope and ownership

This train synchronizes seven artifact owners without nesting one owner's packages inside another repository:

RepositoryOwned release surface
vinary-tree-interopshared retained-resource ABI and language mirrors
libdictensteindictionaries, collection facades, native SDKs, and language packages
liblevenshtein-rustautomata, matching, native SDKs, and language packages
lling-llangweighted finite-state transducer crate, SDK, and npm facade
duallityLevenshtein/WFST bridge crate, SDK, and npm facade
javascript-runtimeshared native, browser-WASM, and WASI JavaScript runtime
liblevenshtein-npmlegacy unscoped npm compatibility name only

The dependency order is interop, libdictenstein, liblevenshtein, lling-llang, duallity, shared JavaScript runtime and scoped facades, then the legacy npm compatibility leaf. llattice@0.1.0 is an already versioned prerequisite outside the synchronized major-version train.

Source and workflow evidence

OwnerReviewed commit / tag targetValidation evidenceRegistry state
vinary-tree-interopd79c97etag validation and GitHub prerelease completedRust crate and @vinary-tree/interop@4.0.0-rc.1 public and smoke-tested
javascript-runtime576b9c3GitHub run 32700242213 succeeded@vinary-tree/vinary-tree@4.0.0-rc.1 public; CommonJS and ESM installed-byte smokes passed
libdictenstein6335a9dclean-source tag validation run 32705525805 and publication run 32739936016 succeededcrates.io artifact independently read back and consumed
liblevenshtein-rustrelease branch includes the clean-source fix d43cd83; final tag awaits the managed-language release-gate correctionlocal default/all-feature suites passed; 32739900519 proved the registry-dependency gate; 32741417024 then exposed four package-lane dependency defects; corrected exact-tag validation pendinglocked crates.io dry-run passes against the public libdictenstein RC; publication pending replacement validation
lling-llang2af235f in isolated release/4.0.0-rc.1 worktreereplacement tag validation run 32741421070 succeededpublication pending Rust prerequisites
duallityf0a644e in isolated release/4.0.0-rc.1 worktreereplacement tag validation run 32741418091 succeededpublication pending Rust prerequisites
liblevenshtein-npm6e205bbfinal exact-tag validation pending scoped facadepublication pending; legacy latest must remain 2.0.4

The commit cells identify source commits, not package digests. The immutable registry bytes and their digests are recorded in the registry table only after read-back.

Registry evidence

CoordinatePublic stateIndependent verification
vinary-tree-interop@4.0.0-rc.1 on crates.iopublishedexact crate resolves; downstream package dry-runs resolve it
@vinary-tree/interop@4.0.0-rc.1published; latest = next = 4.0.0-rc.1; no bootstrap tagCommonJS and ESM resource-lifetime smoke passed; 0.0.0 deprecated as bootstrap-only
@vinary-tree/vinary-tree@4.0.0-rc.1published; latest = next = 4.0.0-rc.1; no bootstrap tagCommonJS and ESM dictionary/query smokes passed; SHA-512 integrity begins sha512-oloKdlDk...; 0.0.0 deprecated as bootstrap-only
libdictenstein@4.0.0-rc.1 on crates.iopublished by run 32739936016; publicly readable by 2026-08-24T14:55:27Zforced crates.io metadata read-back downloaded the public crate; a fresh exact-version binary consumer resolved and compiled it; .crate SHA-256 8c2cf6ce32979447f123bcf9341d84dc410d6621a705f3d4cd1c84310a58bd43
liblevenshtein@4.0.0-rc.1 on crates.iopendinglocked dry-run packaged 2,492 files (46.0 MiB; 4.7 MiB compressed), compiled against the exact public libdictenstein RC, verified the crate, and reached the dry-run upload boundary
lling-llang@4.0.0-rc.1 on crates.iopendingblocked intentionally until exact prerequisites resolve publicly
duallity@4.0.0-rc.1 on crates.iopendingblocked intentionally until exact prerequisites resolve publicly
remaining scoped npm facades0.0.0 reservations onlypublish and installed-byte smokes pending
legacy liblevenshtein@4.0.0-rc.1pending under nextlatest remains legacy 2.0.4

Validation results retained from the release campaign

  • liblevenshtein-rust: cargo nextest run --no-fail-fast --workspace --all-features passed 4,903 tests with 5 skipped, without environment-level target flags.
  • libdictenstein: the equivalent all-feature suite passed 3,046 tests; two exhaustive Loom cases remain intentionally slow/excluded from that run.
  • duallity: the all-feature suite passed all 374 tests.
  • libdictenstein's hosted Clojure lane passed 25 tests and 18,856 assertions; liblevenshtein's Clojure lane passed 9 tests, 19 assertions, and 350 property cases after declaring the missing test-only dependencies.
  • Native, wheel, managed-language, npm, relocation, checksum, and GitHub-release lanes completed in libdictenstein validation run 32702493249 before the publication-only Cargo workflow correction.

Incidents and durable corrections

Target features belong to Cargo's target matrix

All-feature builds initially failed because Gxhash requires AES plus SSE2 on x86/x86-64 and AES plus NEON on ARM/AArch64. The portable minimums now live in target-scoped .cargo/config.toml entries for Linux, macOS, and Windows. Workflow-level RUSTFLAGS that would override Cargo configuration were removed; sanitizer jobs explicitly compose their instrumentation with the same portable baseline. The release never uses target-cpu=native.

Test-only language dependencies are release dependencies

The hosted libdictenstein Clojure test failed because clojure.data.json was used by conformance fixtures but absent from project.clj. The dependency was declared in commit 0f64b7d. The same audit found liblevenshtein property tests using clojure.test.check without a manifest entry; commit 2d5d7de declared it. Both suites then passed from their package-shaped builds.

Publish the exact clean Cargo source

Libdictenstein crates.io run 32704116534 rebuilt and passed every matrix lane, then cargo publish rejected dirty Cargo.toml and Cargo.lock files. The workflow had rewritten valid path + version dependencies into registry-only dependencies immediately before upload. Cargo already normalizes the supported multiple-location form by removing path from the packaged manifest.

The correction keeps exact dependency checkouts where local discovery is needed and invokes cargo publish --locked on the unchanged checkout:

  • libdictenstein 6335a9d — publish exact clean source;
  • liblevenshtein-rust d43cd83 — replace the mutating publication action with exact dependency clones;
  • lling-llang 4fffc88 and duallity 60fb805 — require locked publication.

A release workflow must never add --allow-dirty to conceal source mutation.

Early validation tags were advanced before registry publication

During release-pipeline bootstrap, the libdictenstein, liblevenshtein-rust, lling-llang, and duallity RC tags had already been pushed for validation when the clean-source publication defect, workflow-level target-flag overrides, and this evidence runbook were corrected. No package registry had accepted those projects' 4.0.0-rc.1 bytes. Their annotated tags were advanced to the corrective commits and the complete tag matrices were rerun from scratch.

This is preserved as an incident, not a reusable procedure. The living runbook now requires branch CI and local release gates before the first tag, forbids force-moving a pushed release tag, and requires the next candidate if a defect is discovered afterward. The final tag targets recorded in this ledger are the freeze boundary for this train.

Shipped examples are part of the synchronized version surface

The final documentation audit found release coordinates that were correct in manifests but stale in shipped binding and architecture guides. The fixes were made before the affected packages reached their registries:

  • liblevenshtein-rust updates both Clojure coordinates and the architectural crate-version table to 4.0.0-rc.1;
  • lling-llang commit 2af235f updates its JavaScript guide's exact interop dependency;
  • duallity commit f0a644e updates its JavaScript and cross-language guides, describes interop as the actual dependency rather than a peer dependency, and removes obsolete pre-release wording.

Each repository's release-version synchronizer now owns those examples and fails validation if they drift. Because those commits change shipped package bytes, the older successful tag runs are explicitly invalidated in the source table and complete replacement tag validations are required.

Exact registry dependencies gate downstream validation by design

Liblevenshtein-rust tag-validation run 32739900519 stopped at the publish-contract job because it resolved libdictenstein = "=4.0.0-rc.1" from crates.io and that prerequisite had not been published. This is the intended dependency-order guard, not a source failure. The same tag must be validated again after independent public read-back of libdictenstein; only that replacement run can become release evidence.

Package validation must provision its complete contract

After libdictenstein became public, liblevenshtein-rust replacement run 32741417024 reached the full package graph and found four independent release environment omissions. The source contracts themselves passed; the package lanes had not provisioned everything they exercised:

  • the npm lane inherited Java 17 from the runner while ClojureScript 1.12's Closure compiler requires Java 21 bytecode support;
  • every cibuildwheel lane installed pytest but omitted hypothesis, although the wheel test command collects the property suite;
  • the JVM package tried to resolve io.vinarytree:vinary-tree-interop from Maven Central before the synchronized interop SDK had been published there;
  • the .NET package made the equivalent premature NuGet request for VinaryTree.Interop.

The corrections pin Temurin 25 in the npm lane, install both Python test dependencies in every wheel, stage the exact tagged interop JVM artifact in a job-local Maven repository, and build .NET through the existing exact interop project-reference seam. Public package metadata continues to name the exact 4.0.0-rc.1 interop dependency; only validation-time resolution is local.

Before retagging, the corrected contracts were reproduced locally: the ClojureScript suite passed 2 tests and 4 assertions, Python passed all 14 tests, the JVM source compiled against the isolated staged artifact, and both net8.0 and net10.0 assemblies built with zero warnings and zero errors. Run 32741417024 remains failed evidence; it is never reclassified as successful.

npm trusted publishing and bootstrap normalization are separate controls

GitHub Actions publishes with npm trusted publishing, short-lived OIDC credentials, provenance, and --tag next. The operator's local npm login --auth-type=web is used only for interactive dist-tag and deprecation changes after installed-byte verification. No bypass-2FA token is required or stored.

For each new scoped package, the verified postcondition is:

latest = 4.0.0-rc.1
next = 4.0.0-rc.1
bootstrap is absent
0.0.0 carries a bootstrap-only deprecation

The unscoped legacy package is the exception: it receives the RC under next while latest remains 2.0.4.

Remaining append-only entries

Append one row or subsection when each event completes:

  1. exact tag commit and successful validation run for every owner;
  2. protected-environment approval and registry workflow URL;
  3. public coordinate, digest or checksum, and indexing time;
  4. clean installed-consumer smoke result;
  5. scoped npm tag/deprecation read-back;
  6. explicit deferral reason for every unconfigured registry;
  7. final worktree, temporary-file, GitHub-release, and pgmcp epic audit.

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close