fix(han-planning): pin shared contracts before implementation - #204
Merged
Conversation
Closes #107. The planning chain had no checkpoint forcing an interface or data contract into concrete, buildable form before implementation, so a "trusted" plan could ship a shared contract as a to-be-authored deliverable and a builder would invent it mid-build. Two additive gaps: plan-implementation never required a contract in concrete form, and plan-work-items split one contract across items with no rule against it. Adds han-planning/references/contract-pinning-rule.md, owned by han-planning and consumed by four skills. It defines what counts as a contract, what counts as pinned, the phrases that never close one, and which stage owns pinning it. The rule is binary: there is no deferred-with-reason state, because an author who has one writes "TBD at build" and passes. plan-implementation pins it: a new operating principle, a Decision-field rule making the decision log treat a format grammar the way it already treats a key name, a specialist-brief directive so the finding is generated at all, and a binary aggregation check that raises an Open Question rather than touching the spec-maturity gate's counted trip conditions. plan-work-items keeps it whole: a shared contract is pinned in the item that introduces it with consumers sequenced behind it, and the passive "not draftable" flag gains an exception for a contract this breakdown itself authors. Step 4 now reads the plan's Open Items, including the non-blocking ones it previously never looked at. iterative-plan-review backstops it: five keywords added to both force-up lists and a Contract Check in the iteration checklist. plan-a-feature records the delegation: routing rule 3 gains one carve-out so a shared contract becomes an Open Item rather than vanishing. check-contract-pinning.sh gives the rule a mechanical proxy, reporting four failure classes separately and skipping fenced blocks so a worked example never reads as a deferral. Two tests guard it beyond behavior: the two per-skill copies stay byte-identical, and every phrase the script owns appears in the canonical rule.
…guidance Two conformance fixes plus one gap the contract-pinning work missed. Script calls were fenced code blocks in five skills. The authoring guidance (han-plugin-builder/skills/guidance/references/skill-building-guidance/script-execution-instructions.md) requires prose with an action verb, because Claude may read a fenced block as code to display rather than a command to run. Converted every remaining call site: plan-a-feature, plan-a-phased-build, plan-work-items, and han-reporting/html-summary. plan-a-feature/SKILL.md was 501 lines, one past the 500-line ceiling. The `T#` note lifecycle was split across Step 4 (capture) and Step 5 (flush), which is how the two halves drift apart. Both now live in one owned reference, references/t-note-protocol.md, carrying the qualifying tests, the in-message accumulator form, the flush procedure, and the no-candidate case. The file is 476 lines. The contract-pinning change updated both force-up keyword lists in iterative-plan-review but missed a third in plan-a-feature's finding-resolution.md. A finding that leaves a shared contract un-pinned now forces up to major there too, and the pure-implementation branch names the Open Item carve-out that mechanic-routing.md added.
The CLAUDE.md repository layout named only references/ under the han-planning skills directory, but every one of its five skills also carries scripts/. The plan-implementation long-form doc opened its "What you get back" section with "Four cross-referenced files" and then listed three, omitting artifacts/scope-boundary.md, and its summary bullet promised "All three file paths". The section also never named the two executed checks the skill runs before it summarizes, though the sibling planning docs name theirs.
mxriverlynn
marked this pull request as ready for review
September 8, 2026 19:15
This was referenced Sep 8, 2026
Draft
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.
Summary
han-planning/references/contract-pinning-rule.md) consumed by four skills, plus one executable check with 15 Bats tests.plan-a-feature/SKILL.mdbrought under the 500-line ceiling.Why
The chain (
plan-a-feature→plan-implementation→plan-work-items, withiterative-plan-reviewas backstop) had no checkpoint forcing a contract into concrete form, so a "trusted" implementation plan could ship one as a to-be-authored deliverable. In the grounding incident the ledger's entry types were named but its line grammar never was: the schema doc shipped without it, a scanner invented a parsing regex against the undefined format, and the real grammar was retrofitted a day later. Zero of 17 review findings raised the gap.Two additive gaps caused it.
plan-implementationnever required a contract in concrete form, andplan-work-itemssplit one contract across items with no rule against it. Fixing either alone leaves the other live.What reviewers should look at closely
The rule is binary, with no deferred-with-reason state. That was deliberate: an author who has an escape hatch writes "the grammar depends on the serialization library, TBD at build" and passes while leaving the same hole.
The new aggregation check stays out of the spec-maturity gate. That gate counts findings from distinct specialists, and a binary condition bolted onto counted logic breaks it. An unpinned contract raises an
OQ-Ninstead, which the Step 6 loop already knows how to settle.plan-work-itemsnow reads the plan's Open Items. It previously never looked at that section at all, so a non-blocking open item vanished at the last stage that could see it. This came from a comment on the issue and generalizes past contracts.The script is the only non-prose enforcement. Nine of ten changes are instructions followed by the same class of agent that missed the gap.
check-contract-pinning.shreports four failure classes separately and skips fenced blocks so a worked example never reads as a deferral. Two tests guard it beyond behavior: the per-skill copies stay byte-identical, and every phrase the script owns appears in the canonical rule.How to verify
npm run lintnpm test(95 tests, 15 of them new)bash han-planning/skills/plan-implementation/scripts/check-contract-pinning.sh <a plan file> <its folder>against a real plan folderhan-planning/references/contract-pinning-rule.mdfirst; every other change cites itRisk / rollback
Low. Nothing here changes an existing check's pass condition, and the one new executable check is additive. The largest behavioral change is that
plan-implementationnow treats an unpinned contract as reason to keep iterating rather than to ship, which can add a round on a plan that introduces a format. Revert withgit revert.Not in this PR
/han-release.feature-implementation-plan-template.mdis 163 lines with no Contents list. It is a document skeleton, so a Contents list would be copied into every plan it generates. Left as-is deliberately.