Versioning
An answer from the deadline example is reproducible only under the pins that produced it. This page names the four version axes, the checklist for moving any of them, and the rule for old captures: replay under old pins, recompute under new ones, never overwrite.
docs/build/examples/deadline-appThe four axes
Section titled “The four axes”| Axis | Pinned where | Current value |
|---|---|---|
| SDK package | package.json | @arxo/law 0.3.3, arxo 0.2.0 (Python) |
| Canon package | package.json | @arxo/canon-bgb-fristen 0.1.5 |
| Canon model version | openModel in src/runtime.ts | de.bgb.fristen@0.1.0 |
| Adapter and capture format | src/to-case.ts, src/capture.ts | ADAPTER_VERSION 1.0.0, deadline-app.capture/1 |
Each axis moves for its own reason:
- SDK package. New engine or facade behavior. Answers keep their statuses and values across compatible SDK releases, but bytes may move: replays stay within one SDK.
- Canon package. New canon build: regenerated bindings, corrected metadata, repackaged engine files. The model version it carries may or may not move with it — check the package notes against the model pin.
- Canon model version. New formalization: changed rules, changed questions. A model move can change values and statuses, not just bytes.
- Adapter and capture format. New mapping from form fields to facts
(
toFacts,toCaseInput) or a new capture layout. The adapter version is stamped into every capture so a replay knows which mapping produced it.
The worked case pins all four: the packages above, the model
de.bgb.fristen@0.1.0, the adapter 1.0.0, the capture format
deadline-app.capture/1, the time zone Europe/Berlin, and the policy
urn:de:corpus:clir:bgb-fristen#BGB_FRISTEN_TAG.
What a capture records
Section titled “What a capture records”A capture under CAPTURE_FORMAT deadline-app.capture/1 carries its pins
with the answer, so a replay later still knows its terms:
- the form:
eventDate,durationDays,candidateEnd,legalTime; - the adapter version
ADAPTER_VERSION 1.0.0; - the SDK and canon package versions;
- the model version
de.bgb.fristen@0.1.0, the time zone, and the policy; - the answer: statuses, proof identifiers, the three hashes, and the
canonical document as
documentBase64with itssha256.
verifyCaptureIntegrity checks the bytes against the recorded hash
before replayCapture trusts them; either step fails closed.
Upgrade checklist
Section titled “Upgrade checklist”- Change one axis at a time and note the old and new values.
- Reinstall from the lockfile (
npm ci) so the tree matches the pins. - Run the full suite:
npm test, the typecheck, and the Python checks. Read every failure as a behavior statement before touching code. - Compare the worked case: collect must still compute
2026-03-20withCOMPUTED, truth must still answerTRUE_ONLY, the wrong-date and partial cases must still answerNEITHER, andwhyNotmust still return 2 blockers — unless the upgrade note says otherwise, in which case the note is the new expectation and the suite is updated first. - If bytes moved but values did not, refresh the snapshots from runs you have read, one SDK at a time.
- If the adapter moved, bump
ADAPTER_VERSION, keep the old mapping readable for old captures, and add a regression case for the changed mapping. - If the capture format moved, bump
CAPTURE_FORMAT, keepverifyCaptureIntegritystrict on both formats, and never rewrite old files into the new layout in place.
Replay old, recompute new
Section titled “Replay old, recompute new”- Replay old. To reproduce an old answer, restore its pins — SDK,
canon package, model version, adapter — and run
replayCapture(thereplaycommand or the replay endpoint). Replay re-runs the stored query and compares theresulthash; the checksum step separately verifies the stored document bytes. Neither step establishes byte-equality of the old and new documents, and neither checks the capture’s metadata: restoring the recorded pins is the operator’s job, because the code does not verify the installed environment against them. - Recompute new. To answer under new pins, run
evaluateagain and store a new capture file. Never overwrite the old file: the old capture remains the record of what the old pins answered.
old pins + old capture -> replayCapture (must match)new pins + same form -> evaluate (new file in captures/)Cross-SDK replay is out of scope in both directions: a capture saved by TypeScript is replayed by TypeScript, and a capture saved by Python is replayed by Python. The statuses and values agree; the bytes do not. Keep the old pins installed next to the new ones (separate checkouts or separate machines) while old answers must stay reproducible during an upgrade window.
Documentation for Arxo. Writings — blog.arxo.io.
Anonymous visit counts on stats.arxo.io, no cookies.