workflow-fix: Step 5a spec-freshness sync stages a CLAUDE.md whose workflow.yaml gate-key references cannot resolve, because CLAUDE.md is a FAMILY_OF singleton while .claude/workflow.yaml is in FAMILY_workflow
Highlight text on any card (body, plan, or an event) to anchor a comment, or leave a whole-task comment here. Mention @claude to summon a reply.
No comments yet.
Goal
Make the Step 5a family-atomic spec-freshness sync unable to stage a CLAUDE.md whose gate-key references cannot resolve against the .claude/workflow.yaml the same sync deliberately skipped. Either (a) CLAUDE.md joins FAMILY_workflow so the two move together or neither moves, or (b) the workflow_lint.py gate-key reference check gains the same present-at-main tolerance the SKILL-reference check already has for this exact stale-worktree shape.
Observed failure (task #2538, Step 5a, 2026-08-24)
The Step 5a sync in the issue-2538 worktree staged 17 paths and the commit FAILED with workflow-yaml-lint exit 1:
workflow_lint: CLAUDE.md: unresolved reference ... not in workflow.yaml
workflow_lint: FAIL (1 error(s))
Root cause is a cross-family skew, not a stale spec:
CLAUDE.mdis a singleton in the Step 5aFAMILY_OFmap, so it synced tomain's newer copy. That copy references(see workflow.yaml § gates.clarify_experiment_ask)..claude/workflow.yamlis a member ofFAMILY_workflow, which was dirty with #2538's own payload, so the sync correctly skipped the whole family (the family-atomic fail-safe: any dirty member widens the skip, never a clobber).- Result:
main'sCLAUDE.mdlanded in a tree holding the worktree's olderworkflow.yaml, which does not yet definegates.clarify_experiment_ask. The reference is unresolvable by construction of the sync, not because either file is wrong.
The #2538 session chose RESET over commit, per the spec's own instruction, because committing main's CLAUDE.md without main's workflow.yaml would land a broken cross-reference on the issue branch and then onto main. Restore rc=0, tree clean, HEAD unchanged, payload intact, --check-references back to PASS. The sync therefore cannot complete in any worktree whose payload touches FAMILY_workflow, which is every workflow-surface task that edits workflow.yaml.
Why this is a distinct bug from #2538
Different file, different mechanism. #2538 fixed a missing gh pr ready precondition in .claude/skills/issue/steps/18-step-10d.md. This is the Step 5a sync block's family map (.claude/skills/issue/steps/09-step-5.md) and/or scripts/workflow_lint.py's reference check. #2538's own run merely surfaced it.
The asymmetry worth grounding the fix on
The SKILL-reference check already tolerates this exact stale-worktree shape (#1622/#1672, recorded as "Not blocking"), while the workflow.yaml gate-key reference check hard-FAILs on an identical root cause. One of the two behaviors is wrong for the family-atomic sync; the fix should make them consistent rather than adding a third behavior.
Suggested direction (not prescriptive; the planner owns the design)
- Option (a):
CLAUDE.mdjoinsFAMILY_workflow. Same rationale that already documentstests/issue_skill_source.pyas a singleton-by-cross-import: membership should follow the reference graph, not the directory. Cost: a dirtyworkflow.yamlnow also freezesCLAUDE.md's sync, which is the conservative direction the family-atomic rule already chose everywhere else. - Option (b): present-at-main tolerance in the gate-key check. When an unresolved gate key IS defined in
origin/main'sworkflow.yaml, downgrade to WARN, mirroring the SKILL-reference check's existing tolerance. Cost: a genuinely-deleted gate key referenced byCLAUDE.mdwould WARN instead of FAIL until main catches up. - Audit the rest of the
FAMILY_OFmap for the same shape. Any other singleton that is a cross-family reader of a family member has this bug latent.CLAUDE.mdis unlikely to be the only one; the.claude/rules/*.mdfiles that quoteworkflow.yamlgate keys are the obvious next candidates. - Worth a mechanical pin: a check asserting that every file whose content references
workflow.yamlgate keys is in the sameFAMILY_OFfamily as.claude/workflow.yaml(or is explicitly exempted with a recorded reason), so a future singleton cannot silently re-acquire the skew.
Reproduction
In any worktree whose branch modifies .claude/workflow.yaml, run the Step 5a spec-freshness sync (.claude/skills/issue/steps/09-step-5.md lines 241-599) and attempt the commit. The workflow-yaml-lint pre-commit hook exits 1 on the unresolved CLAUDE.md reference.
Sibling class: the fourth instance, which argues for the generalizing fix
Four tasks now report the same CLASS: a file is missing from, or mis-assigned in, the Step 5a family map, so a half-sync leaves the tree internally inconsistent and a gate goes red. Each has a different member and a different family, so none is a duplicate of another under the (target_file, fingerprint) dedup. The repetition is the signal.
- #2260 (completed):
test_mapping_baselines_wiring_pins.pynot coupled to the.claude/agentsfamily. Half-sync gate red. - #2498 (proposed):
FAMILY_lintomitsscripts/pre_split_review_guard.py. Half-sync reds the step9c lint pins. - #2553 (proposed): the spec-freshness SPECS list omits
.gitleaksignore; the sibling-file arm stages siblings it cannot commit. - #2557 (this task):
CLAUDE.mdis a singleton yet reads.claude/workflow.yaml, aFAMILY_workflowmember.
Three of the four were found the hard way, by a failing commit inside an unrelated task's Step 5a. That is what makes suggested-direction bullet 4 (the mechanical membership pin) the higher-value half of this task: options (a) and (b) fix the CLAUDE.md instance, while a pin that derives family membership from the reference graph closes the class. A planner that fixes only the instance should say why the class is left open.
Note also #2456 (proposed), which enforces bidirectional parity between the two COPIES of FAMILY_OF (Step 5a and Step 10d). That is orthogonal: it makes the two copies agree, not the assignments correct. A fix here must land in both copies to stay #2456-clean.
Provenance
workflow_fix_target: .claude/skills/issue/steps/09-step-5.md (the Step 5a FAMILY_OF map) and/or scripts/workflow_lint.py (the gate-key reference check)
Surfaced by task #2538's own Step 5a spec-freshness sync (2026-08-24), not by a review. The sync staged 17 paths in the issue-2538 worktree and the commit FAILED with workflow-yaml-lint exit 1. The #2538 session chose RESET over commit per the spec's own instruction, so #2538's payload landed without the spec-freshness sync; that deviation is recorded on #2538 at epm:progress v15.
Evidence on #2538: the failing commit output, the staged 17-path set, and the post-restore verification (rc=0, tree clean, HEAD unchanged at 362eb2842f15, payload intact, --check-references back to PASS).