Files
Sylpheed/tools/port/blocked-provenance
MechaCat02 a23c321831 port: land the play-tested work, and only that
Takes the port branch up to 77320d5e -- the state the human play-tested on
2026-09-02 -- for SOURCE paths only. Not a branch merge: `auto/port-p6-audio`
is 366 commits and 938 files, and most of that must not land.

WHAT COMES IN (76 files, all human-confirmed working):
  * the logo splash animation. 08ed3dd1 found it: `pose_at` ASSIGNED the settle
    instant instead of clamping to it, so the splash never animated at all --
    and the same bug manufactured a passing harness result, because the harness
    photographed t past the settle. Confirmed by play-test: "cannot notice any
    obvious difference from the actual game."
  * gamepad input -- (A)/(B) bound additively (`ui_accept` ships with NO joypad
    binding), stick latched with hysteresis at the game's own 61% digitise
    threshold. This is what made (A), video-skip and Extras work at all.
  * menu navigation and flow, menu audio, the exporter, the authored
    declarations, and 23 verification tools under tools/port/.

WHAT IS DELIBERATELY LEFT ON THE BRANCH:
  * everything after c0ae460a -- the F5/F6 title-timing investigation, whose own
    tip commit calls itself a "hand-off for one-minute human checks". Unchecked
    by definition; it goes through the new review gate like anything else.
  * the OPTIONS menu work of 2026-09-03. Real, probably good, NOT play-tested.
  * the F1 repeat mechanism, which its own commit calls "deliberately inert".

WHAT MUST NOT LAND, AND WHY THE .gitignore CHANGED:
  545 MB of extracted game content was committed on that branch -- 850 sprite,
  audio and transcoded video files under `export-probe/` and `export-probe2/`,
  plus 246 MB of loose .wav and .tsv at the repo root. This repository's own
  rule, in this file, is "never game content".

  The rule was not missing. It was written, and it was tightened on that very
  branch, with a careful comment explaining why BOTH `export/` and `data/base/`
  had to be listed -- while the exporter was writing to a third name that
  nobody had thought to list. Enumerating names is the thing that failed. So
  the ignore rules now describe the SHAPE: any top-level `export*/`, game media
  by extension, and loose capture output at the root. Verified both ways -- it
  catches all four offenders and ignores nothing currently tracked.

Verified: `cargo check --workspace` clean; all nine GDScript files parse in
project context, with a positive control (an injected syntax error is detected,
3 lines) so the clean result means something. `tools/port/check-all` was NOT
run -- it needs the container, the export tree and a display.
2026-09-04 16:17:14 +02:00

227 lines
10 KiB
Python
Executable File

