Anti-drift diff demo — acceptance evidence (Phase 7A, Step 7A-12)
Status: PASS — all six acceptance criteria proven end-to-end against our own repo guidance,
using the real knowtation flow project CLI on the project-scoped dogfood Flow
flow_overseer_handover.
This directory is the durable evidence for 7A-12. It is reproducible: re-run
run-demo.sh and the same artifacts, diffs, and transcript are regenerated.
- Repo / branch / Muse: Knowtation
feat/flow-projection-pilot@ea6d4206(7A-11b generator). - Generator:
PROJECTION_GENERATOR_VERSION = 1; active harnessescursor_rule,cli_runbook. - Contract:
docs/FLOW-PROJECTION-GENERATOR-CONTRACT-7A-11.md§10 (acceptance bar) + §4 (staleness/drift).
Simple summary (plain language)
A Flow is the one true copy of a procedure kept in Knowtation. A projection is a printout of
that procedure in the exact format one tool wants (a Cursor rule file, an AGENTS.md). We pointed the
printer at our real "overseer handover" procedure, printed both formats, then changed the procedure
once and reprinted. The reprint differed in exactly the one thing we changed and nothing else.
Deleting a printout lost nothing (we reprinted it identically). Scribbling on a printout by hand was
caught and refused. An out-of-date printout was flagged as stale. And when a format genuinely cannot
hold a field, the printer tells you what it left out instead of hiding it.
Technical summary
The deterministic generator (projectFlow pure over (flow, steps, harness, PROJECTION_GENERATOR_VERSION)) renders canonical knowtation.flow/v0 into byte-stable
knowtation.flow_projection/v0 artifacts. The only non-deterministic value (generated_at) lives in
the envelope and is excluded from content_hash and rendered, so diff is meaningful. A canonical
flow-level change + a 0.1.0 → 0.2.0 version bump produced a diff carrying only that change plus
the version marker, on both harnesses. detectDrift (marker-normalized content compare) and
isProjectionStale (semver lag) gate --check with a non-zero exit. Fidelity (dropped_fields) is
honest per harness. No secrets appear in any rendered byte.
Acceptance criteria — results
| # | Criterion (contract §10) | Command (real CLI) | Result |
|---|---|---|---|
| 1 | Generate marker-first, ordered, secret-free artifacts | flow project … --harness cursor_rule/cli_runbook --out … |
✅ both harnesses, marker line first, 6 steps in ordinal order |
| 2 | Edit canonical → regenerate → clean diff | bump 0.1.0→0.2.0, regenerate |
✅ diff = only the changed summary line + the marker version (@0.1.0→@0.2.0) |
| 3 | Delete loses nothing | rm artifact, regenerate |
✅ IDENTICAL — reproduced byte-for-byte |
| 4 | Hand-edit is caught | scribble + --check |
✅ drift: true (edited), exit 1 — never promoted |
| 5 | Staleness surfaces | --version 0.1.0 --check vs latest 0.2.0 |
✅ stale: true, projection 0.1.0 < latest 0.2.0, exit 1 |
| 6 | Fidelity is honest | --json per harness |
✅ cursor_rule drops ["inputs","outputs","requires","when_not_to_run"]; cli_runbook drops [] |
The clean diff (criterion 2) — the keystone proof
cursor_rule (overseer.cursor.v1-to-v2.diff) and
cli_runbook (overseer.runbook.v1-to-v2.diff) each
show two changed lines and nothing else: the canonical summary/description line and the
generated-marker version. No incidental drift, no reordering, no formatting churn.
-<!-- GENERATED FROM CANONICAL FLOW [email protected] (generator v1) — DO NOT EDIT; … -->
+<!-- GENERATED FROM CANONICAL FLOW [email protected] (generator v1) — DO NOT EDIT; … -->
-Docs-first handover … update durable docs, then regenerate …
+Docs-first handover … update the durable docs (ROADMAP snapshot, next-session plan, coordination doc), then regenerate …
Security checks
- No secrets in any artifact. A scan for
token|oauth|refresh_token|api_key|secret|password|bearerover every rendered file returns only the canonical boundary text "No secrets in captured output" / "No secrets in the block" — i.e. the Flow's own instruction, not a leaked credential. - Untrusted step text rendered inert.
</>are HTML-escaped (muse -C <abs path>); no step field is interpreted or able to widen scope from inside the artifact. - Hand edit never promoted (
editable:falseholds; criterion 4) — the only remedy is regenerate.
Full evidence: artifacts/transcript.txt (every command, output, exit code).
What this demo required (and the one wiring gap it closed)
To project the two project-scoped dogfood Flows via the documented CLI, the operator's local
identity must authorize project scope. The contract (FLOW-STORE-CONTRACT-7A-10 §4) specifies this
flows through local config identity (not a CLI flag). The CLI already read
config.flow?.visible_scopes, but loadConfig did not surface a flow key, so that channel was
inert — the documented command could never resolve a project Flow.
Fix (durable, contract-specified — not a demo shim): lib/config.mjs now surfaces
flow.visible_scopes (validated to a clean string array; deny-by-default when absent; empty/malformed
⇒ undefined). Covered by five new cases in test/config.test.mjs
(loadConfig — flow.visible_scopes). The operator grant itself lives in the git/muse-ignored
config/local.yaml (flow.visible_scopes: [personal, project, org]) — the legitimate per-operator
identity, never committed.
Store finding (follow-up, not fixed here — scope fence: demo only)
The 7A-10b store keys step bodies by step_id only, not (step_id, version)
(getFlow resolves vault.steps.filter(s => s.flow_id === flowId), ignoring version; seedStarterFlows
skips a step whose step_id already exists). Consequence: two versions of the same Flow cannot
carry divergent step bodies in a single store — a step-field edit on v0.2.0 silently renders the
v0.1.0 step text.
- Impact on this demo: none for the proof — we made the canonical change at the flow level
(
summary), which the store versions correctly and both harnesses render. Anti-drift is proven honestly. - Why not fixed here: the step record shape is the frozen 7A-10b contract; versioned step storage is a schema change (Tier 2 decision + its own seven-tier slice), explicitly outside the 7A-12 "demo only" fence.
- Recommendation: track as a Knowtation follow-up (suggest
7A-10c— versioned step keying, e.g.(flow_id, version, ordinal)or a per-version steps array) before any surface needs to edit a step in place. It does not block 7A-13 (Scooling loopback read), which reads whole Flows.
Reproduce
cd ~/knowtation
bash docs/evidence/7A-12/run-demo.sh
The driver uses copied starter bundles (demo-starters/v1, demo-starters/v2) and a throwaway
mktemp data store. It does not touch the shipped flows/starter/ bundles, the live data store,
the real AGENTS.md, or .cursor/rules/ — honoring the 7A-12 scope fence.
Files
| Path | What |
|---|---|
run-demo.sh |
Reproducible driver (real CLI; throwaway store) |
demo-starters/v1/, demo-starters/v2/ |
Canonical Flow bundles before/after the one change (0.1.0/0.2.0) |
artifacts/overseer.v0.1.0.mdc, …v0.2.0.mdc |
cursor_rule projections |
artifacts/overseer.AGENTS.v0.1.0.md, …v0.2.0.md |
cli_runbook projections |
artifacts/overseer.cursor.v1-to-v2.diff, …runbook.v1-to-v2.diff |
The clean diffs (criterion 2) |
artifacts/overseer.AGENTS.handedited.md |
Hand-scribbled artifact (criterion 4 input) |
artifacts/transcript.txt |
Full command/output/exit-code transcript |