Skip to content

gate_paths discards a git grep status inside a pipeline that has no reporting channel #89

Description

@randomparity

Split out of #63 as a deferred site, and recorded as such in ADR 0008's Consequences.

Problem

check-records.sh's gate_paths ends:

} | while IFS= read -r needle; do
    git grep --no-color -lF "$needle" "$base" -- .github/workflows 2>/dev/null |
      sed 's/^[^:]*://' || true
  done | sort -u

git grep reads external bytes — a ref's worth of workflow files — and its status is discarded by || true. A fault is indistinguishable from "the needle does not appear in any workflow", which is the ordinary answer. The result feeds the gate-file rules, so a fault makes a gate file look unreferenced.

This is the same idiom ADR 0005 and ADR 0008 govern, and #63 converted sixteen sites of it. This one was not converted, for a reason that is about shape rather than risk.

Why it was deferred rather than converted

gate_paths's entire body is a pipeline: a { … } group piped into a while loop piped into sort -u. Every statement in it therefore runs in a subshell, so err/err_full would set failed=1 into a subshell that is discarded — ADR 0005's stated "a scan inside a process substitution has no channel at all". Giving this site a report means restructuring gate_paths so its scanning is not inside a pipeline, not adding a status capture to the existing shape.

Converting it inside #63 would have meant either a restructure materially larger than the sixteen mechanical conversions around it, or inventing the private per-scan protocol ADR 0005 decision 1 explicitly refuses.

Expected

  1. gate_paths restructured so a scan fault has a reporting channel — most likely by collecting needles into a variable and running the git grep loop outside a pipeline, the way ADR 0008 decision 6 handles the < <(…) loop sites.
  2. The git grep status captured and branched three ways: 0 matched, 1 no match, >= 2 fault.
  3. A fault reported with a coded E-*-SCAN diagnostic naming the ref and the status, per the convention Sweep the bare if grep / if rg verdict idiom out of the gate scripts #25/Sweep the grep/rg cmd || true verdict-swallow idiom out of check-records.sh (and siblings) #55/check_not_rewritten and evaluate_base_conformance fail open on an unreadable base blob #64/tracked_in_index collapses a git ls-files fault into 'not tracked' #69/Sweep the pipeline-into-grep verdict idiom, which needs PIPESTATUS not a captured $? #63 established.
  4. A regression test with git PATH-stubbed to fault, following the existing convention.
  5. Both mirrors (.github/scripts/skills/tome-of-lore/assets/) stay byte-identical.

Out of scope

The sixteen sites converted in #63, and the in-memory printf … | grep class that ADR 0005 decision 1 and ADR 0008 decision 4 place outside the rule.

Provenance

Found while reviewing ADR 0008 for #63. Recorded in that record's Consequences as a site remaining outside the sweep, with this issue as its owner.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:guardrailsGate scripts, test harnesses, Just recipes, hooks, and CI enforcementbugSomething isn't workingstatus:awaiting-mergegreen + mergeable; human just clicks merge

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions