workflow-fix: step9c violation-path extraction takes every path token per line (snippet false-block residual)
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
Close the false-BLOCK residual in extract_violation_paths
(scripts/step9c_baseline.py, landed by #2316 as 589436e8fd), and exercise or drop
the dead paired_failure_texts harness knob.
The gap
extract_violation_paths extracts EVERY tracked-path-shaped token per violation line,
including tokens embedded in a violation row's SNIPPET (#2316's own T10 trio fixture
extracts scripts/task.py out of a snippet). A branch that adds or edits an offending
line in an ALREADY-red file, such that the new snippet embeds a tracked-path token
absent from the pristine text, yields new_paths = {that token} → rc 1 naming a
NON-offender path.
Narrow (requires the branch to touch a violating line; the pod-shellout snippet's
scripts/task.py is present on both sides in practice) and loud (the audit row names
the path). It is the FALSE-BLOCK direction of the file-grain residual #2316's plan
accepted, and it was NOT stated in that plan.
Surfaced as code-review Minor M1 on #2316 (round 1, verdict PASS) and deliberately carried rather than fixed: see below.
Why this was not fixed inside #2316
The obvious fix — extract only the FIRST path token per line — is not free. It is correct only if EVERY registered member's row grammar leads with the offender path. If any does not, first-token-only silently drops a real offender: a fail-OPEN, which is strictly worse than the narrow loud false-block it replaces, in the gate that adjudicates every session's Step 9c. Trading a loud false-block for a possible silent miss is not a judgement to make without evidence.
Required first deliverable
Read all five VIOLATION_SET_SCAN_NODES members' assertion-message constructions and
record, per member, whether the row grammar leads with the offender path. Only then pick
between:
- first-path-token-per-line — valid ONLY if all five lead with the path;
- per-member row-prefix regexes — grammar-explicit and fail-closed; more work, no fail-open exposure;
- something better the audit suggests.
Acceptance criteria
- A regression test reproducing the class: an already-red file whose branch-side snippet embeds a tracked-path token absent on pristine is classified pre-existing, not NEW. Must FAIL before the fix.
- No fail-OPEN introduced: a real branch-added offender in an already-red file still classifies NEW, pinned per registered member.
- The five-member grammar audit is recorded in the task body or plan, not just inferred.
- M2 —
paired_failure_texts(threaded through_install_compare_fakes/_compare_envby #2316 D9, never passed a non-None value): either exercise it with a paired-entrance text fixture or remove it. tests/test_step9c_baseline*.pygreen; no-flagsworkflow_lint.pyno NEW failures vs the plan-time baseline.
Context
step9c_baseline.py compare IS the Step 9c gate for every session, so a false hard
block wedges the fleet (#1388 precedent). That is why this is worth a task and why the
fix must not be guessed at.