Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion odd/handoffs/2026-04-20-p1-3-challenge-canary.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ date: 2026-04-20
session_span: "2026-04-19 closed"
derives_from: "odd/ledger/2026-04-19-p1-2-encode-dolcheo-landed.md, odd/handoffs/2026-04-20-post-closeout.md, odd/handoffs/2026-04-20-p1-2-encode-canary.md, canon/constraints/core-governance-baseline.md"
governs: "Fresh-session continuation after P1.2 landed. Points the next session at P1.3.1 — retrofit oddkit_challenge to declare governance_source in its envelope, mirroring the encode + telemetry_policy canary shape. First PR in the post-encode sweep."
status: active
status: superseded
superseded_by: "odd/handoffs/2026-04-21-p1-3-2-gate-canary.md"
supersedes: "odd/handoffs/2026-04-20-post-closeout.md"
---

Expand Down
202 changes: 202 additions & 0 deletions odd/handoffs/2026-04-21-p1-3-2-gate-canary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
---
uri: klappy://odd/handoffs/2026-04-21-p1-3-2-gate-canary
title: "Handoff — P1.3.2 oddkit_gate Vodka Refactor + governance_source Envelope"
audience: odd
exposure: nav
tier: 3
voice: neutral
stability: stable
tags: ["odd", "handoff", "session", "epoch-8.3", "p1-3-2", "oddkit-gate", "governance-source", "vodka-anti-pattern", "canary", "sweep"]
epoch: E0008.3
date: 2026-04-21
session_span: "2026-04-20 closed"
derives_from: "odd/ledger/2026-04-20-p1-3-1-challenge-canary-landed.md, canon/constraints/core-governance-baseline.md, canon/principles/vodka-architecture.md"
governs: "Fresh-session continuation after P1.3.1 landed. Points the next session at P1.3.2 — retrofit oddkit_gate to (a) read transition prerequisites from canon at runtime instead of hardcoding them in source, and (b) declare governance_source in its envelope. Second PR in the post-encode sweep. Larger delta than P1.3.1 because gate currently has zero canon integration — the full vodka anti-pattern is still live in runGateAction."
status: active
supersedes: "odd/handoffs/2026-04-20-p1-3-challenge-canary.md"
---

# Handoff — P1.3.2 oddkit_gate Vodka Refactor + governance_source Envelope

