fix(ci): the content scan could not match R-C2-01/02 — a digit in the workstream segment

Checked as part of closing the C2 coverage gaps, and it was live on main. The content
scan's pattern was `R-[A-Z]+-[0-9]+`, which CANNOT match an ID whose workstream segment
carries a digit: `[A-Z]+` consumes the `C` of `R-C2-01` and then demands a `-` where the
`2` is. `R-C2-01` and `R-C2-02` are the only two such IDs in
conformance/requirements/registry.yaml, and the scan was blind to BOTH.

REPRODUCED before the fix, on a throwaway repo whose only change is a manifest declaring
both IDs on real (non-comment) lines, in a path the map keys to nothing:

    $ REPO_ROOT=$T BASE_REF=main ci/touched-requirements.sh
    R-NET-06                     # the all-letter control ID was the ONLY output

It failed by UNDER-attributing, which is the fail-OPEN direction: a change that retyped a
`conformance.home.k3s/R-C2-01` tag, or a manifest self-declaring R-C2-02, contributed
those IDs to NOBODY, so the C2 tests were filtered out of the merge gate. Same defect
class as the map's `*) : ;;` arm — a miss that reads as "nothing touched".

Every other consumer in the repo already allowed the digit, which is why this was the lone
dissenter: test_requirements_for_path() twenty lines above in this same script,
conformance/lib/coverage.py, conformance/lib/status.py and conformance/lib/
run_l1_offline.py all use `R-[A-Z0-9]+-[0-9]+`. Aligned to that form, with the reason
recorded at the line.

