burn-down Part B: 14 small rows fixed and closed across four repos (306 -> 292); no :latest in the hub build; gate list pinned; closed-id duplicates refused; R-262 subset pinned
gates / gates (push) Failing after 1m40s
gates / gates (push) Failing after 1m40s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
## build + gates — no `:latest`; the gate list pinned; duplicate closed ids refused (2026-10-05, burn-down)
|
||||
|
||||
- **R-345:** `build-hub.sh` no longer tags or pushes `felhom-hub:latest` (`--push`, `--multiarch`, local); nothing
|
||||
pulls it. `test_no_latest_push.py` walks `hub/` and `scripts/` build files (red-proofs: the old Makefile, the old
|
||||
build script).
|
||||
- **R-418:** `repo_gates.py`'s docstring lists all 17 gates; `test_repo_gates_docstring.py` keeps list == `GATES`.
|
||||
- **R-416:** `closed_register_gate.py` RULE 4 — an id twice in `CLOSED-ITEMS.md`; decoy in `test_gate_decoys.py`.
|
||||
|
||||
## gates — `script-tests`: every Python test suite under scripts/ runs on every push (R-885) (2026-10-05)
|
||||
|
||||
- `scripts/script_tests_gate.py` (registered in `repo_gates.py`, fast): walks `scripts/` for `test_*.py` and runs each;
|
||||
|
||||
@@ -147,12 +147,11 @@ case "${ACTION}" in
|
||||
info "Building for current platform + pushing..."
|
||||
docker build "${BUILD_ARGS[@]}" \
|
||||
-t "${IMAGE}:${VERSION}" \
|
||||
-t "${IMAGE}:latest" \
|
||||
.
|
||||
|
||||
info "Pushing..."
|
||||
docker push "${IMAGE}:${VERSION}"
|
||||
docker push "${IMAGE}:latest"
|
||||
# never :latest (R-345): the manifest pins a version, and nothing pulls hub:latest (checked 2026-10-05)
|
||||
;;
|
||||
|
||||
--multiarch)
|
||||
@@ -169,7 +168,6 @@ case "${ACTION}" in
|
||||
docker buildx build "${BUILD_ARGS[@]}" \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
-t "${IMAGE}:${VERSION}" \
|
||||
-t "${IMAGE}:latest" \
|
||||
--push \
|
||||
.
|
||||
;;
|
||||
@@ -178,7 +176,6 @@ case "${ACTION}" in
|
||||
info "Building for current platform (local only)..."
|
||||
docker build "${BUILD_ARGS[@]}" \
|
||||
-t "${IMAGE}:${VERSION}" \
|
||||
-t "${IMAGE}:latest" \
|
||||
.
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -50,9 +50,9 @@ WHAT THIS GATE CANNOT SEE — the residual holes, named rather than implied:
|
||||
printed as a WARNING.
|
||||
3. **A closed-sounding verdict that is not true escapes.** `PARTLY CLOSED` leads with no open word.
|
||||
This gate checks where a row FILED, never whether the verdict is honest.
|
||||
4. **A duplicate id WITHIN one register escapes.** `OPEN-ITEMS.md` carries two unrelated findings
|
||||
both numbered R-133 (filed as R-406). Adding that rule would fail the gate on a pre-existing
|
||||
defect, and a registered-but-failing gate refuses every push, so it was deliberately left out.
|
||||
4. ~~A duplicate id WITHIN one register escapes.~~ **Closed 2026-10-05 (R-416):** in `OPEN-ITEMS.md`
|
||||
`register_shape_gate.py` RULE 3 refuses it; in `CLOSED-ITEMS.md` this gate's RULE 4 does (no duplicates
|
||||
existed when it was added, so it was registered green).
|
||||
5. Nothing here reads audits, spikes or inventories. A finding that never reaches either register
|
||||
is invisible to this gate, as it is to `one_register_gate.py`.
|
||||
|
||||
@@ -153,6 +153,16 @@ def main():
|
||||
for rid in sorted(closed_ids & set(open_ids), key=lambda r: (int(re.sub(r"\D", "", r)), r)):
|
||||
convicted.append((open_ids[rid], rid, "", "has a row in BOTH registers"))
|
||||
|
||||
# RULE 4 — a duplicate id WITHIN CLOSED-ITEMS.md (2026-10-05, R-416). The open register's duplicates are
|
||||
# register_shape_gate.py's RULE 3; this file had no such rule, so two closed rows under one id (the R-133/R-406
|
||||
# shape) would make `git show` of "the row that closed R-n" ambiguous. Suffixed ids (R-88a, R-88b) are distinct.
|
||||
first_seen = {}
|
||||
for n, rid, _, _ in rows(CLOSED):
|
||||
if rid in first_seen:
|
||||
convicted.append((n, rid, "", "CLOSED-ITEMS.md has this id twice (first at line %d)" % first_seen[rid]))
|
||||
else:
|
||||
first_seen[rid] = n
|
||||
|
||||
# RULE 3 — a finished row left in the OPEN register (2026-10-03)
|
||||
finished_in_open = []
|
||||
for n, rid, columns, cells, _ in register_table.rows(OPEN):
|
||||
|
||||
@@ -24,6 +24,8 @@ Gates, in order (all must pass; **non-zero exit on any failure**):
|
||||
13. observations a REPORT.md observation with no register row behind it (R-389)
|
||||
14. register-shape a register row whose state cell was eaten, a duplicated id, or a blank line
|
||||
splitting the table — the register mis-stating how many findings exist (R-627)
|
||||
15. script-tests every Python test suite under scripts/ (found by a walk), by exit code (R-885)
|
||||
16. decoy-coverage every registered gate in all four repos has a decoy, or a named exemption (R-421)
|
||||
|
||||
**THE `GATES` TABLE BELOW IS THE LIST; THIS IS A POINTER TO IT.** It drifted once already —
|
||||
it read eleven while thirteen were registered, from 2026-08-24 until 2026-09-01, so
|
||||
|
||||
@@ -25,6 +25,7 @@ Run from the repo root: python3 scripts/test_gate_decoys.py
|
||||
Exit 0 all decoys rejected · 1 a decoy passed (a live hole).
|
||||
"""
|
||||
import io
|
||||
import re
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
@@ -217,6 +218,20 @@ decoy("closed-register/unreadable-row", "closed_register_gate.py",
|
||||
append_to(os.path.join(ROOT, "documentation", "backlog", "CLOSED-ITEMS.md"),
|
||||
u"\n| **R-905** | A row with no state cell at all. |\n"))
|
||||
|
||||
# --- closed-register RULE 4 (2026-10-05, R-416): the same id twice in CLOSED-ITEMS.md ---------------
|
||||
# The id is read from the file's FIRST closed row at run time, so the decoy duplicates a real id rather than an
|
||||
# invented one that could never collide.
|
||||
def _first_closed_id():
|
||||
for line in io.open(os.path.join(ROOT, "documentation", "backlog", "CLOSED-ITEMS.md"), encoding="utf-8"):
|
||||
m = re.match(r"^\| \*\*(R-\d+[a-z]?)\*\* \|", line)
|
||||
if m:
|
||||
return m.group(1)
|
||||
|
||||
|
||||
decoy("closed-register/duplicate-closed-id", "closed_register_gate.py",
|
||||
append_to(os.path.join(ROOT, "documentation", "backlog", "CLOSED-ITEMS.md"),
|
||||
u"\n| **%s** | The same id again. | CLOSED 2026-10-05 | none |\n" % _first_closed_id()))
|
||||
|
||||
# --- closed-register RULE 3 (2026-10-03): a FINISHED row left in the OPEN register ---------------
|
||||
# On 2026-10-03 the open register held 113 rows whose leading verdict was finished — a quarter of the
|
||||
# file. The decoy is that exact shape: a row a session closed in place and never moved. The genuine
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
"""R-345: nothing in this repo's build tooling tags or pushes an image as `:latest`.
|
||||
Scans hub/Makefile, scripts/build-hub.sh and every Dockerfile/Makefile/*.sh under hub/ and scripts/ (a walk).
|
||||
Run: python3 scripts/test_no_latest_push.py"""
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
BAD = re.compile(r"^(?![ \t]*#)[^\n]*?(\bdocker\s+(tag|push)\b[^#\n]*:latest\b|-t\s+\S*:latest\b)", re.M)
|
||||
hits, scanned = [], 0
|
||||
for top in ("hub", "scripts"):
|
||||
for dp, dns, fns in os.walk(os.path.join(ROOT, top)):
|
||||
dns[:] = [d for d in dns if d not in (".git", "__pycache__", "node_modules")]
|
||||
for f in fns:
|
||||
if f in ("Makefile", "Dockerfile") or f.endswith(".sh"):
|
||||
p = os.path.join(dp, f)
|
||||
scanned += 1
|
||||
for m in BAD.finditer(open(p, encoding="utf-8", errors="replace").read()):
|
||||
hits.append("%s: %s" % (os.path.relpath(p, ROOT), m.group(0).strip()))
|
||||
if scanned < 5:
|
||||
print("FAIL: scanned only %d build files — the scope is wrong" % scanned)
|
||||
sys.exit(1)
|
||||
if hits:
|
||||
print("FAIL: a :latest tag/push in build tooling (R-345):\n " + "\n ".join(hits))
|
||||
sys.exit(1)
|
||||
print("OK: %d build files, no docker tag/push of :latest" % scanned)
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python3
|
||||
"""R-418: repo_gates.py's docstring list of gates names exactly the gates in GATES, in the same order.
|
||||
It drifted twice (eleven listed while thirteen ran, 2026-08-24..09-01; then fifteen while seventeen ran). Run:
|
||||
python3 scripts/test_repo_gates_docstring.py"""
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
import repo_gates # noqa: E402
|
||||
|
||||
listed = re.findall(r"^ {1,3}\d+b?\. +([a-z][a-z0-9-]+) ", repo_gates.__doc__, re.M)
|
||||
registered = [g[0] for g in repo_gates.GATES]
|
||||
if listed != registered:
|
||||
print("FAIL: the docstring lists %d gate(s), GATES registers %d" % (len(listed), len(registered)))
|
||||
print(" only listed: %s" % sorted(set(listed) - set(registered)))
|
||||
print(" only registered: %s" % sorted(set(registered) - set(listed)))
|
||||
if set(listed) == set(registered):
|
||||
print(" (same set, different order)")
|
||||
sys.exit(1)
|
||||
print("OK: the docstring lists the %d registered gates, in order" % len(registered))
|
||||
Reference in New Issue
Block a user