Template 14: the plan as a contract of closed sections and scheduled tasks - #19
Merged
Conversation
… tasks A plan stops being a document and becomes a header plus a checklist. Six sections and no others — Why, Paths, References, Out of scope, Tasks, Done when — because a closed set is the only thing that ever capped a plan's size: the 56KB plan we measured got there through `## Notes`, which nothing forbade, growing to half the file. There is no line limit anywhere in the contract except on the description, since a limit that fires on a legitimate plan is worse than the growth it prevents; what there is instead is nowhere for prose to go. `## Decomposition` becomes `## References`, and that cost almost nothing: parseLeaves recognizes a leaf by its `specs/<feature>/` citation anywhere in the file rather than by the heading above it, so Leaf, the `specs/foo/` address and `map trace` all keep working untouched. A task gains four flags and no more — _Depends_, _Priority_, _Status removed_, _Reason_ — and the vocabulary is closed because an italic one-liner is a shape prose also uses: a parser that absorbed any of them would eat a sentence and hand the task a region that is not the task. Three consequences had to land together or the result is worse than before: Task.End covers the flags, Detail excludes them, and renderTask re-emits them along with the continuation. Without the last one, `patch task --method TDD` was a data-loss command that deleted a sixty-line description and every dependency the task declared. `map brief` is the header, `map tasks` is the checklist, and no command returns both — which is what gives "never read the plan" the authority to be a rule. A session pays brief once and --next per task instead of ~14k tokens per reread. --next is now determined (eligible, then priority ascending with absent last, then number compared numerically, which also fixes 1.10 sorting before 1.9) and --ready/--blocked/--deps share that one implementation. `plan approve` writes status and a checksum over the file minus its own checksum line. It is tamper-evidence, not prevention, and it is checked before an edit is applied — a harness that edited by hand and then ran `patch check` would otherwise have its edit resealed by the command that should have reported it. After approval only discovery moves: add allocates the number from a high-water mark that counts struck-out tasks, rm strikes in place, and rewriting a task or the prose is refused. `plan migrate` moves a v1 plan across without deleting anything. Budget, measured because this is where the gain could be lost: entry.md + rules/artifacts.md + rules/tasks.md went from 175 lines / 8539 bytes to 177 / 9248. The caps the tests already imposed still hold. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DmGyL6QvamMBKdHYyrx7Uq
protonspy
force-pushed
the
template-13-and-launch-rtk
branch
from
August 5, 2026 04:29
27b665f to
fbe6a44
Compare
The flag-aware version took over every call site, so the wrapper was dead the moment it was written. Caught by golangci-lint's `unused`, which does not run on the machine this was written on. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DmGyL6QvamMBKdHYyrx7Uq
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.
A plan stops being a document and becomes a header plus a checklist.
Closed sections
Why,Paths,References,Out of scope,Tasks,Done when, and nothing else. That is the only thing that ever capped a plan's size — the 56KB plan we measured got there through## Notes, which nothing forbade, growing to half the file. There is no line limit anywhere in the contract except on the description: a limit that fires on a legitimate plan is worse than the growth it prevents. What there is instead is nowhere for prose to go.## Decompositionbecomes## References, and that cost almost nothing —parseLeavesrecognizes a leaf by itsspecs/<feature>/citation anywhere in the file rather than by the heading above it, soLeaf, thespecs/foo/address andmap traceall keep working untouched.Four flags on a task, and no more
_Depends_,_Priority_,_Status removed_,_Reason_. The vocabulary is closed because an italic one-liner is a shape prose also uses: a parser that absorbed any of them would eat a sentence and hand the task a region that is not the task. An unknown one istask.unknown-flag, reported and left where it sits._Status_never takesopenorcompleted— the box is the state, and a flag that could restate it is theitem-has-two-recordsdefect arriving by another door.(Unit)/(TDD)is reused as the test strategy rather than a new_Test_flag: zero migration, and the concept already had a name.Three consequences had to land together or the result is worse than before:
Task.Endcovers the flags,Detailexcludes them, andrenderTaskre-emits them along with the continuation. Without the last one,patch task --method TDDwas a data-loss command that deleted a sixty-line description and every dependency the task declared.A reading surface, shipped before the rule that depends on it
map briefis the header,map tasksis the checklist, and no command returns both — which is what gives "never read the plan" the authority to be a rule rather than a wish. Forbidding the read without offering the equivalent query produces an agent that disobeys, correctly. A session now paysbriefonce and--nextper task instead of ~14k tokens per reread.--nextis determined: eligible, then priority ascending with absent last, then number compared numerically — which is also the fix for1.10sorting before1.9.--ready,--blockedand--depsshare that one implementation, because two notions of eligibility would be two answers to "what do I work on".The seal
plan approvevalidates, then writesstatus: approvedand achecksum:over the file minus its own checksum line, LF-normalized. It is tamper-evidence, not prevention —reseal --forceis one command away and sha256 is public — and it is checked before an edit is applied, which is the whole value: a harness that edited by hand and then ranpatch checkwould otherwise have its edit resealed by the command that should have reported it. A plan with nostatus:is never checked, which is what makes every pre-existing plan keep working.After approval only discovery moves:
addallocates the number from a high-water mark that counts struck-out tasks (so nothing is stored anywhere),rmstrikes in place, and rewriting a task or the prose is refused. What discovery can never touch is guaranteed structurally —Why,Out of scope,Done whenand the title are reachable only throughappend/prepend/replace, and those are exactly the three refused.plan migratemoves a v1 plan across: renamesDecomposition, moves every other heading toplans/archive/<name>-notes.md, creates missing required sections empty and lets the findings appear — a placeholder that satisfied the validator would be a plan that lies — and writesstatus: draft, neverapproved.Where the implementation differs from
design/plan-format-v2.mdRecorded at the top of that file too, so it is not rediscovered later.
## Pathsdoes not check that a path exists. The proposed warning would need a severityinternal/findingdoes not have (the JSON shape is frozen), and under 0/1/2 it becomes an error — on a document that by construction names files that do not exist yet. That is a validator firing on correct input.task.dependency-cycle, notplan.— §8.3 and §14 contradicted each other; the rule lives beside the nine other flag rules and applies to a spec'stasks.mdequally.plan resealprints no diff against the old seal. A seal is a hash; the old content is not recoverable from it. It prints both hashes and points atgit diff, which has the diff.plan.status-invalidandplan.unsealed—status: approvedwith nochecksum:is a plan claiming a seal that is not there, and every read would silently skip the check._Reason_also marks a task added after approval, not only a removed one. It answers the same question: why this line is not what the approved plan said.Token budget, measured
The one place the goal could be lost: these three files are preloaded into every request on a harness that reads
rules/.entry.mdrules/artifacts.mdrules/tasks.md+2 lines, +709 bytes, against ~14k tokens saved per plan reread. The caps the tests already imposed — 55 lines per rule, 60 for the entry file — still hold; the first drafts blew all three and existing prose had to be compressed to fit.
assets.Versiongoes to"14". Plans are user artifacts andscc updatenever touches them — migration isscc plan migrate.Checks
go test ./...,gofmt -l,go vetclean locally.-racewas not run here (no gcc on this machine; the Windows CI job does not run it either — the Linux and macOS jobs do).TestFreshArtifactsPassTheirOwnValidatorspasses on the v2 template, and the seal canonicalization is frozen by a golden test that covers the CRLF case.🤖 Generated with Claude Code
https://claude.ai/code/session_01DmGyL6QvamMBKdHYyrx7Uq