SCOPE OF THE HOLE. path_requirements() has no arm for platform/homepage/* or
platform/headlamp/* either, so before this the ONLY route to R-C2-01/02 was detection rule
3 (editing the C2 conformance test itself). No path-map arm is added here: c2-root-surface
declares `scope: whole-repo`, so ci/l0.sh Stage 3b's --include-scope union selects it on
EVERY gate invocation regardless of the touched set — which is the right mechanism for an
invariant whose input surface is the whole tree, and strictly stronger than a two-component
path arm would be.

REGRESSION-TESTED, in ci/tests/touched-requirements.test.sh (the suite `make -C ci test`
runs): a fixture declaring R-C2-01 / R-C2-02 / R-OBS-04 from `notes/` — a path outside
path_requirements(), so the IDs can only come from the content scan — asserts both digit
IDs ARE attributed, that the all-letter form still is (control), and that a purely numeric
workstream is not invented (the pattern must not widen the gate on noise).

PROVEN TO DETECT BREAKAGE: with the pattern reverted to `R-[A-Z]+-[0-9]+` the suite reports
`FAIL (2 failed, 14 passed)` naming both C2 IDs as missing; restored, all three ci/ suites
pass (16 assertions in this one).

ALSO: conformance/tests/l0-static/whole-repo-invariants-wired/check.sh cites this pattern
in the comment explaining why its BOGUS_REQ fixture is lowercase. Citation updated so the
reasoning still reads true; the fixture is unaffected (grep -E is case-sensitive, and the
check still passes 26/26).

NOTE: another branch may be editing this same script concurrently. This is a one-line
change to one statement plus its comment — expect a trivial conflict and keep the
`[A-Z0-9]` form.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
jakman85andClaude Opus 5 committed 2026-09-13 16:28:21 -05:00
1 parent 02c58aae15
commit a76ae3bdfa
3 files changed
+50 -2

No files matched your search

+33
View File
@@ -136,6 +136,39 @@ printf 'touched set (clusters/ path map):\n%s\n---\n' "$OUT4"
assert_present "R-ENV-02" "$OUT4" "clusters/* attributes R-ENV-02 (selects placeholder-guard-coupling HALF A)"
assert_present "R-GITOPS-01" "$OUT4" "clusters/* attributes R-GITOPS-01"
# ---------------------------------------------------------------------------------------
# THE ID PATTERN MUST ALLOW A DIGIT IN THE WORKSTREAM SEGMENT (added 2026-09-13)
#
# The content scan's pattern was `R-[A-Z]+-[0-9]+`, which CANNOT match `R-C2-01` or
# `R-C2-02` — `[A-Z]+` consumes the `C` and then demands a `-` where the `2` is. Those are
# the only two registry IDs whose workstream segment carries a digit, and the scan was blind
# to BOTH, in the fail-OPEN direction: a change self-declaring a C2 requirement contributed
# it to nobody, so the C2 conformance tests were filtered out of the merge gate. Found while
# wiring conformance/tests/l0-static/c2-root-surface, which closes those two coverage gaps.
#
# `notes/` is outside path_requirements() on purpose, so the IDs below can only have come
# from the CONTENT SCAN. A neighbouring all-letter ID is asserted too, so a regex that
# somehow matched only the digit form would still fail here.
git -C "$TMP" checkout -q -b feature5 main
cat > "$TMP/notes/c2.yaml" <<'YAML'
kind: Test
metadata:
labels:
conformance.home.k3s/R-C2-01: "true"
conformance.home.k3s/R-C2-02: "true"
conformance.home.k3s/R-OBS-04: "true"
YAML
git -C "$TMP" add -A && git -C "$TMP" commit -qm "declare R-C2-01 / R-C2-02"
OUT5="$(REPO_ROOT="$TMP" BASE_REF=main "$SCRIPT" 2>/dev/null)"
printf 'touched set (digit in the workstream segment):\n%s\n---\n' "$OUT5"
assert_present "R-C2-01" "$OUT5" "an R-ID with a DIGIT in the workstream segment IS attributed (R-C2-01)"
assert_present "R-C2-02" "$OUT5" "the second such ID is attributed too (R-C2-02)"
assert_present "R-OBS-04" "$OUT5" "an all-letter workstream segment still works (control)"
# The pattern must not become so loose that a non-ID token is read as a requirement: a bare
# numeric workstream is not a registry shape, and attributing one would WIDEN the gate on
# noise (over-broad selection, never a false green, but noisy and misleading).
assert_absent "R-1-01" "$OUT5" "a purely numeric workstream segment is not invented from thin air"
echo
if [ "$FAIL" -eq 0 ]; then echo "touched-requirements tests: PASS ($PASS assertions)"; exit 0;
else echo "touched-requirements tests: FAIL ($FAIL failed, $PASS passed)"; exit 1; fi
+16 -1
View File
@@ -345,6 +345,21 @@ main() {
done <<< "$files"
# Self-declared R-IDs on the ADDED/REMOVED lines of the change (see changed_diff).
#
# THE ID PATTERN IS `R-[A-Z0-9]+-[0-9]+`, NOT `R-[A-Z]+-[0-9]+`. The WORKSTREAM segment may
# contain a DIGIT: `R-C2-01` and `R-C2-02` (command & control UI) are the only two such IDs
# in conformance/requirements/registry.yaml today, and the stricter pattern silently failed
# to match BOTH of them — `[A-Z]+` consumes the `C` and then demands a `-` where the `2` is.
# Every other consumer in the repo already allows the digit: test_requirements_for_path()
# twenty lines above uses `R-[A-Z0-9]+-[0-9]+`, as do conformance/lib/coverage.py,
# conformance/lib/status.py and conformance/lib/run_l1_offline.py. This grep was the lone
# dissenter, and it dissented by UNDER-attributing — the fail-OPEN direction. A change that
# retyped a `conformance.home.k3s/R-C2-01` tag, or a manifest self-declaring R-C2-02 from a
# path the map keys elsewhere, contributed those IDs to NOBODY, so the C2 tests were
# filtered out of the merge gate. Same defect class as the map's `*) : ;;` arm: a miss that
# reads as "nothing touched". path_requirements() has no arm for platform/homepage/* or
# platform/headlamp/* either, so before this fix the ONLY route to R-C2-01/02 was rule 3
# (editing the C2 test itself). Regression-tested in ci/tests/touched-requirements.test.sh.
# `^[+-]` keeps hunk headers (`@@`) and the `+++`/`---` file headers out of scope.
# `sed 's/^[+-]//'` then strips the single-char diff marker (safe: -U0 emits one), so
# what remains is the SOURCE line, and `grep -vE '^[[:space:]]*#'` drops whole-line
@@ -358,7 +373,7 @@ main() {
| grep -vE '^(\+\+\+|---)' \
| sed -E 's/^[+-]//' \
| grep -vE '^[[:space:]]*#' \
| grep -hoE 'R-[A-Z]+-[0-9]+' \
| grep -hoE 'R-[A-Z0-9]+-[0-9]+' \
| tr '\n' ' ' || true)"
# Normalize: split, unique, sort. Emit to stdout.
@@ -85,7 +85,7 @@ done
# second would fail.
# Deliberately LOWERCASE: conf_normalize_reqs() upper-cases it, so the selection behaves
# identically — but the literal here does not match ci/touched-requirements.sh's content-scan
# pattern `R-[A-Z]+-[0-9]+`, so editing this file does not attribute a nonexistent requirement
# pattern `R-[A-Z0-9]+-[0-9]+`, so editing this file does not attribute a nonexistent requirement
# to the change. (Same reason the synthetic fixture below carries no requirement label at all.)
BOGUS_REQ="r-nosuchreq-99"
sel_without="$(bash "$RUN_SH" --layer l0 --requirements "$BOGUS_REQ" --print-selection 2>/dev/null || true)"