workflow-fix: pin GNU grep in SKILL.md lint-gate -qv triggers (ugrep shadowing)
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 #928 (emitting agent: orchestrator).
Goal
Pin GNU grep (/usr/bin/grep) or a -qv-free form in the SKILL.md pre-push lint-gate trigger snippets so the gate cannot silently mis-skip when shell grep resolves to ugrep.
Workflow gap
- Bug observed: ugrep 7.5.0 shadows
grepin the session shell (GNU grep 3.7 is at /usr/bin/grep and winswhich, but the profile-initialized shell resolvesgrepto ugrep) and its-q -vcombination returns rc=1 even when non-matching lines are selected (printf 'a\nb\n' | grep -qv '^a'→ rc=1; GNU → rc=0). The Step 10d pre-push lint-gate trigger (grep -qvE '^(tasks/|...)') therefore returnedskip-artifact-onlyon a code-bearing payload — the gate silently disarmed. Live incident: #928 matched-length round merge, 2026-07-08 06:47Z; caught because the verdict contradicted the visible own-diff, re-run with /usr/bin/grep pinned → gate armed, both legs clean, pass. - Why it is a workflow gap: the canonical gate snippets in .claude/skills/issue/SKILL.md (2 hits: the shared form (i)/(ii) block and the surgical form (iii) block) assume GNU
-qvsemantics; any environment where grep is shadowed (this VM, today) silently converts the fail-closed gate into a silent skip — the exact failure class the gate exists to prevent (#931). - Confidence (emitter): high
Proposed change (candidate diff sketch — refine in planning)
- elif grep -qvE '^(tasks/|figures/|eval_results/|ood_eval_results/|raw/|data/|docs/methodology/)' \
+ elif /usr/bin/grep -qvE '^(tasks/|figures/|eval_results/|ood_eval_results/|raw/|data/|docs/methodology/)' \
(both SKILL.md occurrences — lines ~8548 and ~9066; alternatively replace the -qv combo with a shadow-proof form, e.g. [ -n "$(grep -vE '...' file)" ]. Consider ALSO: a workflow_lint check flagging grep -qv/-vq combos on the workflow surface; and investigating/removing the ugrep shadowing itself (profile alias/PATH entry) as the root cause — if removed, the pin is still cheap insurance.)
Scope / surfaces
- Primary target:
.claude/skills/issue/SKILL.md - Grep the workflow surface for the pattern before editing (
/usr/bin/grep -rnE 'grep +-[a-zA-Z]*q[a-zA-Z]*v|grep +-[a-zA-Z]*v[a-zA-Z]*q' .claude/ CLAUDE.md scripts/*.sh) and update every hit; the 2026-07-08 sweep found exactly the two SKILL.md hits.
Constraints / invariants
- Workflow-surface only — never experiment code,
configs/, ortasks/. scripts/workflow_lint.py --check-askspasses; ruff on touched files 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).
Provenance
- workflow_fix_target: .claude/skills/issue/SKILL.md
- fingerprint: c3feefdf168e
Surfaced prose (verbatim): the #928 session's pre-push lint gate returned skip-artifact-only on a 12-file payload containing scripts/ + tests/ paths; isolation showed shell grep = ugrep 7.5.0 with rc-inverted -qv semantics; re-run with /usr/bin/grep pinned armed the gate correctly (pass, both legs clean).