spec(storyboards): first-class branch_set phase field (#2633)#2646
Merged
Conversation
Phases in an any_of branch set previously declared membership implicitly by
sharing a contributes_to flag value that matched a later assert_contribution
step's any_of target. A typo in contributes_to silently broke membership and
made a conformant agent on the correct branch look like it failed everywhere.
Adds an optional branch_set: { id, semantics } object on phases and a new
lint-storyboard-branch-sets script that enforces:
1. Branch-set phases are optional: true.
2. branch_set.semantics is a supported value (any_of today).
3. Peer phases sharing branch_set.id share semantics.
4. Every declared branch_set.id has a matching assert_contribution any_of.
5. contributes_to inside a branch-set phase equals branch_set.id.
Implicit detection is preserved as a fallback so pre-#2633 storyboards keep
working. Migrates schema-validation.yaml (past_start_handled) and
security.yaml (auth_mechanism_verified) to the explicit form. Sets up #2634
contradiction lint to key off an explicit declaration rather than reverse-
engineering topology.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Expert review on PR #2646 converged on five must-fix items. 1. Lint rule `peer_not_declared`: a mixed-mode storyboard (one peer declares branch_set: explicitly, a sibling optional peer still relies on implicit contributes_to for the same flag) would be graded by a runner preferring the explicit declaration as a single-member set — the legacy peer's failing steps would surface as `failed` instead of `peer_branch_taken`. New rule: if any phase declares branch_set:{id:X}, every optional phase whose steps contribute to X must also declare branch_set:{id:X}. Storyboards in pure-implicit mode (no branch_set: anywhere) are unaffected. 2. Lint refactor: export lintDoc(doc, { supportedSemantics }) and tag every violation with a stable `rule` field. Tests assert on rule IDs instead of message prose, and the semantics-conflict test injects a synthetic supported set rather than monkey-patching module state. 3. Doc rewrite for storyboard-schema.yaml "Branch sets": - Minimal YAML example moved ahead of the constraint list. - New storyboards MUST declare branch_set: (was SHOULD); the implicit fallback is explicitly DEPRECATED for new work. - `at_least_n`/`all_of` reserved-name sentence dropped — a documented value the lint rejects is a footgun. - contributes_to: on contributing steps is now called out as still REQUIRED; the phase-level branch_set: does not replace per-step contribution signalling. - Terminology tightened: "aggregation flag" dropped in favor of branch_set.id throughout. - New "When to use a branch set" note: only when the spec permits multiple conformant behaviors, not for optional features or progressive disclosure. 4. runner-output-contract.yaml peer_branch_taken cross-reference updated to point at the new "Branch sets" heading (the old "Per-step grading in any_of branch patterns" heading no longer exists after this PR). Detail shape updated to reference branch_set.id rather than the legacy "aggregation flag" term. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
contributes_tocorrelation to an explicitbranch_set: { id, semantics }phase field, per Promote branch_set to first-class storyboard schema construct #2633.lint-storyboard-branch-sets.cjs(wired intobuild:complianceandnpm test) enforcing the authoring rules.universal/schema-validation.yaml(past_start_handled) anduniversal/security.yaml(auth_mechanism_verified) to the explicit form.Why now
Expert review on #2631 flagged the implicit detection as fragile: a typo in
contributes_to:silently breaks branch-set membership, and a conformant agent on the "correct" branch can look like it failed everywhere. Making the relationship declared (not inferred) closes that gap.This also sets up #2634 (contradiction lint) — keying contradiction detection off an explicit declaration is much simpler than reverse-engineering topology from
contributes_toheuristics. Shipping #2633 first avoids rewriting #2634 a week after it lands.Rules the lint enforces
branch_set:must beoptional: true(otherwise unconditional-fail defeats the any_of semantics).branch_set.semanticsmust be a supported value (any_oftoday;at_least_n/all_ofreserved).branch_set.idsharesemantics.branch_set.idhas a matchingassert_contributionstep withcheck: any_of, allowed_values: [<id>]— otherwise the branch set is dead.contributes_to: XhasX === branch_set.id— catches the exact typo class this PR exists for.Implicit detection stays as a runner fallback so pre-#2633 storyboards keep working unchanged.
Test plan
npm run test:storyboard-branch-sets— 7 tests (1 source-tree guard + 5 per-rule synthetic fixtures + 1 helper test)npm run test:storyboard-scoping— unchanged, passesnpm run build:compliance— new lint runs alongside scoping lint; 10 universal / 6 protocols / 24 specialisms builtnpm run test:unit+npm run typecheck(precommit) — 631 tests passbranch_set.semantics: any_ofis the right v1-only value (vs. leavingsemanticsopen)Sequel: #2634 contradiction lint, now trivially keyed off
branch_set:rather than heuristic detection.🤖 Generated with Claude Code