Files
goldeneye-pc-port/tools_pc/gen_findings_index.py
T
James Dansereau b3b0ff74db v0.3.0 release review: watchdog re-arm, rule-2 sign-offs, GPL source removal, repo hygiene
Per the 2026-09-19 adversarial pre-ship review (findings.md M-192):

- d318watchdog.c: one-shot per OCCURRENCE, not per process -- re-arm after
  600 ticks of signature absence so a Facility replay in the same session
  (AllUnlocked) is still covered.
- model.c: RULE-2-SIGNOFF records for the retained M-183/M-185 and D311
  defensive clamps (user-approved retention as the stability-maximizing
  option; stale 'Threshold: 50.0' comment corrected to 10.0f; both marked
  post-release removal candidates pending full cutscene re-verification).
- reference/mouse-injector/: removed from the public repo (GPLv2 source +
  prebuilt discord-rpc.lib in an MIT project; never compiled here).
  Provenance stub README remains; path gitignored for local re-vendoring.
  AGENTS.md / GEPD-INPUT-PLAN.md / optionsoverlay.c refs updated.
- scratch/: untracked + gitignored (19 session logs/probe sources were
  committed in the release window).
- findings-index.csv: D317 (and 5 other stale rows) now CLOSED -- added
  CLOSED to gen_findings_index.py's verdict vocabulary.
- docs: D310 perf gauge (no change warranted), GE_DEBUG_UNLOCKALL noted in
  security-and-fidelity-status.md, release notes gain the missing D318
  watchdog bullet + FOV-clamp clarification.

Build verified: ./build-pc.sh ntsc-final clean; gen_findings_index.py
--check and gen_env_probes.py --check pass.
2026-09-20 10:51:12 -04:00