> P1.3.1 shipped clean to prod (PR #116 feat, #117 promotion, prod at 0.19.0). Challenge's envelope now declares `governance_source` and a four-peer `governance_uris` array; smoke 126/126 × 5 consecutive on prod; validator VERIFIED 5/5 zero advisories. **Next work unit is P1.3.2** — retrofit `oddkit_gate` following the same canary pattern, but with a larger scope: gate has not yet been governance-driven at all. `runGateAction` hardcodes transition prerequisites, DoD criteria, and completion checks directly in source. This session refactors gate to read those from canon at runtime AND adds the envelope `governance_source` / `governance_uris` the sweep requires. Estimate 90–150 min including validator, longer than P1.3.1 because canon docs may need to be written before code can reference them.

---

## What shipped since the prior handoff

| PR | Repo | Merged SHA | Purpose |
|----|------|-----------|---------|
| #116 | klappy/oddkit | `71ee6ed` | **feat(challenge):** governance_source envelope + peer governance_uris (0.19.0). Squash-merged. |
| #117 | klappy/oddkit | `1b4fce8` | main → prod promotion for 0.19.0. Merge commit. |

**Production state:** `https://oddkit.klappy.dev/health` returns `{"version":"0.19.0"}`. Smoke 126/126 × 5 consecutive on prod. No regressions.

**Validator record:** `agent_011CaE62pg6jJ7yYpRj1o9Do` / `sesn_011CaE63LZhPUX1UAZPbiV7n`. Disposition: **VERIFIED**, 5/5, zero blockers, zero non-blocking advisories. External corroboration pattern (main-bytes grep, live curl ×3 shapes, canon citation, 9-mode curl, 3× independent smoke) is now the default for the sweep.

## What is cleared from the prior handoff

- **[O-open P1]** Challenge envelope retrofit — closed by #116/#117.

## What remains open

- **[O-open P1]** **P1.3.2 — gate vodka refactor + envelope.** See scope section below. This is the next atomic unit.
- **[O-open P2]** `getIndex` strict-mode (`skipBaselineFallback`) — now affects telemetry_policy + encode + challenge. Same limitation, one fix. Pull into a later P1.3.x PR if a tool exercises the code path; otherwise standalone PR.
- **[O-open P3]** **Handoff text corrections on klappy.dev.** Two deferred: (a) P1.2 handoff "bundled baseline" → "minimal fallback"; (b) P1.3 handoff three `discover*` → `fetch*` names. Low priority. Bundle both into a single tiny canon PR at next session's natural PR window.
- **[O-open P4]** **Canon principle on contract-governs-handoff-drift.** Now standing — three recurrences documented (P1.2 ledger's two + P1.3.1 ledger's one). Principle draft text in the P1.3.1 ledger's §"Canon Principle Now Standing" section. Draft location: `canon/principles/contract-governs-handoff-drift.md`. Bundle into the handoff-text-corrections PR.
- **[O-open P5]** `workers/baseline/` bundled-tier build pipeline — separate epoch. Deferred until sweep surfaces concrete need or TruthKit forces the question.
- **[O-open P6]** CHANGELOG render route on klappy.dev + `version_notes_url` on MCP `initialize`. Low priority; slot into a tool-envelope PR window.

---

## P1.3.2 scope — retrofit `oddkit_gate`

### The delta (larger than P1.3.1)

Gate has **zero canon integration today**. `runGateAction` at `workers/src/orchestrate.ts` hardcodes:

- Transition detection (`detectTransition(input)` — regex-based mode recognition)
- Transition-specific prerequisites (`problem_defined`, `constraints_reviewed`, `decisions_locked`, `dod_defined`, `irreversibility_assessed`, `constraints_satisfied`, `dod_met`, `artifacts_present`)
- DoD criteria and evidence requirements

All of this is code, not canon. The sweep thesis says: canon defines vocabulary; code must not hardcode interpretation. Gate is currently the most pure vodka-anti-pattern violation of any remaining tool in the sweep.

**Unlike P1.3.1**, the canon governance docs for gate **do not yet exist in the klappy.dev repo** (no `odd/gate/` directory). This session will need to write canon first, then refactor code — preserving the "canon-first rule is absolute" from the bootstrap contract.

### Work to ship — two-phase scope

**Phase 1: write canon (klappy.dev PR, lands first).**

1. Create `odd/gate/transitions.md` — the canonical list of mode transitions (e.g. `exploration → planning`, `planning → execution`, `* → completion`) with a markdown table of detection patterns, prerequisite IDs, and governance references.
2. Create `odd/gate/prerequisites.md` — the canonical definitions of each prerequisite ID (`problem_defined`, `constraints_reviewed`, etc.), matching the pattern of `odd/challenge/base-prerequisites.md`: each row is `(id, description, check, gap_message)`.
3. Optionally `odd/gate/completion-criteria.md` — DoD and artifact-presence checks if they are sufficiently distinct from prerequisites to warrant their own file.
4. Merge the klappy.dev PR first. Canon must be live before the oddkit PR can reference it.

**Phase 2: refactor oddkit_gate (oddkit PR, lands second).**

1. Add `fetchGateTransitions(fetcher, knowledgeBaseUrl)` → `{ transitions, source }` and `fetchGatePrerequisites(fetcher, knowledgeBaseUrl)` → `{ prerequisites, source }` helpers, following the P1.3.1 per-helper domain-noun tuple pattern.
2. Refactor `runGateAction` to read transitions and prerequisites from canon at runtime; keep the current hardcoded logic as the `"minimal"` fallback (matches encode's soft-fallback pattern, not challenge's hollow-response pattern — gate cannot hollow out without becoming useless, so the minimal tier must preserve today's behavior exactly).
3. Declare `governance_source` and `governance_uris` in the response envelope. Per D4 principle from P1.3.1: because gate will read two peer governance files (transitions + prerequisites), use `governance_uris` (plural array). Shape parity with challenge.
4. Echo `debug.knowledge_base_url` on overrides.
5. Extend `workers/test/canon-tool-envelope.smoke.mjs` with gate assertions matching the P1.3.1 pattern: envelope shape, `governance_source` valid enum, `governance_uris` length 2 (or 3 if completion-criteria ships as separate file), override behavior, and at minimum one assertion per defined transition type.
6. CHANGELOG `[0.20.0]` entry with Added / Changed / Fixed / Known-limitations. MINOR bump per sweep precedent (encode 0.18.0, challenge 0.19.0).
7. Tool description update to reference the two governance docs and the envelope signal.

### Known subtleties

- **Canon-first is mandatory.** Unlike P1.3.1, this session cannot write oddkit code and then "update canon as needed" — the oddkit PR references klappy.dev files that must exist at the SHA the worker pins. Standing rule: klappy.dev PR merged to main before oddkit PR is even opened.
- **Back-compat is critical.** Unlike encode and challenge (where the envelope changes were additive), gate's hardcoded logic is the only behavior callers have today. The minimal fallback must preserve exact current behavior. If a canon doc is missing or malformed, gate must still return the same transitions and prerequisites it does today — just with `governance_source: "minimal"` in the envelope so callers see the degradation.
- **The `detectTransition` regex may not belong in canon.** Detection patterns are low-level parsing; canon governs vocabulary and policy. Candidate split: keep `detectTransition` in code as the parser, have it emit a transition key, and read the transition-specific prerequisite set from canon by key. Mirrors how challenge's parser stays in code but the per-type vocabulary lives in canon.
- **Two URIs vs three URIs for `governance_uris`.** If completion-criteria ships as a third file, the array has three entries. If transitions and prerequisites alone cover the contract, the array has two. Either is coherent under D4's peer-array principle; decide during planning based on how the canon docs actually split.
- **This session may want to split into two sessions.** Phase 1 (canon) + Phase 2 (code) is a lot for one session if canon discussion goes deep. Acceptable to land Phase 1 in session A and Phase 2 in session B. The forward handoff from session A would then be "P1.3.2 Phase 2".

### Out of scope (deferred)

- Any other tool in the sweep (preflight, validate, orient, search, catalog, cleanup, version) — subsequent P1.3.x PRs.
- `getIndex` strict-mode — still deferred.
- `workers/baseline/` build pipeline — still deferred.
- Any edits to existing tools' envelopes — gate only.

### Path 3 workflow

Same shape as P1.3.1, with the Phase 1 canon PR inserted first:

**Phase 1 (klappy.dev):**
1. Clone `klappy/klappy.dev` into `/home/claude/work/klappy.dev`, cut branch `gate/canon-governance-docs` off main.
2. Write `odd/gate/transitions.md`, `odd/gate/prerequisites.md` (and possibly `odd/gate/completion-criteria.md`). Follow `canon/meta/frontmatter-schema` — native YAML types only. Use `odd/challenge/base-prerequisites.md` as the structural template.
3. Commit. Push. Open PR via `urllib.request` + `json.dumps`.
4. Optional lightweight validation: use `oddkit_preflight` to confirm Writing Canon gate criteria are met before opening PR.
5. Squash-merge on self-review (canon docs are lower-risk than code — no need for Sonnet 4.6 validator unless the docs encode contract semantics that need pressure-testing).

**Phase 2 (klappy/oddkit):**
1. Clone `klappy/oddkit`, cut branch `gate/governance-source-envelope` off main.
2. Apply edits locally (canon discovery helpers + envelope retrofit). Run `npm run typecheck` in `workers/`. Run `node workers/test/governance-parser.test.mjs` — must stay at 105/105 (or grow if gate-specific parser tests are added).
3. Commit (version bump to 0.20.0, githook enforces sync).
4. Push. CF auto-deploys to preview. Wait ~25s. Smoke preview with updated script. 3 consecutive clean.
5. Open PR via `urllib.request` + `json.dumps`.
6. Dispatch Sonnet 4.6 read-only validator with required external corroborations (template from P1.3.1):
- Main-branch `orchestrate.ts` bytes grep confirming gate has no canon integration pre-refactor
- Live curl against preview for envelope shape + `governance_source` value
- `oddkit_get` citation on `core-governance-baseline` §Runtime Invariants
- `oddkit_get` on the new canon files (`odd/gate/transitions`, `odd/gate/prerequisites`) to confirm they landed in Phase 1
- 3× independent smoke
7. Accept VERIFIED. Squash-merge. Main-preview smoke 3× clean. Open main → prod PR. Merge. Prod smoke 3× clean.

Estimate: Phase 1 canon writing 30–60 min, Phase 2 code + validation 90–150 min. Total may warrant split across two sessions.

---

## Standing rules (carried from prior handoffs, unchanged)

- **Call `oddkit_time` first every turn.** Pass the prior `server_time` as `reference`. 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 gate's current state or the core-governance-baseline contract.
- **Ground framing in code + canon, not in the latest handoff.** Per P1.3.1 ledger §"Canon Principle Now Standing" — three recurrences justify this as a named principle. If a handoff's word choice disagrees with a contract's enum or a live code reality, the contract/code 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. P1.3.1 shipped with zero advisories specifically because of PRD-first discipline.
- **During execution, produce artifacts, not questions.** Reversion requires one sentence naming the specific unknown.
- **Canon-first is absolute.** This session especially: Phase 1 klappy.dev PR must merge before Phase 2 oddkit PR is opened. Do not write oddkit code that references canon files that do not yet exist.
- **No force-push without `git fetch` first.** 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=/root` in the managed-agent cloud container** (not `/home/user` as 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 deploy` manually.** Githooks + CF auto-deploy handle the pipeline.
- **Branch preview slug rule:** slashes AND dots → hyphens. `gate/governance-source-envelope` → `gate-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 material — read this at session start

Priority order for fresh-session reading:

1. This doc.
2. `klappy://canon/bootstrap/model-operating-contract` — the evolving operating contract.
3. `klappy://odd/ledger/2026-04-20-p1-3-1-challenge-canary-landed` — P1.3.1 closeout with the D4 pivot rationale, validator corroboration pattern, and the three-recurrence evidence for the contract-governs-handoff-drift principle.
4. `klappy://canon/constraints/core-governance-baseline` — the governing contract. Re-read §Runtime Invariants and §What-Ships-in-Baseline (gate's canon docs are candidates for Required-in-Baseline if the build pipeline ever ships).
5. `klappy://canon/principles/vodka-architecture` — the principle this session is applying. Gate is the tool where the anti-pattern has survived longest; this session ends its run.
6. `klappy://canon/principles/agent-self-report-under-stress` — for the validator dispatch.
7. `klappy://canon/meta/frontmatter-schema` — native YAML types only, critical for Phase 1 canon writing.
8. `klappy://odd/challenge/base-prerequisites` — structural template for `odd/gate/prerequisites.md`.
9. `klappy://odd/challenge/stakes-calibration` — reference for table-driven canon that tools parse at runtime.

Reference PRs for canary pattern (same-shape):

- `klappy/oddkit#108` / `#109` — telemetry_policy canary (reference envelope).
- `klappy/oddkit#114` — encode canary completion (P1.2).
- `klappy/oddkit#116` — challenge canary completion (P1.3.1, most recent precedent).

---

## Thin prompt for the next session

```
Resume P1.3.2 per klappy://odd/handoffs/2026-04-21-p1-3-2-gate-canary.

Current state: 0.19.0 in prod (oddkit.klappy.dev), challenge envelope now
declares governance_source + governance_uris (plural array of 4 peer canon
URIs), gate remains the purest remaining vodka anti-pattern in the sweep.
P1.3.1 formally closed at klappy://odd/ledger/2026-04-20-p1-3-1-challenge-canary-landed.

Two-phase scope: (1) write canon docs odd/gate/transitions.md and
odd/gate/prerequisites.md on klappy.dev and merge — canon-first absolute.
(2) refactor oddkit runGateAction to read from canon via {data, source}
helpers, add governance_source + governance_uris (plural) to envelope,
ship as 0.20.0. Orchestrator applies on both repos, Sonnet 4.6 validates
oddkit Phase 2.

Read the handoff. Run the gauntlet on gate's current state + the
core-governance-baseline contract + vodka-architecture principle. Write
the PRD as a file before touching source. May split across two sessions
if Phase 1 canon discussion goes deep.

Credentials in project instructions. No Opus 4.7 execution agents to
oddkit.
```

---

## Provenance

- **Prior session ledger:** `odd/ledger/2026-04-20-p1-3-1-challenge-canary-landed.md` — full retrospective for the P1.3.1 arc.
- **Prior handoff:** `odd/handoffs/2026-04-20-p1-3-challenge-canary.md` — superseded by this document.
- **Merged PRs this cycle:** `klappy/oddkit#116` (feat), `klappy/oddkit#117` (promotion).
- **Target code at current main:** `workers/src/orchestrate.ts` `runGateAction` (currently ~L2097–L2200 post-P1.3.1 edits). Zero canon integration pre-refactor.
Loading