What shipped since the prior handoff
| PR | Repo | Merged SHA | Purpose |
|---|---|---|---|
| #114 | klappy/oddkit | 290dde5 | feat(encode): DOLCHEO batch prefix + governance_source envelope (0.18.0). Squash-merged to main. |
| #115 | klappy/oddkit | e6dbba5 | main → prod promotion for 0.18.0. Merge commit. |
Production state: https://oddkit.klappy.dev/health returns {"version":"0.18.0"}. Envelope smoke 61/61 pass × 3 consecutive runs against https://oddkit.klappy.dev/mcp. No regressions.
Validator record: agent_011CaDj46VwmidBz5g3wMhdJ / sesn_011CaDj48ax5VEXyMfxrDves. Disposition: VERIFIED, 11/11, 3 non-blocking advisories. Corroboration method: the validator pulled main's orchestrate.ts bytes to confirm zero governance_source references, cited core-governance-baseline §Canon-Only to confirm two-tier cascade, verified letter dedup from a live response. External-evidence pattern worked and should be the default for subsequent validator dispatches.
What is cleared from the prior handoff
- [O-open P1.2] Encode batch-mode + canary refactor — closed by #114/#115.
- [O-open P3] Version bump to 0.18.0 — closed by #114 (bundled in feature PR).
What remains open
- [O-open P1] P1.3.1 — challenge
governance_sourceretrofit. See scope section below. This is the next atomic unit. - [O-open P2] Encode index-layer strict-mode.
getIndexlacksskipBaselineFallback; encode'sknowledge_base_urloverride doesn't strict-fall to"minimal"when the target repo lacks encoding-type docs. Documented in 0.18.0 CHANGELOG Known Limitations. Natural to bundle with P1.3.1 if challenge exercises the same code path; otherwise separate PR. - [O-open P3] Handoff-text correction on
klappy://odd/handoffs/2026-04-20-p1-2-encode-canary— rename "bundled baseline" → "minimal fallback" to align with the contract's enum. Tiny follow-up PR on klappy.dev. Low priority. - [O-open P4] Candidate canon principle on contract-governs-handoff-drift. Watch for one more recurrence before committing to the doc.
- [O-open P5] CHANGELOG render route on klappy.dev +
version_notes_urlon MCPinitialize. Low priority; slot into a tool-envelope PR window.
P1.3.1 scoperetrofit oddkit_challenge envelope
The delta
Challenge already reads governance from canon at runtime — four discovery helpers in workers/src/orchestrate.ts:
discoverChallengeTypes(fetcher, knowledgeBaseUrl)— challenge-type docs underodd/challenge-types/discoverBasePrerequisites(fetcher, knowledgeBaseUrl)— gate/challenge base prereqsdiscoverNormativeVocabulary(fetcher, knowledgeBaseUrl)— must/must-not/never vocabularydiscoverStakesCalibration(fetcher, knowledgeBaseUrl)— 9-mode stakes calibration
The gap: runChallengeAction does NOT declare governance_source in its envelope. Prod orchestrate.ts contains zero governance_source references (validator-verified for P1.2 with bytes-level evidence).
Work to ship
- Aggregate tier signal from the four discovery helpers. Each helper's canon fetch can succeed (some challenge-types parsed) or fall through to minimal (hardcoded defaults). The aggregate governance_source for a challenge response is:
"knowledge_base"if all four helpers resolved from canon"minimal"if one or more fell through to hardcoded defaults- Consider whether a middle state (partial knowledge_base) is useful, or whether the strict aggregate is cleaner. Bias toward the strict aggregate; it matches the two-tier pattern P1.2 established.
- Refactor the four helpers to return
{ data, source }tuples (pattern from P1.2'sdiscoverEncodingTypesreturn shape). Update the single caller (runChallengeAction) to aggregate. - Declare
governance_source+governance_uriin the challenge response envelope.governance_uricandidates:"klappy://canon/constraints/challenge"or per-dimension URIs. Check what canon path best represents the challenge vocabulary contract —odd/challenge/stakes-calibration.mdis a strong candidate for the primary governance anchor (it's the 9-mode contract that was the PR #100 root cause). - Smoke test extensions. Mirror the encode assertions from
workers/test/canon-tool-envelope.smoke.mjs:- Envelope shape on challenge responses
governance_sourcepresent and valid- Default KB returns
knowledge_base knowledge_base_urloverride threaded (debug echo at minimum; note the same strict-mode limitation if it applies to challenge's index reads)
- Tool description update. Reference the four discovery sources (challenge-types, prereqs, normative vocabulary, stakes calibration) and the two-tier envelope signal.
- CHANGELOG entry under
[Unreleased]OR a 0.18.1 PATCH / 0.19.0 MINOR bump. Decision deferred to planning in the next session. PATCH is defensible (additive envelope field, no input/output shape change for callers not reading the new field). MINOR is defensible by precedent (encode's addition shipped as MINOR). Pick one, name it in the PR body.
Known subtleties
- PR #100 history. Challenge's stakes-calibration parser was the cause of the 1h 39m prod breakage under the PR #100/#102/#103/#104 arc. The four discovery helpers in orchestrate.ts now handle all 9 modes. Smoke should assert all 9 modes still parse cleanly — pattern from
workers/test/governance-parser.test.mjsTest 7. - Per-mode governance vs global governance. Challenge's behavior varies by mode (exploration/planning/execution/voice-dump/drafting/peer-review-ready/canon-tier-2/canon-tier-1/published-essay). The
governance_sourcesignal applies to the overall vocabulary fetch, not per-mode. Don't overcomplicate. - The PR #100 lesson is load-bearing.
canon/constraints/core-governance-baselinewas written partly in response to this failure. Re-read it during planning — especially §Build-Time Invariants and §Runtime Invariants.
Out of scope (deferred)
- Index-layer strict-mode for
getIndex. Only pull into this PR if challenge's code path exercises it AND the fix is trivial. Otherwise separate PR. - Gate / preflight / validate / orient / search / catalog / cleanup / version refactors — subsequent P1.3.x PRs, one per tool per session.
- Any canon-doc edits (new principles, handoff rewording) — separate klappy.dev PRs.
Path 3 workflow
Same as P1.2:
- Clone klappy/oddkit into
/home/claude/work/oddkit, cut branchchallenge/governance-source-envelopeoff main. - Apply edits locally. Run
npm run typecheckinworkers/. Runnode workers/test/governance-parser.test.mjs— must stay at 105/105. - Commit (githook enforces package.json version sync if bumping).
- Push branch. CF auto-deploys to
https://<slug>-oddkit.klappy.workers.dev/mcp. Wait ~25s. Smoke the preview URL with the updated smoke script. - Open PR via
urllib.request+json.dumps. Path 3 constraint: no shell heredoc JSON. - Dispatch Sonnet 4.6 read-only validator. Template at
/home/claude/work/dispatch-validator.sh(env-var exports fix from P1.2). Required external corroborations:- Main branch's
orchestrate.tsbytes grep for pre-refactor state - Live curl against preview URL for envelope shape +
governance_sourcevalue oddkit_get core-governance-baselinecitation on the tier enum
- Main branch's
- Accept VERIFIED or iterate. Do not trust terminal self-report alone (
canon/principles/agent-self-report-under-stress). - Squash-merge on VERIFIED. Main-preview smoke. Open main → prod promotion PR. Merge. Prod smoke until 3 consecutive clean runs (isolate-warmup pattern confirmed in P1.2).
Estimate: 45–90 min including validator. Smaller than P1.2 because discovery helpers are already canon-governed.
Standing rules (carried from prior handoffs, unchanged)
- Call
oddkit_timefirst every turn. Pass the priorserver_timeasreference. No inferred timestamps. - Declare epistemic mode out loud. Planning until PRD is written and contract decisions are named; execution after the gate; validation via Sonnet 4.6 (context-break required, same-session self-review is not validation).
- Search canon before asking. Especially before claiming anything about challenge's current state or the core-governance-baseline contract.
- Ground framing in code + canon, not in the latest handoff. The P1.2 session hit recency-as-authority three times. The fix is always: read target code, cross-reference the governing contract, then frame scope as a delta. Explicitly: if a handoff's word choice disagrees with a contract's enum, the contract wins.
- PRD before code. Write the plan as a file before touching source. Articulation is the deliverable during planning, not prose in the chat window.
- During execution, produce artifacts, not questions. Reversion requires one sentence naming the specific unknown.
- No force-push without
git fetchfirst. Remote state may have diverged. - GitHub API:
urllib.request+json.dumps, never bash heredoc. The PAT-in-command footgun and JSON-escaping pitfalls are documented; use the proven path. $HOME=/rootin the managed-agent cloud container (not/home/useras the skill doc historically suggested).- Do NOT dispatch Opus 4.7 execution agents to klappy/oddkit. Safety-layer false-positive blocks them. Sonnet 4.6 read-only validation is fine; orchestrator-applies for writes.
- Do NOT run
wrangler deploymanually. Githooks + CF auto-deploy handle the pipeline. - Branch preview slug rule: slashes AND dots → hyphens.
challenge/governance-source-envelope→challenge-governance-source-envelope. - Prod deploy warmup pattern: first smoke run immediately after prod flip can flake as isolates serve mixed versions. Accept 3 consecutive clean runs as the "prod clean" gate.
Reference materialread this at session start
Priority order for fresh-session reading:
- This doc.
klappy://canon/bootstrap/model-operating-contract— the evolving operating contract.klappy://odd/ledger/2026-04-19-p1-2-encode-dolcheo-landed— full closeout for P1.2, including the recency-as-authority failure pattern and how it was resolved.klappy://canon/constraints/core-governance-baseline— the governing contract (§Canon-Only lists challenge-types? encoding-types are there; check whether challenge's governance docs are similarly classified).klappy://canon/principles/agent-self-report-under-stress— for the validator dispatch.klappy://canon/meta/frontmatter-schema— native YAML types only if touching docs.klappy://canon/constraints/ai-voice-cliches— if touching any writing.
Reference PRs for canary pattern (same-shape):
klappy/oddkit#108/#109— telemetry_policy canary (reference envelope).klappy/oddkit#114— encode canary completion (most recent example, P1.2).
Thin prompt for the next session
Resume P1.3.1 per klappy://odd/handoffs/2026-04-20-p1-3-challenge-canary.
Current state: 0.18.0 in prod (oddkit.klappy.dev), encode envelope
now declares governance_source, DOLCHEO batch-prefix input works,
letter dedup in place. P1.2 formally closed at
klappy://odd/ledger/2026-04-19-p1-2-encode-dolcheo-landed.
Read the handoff, run the gauntlet on the challenge code path and the
core-governance-baseline contract, write the PRD as a file before
touching source, then apply the challenge envelope refactor locally
(orchestrator applies, Sonnet 4.6 validates — path 3, no Opus 4.7
execution agents to oddkit).
Credentials in project instructions. Don't over-scope — P1.3.1 alone
is one session's work.
Provenance
- Prior post-closeout handoff:
odd/handoffs/2026-04-20-post-closeout.md— superseded by this document. - Session ledger:
odd/ledger/2026-04-19-p1-2-encode-dolcheo-landed.md— full retrospective for the P1.2 arc. - Merged PRs:
klappy/oddkit#114(feat),klappy/oddkit#115(promotion). - Validator session:
sesn_011CaDj48ax5VEXyMfxrDvesunder agentagent_011CaDj46VwmidBz5g3wMhdJ. Event log ephemeral to the orchestrator's container; the VERIFIED 11/11 disposition is summarized in the ledger linked above.