Liking cljdoc? Tell your friends :D

Vinary Tree 4.0.0-rc.2 release ledger

Train opened: 2026-08-24
Canonical tag: v4.0.0-rc.2
Policy: coordinated release runbook
Predecessor evidence: 4.0.0-rc.1
State: rejected; immutable tags and already-published coordinates retained.

This is the append-only execution record for the corrective RC.2 train. The living runbook defines what an operator must do; this ledger records what was actually observed. A row becomes verified only after the exact public bytes resolve in a clean consumer and exercise their resource-lifetime and collection contracts.

Final outcome

RC.2 was rejected during immutable-tag validation. The vinary-tree-libdictenstein Hackage candidate omitted the comma between vinary-tree-interop >=4 && <5 and vinary-tree-libdictenstein in the conformance test suite's build-depends. Cabal therefore rejected the tagged source at line 62 before an sdist could be produced. This is a source defect, not transient infrastructure, so the RC.2 tags are never moved and the remaining train is never published under RC.2.

Dependency-order failures observed in the same validation window are recorded separately from that defect: root Cargo validation ran before exact libdictenstein@4.0.0-rc.2 existed on crates.io, libdictenstein wheel builds ran before exact vinary-tree-interop@4.0.0-rc.2 existed there, and the shared runtime tarball initially ran before exact @vinary-tree/interop@4.0.0-rc.2 existed on npm. The runtime rerun passed after the npm dependency became public. These results establish the required upstream-first validation order; they do not excuse the invalid Cabal source.

Only the already-validated dependency root and runtime were published before the Cabal defect became visible. Their exact public bytes remain valid and are not unpublished, but neither RC.2 package is promoted to latest. The complete train advances to RC.3.

Colored recovery sequence from a rejected immutable candidate through repaired source, a new candidate, public-byte verification, and downstream release resumption.

Why the train advanced

@vinary-tree/libdictenstein@4.0.0-rc.1 was successfully uploaded by GitHub Actions with npm provenance, but its installed CommonJS and ECMAScript module (ESM) collection traversals failed with:

TypeError: cursor.close is not a function

The facade assumed every runtime cursor implemented close(), return(), nextBatch(), size, and identity. The shared JavaScript runtime's ordinary iterator contract intentionally exposed next() plus Symbol.dispose. Source tests had used a richer mock and therefore did not reproduce the installed runtime shape. This was a package-boundary contract defect, not a registry or authentication failure.

npm package versions are immutable. RC.1 is therefore never overwritten and must never be promoted to latest. The source repair is libdictenstein commit 75dc2cc, Adapt collection cursors to the shared runtime protocol. It:

  1. disposes cursors by capability in the order close(), Symbol.dispose, then return();
  2. derives batching from ordinary next() when nextBatch() is absent;
  3. derives size from the dictionary and treats absent runtime identity as null; and
  4. tests the exact next() plus Symbol.dispose protocol exposed by the shared runtime.

The repaired facade passed all seven npm tests and clean, local packed-tarball CommonJS and ESM smokes covering construction, create/read/update/delete (CRUD), iteration, batching, reduction, and deterministic disposal. Those local bytes are evidence for the fix, not authority to publish RC.1 again.

Immutable RC.1 evidence and disposition

Coordinate or sourceObservationDisposition
libdictenstein@4.0.0-rc.1 on crates.ioPublic and independently consumed; .crate SHA-256 8c2cf6ce32979447f123bcf9341d84dc410d6621a705f3d4cd1c84310a58bd43Valid predecessor; never altered
@vinary-tree/libdictenstein@4.0.0-rc.1Public from GitHub run 32741930425, job 97479602625; npm integrity sha512-Tv29dJ86162/Ai3QyluWtL3S3MLGPVdGga9mfe8jhevJAG4QZCDnfJF6BcV68q1LzzKgSbU1FM8Hg+csmBdp1w==Rejected by installed traversal smoke; deprecate after RC.2 is public; never assign latest
@vinary-tree/interop@4.0.0-rc.1Public; installed CommonJS and ESM resource-lifetime smokes passedValid predecessor; RC.2 is still published for an exact synchronized train
@vinary-tree/vinary-tree@4.0.0-rc.1Public; installed CommonJS and ESM dictionary/query smokes passedValid predecessor; RC.2 is still published for an exact synchronized train
liblevenshtein-rust run 32745399834Corrected RC.1 validation was cancelled before downstream publicationSuperseded by RC.2
lling-llang run 32745514849npm dispatch cancelled before publicationSuperseded by RC.2
duallity run 32745514198npm dispatch cancelled before publicationSuperseded by RC.2

The complete chronology and earlier workflow corrections remain in the RC.1 ledger. This ledger does not reclassify any earlier failure as success.

RC.2 ownership and exact dependency order

