R-428: the gate that hunts label-matching was matching a label (and CI proved it)
gates / gates (push) Successful in 20s
gates / gates (push) Successful in 20s
decoy_coverage_gate.py identified a repository by os.path.basename(root), looked up in a RUNNERS map. Gitea's act-runner checks the repo out into a directory called `hostexecutor`, so on its FIRST CI run the gate reported "unknown repo 'hostexecutor'" and went INCONCLUSIVE - correctly refusing to pass, and blind. A NAME standing in for a FACT, in the first ten lines of the main loop of the gate written that same morning to catch exactly that, by a session with the four shapes on screen. That is the point of R-428 and why it is recorded rather than quietly patched: this class is not carelessness. FIXED: the repo is now identified by which registered runner FILE exists under the root. Verified under a renamed directory - 14 gates found where the name-based version found none. CI also now fetches app-catalog-felhom.eu. The meta-gate walks all four runners, and a gate that cannot see part of its subject must not report a pass on it - the same reasoning, and the same fix, as the two sibling fetches already in the workflow. NOTE ON THE OTHER THREE RED RUNS, all mine and all ordering: felhom-agent and felhom-controller cite R-421, and I pushed them BEFORE felhom.eu carried that row, so instructions_gate correctly convicted "cites R-421, which appears in neither register". The register lives in felhom.eu; any repo citing a new row must be pushed after it. Re-run below.
This commit is contained in:
@@ -92,6 +92,19 @@ jobs:
|
|||||||
git checkout -q FETCH_HEAD
|
git checkout -q FETCH_HEAD
|
||||||
echo "controller CHANGELOG at $(git rev-parse --short=12 HEAD): $(head -1 CHANGELOG.md)"
|
echo "controller CHANGELOG at $(git rev-parse --short=12 HEAD): $(head -1 CHANGELOG.md)"
|
||||||
|
|
||||||
|
- name: Fetch the app catalog (decoy-coverage reads all four runners)
|
||||||
|
# R-421's meta-gate walks every registered gate across all four repos, so it needs all four
|
||||||
|
# present. Without this it reports the catalog's runner as missing — and a gate that cannot
|
||||||
|
# see part of its subject must not report a pass on it. Same reasoning, and the same fix, as
|
||||||
|
# the two sibling fetches above: give the gate what it needs rather than let it skip.
|
||||||
|
run: |
|
||||||
|
git init -q ../app-catalog-felhom.eu
|
||||||
|
cd ../app-catalog-felhom.eu
|
||||||
|
git remote add origin http://gitea.gitea-system.svc.cluster.local:3000/admin/app-catalog-felhom.eu.git
|
||||||
|
git fetch -q --depth 1 origin main
|
||||||
|
git checkout -q FETCH_HEAD
|
||||||
|
echo "catalog at $(git rev-parse --short=12 HEAD)"
|
||||||
|
|
||||||
- name: Classify the push - code or documents (R-404)
|
- name: Classify the push - code or documents (R-404)
|
||||||
# ONE RULE, NOT TWO. The pre-push hook exempts a golden-currency CONVICTION on a
|
# ONE RULE, NOT TWO. The pre-push hook exempts a golden-currency CONVICTION on a
|
||||||
# documents-only push; if CI did not do the same, a drill night would still produce red CI
|
# documents-only push; if CI did not do the same, a drill night would still produce red CI
|
||||||
|
|||||||
@@ -601,6 +601,7 @@ class (an image `VOLUME` at an unmounted path) is still live — `immich-server`
|
|||||||
| **R-425** | **`offbox_rename_gate.py` scans a fixed three-entry `FILES` list.** MEASURED 2026-09-01: `NAS-mentés` in a new `backups_offbox_extra.html` passed. The scope was correct when written and silently narrows every time the feature grows a file. Fix: scan the offbox feature's files by pattern, or assert the FILES list against a discovered set so a new file fails until it is classified. | **OPEN** |
|
| **R-425** | **`offbox_rename_gate.py` scans a fixed three-entry `FILES` list.** MEASURED 2026-09-01: `NAS-mentés` in a new `backups_offbox_extra.html` passed. The scope was correct when written and silently narrows every time the feature grows a file. Fix: scan the offbox feature's files by pattern, or assert the FILES list against a discovered set so a new file fails until it is classified. | **OPEN** |
|
||||||
| **R-426** | **The decoy-coverage exemption list — 20 registered gates that ship WITHOUT a decoy test, each named.** `scripts/decoy_coverage_gate.py`'s `EXEMPT` map is debt, and this row owns it so it lives in the register and not only in a Python literal. **Four kinds:** (a) genuinely covered in the 2026-09-01 sweep but not yet moved into a suite — `hub-copy`, `instructions`, `docker-v`, `image-pins`; (b) blocked by an open hole and therefore un-assertable as rejecting — `site` (R-423), `one-register` (R-424), `offbox-rename` (R-425); (c) shared scripts whose decoy lives in `felhom.eu` and is counted there — `reuse-refs`, `instructions`, `observations` in the controller and agent runners; (d) **no plausible decoy constructed yet** — `hostinstall`, `wire-contract`, `due-checks`, `published`, `image-resolvable`, `volume-persistence`. Group (d) is the honest unknown: six gates whose soundness is UNTESTED, not established. **The list is green today and shrinks; a NEW gate with no decoy fails immediately.** | **OPEN — 20 names; group (d) is six untested gates** |
|
| **R-426** | **The decoy-coverage exemption list — 20 registered gates that ship WITHOUT a decoy test, each named.** `scripts/decoy_coverage_gate.py`'s `EXEMPT` map is debt, and this row owns it so it lives in the register and not only in a Python literal. **Four kinds:** (a) genuinely covered in the 2026-09-01 sweep but not yet moved into a suite — `hub-copy`, `instructions`, `docker-v`, `image-pins`; (b) blocked by an open hole and therefore un-assertable as rejecting — `site` (R-423), `one-register` (R-424), `offbox-rename` (R-425); (c) shared scripts whose decoy lives in `felhom.eu` and is counted there — `reuse-refs`, `instructions`, `observations` in the controller and agent runners; (d) **no plausible decoy constructed yet** — `hostinstall`, `wire-contract`, `due-checks`, `published`, `image-resolvable`, `volume-persistence`. Group (d) is the honest unknown: six gates whose soundness is UNTESTED, not established. **The list is green today and shrinks; a NEW gate with no decoy fails immediately.** | **OPEN — 20 names; group (d) is six untested gates** |
|
||||||
| **R-427** | **`closed_register_gate.py` checks ONE direction only: an open word in a CLOSED row. The mirror — a CLOSED verdict on a row still sitting in `OPEN-ITEMS.md` — is unchecked, and there are TWELVE.** MEASURED 2026-09-01 during the decoy sweep, by reading the leading verdict of every open row with the gate's own predicate: **R-385, R-387, R-341, R-378, R-405, R-88a, R-88b** read unambiguously closed; **R-123, R-190, R-352** read `PARTLY CLOSED` / `MITIGATION SHIPPED` and almost certainly belong where they are. **The rows were NOT moved by this session** — telling a finished row from a partly-finished one is a judgement, and R-378 is itself the record of what happens when a machine makes that judgement on a substring (six still-open rows moved out of the register). **This is R-405's finding mirrored:** that row exists because R-87 sat in the CLOSED file while its state read READY, and the gate written for it looks only the way it was bitten. Fix: the same leading-verdict predicate applied to `OPEN-ITEMS.md`, reporting rather than convicting until the twelve are adjudicated by a person — a gate registered while twelve rows fail it would refuse every push. | **OPEN — 12 rows named; the adjudication is Viktor's, the gate is mine** |
|
| **R-427** | **`closed_register_gate.py` checks ONE direction only: an open word in a CLOSED row. The mirror — a CLOSED verdict on a row still sitting in `OPEN-ITEMS.md` — is unchecked, and there are TWELVE.** MEASURED 2026-09-01 during the decoy sweep, by reading the leading verdict of every open row with the gate's own predicate: **R-385, R-387, R-341, R-378, R-405, R-88a, R-88b** read unambiguously closed; **R-123, R-190, R-352** read `PARTLY CLOSED` / `MITIGATION SHIPPED` and almost certainly belong where they are. **The rows were NOT moved by this session** — telling a finished row from a partly-finished one is a judgement, and R-378 is itself the record of what happens when a machine makes that judgement on a substring (six still-open rows moved out of the register). **This is R-405's finding mirrored:** that row exists because R-87 sat in the CLOSED file while its state read READY, and the gate written for it looks only the way it was bitten. Fix: the same leading-verdict predicate applied to `OPEN-ITEMS.md`, reporting rather than convicting until the twelve are adjudicated by a person — a gate registered while twelve rows fail it would refuse every push. | **OPEN — 12 rows named; the adjudication is Viktor's, the gate is mine** |
|
||||||
|
| **R-428** | **The decoy-coverage gate — written to catch instruments that match a NAME instead of a fact — identified a repository by its DIRECTORY NAME.** MEASURED on its own first CI run (felhom.eu job 490, 2026-09-01): `os.path.basename(root)` looked up in a `RUNNERS` map, and Gitea's act-runner checks the repo out into a directory called `hostexecutor`, so the gate reported *"unknown repo 'hostexecutor'"* and went INCONCLUSIVE. **The gate that hunts label-matching was matching a label, in the first ten lines of its own main loop, and it shipped that way.** FIXED the same day: it now identifies a repo by which registered runner FILE exists under the root, which is a fact. **Recorded rather than quietly patched because it is the strongest evidence in the sweep that this class is not a matter of carelessness** — it was written by a session that had spent the morning reading 29 gates for exactly this, with the four shapes on screen. Verified under a renamed directory before and after. | **CLOSED 2026-09-01 — fixed, and kept as the class's best example** |
|
||||||
|
|
||||||
<!-- DUE-CHECKS-BEGIN — machine-readable. Parsed by scripts/due_checks_gate.py.
|
<!-- DUE-CHECKS-BEGIN — machine-readable. Parsed by scripts/due_checks_gate.py.
|
||||||
One row per dated check. The R-number must have a row above. Dates are UTC.
|
One row per dated check. The R-number must have a row above. Dates are UTC.
|
||||||
|
|||||||
@@ -158,13 +158,22 @@ def main(argv):
|
|||||||
|
|
||||||
for root in roots:
|
for root in roots:
|
||||||
root = os.path.abspath(root)
|
root = os.path.abspath(root)
|
||||||
name = os.path.basename(root)
|
# ⚠ IDENTIFY THE REPO BY ITS RUNNER, NOT BY ITS DIRECTORY NAME.
|
||||||
if name not in RUNNERS:
|
#
|
||||||
inconclusive.append("unknown repo %r — no runner registered for it" % name)
|
# This gate asked `os.path.basename(root)` and looked the answer up in RUNNERS — a NAME
|
||||||
continue
|
# standing in for a FACT, which is the exact class this gate was written to catch. It went
|
||||||
runner = os.path.join(root, RUNNERS[name])
|
# INCONCLUSIVE on its first CI run because Gitea's act-runner checks the repo out into a
|
||||||
if not os.path.isfile(runner):
|
# directory called `hostexecutor`. **The gate that hunts label-matching was matching a
|
||||||
inconclusive.append("%s: runner not found at %s" % (name, runner))
|
# label.** Measured 2026-09-01, CI job 490. Now: whichever registered runner FILE actually
|
||||||
|
# exists under this root is what the repo is.
|
||||||
|
name, runner = None, None
|
||||||
|
for cand, rel in RUNNERS.items():
|
||||||
|
if os.path.isfile(os.path.join(root, rel)):
|
||||||
|
name, runner = cand, os.path.join(root, rel)
|
||||||
|
break
|
||||||
|
if name is None:
|
||||||
|
inconclusive.append("no known gate runner found under %s — tried %s"
|
||||||
|
% (root, ", ".join(sorted(RUNNERS.values()))))
|
||||||
continue
|
continue
|
||||||
labels = gates_of(runner)
|
labels = gates_of(runner)
|
||||||
if labels is None:
|
if labels is None:
|
||||||
|
|||||||
Reference in New Issue
Block a user