Witness — cryptographic fix-regression tracking
The witness toolkit lets you ship every release with a signed manifest that lists every documented fix in your codebase along with a sha256 + marker substring. Anyone with the same git commit can re-derive the public key and verify the signature without a committed private key.
A temporal history (JSONL) tracks how the fix population evolves across releases — so when a regression appears, you can pinpoint the commit that introduced it, not just "it's broken now."
This skill works two ways:
- Inside ruflo — used by ruflo's own CI to gate publishes (see
.github/workflows/v3-ci.ymljobwitness-verify). - In your own project — copy
plugins/ruflo-core/scripts/witness/into your repo, runinit.mjs, register your fixes inwitness-fixes.json, and callregen.mjsfrom your release pipeline.
Quick start (any project)
bash# One-time bootstrap — creates verification.md.json, # verification-history.jsonl, and witness-fixes.json template node plugins/ruflo-core/scripts/witness/init.mjs --root . # Edit witness-fixes.json: add { id, desc, file, marker } per fix. # A "marker" is a distinctive substring that MUST appear in `file` # while the fix is present. If someone reverts the fix, the marker # disappears and `verify` reports it as `regressed`. # Regenerate the manifest (signing requires @noble/ed25519) npm i @noble/ed25519 node plugins/ruflo-core/scripts/witness/regen.mjs \ --manifest verification.md.json \ --history verification-history.jsonl \ --fixes witness-fixes.json # Verify markers are present in the live tree node plugins/ruflo-core/scripts/witness/verify.mjs \ --manifest verification.md.json # Or authenticate the manifest and check source markers in a clean clone. # Generated dist/ entries are explicitly reported as skipped. node plugins/ruflo-core/scripts/witness/verify.mjs \ --manifest verification.md.json --source-only
Temporal queries (ADR-103)
bash# Latest snapshot vs. previous node plugins/ruflo-core/scripts/witness/history.mjs \ --history verification-history.jsonl summary # For each currently-regressed fix, find the commit that introduced it node plugins/ruflo-core/scripts/witness/history.mjs \ --history verification-history.jsonl regressions # Status timeline for a specific fix node plugins/ruflo-core/scripts/witness/history.mjs \ --history verification-history.jsonl timeline --id F1 # Machine-readable for CI node plugins/ruflo-core/scripts/witness/history.mjs \ --history verification-history.jsonl summary --json
summary exits non-zero if any fix newly regressed since the last
snapshot — drop it in CI as a soft pre-merge gate.
Anti-patterns
- Hand-editing
verification.md.json— always regenerate viaregen.mjs, otherwise the signature breaks. - Markers that are too generic (
'function','import') — pick something unique enough thatgrepdoesn't false-positive against unrelated code. - Skipping the history append — without
--history, you lose the ability to bisect when a regression was introduced. - Committing one without the other —
verification.md.jsonandverification-history.jsonlbelong in the same commit; the JSONL is what lets future you verify the signed manifest is the latest in the line.
Files
scripts/witness/lib.mjs— shared regenerate / history logic.scripts/witness/regen.mjs— CLI: sign + append history.scripts/witness/history.mjs— CLI: query the temporal log.scripts/witness/init.mjs— CLI: bootstrap into a fresh project.scripts/witness/verify.mjs— CLI: validate signature + markers.
In ruflo's CI
v3-ci.yml job witness-verify runs after the behavioral smoke tests
and before publish. Failure modes:
| Failure | Cause |
|---|---|
signatureValid: no | manifest hand-edited; re-run regen |
regressed: > 0 | a documented fix lost its marker since issuance |
missing: > 0 | a cited dist file no longer exists; rebuild or remove the entry |
scope: source-only | signature + source markers checked; generated entries intentionally skipped |

