Skip to content

Candidate verification and releases

The repository contains an unpublished 0.1.0 candidate. Candidate verification collects evidence without changing a version, creating a tag or publishing a package. Stable API and maintenance commitments remain a separate decision.

Local baseline versus candidate

pnpm verify:baseline builds the project, runs local checks and real browsers, and measures all JS benchmark suites plus the Rust core. It writes source hashes, a source archive, command logs, environment, asset metadata and platform status.

pnpm verify:candidate validates an existing build and freezes one real tarball. It does not clean dist or rebuild aggregated platform binaries. It adds support and platform-evidence audits, archive/source/asset consistency checks, optional consumer Node runtimes, and production pipeline/Worker measurements. The runners share command/log handling but preserve these different scopes.

sh
pnpm build
pnpm verify:candidate --output artifacts/candidates/local

Use a fresh directory each time. A run.lock rejects overwriting evidence. The verifier saves the archive, source snapshot and hashes before checks, compares them again afterward, and fails if any checked input changes. Independent checks continue after failure and retain their logs; the final exit code remains nonzero. Benchmarks retain observations without a shared-machine speed threshold.

Numerical validation

Ordinary tests use the committed independent oracle without requiring MPFR. To regenerate it, install MPFR and run the generation/check commands deliberately:

sh
pnpm generate:math
python3 scripts/generate-math-oracle.py --check
pnpm check:math --json artifacts/math/accuracy.json
pnpm test --run tests/math.test.ts tests/math-abi.test.ts

The generator imports inputs exactly, computes directed intervals at 256 bits, requires both endpoints to round to the same target value, and confirms at 512 bits. It generates f32 and f64 directly to avoid double rounding. Reports retain per-function/dtype/mode samples, worst errors and inputs, fixture hash, toolchain and binary hashes. Revalidate after changing dependencies, build flags, semantics or budgets. The accuracy archive preserves the original measurements; a new run writes a separate report.

Consumer runtimes

check:package --archive <absolute-path> --node <executable> --json <report> checks the same tarball with another Node runtime. Candidate --node accepts multiple executable paths. No native rebuild occurs for each consumer runtime.

The isolated consumer installs offline with install scripts disabled and checks exports, Node/browser conditions, NodeNext/Bundler declarations, Workers, dual Wasm assets and fallback with the native addon removed. Real browsers and Vite consume the same candidate through LANEOPS_TEST_ARCHIVE.

Evidence

RecordScope
support.json404 signatures × five backends, original I/V/F states, implementation/evidence paths and local ordinary/resident differential calls
package.json / node-*.jsonReal tarball consumption, declarations and missing-addon fallback
math.jsonMPFR samples, per-signature budgets, special values and observed errors
browser/Three-browser/static/Vite/Worker results and failure traces
pipeline-benchmark.json / worker-benchmark.jsonCurrent assets' latency, residency, fusion, responsiveness and memory observations
source.tar.gz / report.jsonRebuildable source, file/archive/asset hashes, commands, platform status and remaining work

Matrix smoke does not replace independent numerical/alias/ABI/memory suites or promote unexecuted targets. Fallback is always F. Historical reports remain available separately; preserve old failed records rather than relabeling them after a later run.

CI and publishing

Local publish fails with missing native assets

pnpm publish from the repository runs prepublishOnly, which invokes check:package --release. This requires native addons for all five supported platforms. A local pnpm build only creates the current platform's addon, so running it on macOS arm64 leaves these release assets missing:

text
dist/laneops.darwin-x64.node
dist/laneops.linux-arm64.node
dist/laneops.linux-x64.node
dist/laneops.win32-x64.node

For local validation, run pnpm build followed by pnpm check:package. pnpm release:check also validates only the local build; it does not assemble the cross-platform package required by prepublishOnly.

For a first/manual publish, follow the steps below to build the complete package in CI and publish its verified archive from your local npm session.

