feat(challenge): governance_source envelope + peer governance_uris (0.19.0)#116
Conversation
….19.0)
P1.3.1 canary retrofit mirroring P1.2's encode pattern. Challenge's response
envelope now declares which tier served its governance vocabulary and exposes
the four peer canon URIs it reads.
Changes:
- Four governance helpers return {<domainNoun>, source} tuples:
* discoverChallengeTypes → {types, source}
* fetchBasePrerequisites → {prerequisites, source}
* fetchNormativeVocabulary → {vocabulary, source}
* fetchStakesCalibration → {calibration, source}
- runChallengeAction aggregates the four sources strictly: any helper
falling through to hardcoded defaults → aggregate = "minimal".
All four from canon → aggregate = "knowledge_base".
- Response envelope (both SUPPRESSED and CHALLENGED paths):
+ result.governance_source: "knowledge_base" | "minimal"
+ result.governance_uris: array of 4 peer URIs (alphabetical)
+ debug.knowledge_base_url echoes override
- Smoke test adds challenge envelope assertions + 9-mode parse integrity
guard (PR #100 regression defense).
Design decision: governance_uris (plural array) intentionally diverges from
encode's singular governance_uri. Challenge reads four peer governance
files with no hierarchy among them; a single anchor would misrepresent
where base-prerequisites and normative-vocabulary live. Consumers that
want a singular anchor can read governance_uris[0] — alphabetical
ordering makes this stable. See CHANGELOG and PRD for full rationale.
Two-tier cascade today ("knowledge_base" | "minimal") because
workers/baseline/ is not yet shipped; the bundled tier from
canon/constraints/core-governance-baseline is a contract aspiration.
Union expands additively when baseline ships.
Verification:
- npm run typecheck: clean
- node workers/test/governance-parser.test.mjs: 105/105 pass
- Live smoke against preview URL: pending (next step)
PRD: /home/claude/work/prd-p1-3-1-challenge-canary.md (local planning artifact)
Closes: P1.3.1 (per klappy://odd/handoffs/2026-04-20-p1-3-challenge-canary)
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
oddkit | 3978232 | Commit Preview URL Branch Preview URL |
Apr 20 2026, 12:27 AM |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Vocab source misclassifies when hardcoded fallback runs
- Derived parsedFromCanon from whether any vocabulary words were actually parsed (parse-success criterion) so that when the canon article exists but yields no rows and the hardcoded RFC 2119 fallback runs, source is classified as 'minimal', matching the other three helpers.
You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit 3978232. Configure here.
| try { | ||
| const content = await fetcher.getFile("odd/challenge/normative-vocabulary.md", knowledgeBaseUrl); | ||
| if (content) { | ||
| parsedFromCanon = true; |
There was a problem hiding this comment.
Vocab source misclassifies when hardcoded fallback runs
Low Severity
parsedFromCanon is set to true when content is truthy (line 669), before any vocabulary tables are actually parsed. If the canon file exists but contains no parseable vocabulary tables, the hardcoded RFC 2119 fallback at lines 711–717 still runs, yet source becomes "knowledge_base". This contradicts the stated aggregation rule in the PR description ("any helper falling through to hardcoded defaults → aggregate = 'minimal'") and the comment at line 662–663 ("Left-falling to the hardcoded RFC 2119 fallback below is the 'minimal' tier"). The other three helpers (discoverChallengeTypes, fetchBasePrerequisites, fetchStakesCalibration) all classify source based on whether parsing produced non-empty results, making fetchNormativeVocabulary the inconsistent outlier.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 3978232. Configure here.
…ndoff Closeout artifacts for the 2026-04-19T21:21Z–2026-04-20T00:59Z session that landed P1.3.1 (oddkit_challenge governance_source + peer governance_uris, shipped as klappy/oddkit#116 + #117, 0.19.0 in prod). New files: - odd/ledger/2026-04-20-p1-3-1-challenge-canary-landed.md: full session retrospective with the D4 decision-pivot rationale, validator external-corroboration pattern, and the three-recurrence evidence for the contract-governs-handoff-drift canon principle (now standing). - odd/handoffs/2026-04-21-p1-3-2-gate-canary.md: forward handoff pointing the next session at P1.3.2 — gate's vodka anti-pattern refactor, two-phase scope (canon-first klappy.dev PR, then oddkit code PR). Frontmatter updates: - odd/handoffs/2026-04-20-p1-3-challenge-canary.md: status active → superseded, with superseded_by pointer to the new P1.3.2 handoff. Not in this PR (carry-forward): - P1.2 handoff 'bundled baseline' → 'minimal fallback' correction - P1.3 handoff three discover* → fetch* name corrections - canon/principles/contract-governs-handoff-drift.md draft All three deferred to bundle into a single small canon PR in a subsequent session per P1.3.2 handoff's O-open items.


Summary
P1.3.1 canary retrofit for
oddkit_challenge— mirrors the encode pattern from PR #114, first post-encode tool in the governance anti-pattern sweep.What changed
{<domainNoun>, source}tuples:discoverChallengeTypes→{types, source}fetchBasePrerequisites→{prerequisites, source}fetchNormativeVocabulary→{vocabulary, source}fetchStakesCalibration→{calibration, source}runChallengeActionaggregates sources strictly: any helper falling through to hardcoded defaults → aggregate ="minimal". All four from canon →"knowledge_base".SUPPRESSEDandCHALLENGEDpaths):result.governance_source:"knowledge_base"|"minimal"result.governance_uris: array of 4 peer canon URIs (alphabetical by path-tail)debug.knowledge_base_urlechoes overrideDesign decision:
governance_uris(plural) vs encode'sgovernance_uri(singular)Intentional shape divergence. Encode's encoding-type docs sit under one canonical umbrella (
canon/definitions/dolcheo-vocabulary). Challenge reads four peer governance files with no hierarchy among them — a single anchor on any one of them (e.g.stakes-calibrationbecause of its PR #100 weight) would misrepresent wherebase-prerequisitesandnormative-vocabularylive. Accurate representation outranks envelope-shape parity with encode. Consumers that prefer a singular anchor can readgovernance_uris[0]; alphabetical ordering keeps this stable. Called out explicitly in CHANGELOG so consumers reading both tools aren't surprised.Two-tier cascade note (for validator)
Enum is
"knowledge_base" | "minimal"today, not the three-tier shape incanon/constraints/core-governance-baseline.workers/baseline/is not yet shipped — thebundledtier is a contract aspiration, not in-repo code. Same reality under which telemetry_policy (#106/#108) and encode (#114) shipped; parity with those precedents, not a contract deviation. Union expands additively to include"bundled"when the baseline build pipeline ships.Verification
npm run typecheck: cleannode workers/test/governance-parser.test.mjs: 105/105 pass (no regression)https://challenge-governance-source-envelope-oddkit.klappy.workers.dev/mcpPRD
Planning artifact at
/home/claude/work/prd-p1-3-1-challenge-canary.md(local to orchestrator session, not committed). PRD § numbers referenced in commit message and inline comments.Closes
P1.3.1 per
klappy://odd/handoffs/2026-04-20-p1-3-challenge-canary.Next in sweep: one of {gate, preflight, validate, orient, search, catalog, cleanup, version}, to be decided in next session's handoff.
Note
Medium Risk
Changes the
oddkit_challengeresponse contract by adding new envelope fields and refactoring governance-loading helpers, which could impact downstream consumers and caching behavior if assumptions about result shape exist.Overview
oddkit_challengeresponses now includeresult.governance_source(strictly aggregated across the four challenge governance fetches) andresult.governance_uris(an ordered array of the four peer governance documents), and theknowledge_base_urloverride is echoed asdebug.knowledge_base_urlin bothSUPPRESSEDandCHALLENGEDpaths.Internally, the four challenge governance helpers were refactored to return
{<domainNoun>, source}tuples and their source classification is cached/reset alongside existing caches. The worker tool description and live envelope smoke test were updated to assert the new fields (including 9-mode coverage), and the release bumps to0.19.0with corresponding changelog notes.Reviewed by Cursor Bugbot for commit 3978232. Bugbot is set up for automated code reviews on this repo. Configure here.