Skip to content

Template 14: the plan as a contract of closed sections and scheduled tasks - #19

Merged
protonspy merged 2 commits into
mainfrom
template-13-and-launch-rtk
Aug 5, 2026
Merged

Template 14: the plan as a contract of closed sections and scheduled tasks#19
protonspy merged 2 commits into
mainfrom
template-13-and-launch-rtk

Conversation

@protonspy

@protonspy protonspy commented Aug 5, 2026

Copy link
Copy Markdown
Owner

A plan stops being a document and becomes a header plus a checklist.

Rebased onto main after the caveman.md and launch --rtk commits landed there separately — this PR is now the single plan-v2 commit.

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.

## 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.

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 is task.unknown-flag, reported and left where it sits. _Status_ never takes open or completed — the box is the state, and a flag that could restate it is the item-has-two-records defect 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.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.

A reading surface, shipped before the rule that depends on it

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 rather than a wish. Forbidding the read without offering the equivalent query produces an agent that disobeys, correctly. A session now pays brief once and --next per task instead of ~14k tokens per reread.

--next is determined: eligible, then priority ascending with absent last, then number compared numerically — which is also the fix for 1.10 sorting before 1.9. --ready, --blocked and --deps share that one implementation, because two notions of eligibility would be two answers to "what do I work on".

The seal

plan approve validates, then writes status: approved and a checksum: over the file minus its own checksum line, LF-normalized. It is tamper-evidence, not preventionreseal --force is 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 ran patch check would otherwise have its edit resealed by the command that should have reported it. A plan with no status: is never checked, which is what makes every pre-existing plan keep working.

After approval only discovery moves: add allocates the number from a high-water mark that counts struck-out tasks (so nothing is stored anywhere), rm strikes in place, and rewriting a task or the prose is refused. What discovery can never touch is guaranteed structurally — Why, Out of scope, Done when and the title are reachable only through append/prepend/replace, and those are exactly the three refused.

plan migrate moves a v1 plan across: renames Decomposition, moves every other heading to plans/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 writes status: draft, never approved.

Where the implementation differs from design/plan-format-v2.md

Recorded at the top of that file too, so it is not rediscovered later.

  • ## Paths does not check that a path exists. The proposed warning would need a severity internal/finding does 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.
  • The cycle finding is task.dependency-cycle, not plan. — §8.3 and §14 contradicted each other; the rule lives beside the nine other flag rules and applies to a spec's tasks.md equally.
  • plan reseal prints 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 at git diff, which has the diff.
  • Two rules more than planned: plan.status-invalid and plan.unsealedstatus: approved with no checksum: 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/.

File Before After
entry.md 67 lines / 3170 B 67 / 3169
rules/artifacts.md 55 / 2749 55 / 3025
rules/tasks.md 53 / 2620 55 / 3054
total 175 / 8539 177 / 9248

+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.Version goes to "14". Plans are user artifacts and scc update never touches them — migration is scc plan migrate.

Checks

go test ./..., gofmt -l, go vet clean locally. -race was not run here (no gcc on this machine; the Windows CI job does not run it either — the Linux and macOS jobs do). TestFreshArtifactsPassTheirOwnValidators passes 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

… 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
protonspy force-pushed the template-13-and-launch-rtk branch from 27b665f to fbe6a44 Compare August 5, 2026 04:29
@protonspy protonspy changed the title Template 14: the plan as a contract, plus the compressed register and RTK at launch Template 14: the plan as a contract of closed sections and scheduled tasks Aug 5, 2026
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
@protonspy
protonspy merged commit 2f01078 into main Aug 5, 2026
4 checks passed
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.

1 participant