#!/usr/bin/env python3
"""Date every open row in BLOCKED.md from history, instead of guessing.
`BLOCKED.md` is required to record the HANDOFF commit each row derives from, and
none of the rows in the two open tables do. The file itself says why: nobody
knows when most of them were written, and inventing a sha would be worse than
admitting there is none.
But git does know. A row's derivation is not a memory, it is the commit that
introduced the row -- recoverable with a pickaxe over the file's own history.
This prints, per row:
introduced the oldest commit whose diff added the row's key phrase
HANDOFF@ `git log -1 -- docs/port/HANDOFF.md` as of that commit
unread commits touching docs/re/ ON ANY REF that are not ancestors of
that commit -- decoding the row has never been read against
`--all`, not my own ancestry, and that distinction is the whole finding. Counted
against my checkout every row scores ZERO, which is true and useless: the
Decoder's live decoding sits on `origin/auto/no-disc-and-menu-captures`, `main`
is a hundred-odd commits behind it, and HANDOFF has not moved in four
milestones [refuted] -- 🔴 corrected 2026-09-01: **on `main`**. Flat, that
sentence is the claim this port WITHDREW in `BLOCKED.md` on 2026-08-30, where the
missing qualifier was recorded as carrying the whole meaning: HANDOFF has moved
over a hundred times, just not on the branch this checkout reads. The reasoning
below needs the qualifier to work at all -- the sha is constant BECAUSE `main`'s
copy is frozen, not because the document is. So a row can be derived from the
newest HANDOFF `main` has and still
be a day behind the decoding -- and the instruction to record the HANDOFF sha
CANNOT DETECT THAT, because the sha it asks for is constant.
That is the rot mechanism the 2026-08-30 audit found three instances of, and it
is not the one the header of BLOCKED.md describes.
Nothing here is authored. Every field is read out of git, and a row whose key
phrase has been rewritten since it was introduced reports `?` rather than a
plausible-looking sha.
"""
import re, subprocess, sys
DOC = "docs/port/BLOCKED.md"
def git(*a):
return subprocess.run(["git", *a], capture_output=True, text=True).stdout.strip()
TOP = 3
def idf_of(commits):
"""log(N / how many subjects use the word) -- rarity, from the corpus itself."""
import collections, math
df = collections.Counter()
for _, subj in commits:
df.update(tokens(subj))
n = len(commits)
return collections.defaultdict(lambda: math.log(n), {w: math.log(n / c) for w, c in df.items()})
def key_of(cell):
"""The longest markdown-free fragment -- what to pickaxe for.
Cells get struck through and re-emphasised as they are resolved, so the cell
as it stands today is not what was committed. The inner text survives that.
"""
frags = [f.strip(" ?.") for f in re.split(r"[*~`]+", cell)]
frags = [f for f in frags if len(f) >= 20]
return max(frags, key=len) if frags else None
def rows():
"""Every table row in the open sections, in file order."""
open_only, out = False, []
for line in open(DOC, encoding="utf-8"):
if line.startswith("## "):
open_only = line.startswith("## Still open")
continue
if not open_only or not line.startswith("| "):
continue
cells = [c.strip() for c in line.strip().strip("|").split(" | ")]
if len(cells) < 4 or cells[0] in ("Milestone", "---"):
continue
out.append(cells)
return out
STOP = set("""this that with from what which when does than the and are was were
have has been will would could should port game screen menu audio does not any
each only its it's whether where else same both very more most into onto over
under about after before still open blocked answered measured wrong right first
second third disc file files commit branch docs main head sha row rows table
mission handoff decoder agent claim claims""".split())
def stem(w):
"""Crudest possible stemmer, and it earns its place with a control.
Without it `looping` does not match `loop` and the P6 row whose answer is
sitting in an unread commit scores zero -- which is what happened.
"""
for suf in ("ping", "ing", "ted", "ed", "es", "s"):
if w.endswith(suf) and len(w) - len(suf) >= 4:
return w[: -len(suf)]
return w
def tokens(text):
ws = re.findall(r"[a-z0-9_]{4,}", text.lower())
return {stem(w) for w in ws if w not in STOP}
def rank(rt, commits, idf):
"""Score every unread commit against one row, rarest words first.
A COUNT of shared words is the wrong instrument: `menu` and `loop` shared
scores the same as `plate` and `pulse`, and in this corpus almost everything
says `menu`. Weighting each shared stem by log(N / commits containing it)
lets one rare word outrank two common ones -- and it removes the threshold,
which was the part that could be tuned. The list is RANKED, fixed length,
so nothing is decided by a cutoff nobody can justify.
"""
out = []
for sha, subj in commits:
shared = rt & tokens(subj)
if shared:
out.append((sum(idf[w] for w in shared), sha, subj, shared))
return sorted(out, reverse=True)
def overlap(rs):
"""Which unread commits NAME something an open row is about.
Crude on purpose, and it says so: word overlap between a row and a commit
SUBJECT, ranked by rarity, top few printed with the words that earned the
rank so the reader judges rather than trusting the match. It cannot tell
relevance from coincidence -- it narrows 196 commits to a short list worth
opening, and nothing more.
"""
log = git("log", "--all", "--not", "HEAD", "--format=%h\t%s", "--", "docs/re/")
commits = [l.split("\t", 1) for l in log.splitlines() if "\t" in l]
print(f" {len(commits)} unread docs/re/ commit(s) exist on other refs.")
print(" Crude word overlap with the open rows -- a reading list, not a verdict:\n")
idf = idf_of(commits)
hits = struck = dropped = 0
for cells in rs:
if cells[0].startswith("~~"):
struck += 1 # already struck; re-reading it settles nothing
continue
scored = rank(tokens(cells[0] + " " + cells[1]), commits, idf)
dropped += max(0, len(scored) - TOP)
for score, sha, subj, shared in scored[:TOP]:
hits += 1
print(f" {re.sub(r'[*~`]', '', cells[0])[:36]:<36} {sha} {score:5.1f} {subj[:58]}")
print(f" {'':<36} {'':<8} via {', '.join(sorted(shared))}")
if not hits:
print(" (no row shares a word with any unread commit)")
# Every discard, counted. A detector that can drop a candidate in silence
# has an unfalsifiable clean run -- which is how the P6 looping row stayed
# marked open for a day while its answer sat in `712cac8`, and how the same
# class of miss went unnoticed in the Decoder's checker on the same day.
print(f"\n suppressed: {struck} struck row(s) not scanned; {dropped} scoring")
print(f" pair(s) ranked below top-{TOP} and not shown; {len(STOP)} word(s)")
print(" stoplisted and unable to match at any rank.")
print()
def control():
"""Known positive: the row whose answer is demonstrably in an unread commit.
`P6 looping` asks where the menu loop restarts. `712cac8` measures it at
9.44 s and the port has since shipped that value, so the pair MUST match. It
did not, until stemming -- the check exists so that regression is loud.
"""
log = git("log", "--all", "--not", "HEAD", "--format=%h\t%s", "--", "docs/re/")
commits = [l.split("\t", 1) for l in log.splitlines() if "\t" in l]
scored = rank(tokens("P6 looping where a menu loop restarts"), commits, idf_of(commits))
at = next((i for i, r in enumerate(scored) if r[1].startswith("712cac8")), None)
ok = at is not None and at < TOP
print(f" control: P6-looping vs 712cac8 -> rank {at} of {len(scored)} scoring "
f"{'' if ok else f'🔴 OUTSIDE TOP-{TOP}, THE KNOWN POSITIVE IS MISSED'}")
return ok
def main():
if "--control" in sys.argv:
sys.exit(0 if control() else 1)
rs = rows()
if not rs:
sys.exit(f"{DOC}: no rows found under a '## Still open' heading")
head_handoff = git("log", "-1", "--format=%h", "--", "docs/port/HANDOFF.md")
print(f" {DOC}: {len(rs)} rows in the open tables")
print(f" HANDOFF is at {head_handoff} today\n")
print(f" {'row':<44} {'introduced':<12} {'date':<11} {'HANDOFF@':<9} unread")
unknown = 0
for cells in rs:
milestone, needs = cells[0], cells[1]
label = re.sub(r"[*~`]", "", milestone)[:43]
key = key_of(needs) or key_of(milestone)
sha = date = handoff = "?"
since = "-"
if key:
# oldest commit whose diff changed the number of occurrences
log = git("log", "--format=%h %ad", "--date=short", "-S", key, "--", DOC)
if log:
sha, date = log.splitlines()[-1].split()
handoff = git("log", "-1", "--format=%h", sha, "--", "docs/port/HANDOFF.md")
unread = git("log", "--all", "--not", sha, "--format=%h", "--", "docs/re/")
since = str(len(unread.splitlines())) if unread else "0"
if sha == "?":
unknown += 1
flag = ""
if since not in ("-", "0") and not milestone.startswith("~~"):
flag = f" <- never read against {since} docs/re/ commit(s)"
print(f" {label:<44} {sha:<12} {date:<11} {handoff:<9} {since:>3}{flag}")
print()
overlap(rs)
if unknown:
print(f" ⚠️ {unknown} row(s) could not be dated: the key phrase has been")
print(" rewritten since it was introduced, so history cannot place it.")
print(" Not a staleness verdict. A high `unread` is not a wrong row -- most of")
print(" that decoding is irrelevant to most rows. It is the size of the surface")
print(" nobody has looked at, and it is what the HANDOFF sha was supposed to be.")
main()