All three scheduled checks were permanently red, which is how a nine-day outage of
the canonize job went unnoticed: one more red cross among red crosses is invisible.
A check that can only ever be red cannot report anything.
An acknowledgement takes a known finding out of the red verdict without hiding it -
it still prints, with its reason and its deadline. Red is reserved for what is not
acknowledged, which is to say: for the new.
Three rules keep the list from becoming the next blind spot, which is the obvious
objection to this whole idea:
- Every entry needs a deadline. Once it passes, the entry stops acknowledging and
says so, so the finding counts again.
- "Permanent" is only expressible as an ADR reference. A permanent exception
without a decision record is already an error per AGENTS.md; here it cannot even
be written down.
- An entry that matches nothing reports itself, so the file cannot quietly
accumulate lines for problems that no longer exist.
Four entries to start: notfallhandbuch (ADR-0016, deliberately unmirrored),
threadnet-wiki (ADR-0015, the wiki mirrors the other way round), gameserver (sorb:
not part of ThreadNet - dated, so the ADR-or-move decision does not drift), and the
zero-job pipeline artifact.
Verified rather than argued, including the counter-proofs #0104 asks for: today
four are acknowledged and one real finding stays red; adding a fresh finding still
turns it red; and with the clock moved past the deadlines the dated entries stop
acknowledging and report themselves. The scope column was added after the first run
showed each check reporting the other's entries as ineffective.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ADR-0012 made docs/issues/ canonical for the management scope only and left
gitops, ThreadNet-Web and threadnet-call on GitLab "until the component adopts".
That split produced exactly what it invited: two numbering worlds where
management#20 and gitops#20 are different issues, drift nobody had to answer for
(gitops#61 carried no milestone since 2026-08-11), and component backlogs that
host sessions without lab access cannot read at all.
The 46 open component issues are now files 0056-0101. The file id is the
group-wide identifier; provenance lives in the frontmatter (new field `projekt`
plus gitlab_iid) and in the filename, so "gitops#61" still finds 0091. Bodies are
copied verbatim; comments and history stay on GitLab, as with the 2026-08-11
management import.
Both scripts learned the second dimension: spiegel_issues.py routes each file to
its origin project, reopens issues that are open in the repo but closed on the
board, and writes the new iid back after creating one; gruppenpruefung.py checks
drift across all four trackers instead of management alone. What the mirror
cannot decide stays a finding, not a silent state.
Two things needed a hand, both recorded in the files: gitops#61 had no milestone
(M1 - it is a live account-takeover path) and carried two area labels where the
schema holds one. The Gitea migration footers in the imported bodies point at
decommissioned trackers; their links are removed, the provenance sentence stays.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Declaring threadnet-wiki as a component took the check from 23 to 72 findings,
46 of them Wiki.js git-storage commits. Those are the same class ADR-0009 already
exempted for the rotation bot — written without a human present, so attributing
them to a person would be wrong — but the exemption held exactly one name.
Matching is on the address rather than the display name on purpose: the Wiki.js
account shows up as 'Administrator', which is far too generic to silence findings
with. Down to 25, and the checks that should still fire do: eight non-canonical
commits remain, all of them mine from the past two days.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gate 4, slice 5: eight component declarations under docs/components/
(filename = canonical slug, F-008 answered by construction; staged
dormancy of thread-net-git/threadnet-operating finally representable,
game-operating/gameserver as external with their field-test caveats),
five pointer-rollout follow-up issues (0035-0039, ADR-0013),
gruppenpruefung.py joins the stillstandspruefung family (runtime group
list vs declarations, pointer presence, group-wide milestone/priority
duty, issue drift, git hygiene since the 2026-08-07 rule boundary,
bot exception per ADR-0009) with its own scheduled CI job, and
spiegel_issues.py mirrors repo to GitLab (title, state, milestone,
priority, due, status label only - never descriptions, never
backwards, dry-run by default, GitLab-only issues are reported and
never auto-closed).
Verified - all four pattern demos fire (acceptance criterion 5, 4/4):
A) old CLAUDE.md claims M1-M4 while the frozen export knows M5;
B) hygiene over full clone history finds 222 real-clock commits by
own identities (matches the frozen Session-1 numbers per repo);
C) covered in slices 3/4 (five task blocks, now 0);
D) covered in slice 3 (orphaned SHA citations, now resolved/curated).
Live run (read-only): exactly the four missing pointers (F-011) and
gitops#61 without milestone as red findings, zero drift on all 26
mirrored issues, group list consistent. Mirror dry-run plans 7
creations, 0 updates, wrote nothing. Offline chain green: validate
0/0, gen_status --check current, drift 0, prosa 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>