workflow-fix: inline-gate contract test scans all anchors
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.
Overview / Motivation
Auto-filed by the workflow-fix-on-bug protocol from a workflow-fix candidate raised on task #1516 (emitting agent: implementer, round 1; parked under the recursion guard, routed by the 2026-07-18 /daily Step C parked-candidate sweep).
Goal
Make tests/test_inline_payload_lint_gate_contract.py scan ALL "Inline
payload lint gate" anchor occurrences in SKILL.md (pass if ANY window carries
every needle), or anchor it to the canonical Step 9a-ter heading, so an
earlier mention of the gate no longer false-fails the contract pin.
Workflow gap
- Bug observed:
test_skill_9a_ter_carries_inline_payload_lint_gatefails on pristine main — the test scans a 4,000-char window after the FIRST "Inline payload lint gate" occurrence in SKILL.md, but the #1500-era block at ~L6524 added an EARLIER occurrence whose window lacks the pinnedscripts/workflow_lint.pyneedle, so the contract test reads the canonical 9a-ter block as lost. - Why it is a workflow gap: the contract test keys on first-occurrence position rather than the canonical block, so any SKILL.md edit mentioning the gate earlier breaks the pin with no real contract drift — a red mapped test every Step 9c consumer trips over.
- Confidence (emitter): high
- verified-at-filing:
uv run python -m pytest tests/test_inline_payload_lint_gate_contract.py -x -q→ 1 failed (AssertionError at tests/test_inline_payload_lint_gate_contract.py:71) — red reproduced on main at compose time; context read of the test (L50-75) confirmsidx = text.find(ANCHOR)single-first-occurrence scan + 4,000-char window as claimed;git log --oneline --since='7 days ago' -- tests/test_inline_payload_lint_gate_contract.py→ 1 commit (31d1c63dba, the #1460 pin itself — no anchor fix landed) (2026-07-19)
Proposed change (candidate diff sketch — refine in planning)
- idx = text.find(ANCHOR); window = text[idx : idx + 4000]
+ starts = [m.start() for m in re.finditer(re.escape(ANCHOR), text)]
+ windows = [text[s : s + 4000] for s in starts]
+ for needle, why in (...): assert any(needle in w for w in windows)
Scope / surfaces
- Primary target:
.claude/skills/issue/SKILL.md, tests/test_inline_payload_lint_gate_contract.py - Grep the workflow surface for the pattern before editing
(
grep -rln 'Inline payload lint gate' .claude/ CLAUDE.md scripts/ tests/) and confirm which occurrence is the canonical Step 9a-ter block; list every hit in the plan.
Constraints / invariants
- Workflow-surface only — never experiment code,
configs/, ortasks/. - The fix must keep the pin's teeth: the canonical 9a-ter block losing a needle must still FAIL (the any-window form must not let a needle migrate to a non-canonical mention and mask real drift — the planner weighs any-window vs canonical-heading anchoring on exactly this).
- Full test file passes after the fix;
scripts/workflow_lint.pyno-flags run passes. - This session runs under
EPM_WORKFLOW_FIX_SESSION=1and carries aworkflow_fix_target:Provenance line — it MUST NOT auto-route any of its own subagents' workflow-fix candidates (recursion guard, § Recursion guard).
Provenance
- workflow_fix_target: .claude/skills/issue/SKILL.md, tests/test_inline_payload_lint_gate_contract.py
- fingerprint: 4be7f080de5d
target_file: .claude/skills/issue/SKILL.md, tests/test_inline_payload_lint_gate_contract.py bug_observed: test_skill_9a_ter_carries_inline_payload_lint_gate fails on pristine main — the test scans a 4,000-char window after the FIRST "Inline payload lint gate" occurrence in SKILL.md, but the #1500-era block at ~L6524 added an EARLIER occurrence whose window lacks the pinned scripts/workflow_lint.py needle, so the contract test reads the canonical 9a-ter block as lost. why_workflow_gap: the contract test keys on first-occurrence position rather than the canonical block, so any SKILL.md edit mentioning the gate earlier breaks the pin with no real contract drift — a red mapped test every Step 9c consumer trips over. proposed_change: scan ALL anchor occurrences (pass if ANY window carries every needle), or anchor to the canonical Step 9a-ter heading. diff_sketch: |
- idx = text.find(ANCHOR); window = text[idx : idx + 4000]
- starts = [m.start() for m in re.finditer(re.escape(ANCHOR), text)]
- windows = [text[s : s + 4000] for s in starts]
- for needle, why in (...): assert any(needle in w for w in windows) confidence: high related_task: #1516