171 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Generate docs/dev/findings-index.csv from the §F/§H tables in findings.md.
Agentic speed-ups plan Step 4 / R8: findings.md is ~200 KB. Agents should grep
this CSV (label, status, one-liner) to decide *which* Dxx entries to actually
read, instead of linear-reading the log.
Heuristic parser: every markdown table row whose first cell matches a Dxx
label (`D12`, `D88.4`, `D75 · D77`, `D24-D30`, ...). The topic cell is
truncated to a one-liner; the status cell is normalised to a short bucket
(RESOLVED / OPEN / FIXED / PARTIAL / PROPOSED / ?) with the raw text kept.
Usage:
python tools_pc/gen_findings_index.py # write the CSV
python tools_pc/gen_findings_index.py --check # exit 1 if stale
python tools_pc/gen_findings_index.py --stdout # print, don't write
"""
from __future__ import annotations
import csv
import io
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
SRC = ROOT / "docs" / "dev" / "findings.md"
OUT = ROOT / "docs" / "dev" / "findings-index.csv"
LABEL_RE = re.compile(r"^D\d+(?:\.\d+)?(?:[-–]D\d+)?(?:\s*[·,]\s*D\d+(?:\.\d+)?)*\+?$")
STATUS_BUCKETS = [
("FIXED", re.compile(r"\bfixed\b", re.I)),
("RESOLVED", re.compile(r"\bresolved\b", re.I)),
("PARTIAL", re.compile(r"\bpartial|clamp landed|landed\b|safety-net", re.I)),
("PROPOSED", re.compile(r"\bproposed|not applied|design\b", re.I)),
("OPEN", re.compile(r"\bopen\b|not started|awaiting|owed|pending", re.I)),
]
def one_liner(cell: str, limit: int = 160) -> str:
"""Strip markdown emphasis/code and collapse to a single short line."""
txt = cell.replace("**", "").replace("`", "")
txt = re.sub(r"\[([^\]]+)\]\([^)]+\)", r"\1", txt) # [t](u) -> t
txt = re.sub(r"\s+", " ", txt).strip()
# first sentence-ish
m = re.match(r"(.{20,}?[.—:])\s", txt)
if m and len(m.group(1)) <= limit:
txt = m.group(1)
if len(txt) > limit:
txt = txt[: limit - 1].rstrip() + "…"
return txt
LEAD_RE = re.compile(
r"^\**\s*(OPEN|RESOLVED|FIXED|PROPOSED|PARTIAL|LANDED|CLAMP|DISPROVEN"
r"|ROOT-CAUSED|GUARDED|ANALYZED|DIAGNOSTIC SHIPPED|NOT A BUG|CLOSED)",
re.I,
)
def bucket(status_cell: str) -> str:
# An explicit leading verdict token wins over prose keywords deeper in the
# cell (e.g. "OPEN (parked). ... D168 fixed ..." is OPEN, not FIXED).
lead = LEAD_RE.match(status_cell.strip())
if lead:
tok = lead.group(1).upper()
return {
"LANDED": "PARTIAL",
"CLAMP": "PARTIAL",
"DISPROVEN": "RESOLVED",
"ROOT-CAUSED": "RESOLVED",
"GUARDED": "PARTIAL",
"ANALYZED": "PARTIAL",
"DIAGNOSTIC SHIPPED": "PARTIAL",
"NOT A BUG": "RESOLVED",
}.get(tok, tok)
for name, rx in STATUS_BUCKETS:
if rx.search(status_cell):
return name
return "?"
def split_row(line: str) -> list[str] | None:
line = line.strip()
if not line.startswith("|"):
return None
# split on '|' that is not inside backticks
cells, buf, tick = [], [], False
for ch in line:
if ch == "`":
tick = not tick
buf.append(ch)
elif ch == "|" and not tick:
cells.append("".join(buf))
buf = []
else:
buf.append(ch)
cells.append("".join(buf))
cells = [c.strip() for c in cells]
# leading/trailing empty from outer pipes
if cells and cells[0] == "":
cells = cells[1:]
if cells and cells[-1] == "":
cells = cells[:-1]
return cells or None
def rows():
section = None
for raw in SRC.read_text(encoding="utf-8").splitlines():
h = re.match(r"^#+\s+([A-Z])\.\s", raw) or re.match(r"^#+\s.*§?([FH])\b", raw)
if raw.startswith("### ") and re.search(r"\b([FH])\.", raw):
section = re.search(r"\b([FH])\.", raw).group(1)
cells = split_row(raw)
if not cells or len(cells) < 2:
continue
label = cells[0].replace("–", "-")
if not LABEL_RE.match(cells[0]):
continue
topic = cells[1]
status = cells[2] if len(cells) > 2 else ""
yield {
"label": label,
"bucket": bucket(status),
"one_liner": one_liner(topic),
"status_raw": one_liner(status, 200) if status else "",
}
def build_csv() -> str:
buf = io.StringIO()
w = csv.DictWriter(
buf, fieldnames=["label", "bucket", "one_liner", "status_raw"], lineterminator="\n"
)
w.writeheader()
seen = set()
for r in rows():
key = r["label"]
if key in seen:
continue
seen.add(key)
w.writerow(r)
return buf.getvalue()
def main() -> int:
args = set(sys.argv[1:])
text = (
"# GENERATED by tools_pc/gen_findings_index.py -- do not hand-edit.\n"
"# Grep this to pick which findings.md entries to read; it is not authoritative.\n"
+ build_csv()
)
if "--stdout" in args:
sys.stdout.write(text)
return 0
want = text.encode("utf-8")
if "--check" in args:
cur = OUT.read_bytes() if OUT.exists() else b""
if cur != want:
sys.stderr.write("findings-index.csv is stale: re-run gen_findings_index.py\n")
return 1
return 0
OUT.write_bytes(want)
print(f"wrote {OUT.relative_to(ROOT)} ({text.count(chr(10))} lines)")
return 0
if __name__ == "__main__":
raise SystemExit(main())