Skip to content

Load plan schemas through the registry and close #6 - #168

Draft
mchwang wants to merge 1 commit into
mainfrom
feat/6-plan-library-alignment
Draft

mchwang wants to merge 1 commit into
mainfrom
feat/6-plan-library-alignment

Conversation

@mchwang

@mchwang mchwang commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

Closes #6.

Summary

#6 was an umbrella issue. PR #4 delivered its library part, and later lanes delivered most of the runner part. This PR closes the remaining library and test gaps and moves the remaining runtime gaps to their own issues. docs/implementation/plan-library-alignment.md maps every obligation in #6 to its code and tests, or to the issue it moved to.

Schema loading (core/plan.ts, core/planning-author.ts)

  • loadPlanSchemas compiles every version in schema/versions.json from its retained snapshots into one validator. Each plan or edit reply is checked by the version it declares; a value with no registered version is checked by the current schema, so v1 callers see the same /schema_version error as before.
  • The loader refuses at module load: an invalid version key; a path with no snapshot, or one already named in the registry; a snapshot whose $id differs from its path, that does not require schema_version with a one-value enum, or whose plan/edit role differs; a validator key or implementation reused, or paired with another semantics document; a missing current version.
  • A validator key with no implementation loads, and that version is refused as unsupported by validate, assertPlan and assertEditReply (docs/plan-format.md: "Treat a missing validator implementation as unsupported"). Before, any v1 registry change other than the exact v1 entry failed module load; test/registry.test.ts still pins the key to v<version>.
  • importPlan requires the current version (no migrations exist). applySuggestion requires the reply's version to equal the plan's. Drafts get the current plan schema; suggestions get the previous plan's edit schema.
  • Behaviour for v1 callers is unchanged: same codes, messages and check order.

Released files pinned

  • test/schema-versions.test.ts pins the SHA-256 of every file a registry entry names. .gitattributes keeps schema/versions/** and the CLI copies LF on checkout.

New tests for the remaining #6 gaps

  • Path identity and base entries (test/review.test.ts): the refusal without a known identity, case and NFC keys, the non-ASCII refusal on case-insensitive checkouts, and Git mode mapping (symlink targets verbatim, gitlinks, executable and odd-named files).
  • Hostile text (test/planning-author.test.ts): repository, issue, lesson, feedback, previous-plan and continuation-context text, in initial drafts, revised drafts and suggestions.
  • Output limits: the decoded supervisor output at the exact stdout and combined limits, in real Docker (test/agent-supervisor.test.ts); the 1 MiB parser limit on a decoded Claude answer in draft validation and the envelope fixtures (test/agent-adapter.test.ts); the 300-unit quote of a failed planning run (test/planning-provider.test.ts).

Not testable while v1 is the only version

Listed in the implementation note: module-level selection in assertPlan/assertEditReply, the current-version import check, the reply/plan version check, which schema each provider gets, and the unsupported refusal on shape-only paths. The loader behaviour behind them is tested through an injected two-version loader.

Follow-up issues

Validation

Base 22e76a8bc90b59c8407bb78bee1c229b249b4936 (baseline), head f9c2e6b11c884e6814790d7f666c4e2cce3a67be (validated head).

Gate Result
Typecheck (npm run typecheck) Pass
Full suite without Docker (vitest --project parallel) 2025/2025 on the final tree
New real-Docker test (agent-supervisor, "decoded output at the … limit") 2/2, run alone
Full real-Docker suite Not run locally (one Docker owner per repo); CI real-docker is the gate
CI Pending

Load-related failures, separate from product results: at load average ~140 (other agents on the machine), three full runs each had one timing failure in files this PR does not touch: pre-merge.test.ts "aborts remote work early enough…", review.test.ts "keeps review load available…", planning-worker.test.ts "never deletes Ask's folders…". Each passed 3/3 alone and in later full runs.

Each new test was checked against a deliberate break of its behaviour; the breaks are listed in the implementation note.

Review record

Round Type and reviewer Pair Findings Changed / declined
1 Independent agent 22e76a8 / uncommitted 8: latent version gaps (imports, reply vs plan version, shared validator keys, double selection), weak tests, CRLF digests All fixed
2 Independent agent same Snapshot not pinned to its version; doc/test-name accuracy; CLI-copy rule All fixed
3–5 Independent agent same required check; evidence overstated; unsupported version passing shape-only paths documented as untested; error-code consistency All fixed
6–12 Independent agent same Doc precision; reused implementations; safe-integer key test; shared semantics paths; missing table rows All fixed
13–17 Independent agent same assertPlan/assertEditReply now refuse unsupported versions; table rows for mounts, termination, schema/output channels, prompt bytes All fixed
18–31 Independent agent same Comment and title wording; 300-unit quote test added; continuation-context hostile test; role check (plan/edit) and its edit half; message names the version All fixed. Declined: the typeof guard in select (needed for TypeScript narrowing); a mutable Map behind a shallow freeze (production loader not exported); pinning examples/ (not conformance fixtures; no test reads them)
32 Independent agent 22e76a8 / tree committed as f9c2e6b None Clean pass

Self-review ran between rounds; every independent round reviewed the full diff against the base. Copilot review has not been requested: this PR is a draft.

Review-lesson audit

Findings were classified against existing rules:

  • Claims in docs and test titles stronger than the tests: covered by CLAUDE.md "Treat every behavioural claim … as something to verify".
  • Behaviour unreachable while v1 is the only version: recorded as explicitly untested in the implementation note (one-off for this PR; the next version's PR must add the tests).
  • Latent second-version defects (version pinning, role swap, shared validators): one-off design hardening for the loader introduced here.
    No new AGENTS.md rule is needed.

🤖 Generated with Claude Code

Every version in schema/versions.json is now compiled from its retained
snapshots, and plans and edit replies are checked by the version they
declare. The loader refuses a registry that disagrees with the snapshots
or validators, and treats a version with no validator as unsupported.

Pin the released v1 files by SHA-256, keep them LF on checkout, and add
the remaining #6 tests: path identity and Git mode mapping, hostile text
in every authoring prompt, and output limits at the exact byte.

Runtime gaps move to #162-#166.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Align plan library with clarified v1 review contracts

1 participant