All seven owners derive their registry spellings from their own release/version.json. The release cut is:

  1. vinary-tree-interop — publish and independently verify the shared ABI crate and @vinary-tree/interop;
  2. libdictenstein — publish and verify the dictionary crate, then its repaired scoped npm facade;
  3. liblevenshtein-rust — publish and verify the matching crate and facade;
  4. lling-llang, then duallity — publish and verify their exact Rust and npm dependencies;
  5. javascript-runtime — publish the exact shared native/WASM/WASI runtime;
  6. finish all scoped npm facade read-backs and dist-tag normalization; and
  7. publish the legacy liblevenshtein compatibility facade under next only.

The canonical, Cargo, npm, Maven, Clojars, NuGet, Swift, CMake, and pkg-config spelling is 4.0.0-rc.2; PyPI uses 4.0.0rc2, LuaRocks uses 4.0.0rc2-1, RubyGems uses 4.0.0.rc.2, and opam uses 4.0.0~rc2. Hackage and Fortran Package Manager (fpm) build numeric 4.0.0 candidates but do not upload during the RC.

Source freeze and validation evidence

Record commits only after every change is committed and pushed. Never tag a dirty worktree or substitute a branch name for the immutable tag.

OwnerRC.2 commitTag validationSource/package gatesState
vinary-tree-interop6694ad4fcb5ce498f69b77cb14ce1ea7a2f20033run 32757693604complete tag matrix passedverified dependency root
libdictenstein8a433a37954439bf68cdb600e428ed491a8fd91c (contains repair 75dc2cc)run 32757694937Cabal parse failed; four wheels also preceded public interop craterejected source
liblevenshtein-rustdb187f7557110947c4226d2f76c2b3250245eaccrun 32757696054exact libdictenstein crate not yet publicsuperseded downstream
lling-llang903cbe7bf92e04c96d44d39dd88f2e2991a472ce on isolated RC.2 release branchrun 32757693027complete tag matrix passedsuperseded downstream
duallity4ff7b00bbc0b91485834cb30ebaa2dbe7adacf8b on isolated RC.2 release branchrun 32757694845complete tag matrix passedsuperseded downstream
javascript-runtimefc293130817e9abbb965d0e341cd4aa483cff138run 32757694885, attempt 2six native targets plus browser-WASM/WASI and tarball passed after interop npm publicationverified public subset
liblevenshtein-npm447a9e85dd79010411fdc76ad3d6633f3aa9fc62run 32757696127compatibility package gate passedsuperseded downstream

Pre-tag local verification on 2026-08-24

OwnerEvidence
complete trainseven-owner checker accepted the standalone ownership graph, exact RC.2 edges, npm next, Hackage/fpm embargoes, and legacy latest protection
vinary-tree-interoplocked Cargo check passed; JavaScript resource-identity suite passed 2/2
libdictensteinrelease/all-feature nextest passed 3,046/3,046; JavaScript facade suite passed 7/7, including the shared-runtime iterator regression; binding and binding-documentation gates passed
liblevenshtein-rustrelease/all-feature nextest passed 4,903/4,903 with 5 expected skips; JavaScript contract suite passed 3/3 and ClojureScript passed 2 tests/4 assertions; binding, binding-documentation, and MathJax gates passed
lling-llangrelease/all-feature nextest passed 2,841/2,841; JavaScript facade suite passed 6/6; binding, binding-documentation, and MathJax gates passed after the exact-pin checker was generalized to prerelease SemVer
duallityrelease/all-feature nextest passed 374/374; JavaScript facade suite passed 2/2; binding, binding-documentation, and MathJax gates passed
javascript-runtimebrowser-WASM/WASI suite passed 10/10 and the version gate passed; a workstation-only Cargo check encountered duplicate logical paths because the temporary release worktrees are linked into a sibling layout, so the exact clean-checkout tag workflow remains the authoritative Rust topology check
liblevenshtein-npmversion protection and compatibility suite passed 3/3

All validation output was captured under /tmp for review. It is temporary evidence: the final cleanup step removes those logs after the durable results and workflow URLs have been appended here.

Registry evidence

Append one row only after public read-back. A successful workflow upload without a fresh-consumer smoke remains uploaded, unverified, never verified.

