From 01a05c7b0d523ae4c624ce3a42af9c20d7f31def Mon Sep 17 00:00:00 2001 From: Chris Klapp Date: Thu, 30 Apr 2026 08:50:34 -0400 Subject: [PATCH 1/8] =?UTF-8?q?fix(canon):=20supersede=20encode=20architec?= =?UTF-8?q?ture=20brief=20=E2=80=94=20described=20pre-PR-#96=20state=20as?= =?UTF-8?q?=20if=20current;=20preserved=20with=20addendum=20(Audit=202026-?= =?UTF-8?q?04-30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../encode-architecture-problem-and-gaps.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/architecture/encode-architecture-problem-and-gaps.md b/docs/architecture/encode-architecture-problem-and-gaps.md index 22d24a6..21c02d8 100644 --- a/docs/architecture/encode-architecture-problem-and-gaps.md +++ b/docs/architecture/encode-architecture-problem-and-gaps.md @@ -13,9 +13,23 @@ derives_from: "canon/definitions/dolcheo-vocabulary.md, canon/principles/prompt- complements: "odd/encoding-types/decision.md, odd/encoding-types/observation.md, odd/encoding-types/learning.md, odd/encoding-types/constraint.md, odd/encoding-types/handoff.md, odd/encoding-types/open.md, odd/encoding-types/encode.md" governs: "Implementation brief for the oddkit_encode vodka refactor (Phase 2 of E0008.4). Names the problem, evaluates alternatives, recommends Alternative D — Governance-defined field schemas with format-agnostic serialization." provenance: "Originated in klappy/truthkit-kb at docs/architecture/encode-architecture-problem-and-gaps.md (commit prior to 2026-04-16). Migrated verbatim to klappy.dev as the implementation brief for the oddkit encode refactor, with frontmatter added for canon discoverability. The TruthKit-KB origin is preserved in repo history; this doc is now the oddkit-canonical version." -status: active +status: superseded +superseded_by: "docs/architecture/encode-current-state-2026-04-30.md" +supersession_addendum_at: 2026-04-30 +supersession_reason: "Audit 2026-04-30 — described code state that PR #96 retired on 2026-04-16; failed canon/principles/code-claims-require-code-observation" --- +> **STATUS — SUPERSEDED BY AUDIT 2026-04-30.** This document was published in PR #157 (E0008.4 Phase 1, merged 2026-04-30T05:08:53Z) but described code state that PR #96 in `klappy/oddkit` had retired on 2026-04-16T02:14:13Z. The architectural problem this document analyzes was already resolved before this document was published. See `klappy://canon/principles/code-claims-require-code-observation` for the principle this failure earned, and `klappy://docs/architecture/encode-current-state-2026-04-30` for what the worker actually does today. This document is preserved for postmortem value, not removed. + +**What was wrong:** This brief diagnoses six gaps in the encode parser. As of 2026-04-30 (the day this brief was migrated into klappy.dev canon), five of those six gaps were already resolved in `klappy/oddkit@workers/src/orchestrate.ts` by PR #96 — which had merged two weeks prior, on the same day this brief was authored in `klappy/truthkit-kb`. The brief became stale on arrival and was cited authoritatively across multiple subsequent canon documents and a user-memory entry without any reader verifying against current code state. The audit on 2026-04-30 (afternoon) caught the propagation chain and shipped this supersession. + +**What's still true:** Gap 1's framing ("the parser hardcodes four English keywords against a vocabulary of seven dimensions") is accurate for the Node CLI surface (`klappy/oddkit src/tasks/encode.js`). The CLI is queued for deprecation per `klappy://odd/handoffs/2026-04-30-cli-encode-deprecation` rather than backport. + +**What you should read instead:** `klappy://docs/architecture/encode-current-state-2026-04-30` is the accurate current-state description. `klappy://odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d-revised` scopes the actual remaining Phase 2 work. + +--- + + # Encode Architecture: Problem, Gaps, and Alternatives Analysis > The encode tool's parser and the governance it claims to serve are completely disconnected. The parser recognizes four English keywords via hardcoded regex. The governance defines six extensible dimensions via canon articles. The model does all the categorization work — and the parser throws it away. The fix must make governance the source of truth for encoding behavior: the server searches canon at encode time, dynamically builds extraction patterns from what it finds, teaches the calling model how to structure input, and supports ad-hoc types that any knowledge base can define without server changes. From 47cc941d9f2920f2415faba5011b5bc1c6451dfd Mon Sep 17 00:00:00 2001 From: Chris Klapp Date: Thu, 30 Apr 2026 08:50:35 -0400 Subject: [PATCH 2/8] =?UTF-8?q?fix(canon):=20supersede=20Phase=202=20hando?= =?UTF-8?q?ff=20=E2=80=94=20scoped=20against=20pre-PR-#96=20state;=20prese?= =?UTF-8?q?rved=20with=20addendum=20(Audit=202026-04-30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-04-30-encode-vodka-refactor-alternative-d.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d.md b/odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d.md index d0749c6..da17963 100644 --- a/odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d.md +++ b/odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d.md @@ -12,9 +12,23 @@ date: 2026-04-30 derives_from: "docs/architecture/encode-architecture-problem-and-gaps.md, odd/encoding-types/decision.md, odd/encoding-types/observation.md, odd/encoding-types/learning.md, odd/encoding-types/constraint.md, odd/encoding-types/handoff.md, odd/encoding-types/open.md, odd/encoding-types/serialization-format.md, odd/encoding-types/how-to-write-encoding-types.md, canon/definitions/dolcheo-vocabulary.md, canon/constraints/release-validation-gate.md, canon/constraints/core-governance-baseline.md, odd/ledger/2026-04-20-p1-3-4-encode-canon-parity-landed.md" complements: "odd/handoffs/2026-04-21-p1-3-2-gate-canary.md, odd/handoffs/2026-04-20-p1-3-4-encode-canon-parity.md" governs: "Phase 2 implementation gate for the oddkit_encode vodka refactor: the parser must read encoding-type and serialization-format governance from canon at runtime, parse TSV input against governance-defined field schemas, score per-type quality from governance criteria, return per-type artifacts in a markdown stream, and declare governance_source + governance_uris in the response envelope." -status: active +status: superseded +superseded_by: "odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d-revised.md" +supersession_addendum_at: 2026-04-30 +supersession_reason: "Audit 2026-04-30 — described code state that PR #96 retired on 2026-04-16; failed canon/principles/code-claims-require-code-observation" --- +> **STATUS — SUPERSEDED BY AUDIT 2026-04-30.** This document was published in PR #157 (E0008.4 Phase 1, merged 2026-04-30T05:08:53Z) but described code state that PR #96 in `klappy/oddkit` had retired on 2026-04-16T02:14:13Z. The architectural problem this document analyzes was already resolved before this document was published. See `klappy://canon/principles/code-claims-require-code-observation` for the principle this failure earned, and `klappy://docs/architecture/encode-current-state-2026-04-30` for what the worker actually does today. This document is preserved for postmortem value, not removed. + +**What was wrong:** This handoff scoped a Phase 2 refactor of work that PR #96 had already shipped to `klappy/oddkit` main on 2026-04-16. The acceptance criteria, validator checklist, and pitfalls listed below describe a desired end-state that the worker had largely already reached. The audit on 2026-04-30 (afternoon) traced the citation chain — this handoff inherited its framing from the architecture brief, which inherited it from a state-of-the-world snapshot taken before PR #96. + +**What's still true:** The release-validation-gate requirements named here (Bugbot to completed, Sonnet 4.6 read-only validator via Managed Agents, canon outranks session shortcuts) remain mandatory for Phase 2. The pitfall list (stop-word filters, derivation caches, set-intersection matchers, parallel-release version collisions) remains accurate. + +**What you should read instead:** `klappy://odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d-revised` is the accurate Phase 2 handoff. It scopes five small worker items (envelope plural alignment, dedup-by-letter bug, fallback baseline gap, self-teaching surface, schema-driven check evaluator) plus the Open dedup bug surfaced by the audit. + +--- + + # Handoff — oddkit_encode Vodka Refactor (Alternative D, Governance-Driven Parser, E0008.4 Phase 2) > Phase 1 landed governance into canon. The seven encoding-type articles (D, O, L, C, H, E, Open) and the serialization-format article now carry field schemas, quality criteria, trigger words, and serialization rules — everything the parser needs to be governance-driven. The architecture brief at `klappy://docs/architecture/encode-architecture-problem-and-gaps` recommends Alternative D and resolves the design questions. Phase 2 is the parser refactor that makes the canon the source of truth. From ab0512e1eaae4eb2ed00a11c95279051112d3a05 Mon Sep 17 00:00:00 2001 From: Chris Klapp Date: Thu, 30 Apr 2026 08:50:36 -0400 Subject: [PATCH 3/8] =?UTF-8?q?fix(canon):=20supersede=20Phase=201=20close?= =?UTF-8?q?out=20ledger=20=E2=80=94=20O-04=20inherited=20stale=20framing;?= =?UTF-8?q?=20preserved=20with=20addendum=20(Audit=202026-04-30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...phase-1-encode-governance-migration-landed.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/odd/ledger/2026-04-30-e0008-4-phase-1-encode-governance-migration-landed.md b/odd/ledger/2026-04-30-e0008-4-phase-1-encode-governance-migration-landed.md index 71580fe..30066b8 100644 --- a/odd/ledger/2026-04-30-e0008-4-phase-1-encode-governance-migration-landed.md +++ b/odd/ledger/2026-04-30-e0008-4-phase-1-encode-governance-migration-landed.md @@ -12,9 +12,23 @@ date: 2026-04-30 derives_from: "docs/architecture/encode-architecture-problem-and-gaps.md, odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d.md, odd/ledger/2026-04-20-p1-3-4-encode-canon-parity-landed.md, canon/definitions/dolcheo-vocabulary.md, canon/constraints/release-validation-gate.md" complements: "odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d.md, odd/encoding-types/decision.md, odd/encoding-types/observation.md, odd/encoding-types/learning.md, odd/encoding-types/constraint.md, odd/encoding-types/handoff.md, odd/encoding-types/open.md" governs: "Closeout for Phase 1 of E0008.4 (encode governance migration from truthkit-kb into oddkit canon). Records the canon-only ship that prepares Phase 2 (parser refactor in klappy/oddkit). PR klappy/klappy.dev#157." -status: active +status: superseded +superseded_by: "odd/ledger/2026-04-30-audit-cleanup-encode-artifacts-landed.md" +supersession_addendum_at: 2026-04-30 +supersession_reason: "Audit 2026-04-30 — described code state that PR #96 retired on 2026-04-16; failed canon/principles/code-claims-require-code-observation" --- +> **STATUS — SUPERSEDED BY AUDIT 2026-04-30.** This document was published in PR #157 (E0008.4 Phase 1, merged 2026-04-30T05:08:53Z) but described code state that PR #96 in `klappy/oddkit` had retired on 2026-04-16T02:14:13Z. The architectural problem this document analyzes was already resolved before this document was published. See `klappy://canon/principles/code-claims-require-code-observation` for the principle this failure earned, and `klappy://docs/architecture/encode-current-state-2026-04-30` for what the worker actually does today. This document is preserved for postmortem value, not removed. + +**What was wrong:** This ledger's Observations section (specifically [O-04]) claimed that "the parser still hardcodes the four English keywords... runtime read and parser logic are decoupled in the current implementation." Both halves are wrong as stated. The worker parser was governance-driven via PR #96 (merged 2026-04-16) and its runtime governance reads ARE wired into its parsing logic. The ledger inherited the error from the handoff and the architecture brief, both of which were authored against pre-#96 state. + +**What's still true:** The procedural lessons graduated in this ledger remain valid — L-01 (verbatim migration with provenance frontmatter), L-02 (release-validation-gate's three rules don't apply uniformly to canon-only PRs), L-03 (persist-to-project-storage means canon repo, not download storage), and the C-03 graduation of L-03 to constraint. The Phase 1 ship itself was real — five enriched encoding-type articles, one enriched in place (open.md), one tag sync (serialization-format.md), one architecture brief, one handoff, one ledger. The work landed; the framing of why was wrong. + +**What you should read instead:** `klappy://odd/ledger/2026-04-30-audit-cleanup-encode-artifacts-landed` is the accurate closeout ledger for the cleanup PR that supersedes this one and adds the new constraint that prevents the same chain from forming again. + +--- + + # E0008.4 Phase 1 Closeout — Encode Governance Migration from TruthKit-KB > Phase 1 of E0008.4 shipped as a canon-only PR (klappy/klappy.dev#157, 9 files, +814/-57). The seven encoding-type articles (D, O, L, C, H, E, Open) and the serialization-format article now carry field schemas, TSV serialization examples, expanded trigger words, per-type quality criteria, and narrative sections — exactly what Alternative D needs to be governance-driven. The architecture brief originally written in `klappy/truthkit-kb` is now oddkit canon at `klappy://docs/architecture/encode-architecture-problem-and-gaps`, copied verbatim with klappy.dev frontmatter and a `provenance` field documenting the migration. The Phase 2 implementation handoff is at `klappy://odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d`. No code changes; the parser refactor is Phase 2 in `klappy/oddkit`. From d270c87fee091692cc12fc0fd80f3329514cfe0d Mon Sep 17 00:00:00 2001 From: Chris Klapp Date: Thu, 30 Apr 2026 08:50:37 -0400 Subject: [PATCH 4/8] feat(canon): graduate tier-1 principle code-claims-require-code-observation (Audit 2026-04-30, structural fix for staleness chain) --- .../code-claims-require-code-observation.md | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 canon/principles/code-claims-require-code-observation.md diff --git a/canon/principles/code-claims-require-code-observation.md b/canon/principles/code-claims-require-code-observation.md new file mode 100644 index 0000000..ba9bf8f --- /dev/null +++ b/canon/principles/code-claims-require-code-observation.md @@ -0,0 +1,102 @@ +--- +uri: klappy://canon/principles/code-claims-require-code-observation +title: "Principle — Code Claims Require Code Observation (Canon Does Not Govern Reality)" +audience: canon +exposure: nav +tier: 1 +voice: neutral +stability: stable +tags: ["canon", "principles", "code-observation", "verification", "reality-is-sovereign", "you-cannot-verify-what-you-did-not-observe", "anti-staleness", "epistemic-discipline", "audit-2026-04-30"] +epoch: E0008.4 +date: 2026-04-30 +derives_from: "canon/principles/dry-canon-says-it-once.md, canon/principles/vodka-architecture.md, canon/observations/time-blindness-axiom-violation.md" +complements: "canon/constraints/release-validation-gate.md, canon/principles/contract-governs-handoff-drift.md, canon/methods/supersession.md" +governs: "Any claim that asserts what running code currently does. Architecture briefs, handoffs, ledgers, READMEs, essays, design docs, and prompt-side context all fall under this principle when they describe code behavior." +status: active +--- + +# Principle — Code Claims Require Code Observation + +> Canon governs *what should be*. Code observation is the only ground for claims about *what currently is*. A claim of the form "the parser still hardcodes X," "the worker currently does Y," "tool Z does not yet read governance," is a debt that cannot be paid by reading another canon document — it can only be paid by reading the code at HEAD. Citing canon as evidence of code state is laundering inference into authority. Reality Is Sovereign; canon is not. + +--- + +## Summary — Why This Constraint Exists + +Canon documents are durable. Code is not. A canon document that describes code behavior is correct only at the moment it is written, against the commit it was written against. Every subsequent reader who treats that document as authoritative without re-verifying against current code is one link further from observation. After enough links, a stale claim has the social weight of consensus and the actual weight of zero — but the system can no longer tell which. + +This is the failure mode that caused the Audit 2026-04-30 cleanup. An architecture brief in `klappy/truthkit-kb` was written on 2026-04-16 against an encode parser state that PR #96 in `klappy/oddkit` retired the same day. The brief described that retired state as the current problem. The brief was cited by P1.3.4's H-01 handoff (2026-04-20) as authoritative on current code state. P1.3.4's handoff was cited by user memory. User memory was cited by the model in a planning conversation (2026-04-30) without anyone in the chain reading the actual code. Phase 1 of E0008.4 then propagated the stale framing into oddkit canon, where it sat for less than an hour before the operator caught the inconsistency and asked the model to read the code. By that point, three published canon artifacts had been written against fiction. + +The chain failed at every link, but no individual link was negligent in the conventional sense — each one trusted its source, which trusted its source, which trusted its source. The structural fix is to refuse to ratify any code-state claim without an independent code observation. Canon is not allowed to be the only evidence for a claim about what code does. + +--- + +## The Test + +Before any assertion of the form "the X currently does Y," ask: did I read the code, or did I read a document that told me the code does Y? If the latter, the assertion is unverified. Refuse it, or read the code. + +This is not pedantry. It is the same axiom as `klappy://canon/observations/time-blindness-axiom-violation` ("never substitute inference for observation"), applied to the code surface. The axiom doesn't care whether the inference came from chronological context, social context, or document context. Inference is not observation, ever, regardless of how authoritative its source feels. + +--- + +## Practical Application + +**For any canon document that describes code behavior:** include `describes_state_at: ` in frontmatter. Future readers can compare against current HEAD and detect potential staleness mechanically. (`oddkit_audit` may eventually surface this; not blocking on that.) + +**For any model conversation in execution mode:** before claiming "the tool does X," fetch the code. `git clone --depth 1` is cheap. `curl https://api.github.com/.../contents/path` is cheaper. No claim about code state may be sourced exclusively from canon, ever. + +**For any model conversation in planning mode:** when a handoff or architecture brief asserts a code-state claim, treat it as a hypothesis to verify, not a fact to plan around. The cost of one code read is nothing compared to the cost of planning a refactor of code that has already been refactored. + +**For any author of a new canon document:** if the document makes a claim about current code state, cite the commit you read. Do not cite another document that made the claim before you. Re-observe. + +--- + +## Anti-Patterns This Principle Forbids + +- "The parser currently does X." (Source: another canon document.) +- "The tool still hardcodes Y." (Source: a handoff written six versions ago.) +- "The worker doesn't yet read governance from canon." (Source: an architecture brief from a different repo, written the same day a PR resolved that exact problem in this repo.) +- "Per the existing implementation, Z is the case." (Source: a README that was last updated two minor versions ago.) + +In every case, the fix is the same: read the code. Then either ratify the claim or correct it. + +--- + +## Anti-Patterns This Principle Permits + +- "Per `canon/principles/vodka-architecture`, the design intent is that..." — canon governs intent. +- "The release-validation-gate constraint requires..." — canon governs constraints. +- "DOLCHEO defines seven dimensions..." — canon governs definitions. +- "The handoff at klappy://... names the scope as..." — canon governs scope statements. + +Canon governs intent, constraint, definition, plan, decision. Canon does not govern code behavior. Two different epistemic categories. Do not collapse them. + +--- + +## Relationship to Existing Canon + +This principle complements rather than replaces: + +- **Reality Is Sovereign** (Axiom 1) — the foundational version of this rule across all domains. This principle applies it specifically to the code-vs-canon interface. +- **You Cannot Verify What You Did Not Observe** (Axiom 4) — the verification half. This principle names the most common shape of the violation: substituting document-reading for code-reading. +- **DRY: Canon Says It Once** (`klappy://canon/principles/dry-canon-says-it-once`) — protects canon from self-redundancy. This principle protects canon from claiming authority it doesn't possess. +- **Vodka Architecture** (`klappy://canon/principles/vodka-architecture`) — the structural reason canon must not embed code claims: canon is meant to be slow and stable; code is meant to be fast and replaceable. Mixing the two corrupts both. +- **Time-Blindness Axiom Violation** (`klappy://canon/observations/time-blindness-axiom-violation`) — the observation that motivated the `oddkit_time` first-call rule. This principle is the same shape: substituting inference for observation, this time for code state instead of clock state. + +--- + +## How This Principle Was Earned + +Audit 2026-04-30 traced six links of citation across two repositories before any reader stopped to verify. The architecture brief was correct on the day it was written, stale within hours, and cited as authoritative for two weeks. PR #157 (E0008.4 Phase 1) shipped the stale framing into klappy.dev canon before the operator's question — "Why wasn't the journal included?" — opened the second-order audit that found the deeper rot. The cleanup PR that this principle ships within supersedes three artifacts and adds this constraint so the same chain cannot form again without immediate detection. + +The lesson is not that the original brief was wrong. The lesson is that no document, no matter how recent or authoritative, can substitute for direct observation of code state. Code state moves; canon does not. + +--- + +## See Also + +- [Audit 2026-04-30 Cleanup Ledger](klappy://odd/ledger/2026-04-30-audit-cleanup-encode-artifacts-landed) — the cleanup that earned this principle +- [Reality Is Sovereign](klappy://canon/axioms/reality-is-sovereign) — Axiom 1 +- [You Cannot Verify What You Did Not Observe](klappy://canon/axioms/verify-what-you-observed) — Axiom 4 +- [DRY: Canon Says It Once](klappy://canon/principles/dry-canon-says-it-once) — companion principle on canon's epistemic role +- [Time-Blindness Axiom Violation](klappy://canon/observations/time-blindness-axiom-violation) — same-shape violation in a different domain From 41f2ec95c456c573fa947c066ac877a0df8e9e43 Mon Sep 17 00:00:00 2001 From: Chris Klapp Date: Thu, 30 Apr 2026 08:50:38 -0400 Subject: [PATCH 5/8] feat(canon): current-state encode architecture doc, sourced by direct code observation at klappy/oddkit@1a1f093 (Audit 2026-04-30) --- .../encode-current-state-2026-04-30.md | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 docs/architecture/encode-current-state-2026-04-30.md diff --git a/docs/architecture/encode-current-state-2026-04-30.md b/docs/architecture/encode-current-state-2026-04-30.md new file mode 100644 index 0000000..1acdf2a --- /dev/null +++ b/docs/architecture/encode-current-state-2026-04-30.md @@ -0,0 +1,115 @@ +--- +uri: klappy://docs/architecture/encode-current-state-2026-04-30 +title: "Encode Current State (2026-04-30) — Governance-Driven Worker, Stale CLI, Five Remaining Items" +audience: docs +exposure: nav +tier: 2 +voice: neutral +stability: semi_stable +tags: ["odd", "oddkit", "encode", "architecture", "current-state", "vodka-architecture", "governance-driven", "code-observation", "audit-2026-04-30", "epoch-8.4"] +epoch: E0008.4 +date: 2026-04-30 +describes_state_at: "klappy/oddkit@1a1f093 (main, 2026-04-29) and klappy/klappy.dev@125cf8d1 (main, 2026-04-30, post-PR-#157)" +derives_from: "canon/principles/code-claims-require-code-observation.md, docs/architecture/encode-architecture-problem-and-gaps.md" +complements: "odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d-revised.md, odd/handoffs/2026-04-30-cli-encode-deprecation.md" +supersedes: "docs/architecture/encode-architecture-problem-and-gaps.md" +governs: "Authoritative current-state description of the encode tool surface across both the Cloudflare Workers MCP server and the Node CLI MCP server. Replaces the predecessor architecture brief, which described a pre-PR-#96 state retired on 2026-04-16." +status: active +--- + +# Encode Current State (2026-04-30) + +> The Cloudflare Workers MCP encode handler is governance-driven and has been since PR #96 merged on 2026-04-16T02:14:13Z. It discovers encoding types from canon at runtime, parses three input shapes (DOLCHEO-prefixed batches, TSV, unstructured prose), scores per-type quality from canon-defined criteria, and emits per-artifact markdown. Five small items remain (envelope plural alignment, dedup-by-letter bug, fallback baseline gap, self-teaching surface, schema-driven check evaluation). The Node CLI surface (`src/tasks/encode.js`) still uses the pre-#96 four-keyword regex and is queued for deprecation. This document supersedes the predecessor architecture brief, which described pre-#96 state as if it were current. + +--- + +## Summary — What Is True Today, Verified by Reading the Code + +This document was written by reading `klappy/oddkit` HEAD on 2026-04-30. Specifically: `workers/src/orchestrate.ts` lines 434–560 (governance discovery), 1150–1330 (parsers + quality scorer), 3235–3340 (action handler); and `src/tasks/encode.js` (legacy CLI). Every claim of code behavior in this document corresponds to a specific function or line range that was directly observed at the cited commits. + +This is the discipline named in `klappy://canon/principles/code-claims-require-code-observation`, the principle that ships in the same PR as this document. The predecessor brief did not follow that discipline; this one does. + +--- + +## What the Worker Encode Handler Actually Does + +`runEncodeAction` in `workers/src/orchestrate.ts:3235` orchestrates four phases: discover encoding types from canon, choose a parser based on input shape, score each parsed artifact, emit per-artifact markdown. + +**Phase 1 — Governance discovery (`discoverEncodingTypes`, line 434).** The function reads the canon index, filters for entries tagged `encoding-type` whose path includes `encoding-types/`, fetches each article, parses the Letter and Name from the Type Identity table, parses trigger words from the Trigger Words section's code block, parses quality criteria from the Quality Criteria table, and stems each trigger word into ordered token sequences for runtime matching. Falls back to a six-letter inline baseline (D, O, L, C, H, E) when canon is unreachable, declaring `governance_source: "minimal"` honestly. **One known bug:** the function dedupes by letter alone (line 512), so when both `observation.md` and `open.md` register letter `O`, `open.md`'s quality criteria are silently dropped — Open is registered in name only, scored against Observation's criteria. + +**Phase 2 — Parser cascade (line 3253).** Three parsers, selected in order: `parsePrefixedBatchInput` (DOLCHEO `[D]/[O]/[L]/[C]/[H]/[E]/[O-open]` tags, line 1150), `parseStructuredInput` (TSV, line 1213), `parseUnstructuredInput` (prose, line 1225). The unstructured parser stems each paragraph once, then for each type checks whether the type's stemmed phrase set intersects the paragraph's stemmed token set. Multi-typing is intentional — a paragraph matching multiple types is emitted as multiple artifacts, mirroring what an LLM would do with separate TSV rows. Stop-word filtering is disabled on both sides per the P1.3.3 lesson. + +**Phase 3 — Quality scoring (`scoreArtifactQuality`, line 1259).** Each artifact is scored against its type's quality criteria. The scorer interprets each criterion's `check` string by hardcoded keyword matching (`check.includes("non-empty")`, `check.includes("10")`, `check.includes("number")`, etc.). This is the one place where canon governance is read but interpreted opinionatedly by the server — a vodka-architecture imperfection that works correctly for the current criteria but constrains how new criteria can be authored. When `context` is provided, criteria evaluate against `body + context` so background information counts toward quality without becoming separate artifacts. + +**Phase 4 — Markdown emission and envelope.** Per-artifact sections with type, name, quality level, body, gaps, and suggestions. Envelope declares `governance_source` (`"knowledge_base"` or `"minimal"`) and `governance_uri` (singular, `"klappy://canon/definitions/dolcheo-vocabulary"`). State updated to track encoded artifact tags. + +--- + +## What the Predecessor Brief Got Right and Wrong + +The predecessor brief at `klappy://docs/architecture/encode-architecture-problem-and-gaps` was authored against a pre-PR-#96 state of the worker. PR #96 (`feat: governance-driven encode architecture`) merged on 2026-04-16T02:14:13Z and resolved most of the brief's six gaps before the brief was migrated into klappy.dev canon on 2026-04-30. Mapping the brief's six gaps against current reality: + +**Gap 1 (parser knows 4 types, hardcoded regex):** Resolved in the worker by `discoverEncodingTypes`. Still true in the CLI (`src/tasks/encode.js:22`), which is queued for deprecation per `klappy://odd/handoffs/2026-04-30-cli-encode-deprecation`. + +**Gap 2 (single-blob output):** Resolved. Three parsers emit per-row/per-paragraph artifacts. + +**Gap 3 (no discovery mechanism):** Resolved. `discoverEncodingTypes` is the discovery mechanism, indexed by the `encoding-type` frontmatter tag. + +**Gap 4 (model can't learn from governance):** Partially resolved. The result envelope returns letter and name for each governance type, which lets the model learn the registry. Field schemas, quality criteria, and serialization format are NOT returned, so the model has no self-teaching loop for input format or scoring rubric. This is one of the five remaining items. + +**Gap 5 (monolithic quality scoring):** Resolved with a caveat. Per-type scoring works correctly. The hardcoded keyword interpretation of criterion `check` strings is a structural debt, not a behavioral defect. + +**Gap 6 (ad-hoc types are fiction):** Resolved. Any new article tagged `encoding-type` is auto-discovered. + +The brief's recommended Alternative D was effectively the implementation that PR #96 shipped. The brief was correct; it was just describing a problem that was already solved. + +--- + +## The Five Remaining Worker-Side Items + +Listed in priority order. All five are small. None individually justifies a major refactor; together they constitute Phase 2 of E0008.4. + +**Item 1 — `governance_uris` plural array (envelope alignment).** The challenge action (P1.3.1) and the gate action (P1.3.2) declare `governance_uris: string[]`, an alphabetical-by-path array of every peer governance document consulted at runtime. The encode action declares only `governance_uri: "klappy://canon/definitions/dolcheo-vocabulary"` (singular, single value, not the dynamic list of files actually read). This is a contract inconsistency with the canary precedent. Fix: emit `governance_uris` as an alphabetical array of the eight to nine encoding-type articles + `serialization-format.md` actually consulted on the request, retain `governance_uri` for one minor as a deprecation alias. + +**Item 2 — Dedup-by-letter bug drops Open's quality criteria.** `discoverEncodingTypes` keeps the first article per letter, so `observation.md` (alphabetically prior) wins over `open.md`. Open's five quality criteria are never applied; Open artifacts are scored against Observation's four. Fix: dedup by `(letter, facet)` pair instead of letter alone, with `facet` read from frontmatter. Keep Observation as letter `O` with no facet (or `facet: closed`), keep Open as letter `O` with `facet: open`. Scorer selects criteria by full pair. + +**Item 3 — Inline fallback baseline missing seventh entry.** `discoverEncodingTypes` fallback registers only the original six letters (D, O, L, C, H, E). Open is not in the bundled fallback. When canon is unreachable, the tool reports six types instead of seven. Fix: add Open as a `(letter: "O", facet: "open", name: "Open", ...)` entry to the fallback array, with the dedup logic from Item 2 in place to keep both O entries. + +**Item 4 — Self-teaching surface (Gap 4 finish).** Return field schemas, per-type quality criteria, and the serialization-format article URI in the encode result envelope so the model can learn the input format and scoring rubric from a single tool call rather than needing a separate `oddkit_get` per article. Format: `governance_extended: { types: [{ letter, facet, name, fieldSchema, qualityCriteria, triggerWords }, ...], serializationFormatUri }`. Optional response field; gated by a request param to avoid token bloat for callers who don't need it. + +**Item 5 — Schema-driven `check` evaluator.** Replace the hardcoded `check.includes("...")` keyword matching in `scoreArtifactQuality` with a small evaluator that understands a defined vocabulary of primitives (`field_X_non_empty`, `body_words_gte_N`, `body_matches_pattern_Y`, `body_does_not_contain_Z`). Update existing canon Quality Criteria tables to use the structured form. Fully resolves the vodka-architecture imperfection — server stops opinionating on what `check` strings mean. This item is the largest of the five and is the principled close on Phase 2; can be deferred to 0.29.0 if Phase 2 is otherwise ready to ship. + +--- + +## What the CLI Encode Path Actually Does + +`src/tasks/encode.js:detectEncodeType` (line 22) is the original four-keyword regex — `decision`, `insight`, `boundary`, `override`. Wired via `src/mcp/orchestrate.js:22` and `src/core/actions.js:17`. Same MCP tool name as the worker; entirely different implementation. The CLI is the only surface where the predecessor brief's framing remains accurate, and it is queued for deprecation rather than backport per operator decision. + +See `klappy://odd/handoffs/2026-04-30-cli-encode-deprecation` for the deprecation timeline. + +--- + +## Provenance and Verification Path + +This document was authored by directly reading the following files at the cited commits, in this order: + +1. `klappy/oddkit@1a1f093:workers/src/orchestrate.ts` — confirmed `discoverEncodingTypes`, three parsers, scorer, action handler signatures and bodies. +2. `klappy/oddkit@1a1f093:src/tasks/encode.js` — confirmed CLI parser is unchanged from pre-#96 state. +3. `klappy/oddkit@1a1f093:CHANGELOG.md` — confirmed PR #96 merge timing (no entry; verified via GitHub API). +4. GitHub API — confirmed PR #96 merged 2026-04-16T02:14:13Z to klappy/oddkit main. +5. Live `oddkit_encode` call against the production worker — confirmed `governance_source: "knowledge_base"`, six letters returned, Open dedup bug observable. +6. `klappy/klappy.dev@125cf8d1:odd/encoding-types/open.md` — confirmed Open has 5 criteria (vs Observation's 4) so the dedup bug is detectable from output alone. + +Anyone validating this document should re-walk steps 1, 2, and 5 against the then-current HEAD before treating its claims as load-bearing for future planning. + +--- + +## See Also + +- [Code Claims Require Code Observation](klappy://canon/principles/code-claims-require-code-observation) — the principle this document operationalizes +- [Encode Architecture Problem and Gaps (Superseded)](klappy://docs/architecture/encode-architecture-problem-and-gaps) — the predecessor brief, kept for postmortem value +- [Audit 2026-04-30 Cleanup Ledger](klappy://odd/ledger/2026-04-30-audit-cleanup-encode-artifacts-landed) — the cleanup PR this document ships within +- [Phase 2 Revised Handoff](klappy://odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d-revised) — the actual remaining work +- [CLI Encode Deprecation Handoff](klappy://odd/handoffs/2026-04-30-cli-encode-deprecation) — the CLI retirement path +- PR #96 (klappy/oddkit) — `feat: governance-driven encode architecture`, merged 2026-04-16T02:14:13Z +- PR #157 (klappy/klappy.dev) — E0008.4 Phase 1, merged 2026-04-30T05:08:53Z From 5d676e1af2686091e38d052214142abf7b60b2d7 Mon Sep 17 00:00:00 2001 From: Chris Klapp Date: Thu, 30 Apr 2026 08:50:39 -0400 Subject: [PATCH 6/8] feat(canon): revised Phase 2 handoff scoping five small worker items + Open dedup bug, target oddkit 0.28.0 (Audit 2026-04-30) --- ...de-vodka-refactor-alternative-d-revised.md | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d-revised.md diff --git a/odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d-revised.md b/odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d-revised.md new file mode 100644 index 0000000..3a839f2 --- /dev/null +++ b/odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d-revised.md @@ -0,0 +1,152 @@ +--- +uri: klappy://odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d-revised +title: "Handoff (Revised) — oddkit_encode Phase 2 (Five Worker Items + Open Dedup Bug, Scoped Against Real Code State)" +audience: docs +exposure: nav +tier: 2 +voice: neutral +stability: semi_stable +tags: ["odd", "handoff", "session", "epoch-8.4", "p2-encode-vodka", "oddkit-encode", "alternative-d", "governance-driven", "release-validation-gate", "managed-agent-validation", "audit-2026-04-30", "revised"] +epoch: E0008.4 +date: 2026-04-30 +describes_state_at: "klappy/oddkit@1a1f093 (main, 2026-04-29) and klappy/klappy.dev@125cf8d1 (main, 2026-04-30, post-PR-#157)" +derives_from: "docs/architecture/encode-current-state-2026-04-30.md, canon/principles/code-claims-require-code-observation.md, canon/constraints/release-validation-gate.md, canon/constraints/core-governance-baseline.md" +complements: "docs/architecture/encode-current-state-2026-04-30.md, odd/handoffs/2026-04-30-cli-encode-deprecation.md" +supersedes: "odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d.md" +governs: "Phase 2 implementation gate for the oddkit_encode worker — the five small remaining items (envelope plural alignment, dedup-by-letter bug, fallback baseline gap, self-teaching surface, schema-driven check evaluator) plus the dedup bug surfaced by Audit 2026-04-30. CLI deprecation is out of scope per separate handoff. Replaces the predecessor handoff, which scoped against pre-PR-#96 state." +status: active +--- + +# Handoff (Revised) — oddkit_encode Phase 2 + +> The Worker encode handler has been governance-driven since PR #96 merged on 2026-04-16. The predecessor handoff scoped a refactor of work that was already done. This revised handoff scopes the actual remaining surface — five small worker items plus one bug surfaced by Audit 2026-04-30 (Open's quality criteria silently dropped by dedup-by-letter). CLI deprecation is queued in a separate handoff per operator decision. Target version: 0.28.0. + +--- + +## Summary — What's Actually Left + +Read `klappy://docs/architecture/encode-current-state-2026-04-30` first. It describes what the worker actually does at HEAD, mapped against the predecessor brief's six gaps. Five are resolved; one (Gap 4, model self-teaching) is partially resolved; the predecessor handoff missed an additional bug (Open dedup) that the audit caught. + +Five items, in priority order, all small. Items 1–3 are mandatory for Phase 2; item 4 is the principled close on Gap 4; item 5 (the schema-driven evaluator) is the largest and may slide to 0.29.0 if Phase 2 is otherwise ready to ship. + +--- + +## Items + +### Item 1 — `governance_uris` plural array (envelope alignment) + +The challenge action (P1.3.1) and gate action (P1.3.2) declare `governance_uris: string[]`, an alphabetical-by-path array of every peer governance document consulted at runtime. Encode declares only `governance_uri: "klappy://canon/definitions/dolcheo-vocabulary"` (singular, single static value). + +**Fix:** In `runEncodeAction`, build an alphabetical array of every encoding-type article URI actually fetched plus `klappy://odd/encoding-types/serialization-format` plus `klappy://odd/encoding-types/how-to-write-encoding-types`. Emit as `governance_uris`. Retain `governance_uri` as a deprecation alias for one minor (0.28.0 ships both; 0.29.0 removes the singular). + +**Acceptance:** Smoke encode call returns `governance_uris` containing the eight or nine actual files consulted, alphabetical. Cursor Bugbot diff against the challenge/gate envelope shape passes structural parity. + +### Item 2 — Dedup-by-letter bug drops Open's quality criteria + +`discoverEncodingTypes` at `workers/src/orchestrate.ts:512` dedupes by letter alone. When both `observation.md` and `open.md` register letter `O`, alphabetical iteration keeps `observation.md`'s criteria (4) and silently drops `open.md`'s (5). Open is registered in name only. + +**Verification of the bug:** A live `oddkit_encode` call with input `[O-open P1] ` returns `quality.score: 4, maxScore: 4` — Observation's max, not Open's 5. Direct evidence the bug is shipping in production today. + +**Fix:** Dedup by `(letter, facet)` pair. Read `facet` from frontmatter on each encoding-type article. Keep Observation as `(O, undefined)` or `(O, "closed")`; keep Open as `(O, "open")`. Scorer selects criteria by full pair, matching the `facet` field set by the prefix parser on each parsed artifact. + +**Acceptance:** Same `oddkit_encode` call with `[O-open P1]` input now returns `maxScore: 5` and applies Open's five criteria (Substance, Priority assigned, Closure path, Specificity, Owner clarity). Observation calls (`[O]` prefix or unstructured) continue to apply Observation's four. Regression test added against the canon URIs that surfaced the bug. + +### Item 3 — Inline fallback baseline missing seventh entry + +`discoverEncodingTypes` fallback (the `defaults` array at line ~538) registers only D, O, L, C, H, E. Open is missing. When canon is unreachable, the tool drops to six types instead of seven, and the prefix parser's `[O-open]` tag falls through to the Observation handler. + +**Fix:** Add a seventh entry to the `defaults` array with `letter: "O"`, `facet: "open"`, `name: "Open"`, and Open's trigger words from canon. Requires Item 2's dedup-by-pair to be in place first or the new entry will be dropped by the existing dedup. + +**Acceptance:** Worker booted with canon unreachable (test by pointing `knowledge_base_url` at a 404 endpoint) returns seven types in `governance` envelope, including Open with its facet. + +### Item 4 — Self-teaching surface (close Gap 4) + +Currently `governance` envelope returns only `[{ letter, name }]` per type. Field schemas, quality criteria, and serialization format are not surfaced, so the model learns the registry but not the input format or the scoring rubric. Forces the model to make separate `oddkit_get` calls per article to learn how to write good encodings. + +**Fix:** Add an optional response field `governance_extended: { types: [{ letter, facet, name, fieldSchema, qualityCriteria, triggerWords }], serializationFormatUri, howToWriteUri }`. Gated by a request param `include_governance_details: boolean` (default false) to avoid token bloat for callers who already know the format. When true, the response includes the parsed schemas and criteria from canon directly. + +**Acceptance:** `oddkit_encode` called with `include_governance_details: true` returns the full self-teaching payload. Same call without the flag returns the existing minimal envelope. Token-count regression smoke confirms no bloat for default callers. + +### Item 5 — Schema-driven `check` evaluator (defer-eligible) + +`scoreArtifactQuality` at line 1259 interprets criterion `check` strings by hardcoded keyword matching: `check.includes("non-empty")`, `check.includes("10")`, `check.includes("number")`, `check.includes("interpretation")`, `check.includes("prohibition")`. Works for current criteria; constrains how new criteria can be authored. + +**Fix:** Define a small evaluator vocabulary of primitives — `field_X_non_empty`, `body_words_gte_N`, `body_matches_pattern_Y`, `body_does_not_contain_Z`, `field_X_matches_pattern_Y`, `priority_band_present`. Update existing canon Quality Criteria tables to use this structured form alongside the human-readable text (machine-readable column added). Evaluator becomes a pure function of `(criterion, artifact)` with no hardcoded keyword interpretation. + +**Defer condition:** If Items 1–4 land cleanly and the schema-driven evaluator becomes a substantial implementation in its own right, ship Phase 2 as 0.28.0 with Items 1–4 only and queue Item 5 as Phase 3 / 0.29.0. Operator decides at the gate. + +**Acceptance (when shipped):** `scoreArtifactQuality` contains zero `check.includes(...)` calls. All criteria evaluation flows through the primitive vocabulary. Canon migration of existing Quality Criteria tables ships in the same PR (in klappy.dev) so the old `check` strings don't sit in canon as dead syntax. + +--- + +## Release Validation Gate — Mandatory + +This refactor touches `orchestrate.ts`, the matcher implementation (Item 2), governance reads (Item 1, Item 4), the response envelope (Items 1, 4), and action behavior (all five items). Per `klappy://canon/constraints/release-validation-gate` (tier 1): + +1. **Cursor Bugbot must reach `completed` before promotion merge.** `in_progress` is not non-blocking. +2. **Independent Sonnet 4.6 read-only validator agent must be dispatched via Managed Agents before promotion merge.** Same-session smoke and self-calls do not satisfy. Fresh-context validation per `klappy://canon/principles/verification-requires-fresh-context`. +3. **Canon outranks session-scoped recommendations.** If the session ledger ends up suggesting a shortcut on either of the above, surface the conflict and follow canon. + +The validator agent should specifically confirm: + +- `governance_uris` is an alphabetical array of actually-consulted articles (Item 1). +- `[O-open P1]` input scores against Open's 5 criteria, not Observation's 4 (Item 2). +- Worker with unreachable canon returns 7 types including Open (Item 3). +- `include_governance_details: true` returns parsed field schemas and criteria; absence returns minimal envelope (Item 4). +- If Item 5 shipped: zero `check.includes(...)` calls in `scoreArtifactQuality`. + +--- + +## Out of Scope + +- **CLI deprecation.** Separate handoff at `klappy://odd/handoffs/2026-04-30-cli-encode-deprecation`. Operator decision is deprecation, not parity. +- **LLM-in-the-loop encoding.** Alternative E in the predecessor brief; TruthKit territory, not oddkit. +- **Schema enforcement that rejects unknown fields.** Server should be permissive; extra fields surface as warnings, not errors. +- **Removal of `governance_uri` (singular).** 0.28.0 retains it as a deprecation alias; 0.29.0 removes. +- **Phase 1 supersession of older articles.** Already handled in PR #157 by in-place replacement; no chain needed. +- **P11 (gate mechanical enforcement of release-validation-gate).** Separate next-epoch capability. + +--- + +## Pitfalls Carried Forward from the Sweep + +These bit during P1.3.1 through P1.3.4 and remain live for any orchestrate.ts change: + +- **Stop-word filters silently destroy short trigger words.** Tokenize with stop-words disabled on both sides when vocabulary contains words like "to," "in," "of." See P1.3.3 prod-break. +- **Module-memory caches that derive structure on first request lie about cache hits.** Don't introduce new derivation caches; rebuild per request from cached canon. +- **Set-intersection is the canon-parity matcher, not regex.** Stem both sides, take the intersection of token sets, threshold. Regex is the unstructured fallback only. +- **Bugbot autofix design over orchestrator design.** When Bugbot proposes an autofix, prefer it unless canon names a reason for divergence. +- **Parallel-release version collisions.** Confirm 0.28.0 isn't already cut on prod before opening the PR. + +--- + +## Successor Pattern + +When Phase 2 ships clean to prod: + +1. Open closeout ledger at `odd/ledger/2026-MM-DD-encode-vodka-refactor-phase-2-landed.md` mirroring `klappy://odd/ledger/2026-04-20-p1-3-4-encode-canon-parity-landed`. +2. Flip this handoff's frontmatter to `status: superseded`, `superseded_by: `. +3. Update `oddkit_encode` tool description to reflect new envelope (`governance_uris` plural, `include_governance_details` param). +4. Update `klappy://docs/architecture/encode-current-state-2026-04-30` to reflect the new state, OR supersede with a fresh current-state doc dated to the merge. +5. If CLI deprecation hasn't shipped yet, decide whether Phase 2 unblocks or accelerates the deprecation timeline. + +--- + +## Open Items (carried forward to next session) + +| Tag | Description | Priority | +|---|---|---| +| O-open | Confirm 0.28.0 is the right minor version before opening the PR (parallel-release check). | P1 | +| O-open | Decide at the gate whether Item 5 ships in 0.28.0 or defers to 0.29.0. Depends on Items 1–4 implementation cost. | P1 | +| O-open | After Phase 2 lands: TruthKit-KB sync — replace its older D/O/L/C/H/Q articles with the now-canonical oddkit versions, or maintain divergence intentionally. | P3 | + +--- + +## See Also + +- [Encode Current State (2026-04-30)](klappy://docs/architecture/encode-current-state-2026-04-30) — what the worker actually does today +- [Code Claims Require Code Observation](klappy://canon/principles/code-claims-require-code-observation) — the principle that prevents the next stale-handoff cycle +- [Audit 2026-04-30 Cleanup Ledger](klappy://odd/ledger/2026-04-30-audit-cleanup-encode-artifacts-landed) — the cleanup that surfaced the dedup bug and the staleness chain +- [CLI Encode Deprecation Handoff](klappy://odd/handoffs/2026-04-30-cli-encode-deprecation) — the parallel CLI retirement path +- [P1.3.4 Closeout — Encode Canon-Parity](klappy://odd/ledger/2026-04-20-p1-3-4-encode-canon-parity-landed) — prior ship in the encode arc +- [Release Validation Gate](klappy://canon/constraints/release-validation-gate) — gate mandatory for this refactor From 0e9a7a8346c04ee1a3720f0401cab907446956bc Mon Sep 17 00:00:00 2001 From: Chris Klapp Date: Thu, 30 Apr 2026 08:50:40 -0400 Subject: [PATCH 7/8] feat(canon): CLI encode deprecation handoff per operator decision, telemetry-gated removal target 0.30.0 (Audit 2026-04-30) --- .../2026-04-30-cli-encode-deprecation.md | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 odd/handoffs/2026-04-30-cli-encode-deprecation.md diff --git a/odd/handoffs/2026-04-30-cli-encode-deprecation.md b/odd/handoffs/2026-04-30-cli-encode-deprecation.md new file mode 100644 index 0000000..2f4446c --- /dev/null +++ b/odd/handoffs/2026-04-30-cli-encode-deprecation.md @@ -0,0 +1,90 @@ +--- +uri: klappy://odd/handoffs/2026-04-30-cli-encode-deprecation +title: "Handoff — Deprecate Node CLI Encode Path (src/tasks/encode.js Consumers, Worker Is Source of Truth)" +audience: docs +exposure: nav +tier: 2 +voice: neutral +stability: semi_stable +tags: ["odd", "handoff", "session", "epoch-8.4", "cli-deprecation", "node-cli", "src-tasks-encode-js", "vodka-architecture", "single-source-of-truth", "audit-2026-04-30"] +epoch: E0008.4 +date: 2026-04-30 +derives_from: "canon/principles/code-claims-require-code-observation.md, odd/ledger/2026-04-30-audit-cleanup-encode-artifacts-landed.md, docs/architecture/encode-current-state-2026-04-30.md" +complements: "docs/architecture/encode-current-state-2026-04-30.md" +governs: "Deprecation path for the Node CLI encode tool surface (klappy/oddkit src/tasks/encode.js, src/mcp/orchestrate.js, src/core/actions.js encode handlers). Worker (workers/src/orchestrate.ts runEncodeAction) is the single source of truth for encode behavior." +status: active +--- + +# Handoff — Deprecate Node CLI Encode Path + +> The Cloudflare Workers MCP server (`workers/src/orchestrate.ts:runEncodeAction`) is governance-driven and current. The Node CLI MCP server (`src/tasks/encode.js`, wired via `src/mcp/orchestrate.js` and `src/core/actions.js`) still uses the original four-keyword `detectEncodeType` regex. Same tool name, two surfaces, divergent behavior. The audit confirmed this; the operator confirmed deprecation is the right path. This handoff queues the work. + +--- + +## Summary — What and Why + +The CLI encode path is not just stale — it is structurally inconsistent with the canon-driven worker. Maintaining two implementations of the same MCP tool is a vodka-architecture violation: the code surface that consumes the canon should be a single thin server, not two diverging ones. Operator decision is to deprecate the CLI path rather than port it. + +This is not a Phase 2 blocker. The CLI is rarely used (consumer count unknown but presumed near-zero — the production deployment is the worker). Deprecation can run on its own timeline, gated only by confirming there are no active CLI consumers. + +--- + +## Scope + +**In scope:** + +1. Add a deprecation notice to `src/tasks/encode.js` (top-of-file JSDoc warning + console.warn at runtime). +2. Add a deprecation notice to `src/mcp/orchestrate.js` and `src/core/actions.js` for the `encode` action paths. +3. Update `README.md` and any setup docs that mention the Node CLI as an alternative to the Workers deployment. +4. Schedule removal: target oddkit 0.30.0 (or whatever minor lands one quarter from this handoff date — operator confirms before removal). +5. Confirm zero active CLI consumers via telemetry (`telemetry_public` query for `transport: "stdio"` or equivalent, last 30 days) before final removal. + +**Out of scope:** + +- Porting the CLI parser to governance-driven. Decision is deprecation, not parity. +- Removing the Node CLI entirely. Other CLI tools (search, get, catalog, version) may remain; only the encode action is deprecated. (Verify this — if the entire Node CLI is dormant, broader retirement may be cheaper than per-action deprecation.) +- Worker-side changes. The worker is the source of truth and is unaffected. + +--- + +## Acceptance Criteria + +For the deprecation PR: + +1. CLI users invoking `encode` see a clear deprecation notice with a link to migrate to the Workers MCP server URL. +2. README and docs no longer present the CLI as a peer to the Workers deployment for encode functionality. +3. The deprecation notice references this handoff and the target removal version. + +For the eventual removal PR: + +1. Telemetry shows no encode CLI calls in the prior 30 days. +2. `src/tasks/encode.js`, `src/mcp/orchestrate.js` encode wiring, and `src/core/actions.js` encode handler removed in one commit. +3. Tests touching the CLI encode path removed; coverage gate not regressed. +4. CHANGELOG entry naming the removal version, the date, and the operator decision. + +--- + +## Pitfalls + +- **Don't remove without telemetry confirmation.** If a single consumer is still calling the CLI encode path, removal will break them silently. Telemetry first, removal second. +- **Don't conflate CLI encode with CLI as a whole.** Other CLI actions may have their own consumer profiles. Scope discipline matters. +- **Don't backport governance-driven encode to the CLI as a "nice to have."** Operator decision is deprecation. Backporting is parity work and was explicitly declined; doing it anyway is mode collapse. + +--- + +## Open Items + +| Tag | Description | Priority | +|---|---|---| +| O-open | Confirm zero active CLI encode consumers via telemetry before scheduling removal. | P2 | +| O-open | Decide whether the entire Node CLI should be retired alongside the encode path or whether other CLI actions remain. Cheaper to retire whole if dormant. | P2 | +| O-open | If retaining the CLI for non-encode actions, decide whether to ship a polyfill that proxies CLI encode calls to the worker rather than failing outright. Adds compatibility surface; pure deprecation is cleaner. | P3 | + +--- + +## See Also + +- [Audit 2026-04-30 Cleanup Ledger](klappy://odd/ledger/2026-04-30-audit-cleanup-encode-artifacts-landed) — the parent handoff that surfaced this +- [Encode Current State (2026-04-30)](klappy://docs/architecture/encode-current-state-2026-04-30) — what the worker actually does today +- [Vodka Architecture](klappy://canon/principles/vodka-architecture) — the principle that motivates single-implementation discipline +- [Code Claims Require Code Observation](klappy://canon/principles/code-claims-require-code-observation) — the principle this audit graduated From 1dc779889e8d81cd176fc1ab0c2b20b0dc20e144 Mon Sep 17 00:00:00 2001 From: Chris Klapp Date: Thu, 30 Apr 2026 08:50:41 -0400 Subject: [PATCH 8/8] =?UTF-8?q?feat(canon):=20audit=20closeout=20ledger=20?= =?UTF-8?q?for=20cleanup=20PR=20=E2=80=94=20three=20supersessions,=20one?= =?UTF-8?q?=20principle=20graduated,=20CLI=20deprecation=20queued,=20Open?= =?UTF-8?q?=20dedup=20bug=20surfaced=20(Audit=202026-04-30)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...0-audit-cleanup-encode-artifacts-landed.md | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 odd/ledger/2026-04-30-audit-cleanup-encode-artifacts-landed.md diff --git a/odd/ledger/2026-04-30-audit-cleanup-encode-artifacts-landed.md b/odd/ledger/2026-04-30-audit-cleanup-encode-artifacts-landed.md new file mode 100644 index 0000000..4354f6b --- /dev/null +++ b/odd/ledger/2026-04-30-audit-cleanup-encode-artifacts-landed.md @@ -0,0 +1,154 @@ +--- +uri: klappy://odd/ledger/2026-04-30-audit-cleanup-encode-artifacts-landed +title: "Audit 2026-04-30 Cleanup Closeout — Three Stale Artifacts Superseded, Code-Observation Principle Earned, CLI Deprecation Queued" +audience: docs +exposure: nav +tier: 2 +voice: neutral +stability: semi_stable +tags: ["odd", "ledger", "session", "epoch-8.4", "audit-2026-04-30", "supersession", "code-observation-principle", "cli-deprecation", "encode", "post-mortem", "structural-fix"] +epoch: E0008.4 +date: 2026-04-30 +describes_state_at: "klappy/oddkit@1a1f093 (main) and klappy/klappy.dev@125cf8d1 (main, post-PR-#157, pre-cleanup-PR)" +derives_from: "canon/principles/code-claims-require-code-observation.md, docs/architecture/encode-current-state-2026-04-30.md, odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d-revised.md, odd/handoffs/2026-04-30-cli-encode-deprecation.md, odd/ledger/2026-04-30-e0008-4-phase-1-encode-governance-migration-landed.md" +complements: "odd/ledger/2026-04-20-p1-3-4-encode-canon-parity-landed.md" +governs: "Closeout for the Audit 2026-04-30 cleanup PR. Records what the audit found, what was superseded, what was added, and what structural changes prevent the same failure mode from recurring." +status: active +--- + +# Audit 2026-04-30 Cleanup Closeout + +> Audit found that three artifacts shipped in PR #157 (Phase 1) described code state that PR #96 in `klappy/oddkit` had retired two weeks earlier. Cleanup PR supersedes the three artifacts in place (preserved for postmortem), publishes a current-state architecture doc and a revised Phase 2 handoff scoped against actual remaining work, queues CLI deprecation per operator decision, and graduates a new tier-1 principle — `code-claims-require-code-observation` — that names the failure mode so it cannot recur silently. The audit also surfaced a previously undetected production bug: `discoverEncodingTypes` dedupes by letter alone, silently dropping Open's quality criteria when both Observation and Open register letter `O`. Bug fix is queued in the revised Phase 2 handoff. + +--- + +## Summary — Why This Cleanup Was Necessary + +The Phase 1 ship (PR #157, merged 2026-04-30T05:08:53Z) brought three documents into klappy.dev canon that described a problem state already resolved in `klappy/oddkit`. Within an hour of merge, the operator asked the model to verify the framing against current code. Direct code observation revealed that the architecture brief, the Phase 2 handoff, and the closeout ledger were all written against a snapshot of `workers/src/orchestrate.ts` that had been retired by PR #96 on 2026-04-16T02:14:13Z — the same day the architecture brief was authored in `klappy/truthkit-kb`. + +The brief was correct on the day it was written. It became stale within hours. It was cited as authoritative across multiple subsequent canon documents and a user-memory entry over a two-week period. No reader in the citation chain stopped to verify against current code — each one trusted the prior link. By the time PR #157 published the brief into klappy.dev canon, the chain was six links from any actual code observation. The model that authored Phase 1 (in this session) was the seventh link. Three published canon artifacts are the receipt. + +This cleanup PR is the corrective. It does three things at the document layer (supersede the three stale artifacts in place; ship accurate replacements) and one thing at the structural layer (graduate the `code-claims-require-code-observation` principle to tier-1 canon, so the next time anyone — model or human — is about to make a code-state claim sourced from another document, the principle catches it). + +--- + +## Decisions + +**[D-01] Supersede the three stale artifacts in place rather than delete them.** Each gets a `status: superseded` flip, a `superseded_by` frontmatter field pointing to its replacement, a `supersession_reason` field naming the audit, and an addendum block prepended to the body that names what was wrong, what's still true, and what to read instead. Original bodies preserved verbatim below the addendum. Rationale: the artifacts are valuable as postmortem evidence — the failure mode is more legible when the failing documents are still readable. + +**[D-02] Ship a fresh `encode-current-state-2026-04-30` architecture document with `describes_state_at` frontmatter naming the exact commits read.** Not a patch of the predecessor brief; a fresh document. Reason: the predecessor document's structure was a problem-and-alternatives analysis; the replacement needs a current-state structure. Different shapes, different documents. + +**[D-03] Ship a revised Phase 2 handoff (`-revised` slug) scoping the actual five remaining worker items plus the Open dedup bug surfaced by the audit.** Predecessor handoff stays superseded; revised handoff supersedes it explicitly via `supersedes:` frontmatter. Rationale: handoff scope changes warrant new documents, not in-place edits, because handoff scope is contractual. + +**[D-04] Graduate `code-claims-require-code-observation` to tier-1 canon.** Tier-1 because it is load-bearing — every model conversation in this project will exercise it, and violating it caused the failure cascade that necessitated this entire cleanup. Naming convention follows existing tier-1 principles (`klappy://canon/principles/...`). Includes anti-pattern catalogue, anti-pattern-permitted catalogue, and explicit relationship to existing axioms. + +**[D-05] Queue CLI encode deprecation rather than backport governance-driven parsing.** Operator decision. Separate handoff at `klappy://odd/handoffs/2026-04-30-cli-encode-deprecation`. Telemetry-gated removal target: 0.30.0 or later, pending zero-consumer confirmation. + +**[D-06] Adopt `describes_state_at` frontmatter field as a soft convention (not yet a constraint).** Documents that describe code state should cite the commit they were written against. Not yet enforced by tooling; surfaces stale claims to careful readers and to a future `oddkit_audit` extension if one ships. + +--- + +## Observations + +**[O-01]** The architecture brief in `klappy/truthkit-kb` and PR #96 in `klappy/oddkit` were authored on the same day (2026-04-16). The brief described a problem; the PR shipped its resolution. Neither cross-referenced the other; the brief became stale within hours. + +**[O-02]** The citation chain that propagated the staleness: TruthKit-KB architecture brief (2026-04-16) → P1.3.4 closeout ledger H-01 in klappy.dev (2026-04-20) → user memory entry #14 (cumulative, last touched in this session) → model planning conversation (2026-04-30 morning) → PR #157 architecture brief migration + Phase 2 handoff + Phase 1 ledger (2026-04-30 04:51 UTC). Six links. No code observation at any link. The seventh link — this audit (2026-04-30 05:13 UTC) — was the first reader to clone the repo and read the actual code. + +**[O-03]** The audit surfaced a previously undetected production bug in `workers/src/orchestrate.ts:discoverEncodingTypes` (line 512). The function dedupes encoding types by letter alone. When both `observation.md` (registered letter `O`, no facet) and `open.md` (registered letter `O`, facet `open`) are discovered, alphabetical iteration keeps Observation first and silently drops Open's quality criteria. Verified by live `oddkit_encode` call against the production worker after PR #157's Open enrichment landed: an `[O-open P1]` artifact returned `quality.maxScore: 4` (Observation's max) instead of `5` (Open's max). The Phase 1 ship is functionally less effective than its closeout ledger claimed; the revised Phase 2 handoff (Item 2) names the fix. + +**[O-04]** Worker telemetry shows `governance_source: "knowledge_base"` for the audit's verification call, with all eight encoding-type articles fetched (constraint, decision, encode, handoff, learning, observation, open, serialization-format). Cache hits all around. The governance discovery infrastructure works correctly; the bug is in the dedup step downstream of discovery. + +**[O-05]** PR #157 was technically correct in its scope as defined. The five Phase 1 actions (replace D/O/L/C/H, enrich O-open, sync serialization-format tag, copy architecture brief verbatim, write Phase 2 handoff, write Phase 1 closeout ledger) all completed. The framing of WHY was wrong, not the WHAT. The work landed; the explanation was fiction. + +--- + +## Learnings + +**[L-01] Canon governs intent, constraint, definition, plan, and decision. Canon does not govern code behavior.** Two different epistemic categories. A canon document that describes "what the code does" is making a claim of a different kind than a canon document that describes "what the code should do." The former requires direct code observation and is stale within commits; the latter requires reasoning and is stable across commits. Failing to distinguish them is the root cause of the audit failure. Graduated to canon as `klappy://canon/principles/code-claims-require-code-observation` (tier 1, this PR). + +**[L-02] Document staleness propagates through citation faster than direct observation can correct it.** Six links of citation in two weeks; one link of observation in fifteen minutes corrected all six. The asymmetry is structural — citing is cheap, observing is slightly less cheap, but citation compounds while observation does not. The structural fix is to refuse to ratify code-state claims sourced from documents — which the new principle now does. + +**[L-03] User memory entries are themselves a citation surface and inherit staleness from their sources.** Entry #14 carried the stale framing for two weeks. The fix in this session (memory replace) was downstream of the observation; the structural fix is the same principle — memory entries describing code state should be re-verified before being acted on, not treated as ground truth. + +**[L-04] Operator catches what model misses, but only when the model produces enough surface to be questioned.** The "Why wasn't the journal included?" question opened the audit because the missing ledger was a visible surface that prompted scrutiny of the surrounding context. If the model had silently shipped Phase 1 without the operator's question, the staleness might have persisted through Phase 2 implementation and surfaced as a much more expensive failure (a Phase 2 PR rebuilding work that didn't need rebuilding). The lesson is not "always rely on the operator to catch you" — the lesson is "produce the surfaces that allow operator scrutiny to work, and don't hide behind succinctness." + +**[L-05] In-place supersession with addendum-on-top preserves the failure mode for postmortem while clearly signaling current state.** The pattern: flip status, add `superseded_by` and `supersession_reason` frontmatter, prepend an addendum that names what was wrong, what's still true, and what to read instead. The original body remains intact below. Future readers see the supersession immediately; future archaeologists can still read the failed document as-shipped. Better than deletion (which loses the evidence) and better than rewrite-in-place (which obscures the failure). + +--- + +## Constraints + +**[C-01] (NEW, GRADUATED THIS PR) Code claims require code observation.** Any assertion of the form "the X currently does Y" must be backed by direct code observation against current HEAD, not citation of another document that made the claim previously. See `klappy://canon/principles/code-claims-require-code-observation` for the full principle, anti-patterns, and verification path. + +**[C-02] (CARRIED FORWARD) Milestone ledgers ship in the same PR as the milestone work.** Graduated in the prior session (this PR's predecessor ledger, L-03 → C-03). Reaffirmed by this PR shipping its own ledger in-PR. + +--- + +## Handoffs + +**[H-01] Next session: Phase 2 implementation in `klappy/oddkit`.** Read `klappy://odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d-revised` as the implementation contract. Five worker items + Open dedup bug. Target 0.28.0. Full release-validation-gate (Bugbot completed + Sonnet 4.6 read-only validator via Managed Agents). + +**[H-02] CLI deprecation track (parallel, lower priority).** Separate handoff at `klappy://odd/handoffs/2026-04-30-cli-encode-deprecation`. Operator decision is deprecation, not backport. Telemetry-gated. + +**[H-03] L-05 graduation candidate.** "In-place supersession with addendum-on-top" is a candidate for graduation as a tier-2 method (`klappy://canon/methods/in-place-supersession-with-addendum`) if it reuses unprompted in two more sessions. Watch for future supersession work. + +**[H-04] Soft-convention adoption: `describes_state_at` frontmatter on architecture/state docs.** Not enforced by tooling yet. If `oddkit_audit` graduates a stale-claim detector, this field becomes its primary input. + +**[H-05] After Phase 2 ships: TruthKit-KB sync.** Replace TruthKit-KB's older D/O/L/C/H/Q articles with the now-canonical oddkit versions, OR maintain divergence intentionally. Likely one-direction sync (TruthKit reads oddkit baseline + adds harness-specific overlay). Decision deferred to post-Phase-2. + +--- + +## Encodes + +**[E-01]** Audit 2026-04-30 cleanup complete. PR (TBD-number) opened, mergeable, file count: 7 (3 supersession addendums + 4 new artifacts including this ledger + the new constraint principle + 2 new handoffs + 1 current-state architecture doc). New tier-1 canon principle graduated: `code-claims-require-code-observation`. + +--- + +## Files in This PR + +| Status | File | Purpose | +|---|---|---| +| modified | `docs/architecture/encode-architecture-problem-and-gaps.md` | Status flipped to superseded; addendum prepended | +| modified | `odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d.md` | Status flipped to superseded; addendum prepended | +| modified | `odd/ledger/2026-04-30-e0008-4-phase-1-encode-governance-migration-landed.md` | Status flipped to superseded; addendum prepended | +| added | `canon/principles/code-claims-require-code-observation.md` | NEW tier-1 principle | +| added | `docs/architecture/encode-current-state-2026-04-30.md` | Accurate current-state replacement for predecessor brief | +| added | `odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d-revised.md` | Accurate Phase 2 scope | +| added | `odd/handoffs/2026-04-30-cli-encode-deprecation.md` | CLI deprecation track | +| added | `odd/ledger/2026-04-30-audit-cleanup-encode-artifacts-landed.md` | This ledger | + +--- + +## Timeline (UTC) + +| Time | Event | +|---|---| +| 04:14:50 | Session started (Phase 1 work) | +| 04:51:06 | PR #157 opened | +| 05:00:00 | Operator catches missing ledger; addendum added | +| 05:08:53 | PR #157 merged to main | +| 05:09:52 | Operator: "What's next?" — model proposes Phase 2 | +| 05:13:00 | Model dictates Phase 2 plan citing stale handoff claims | +| 05:13:53 | Operator confirms direction; model clones repo, reads code | +| 05:13–05:25 | Model verifies via direct code observation; staleness chain becomes visible | +| 05:26:21 | `oddkit_version` confirms prod state; live encode call confirms Open dedup bug | +| 05:26:00 | Audit findings presented to operator | +| 12:41:58 | Session resumed (7h 15m gap); operator gates one-PR cleanup with code-observation principle | +| (this PR) | Cleanup PR opened with seven file changes | + +--- + +## References + +- Cleanup PR: (TBD — added by branch creation step) +- Phase 1 PR (the cause): https://github.com/klappy/klappy.dev/pull/157 +- Worker refactor that retired the brief's premise: `klappy/oddkit` PR #96, merged 2026-04-16T02:14:13Z +- New principle: `klappy://canon/principles/code-claims-require-code-observation` +- Current-state architecture: `klappy://docs/architecture/encode-current-state-2026-04-30` +- Revised Phase 2 handoff: `klappy://odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d-revised` +- CLI deprecation handoff: `klappy://odd/handoffs/2026-04-30-cli-encode-deprecation` +- Predecessor (superseded) ledger: `klappy://odd/ledger/2026-04-30-e0008-4-phase-1-encode-governance-migration-landed` +- Predecessor (superseded) handoff: `klappy://odd/handoffs/2026-04-30-encode-vodka-refactor-alternative-d` +- Predecessor (superseded) brief: `klappy://docs/architecture/encode-architecture-problem-and-gaps` +- Sibling ledger: `klappy://odd/ledger/2026-04-20-p1-3-4-encode-canon-parity-landed` +- Bootstrap: `klappy://canon/bootstrap/model-operating-contract`