Conversation
Production preview test caught a real show-stopper: the MCP tool's mode parameter Zod schema accepted only exploration/planning/execution but the calibration governance article (odd/challenge/stakes-calibration) defines 9 modes. The 6 writing-lifecycle modes (voice-dump, drafting, peer-review-ready, canon-tier-2, canon-tier-1, published-essay) were unreachable from the public API — schema validation rejected them before runtime ever saw them. Net effect of the bug: the voice-dump suppression invariant — the load-bearing feature of PR #100, named in evidence as load-bearing — could not be exercised through the public MCP tool. Internal tests worked because they bypassed the schema. The CI 'Test CF Preview' job failed on cold-start timeout (red herring); the real failure was discovered by manual curl against the preview. Two sites in workers/src/index.ts: - Line 170: unified oddkit tool - Line 235: dedicated oddkit_challenge tool Both expanded to the full 9-mode enum. Description text updated to explain the two mode families and call out voice-dump suppression. Longer-term direction (not this commit): drop the enum entirely and let canon be the validator. The runtime already validates against the calibration table at fetchStakesCalibration time — having the schema also enforce vocabulary is the same Vodka anti-pattern shape that PR #100 fixed for stop words. Tracked as a follow-up. Verification: - npm run typecheck: clean - workers/test/governance-parser.test.mjs: 97/97 against main - Manual preview curl with mode=voice-dump pending after this deploys Lesson: testing the running preview is not optional. PR #100 had typecheck pass, parser test 97/97, smoke 6/6, AND production preview deploy succeed — and still shipped a feature the schema blocked from being called. Three layers of verification missed it because none of them exercised the public API contract.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
oddkit | 3a58851 | Commit Preview URL Branch Preview URL |
Apr 17 2026, 03:22 PM |
klappy
added a commit
that referenced
this pull request
Apr 17, 2026
Parallels PR #102 which fixed the same enum in workers/src/index.ts. The local tool registry at src/core/tool-registry.js drives the local MCP server (src/mcp/server.js) and CLI (src/cli.js) and had the same 3-mode enum, creating a contract divergence between the deployment surfaces for the same logical API. Two sites in src/core/tool-registry.js: - Line 47-55 (unified oddkit tool) - Line 113-121 (dedicated oddkit_challenge tool) Both expanded to the full 9-mode enum with description text matching PR #102's style. Mode families explained, voice-dump suppression called out in the dedicated tool description. Sweep verified: grep across src/ and workers/ for the 3-mode string returns only the first line of each 9-mode block now — zero stale enums. Caught by bugbot on PR #103 (the promotion PR for #102). Flagged appropriately as Low severity (the CF Worker surface is the primary production path; the local surface is used for dev/CLI). Fixing in a separate PR so #103 can promote cleanly without rebase. Verification: - npm run typecheck: clean - tests/smoke.sh: 6/6 pass Longer-term (same as #102 flagged): drop enum entirely and let canon be the validator. Hardcoding mode vocabulary in schema is the same Vodka anti-pattern shape challenge stop words used to be.
klappy
added a commit
that referenced
this pull request
Apr 17, 2026
) Parallels PR #102 which fixed the same enum in workers/src/index.ts. The local tool registry at src/core/tool-registry.js drives the local MCP server and CLI and had the same 3-mode enum, creating contract divergence between surfaces. Both sites expanded to 9-mode enum with description text matching PR #102 style.
This was referenced Apr 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Schema unblock for the voice-dump suppression invariant
Caught by actually testing the production preview after PR #100 merged. The MCP tool's
modeparameter Zod schema only acceptedexploration,planning,execution— butodd/challenge/stakes-calibrationdefines 9 modes. The 6 writing-lifecycle modes were unreachable from the public API.Demonstration
The voice-dump suppression invariant — the load-bearing feature PR #100's evidence note specifically calls out — was unreachable from the public MCP tool. Schema validation rejected the call before runtime ever saw it.
Fix
Two enum sites in
workers/src/index.tsexpanded from 3 modes to all 9.How three layers of verification missed this
The CI "Test CF Preview" job failed on cold-start timeout (red herring) and exercised orient/search/validate/preflight — none of them with
mode: voice-dump. The bug was reachable only by calling the tool with the load-bearing mode value through the public contract.Longer-term follow-up (not this PR)
Drop the enum entirely. Let canon be the validator. Runtime already validates against the calibration table at
fetchStakesCalibrationtime. Having the schema also enforce vocabulary is the same Vodka Architecture anti-pattern PR #100 fixed for stop words — domain opinion living in worker source instead of canon. Tracked as a follow-up issue.Effect on PR #101 (prod promotion)
Hold #101 until this lands. Promoting PR #100 to prod without this fix ships a feature whose load-bearing invariant is unreachable.
Verification
npm run typecheck: cleanworkers/test/governance-parser.test.mjs: 97/97 against mainmode=voice-dumppending after this deploysLesson recorded
Testing the running preview is not optional. Three layers of verification missed this because none exercised the public API contract end-to-end. Adding a preview-contract test (curl-based, exercises every documented
modevalue) is the next workflow improvement.Note
Low Risk
Low risk: only broadens Zod validation for the
modeargument onoddkitandoddkit_challenge, with no execution-path changes beyond accepting additional enum values.Overview
Updates the MCP request schemas so the
modeparameter accepts all 9 canon-defined modes (adds writing-lifecycle values likevoice-dump,drafting, andpublished-essay) instead of onlyexploration/planning/execution.This unblocks clients from calling
oddkitandoddkit_challengewithmode=voice-dump(and related lifecycle modes) without failing argument validation, and clarifies the mode semantics in the parameter descriptions.Reviewed by Cursor Bugbot for commit 3a58851. Bugbot is set up for automated code reviews on this repo. Configure here.