CoordinateWorkflow and protected environmentPublic digestFresh-consumer proofState
vinary-tree-interop@4.0.0-rc.2run 32760364827, crates-io-interopSHA-256 7c17dedd9710550fd553357d68dd55a3ec4f47d2930d4aaa1802d6a8c18072beclean exact Cargo consumer compiled registry bytes and checked ABI constants, null resource semantics, and every status round tripverified; retained
@vinary-tree/interop@4.0.0-rc.2run 32762325597, protected npmintegrity sha512-YbbOekjHuumCueqZUH2KBrXqU3XZLcTA5yL4Uml8BmJy4CO6l4OAyeKtXbhPeutuRI9P0TPBw5wUPIAvgmSAVQ==; SHA-1 4f29fdbacb7d9a644782c793dda70db70c5bd14fclean exact install passed CommonJS and ESM runtime-identity and interface-version smokesverified; retained under next only
libdictenstein@4.0.0-rc.2pendingpendingexact Cargo consumer pendingnot published
@vinary-tree/libdictenstein@4.0.0-rc.2pendingpendingCJS/ESM CRUD, traversal, batching, reduction, and disposal smoke pendingnot published
liblevenshtein@4.0.0-rc.2pendingpendingexact Cargo construction/query smoke pendingnot published
@vinary-tree/liblevenshtein@4.0.0-rc.2pendingpendingCJS/ESM query and disposal smoke pendingnot published
lling-llang@4.0.0-rc.2pendingpendingexact Cargo consumer pendingnot published
@vinary-tree/lling-llang@4.0.0-rc.2pendingpendingCJS/ESM traversal smoke pendingnot published
duallity@4.0.0-rc.2pendingpendingexact Cargo consumer pendingnot published
@vinary-tree/duallity@4.0.0-rc.2pendingpendingCJS/ESM bridge smoke pendingnot published
@vinary-tree/vinary-tree@4.0.0-rc.2run 32763394585, protected npmintegrity sha512-c4gL6ONYJ8lU/YtdhFjo4aRAfoxCsHroERqdATlX4hX+3ZF2Zc73QFHFGlW+1IidVBdAZckwvZmHKkxUS3pKDQ==; SHA-1 3ff2f631bbcfbeaabcd2ba56704d54feb9117b84clean exact install passed native CommonJS/ESM, headless-Chromium browser-WASM, and Node WASI dictionary/query/closure smokesverified; retained under next only
liblevenshtein@4.0.0-rc.2pending under next onlypendingCJS/ESM compatibility smoke pendingnot published

Closed operator checklist

This checklist is retained as evidence of where execution stopped. Do not continue it and do not substitute RC.2 into the metadata commands below; the RC.3 ledger owns all subsequent release actions.

  • [ ] Run every owner synchronizer in read-only mode and the seven-owner scripts/check-release-train.py gate.
  • [ ] Verify no living manifest, workflow, example, guide, or generated lockfile retains an RC.1 coordinate; retain RC.1 only in historical ledgers.
  • [ ] Run project tests, binding/documentation gates, package dry runs, workflow syntax checks, and pgmcp bug-gate in every changed owner.
  • [ ] Commit and push every owner with an enumerated release message; create new annotated v4.0.0-rc.2 tags. Never move an RC.1 tag.
  • [ ] Dispatch validate-only at each RC.2 tag and record its run URL and exact commit above.
  • [ ] Publish one registry at a time in dependency order. After each upload, resolve and exercise the exact public bytes before releasing a dependent.
  • [ ] Deprecate @vinary-tree/libdictenstein@4.0.0-rc.1 with a message directing users to RC.2 or newer; record the read-back. Do not unpublish it.
  • [ ] After each scoped RC.2 package passes installed-byte smoke tests, set latest = next = 4.0.0-rc.2, remove bootstrap, and retain the explicit 0.0.0 bootstrap deprecation.
  • [ ] Keep unscoped liblevenshtein@latest at 2.0.4; only its next tag may point at 4.0.0-rc.2.
  • [ ] Record every configured non-npm registry result or an explicit deferral reason, clean temporary evidence files, verify clean worktrees, and update the pgmcp epic with final evidence.

Interactive npm metadata commands

These commands were planned but were not executed for the rejected train. They remain historical procedure evidence only.

Only run these after the exact RC.2 package passes its installed-byte smoke. The operator uses web authentication; publication itself continues to use GitHub Actions trusted publishing and provenance.

RELEASE_VERSION="4.0.0-rc.2"
NPM_PACKAGE="@vinary-tree/libdictenstein"

npm login --auth-type=web
npm whoami
npm dist-tag add "${NPM_PACKAGE}@${RELEASE_VERSION}" latest --auth-type=web
npm dist-tag rm "${NPM_PACKAGE}" bootstrap --auth-type=web
npm deprecate "${NPM_PACKAGE}@0.0.0" \
  "Bootstrap-only placeholder; use ${NPM_PACKAGE}@${RELEASE_VERSION} or newer." \
  --auth-type=web
npm deprecate "${NPM_PACKAGE}@4.0.0-rc.1" \
  "Rejected release candidate: installed collection traversal is broken; use ${NPM_PACKAGE}@${RELEASE_VERSION} or newer." \
  --auth-type=web
npm view "${NPM_PACKAGE}" versions dist-tags --json
npm view "${NPM_PACKAGE}@0.0.0" deprecated --json
npm view "${NPM_PACKAGE}@4.0.0-rc.1" deprecated --json

Repeat scoped tag normalization only for packages whose RC.2 public bytes have passed their own smoke. Never apply the latest mutation to the unscoped legacy package.

Completion condition

RC.2 is complete only when every intended coordinate is either independently verified or explicitly deferred, all npm dist-tags satisfy their scoped or legacy postconditions, every checksum and workflow URL is recorded here, all temporary artifacts are removed, and each release worktree is clean. Merely creating tags, uploading packages, or passing source tests is insufficient.

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