For manual assembly, build JS/Wasm first and collect all five native-* artifacts from the same commit into dist/, along with their validation evidence. Then follow the release candidate checks below. Running pnpm build or pnpm build:ts after aggregation removes the collected addons. Keep the --release check enabled so incomplete packages cannot be published from the repository.

First publish from a local npm session

Push the release commit to the GitHub repository first. The local checkout must remain on that commit when verifying the downloaded artifact. Start the Release candidate (no publish) workflow on that branch; it builds and validates the complete package without publishing or requiring npm credentials:

sh
gh workflow run candidate.yml --ref main
gh run list --workflow candidate.yml --branch main

Use the selected run ID in the following commands. Wait for the entire workflow, including the Node version matrix, to succeed. Failed runs also upload artifacts for diagnosis; an uploaded artifact alone does not mean the run passed. Use a fresh download directory:

sh
gh run watch <run-id> --exit-status
gh run download <run-id> --name release-candidate --dir artifacts/first-publish
pnpm exec tsx scripts/check-candidate-artifact.ts artifacts/first-publish
pnpm check:package --release --archive artifacts/first-publish/laneops-0.1.0.tgz

check-candidate-artifact validates the release report, source commit and archive hash. check:package then checks that same archive on the local runtime. Use the downloaded filename if the version differs from 0.1.0.

After both checks pass, log in to npm and publish that exact tarball:

sh
npm login
npm publish ./artifacts/first-publish/laneops-0.1.0.tgz --access public

Publishing an existing tarball with npm does not rerun the repository's prepublishOnly or repack the local dist/; the archive has already passed the release checks above. The local publish uses the authenticated npm session.

Subsequent tag releases

Once automated npm publishing is configured, push a v<version> tag matching package.json. The Release workflow (release.yml) runs the complete candidate workflow and publishes its verified archive. The version must not already be published; use the next version after the manual first publish.

Candidate and tag workflows

The non-publishing candidate workflow can run manually or from CI:

  1. Build and execute checks on macOS arm64/x64, Linux glibc arm64/x64 and Windows x64. Upload source identity, logs and binary hashes for each target.
  2. Build JS/dual Wasm, then collect all five native files. Do not run build:ts after aggregation because it clears dist.
  3. Run verify:candidate --release --platforms artifacts/platforms. Require matching commits, clean source, logs and binary hashes for every platform.
  4. Download the same candidate archive in the Node 22.18.0/24.x/26.x matrix, verify its report and hash, then run check:package --release with an explicit --archive argument. Verification tooling and consumers both use the matrix's Node version; the matrix does not rebuild or repack the library. Each consumer report records the runtime and archive hash.

The candidate workflow includes the Node matrix, both for manual runs and when called by CI or the tag workflow. Node compatibility is a reusable workflow that requires the candidate artifact from the same run, so it has no separate manual trigger.

The tag workflow waits for the complete candidate workflow. Immediately before publishing, it validates report status, required checks, commit and tarball hash, then publishes that exact archive without repacking. Missing assets/evidence cannot pass.

The full baseline, including every JS benchmark suite and the Rust core benchmark, runs separately through the manual Baseline validation workflow (baseline.yml). Ordinary CI retains the candidate's correctness checks and pipeline/Worker measurements without also running the complete baseline.

A local passed report does not certify all release targets. stableReady is always false by design: a single automatic report does not grant an API/maintenance commitment. Review platform/Node evidence, contracts and known limitations separately.

Consumer boundaries

The package is ESM. It does not promise CommonJS, Bun, Deno, musl native binaries or extra CPU targets. When native cannot load, auto may use Wasm; explicit native retains the error. Browsers need modules, WebAssembly and fetch, plus Workers for the asynchronous entry. Shared memory and cross-origin isolation are unnecessary.

Deploy JS/Worker/native/Wasm assets from one build. ABI v6 and the registry fingerprint must match, including custom asset URLs. Respect host CSP and asset origin/loading rules. See browser integration, contracts and remaining validation.

Released under the MIT License.