| name | witness |
| description | Sign, verify, and track fix-marker regressions over time using a deterministic Ed25519 witness manifest. Works in any project โ clone the toolkit, run init, register fixes, regen on each release. |
| argument-hint | init|regen|verify|history [...] |
| allowed-tools | Bash(node *), Read, Write, Edit |
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.yml job witness-verify).
- In your own project โ copy
plugins/ruflo-core/scripts/witness/
into your repo, run init.mjs, register your fixes in
witness-fixes.json, and call regen.mjs from your release pipeline.
Quick start (any project)
node plugins/ruflo-core/scripts/witness/init.mjs --root .
npm i @noble/ed25519
node plugins/ruflo-core/scripts/witness/regen.mjs \
--manifest verification.md.json \
--history verification-history.jsonl \
--fixes witness-fixes.json
node plugins/ruflo-core/scripts/witness/verify.mjs \
--manifest verification.md.json
Temporal queries (ADR-103)
node plugins/ruflo-core/scripts/witness/history.mjs \
--history verification-history.jsonl summary
node plugins/ruflo-core/scripts/witness/history.mjs \
--history verification-history.jsonl regressions
node plugins/ruflo-core/scripts/witness/history.mjs \
--history verification-history.jsonl timeline --id F1
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 via regen.mjs,
otherwise the signature breaks.
- Markers that are too generic (
'function', 'import') โ pick something
unique enough that grep doesn'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.json and
verification-history.jsonl belong 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 |