From eaa00f0ed2f40f2495162223a813f6de58205a2e Mon Sep 17 00:00:00 2001 From: Thore Cimbal Date: Mon, 10 Aug 2026 12:00:00 +0000 Subject: [PATCH] analysis: add 16 evidence-backed drift findings Twelve drift findings and four works-well findings, each citing file paths, line numbers, commit hashes or rows in analysis/data/. Every 'neckbeard mechanism' field names a concrete rule in neckbeard v0.1.1 or states explicitly that none exists. --- ...5-decided-but-absent-from-steering-docs.md | 47 ++++++++++++++++ ...p-anonymisation-covers-one-of-six-repos.md | 56 +++++++++++++++++++ ...-author-identity-unification-incomplete.md | 34 +++++++++++ ...4-open-work-lives-only-in-host-markdown.md | 46 +++++++++++++++ ...005-dead-gitea-tracker-still-referenced.md | 44 +++++++++++++++ ...le-branches-publish-pre-rewrite-history.md | 43 ++++++++++++++ ...rror-scope-claims-contradict-each-other.md | 47 ++++++++++++++++ .../F-008-component-slugs-inconsistent.md | 42 ++++++++++++++ ...doc-attention-does-not-follow-work-mass.md | 47 ++++++++++++++++ ...-010-stand-labels-lag-their-own-commits.md | 53 ++++++++++++++++++ .../F-011-component-claude-md-claim-unmet.md | 44 +++++++++++++++ .../findings/F-012-orphaned-sha-references.md | 46 +++++++++++++++ .../F-013-mirror-topology-actually-holds.md | 49 ++++++++++++++++ .../findings/F-014-issue-hygiene-is-real.md | 49 ++++++++++++++++ .../F-015-rewrite-mapping-is-sound.md | 43 ++++++++++++++ .../F-016-self-documentation-is-honest.md | 49 ++++++++++++++++ 16 files changed, 739 insertions(+) create mode 100644 analysis/findings/F-001-milestone-m5-decided-but-absent-from-steering-docs.md create mode 100644 analysis/findings/F-002-timestamp-anonymisation-covers-one-of-six-repos.md create mode 100644 analysis/findings/F-003-author-identity-unification-incomplete.md create mode 100644 analysis/findings/F-004-open-work-lives-only-in-host-markdown.md create mode 100644 analysis/findings/F-005-dead-gitea-tracker-still-referenced.md create mode 100644 analysis/findings/F-006-stale-branches-publish-pre-rewrite-history.md create mode 100644 analysis/findings/F-007-mirror-scope-claims-contradict-each-other.md create mode 100644 analysis/findings/F-008-component-slugs-inconsistent.md create mode 100644 analysis/findings/F-009-doc-attention-does-not-follow-work-mass.md create mode 100644 analysis/findings/F-010-stand-labels-lag-their-own-commits.md create mode 100644 analysis/findings/F-011-component-claude-md-claim-unmet.md create mode 100644 analysis/findings/F-012-orphaned-sha-references.md create mode 100644 analysis/findings/F-013-mirror-topology-actually-holds.md create mode 100644 analysis/findings/F-014-issue-hygiene-is-real.md create mode 100644 analysis/findings/F-015-rewrite-mapping-is-sound.md create mode 100644 analysis/findings/F-016-self-documentation-is-honest.md diff --git a/analysis/findings/F-001-milestone-m5-decided-but-absent-from-steering-docs.md b/analysis/findings/F-001-milestone-m5-decided-but-absent-from-steering-docs.md new file mode 100644 index 0000000..dc9c3ea --- /dev/null +++ b/analysis/findings/F-001-milestone-m5-decided-but-absent-from-steering-docs.md @@ -0,0 +1,47 @@ +# F-001: Milestone M5 was decided and executed, but the steering docs still call it an open question + +category: claim-vs-reality +confidence: high + +evidence: +- `roadmap.md:6-14` (last commit 2026-08-09, `git log -1 main -- roadmap.md`) states + the milestone set as "M1–M4", gives the distribution "M1 33 · M2 21 · M3 4 · M4 12 + von 70" under "Stand 2026-08-06", and frames the Härtung milestone as an explicitly + open question: "Ob das ein eigener Meilenstein „Härtung" werden soll oder M1 bewusst + breit bleibt, ist **offen** — zu entscheiden im Refinement, nicht nebenbei." +- `CLAUDE.md:98` (last commit 2026-08-09) likewise binds every issue to "Gruppen-Milestones + M1–M4". +- Measured against the live tracker (`analysis/data/gitlab_issues.json`, 71 open issues): + M1 19 · M2 22 · M3 4 · M4 12 · **M5 — Härtung 14**. The milestone exists and is populated. +- All 14 M5 issues live in `axion1337.chat-gitops` and carry `updated_at` 2026-08-09. +- `verfahren/retro/2026-08-09.md:115-117` records the decision: "**M5 — Härtung** angelegt, + 14 Issues aus M1 verschoben", with the dividing line and the resulting distribution + "M1 18 · M2 21 · M3 4 · M4 13 · M5 14". +- No ADR covers it: `decisions/` holds 0001-0009, none mentions M5 or Härtung + (`grep -rn 'M5\|Härtung' decisions/` -> no match). +- The retro's own numbers are already stale on the day they were written: retro says + M1 18 / M2 21 / M4 13 / 70 total, the tracker says M1 19 / M2 22 / M4 12 / 71 total. + +impact: The two documents a new session is told to read first (`CLAUDE.md`, then +`roadmap.md`) describe a milestone set that no longer exists, and pose as undecided a +question that was decided. An agent following `CLAUDE.md:98` would file a hardening issue +into M1, silently undoing the split. The decision itself survives only as a bullet in a +dated retro file — the one place the repo's own rules do not point sessions to. +`CLAUDE.md:79-82` makes an ADR mandatory for process decisions and calls documenting an +exception instead of deciding it "ein Fehler"; by the repo's own standard this decision is +under-recorded. + +root-cause pattern: **Decision executed in the tool, documentation not carried along.** +The change was made where the work is (GitLab milestones), noted where the session ended +(the retro), and never propagated to the documents that claim to be canonical. + +neckbeard mechanism: Partly prevented, partly a gap. +Prevented: ADR-0002 (`docs/adr/0002-in-repo-issues.md`, Decision) puts issues in the repo +as `docs/issues/NNNN-slug.md`, so re-bucketing 14 issues *is* a commit in the same tree as +`roadmap.md` — a reviewer sees the docs that were not updated alongside it. `AGENTS.md:79` +plus `scripts/gen_status.py` make `STATUS.md` a generated index ("do not edit by hand"), so +counts are never hand-copied prose that can rot. `WORKFLOW.md:128` puts "STATUS review: +anything stale or surprising" on the refinement agenda. +**Gap in neckbeard:** it has no milestone or roadmap concept at all — no artifact type in +`schema.yaml` groups issues into a delivery bucket, and nothing would have flagged the +M1-vs-M5 split as needing an ADR. Session 2 must decide where "worauf zahlt es ein" lives. diff --git a/analysis/findings/F-002-timestamp-anonymisation-covers-one-of-six-repos.md b/analysis/findings/F-002-timestamp-anonymisation-covers-one-of-six-repos.md new file mode 100644 index 0000000..1110bfe --- /dev/null +++ b/analysis/findings/F-002-timestamp-anonymisation-covers-one-of-six-repos.md @@ -0,0 +1,56 @@ +# F-002: The timestamp anonymisation rule reaches one of six repos; 237 commits still publish real working hours + +category: claim-vs-reality +confidence: high + +evidence: +- `CLAUDE.md:116-134` declares the rule for "**alle** Repos der Gruppe `axion1337.chat` + und die ThreadNet-Dienste": author *and* committer date set to 12:00:00 UTC, with the + stated purpose "damit sich aus der Historie keine persönlichen Arbeitszeiten ablesen + lassen". +- Measured over every ref of all six repos (`analysis/data/timestamp_anonymisation.tsv`, + produced by `analysis/scripts/inv_timestamps.py`, author time rendered in UTC): + + | repo | own/agent commits with real clock time | + |---|---| + | management | 0 | + | axion1337.chat-gitops | 187 | + | threadnet-operating | 21 | + | thread-net-git | 11 | + | threadnet-call | 14 (all on `origin/livekit`) | + | ThreadNet-Web | 4 | + + Total 237. Upstream Element/Matrix commits are excluded from that count — they were + never this project's to rewrite. +- `thread-net-git` and `threadnet-operating` were not rewritten at all: they hold **no** + 12:00:00 commits and appear in no section of `shared/commit-zuordnung-2026-08-07.md` + (sections cover gitops, management, ThreadNet-Web, threadnet-call only). +- The exposed times are exactly the ones the rule exists to hide. On + `axion1337.chat-gitops`'s `turn-secret-rotation-20260728-192656` branch alone, the + hour-of-day distribution of the 41 commits is 00h ×1, 01h ×6, 21h ×8, 22h ×1, 23h ×6. +- All of this is publicly readable: every one of the six repos mirrors to + `rohana.axion1337.de`, verified in sync by `git ls-remote` (see F-013). +- `CLAUDE.md:143-147` does carry a caveat, but it names push times, issue and comment + timestamps, pipeline runs and package publications — **not** the git history itself. + `shared/commit-zuordnung-2026-08-07.md:41-44` discloses the untouched pre-boundary + commits, but frames it as an SHA matter ("haben ihre SHA behalten"), not as a + 147-commit hole in the privacy goal. + +impact: The rule's stated goal is not achieved for five of six repos, while both the rule +and its caveat read as though the remaining exposure were limited to non-git surfaces. +Anyone reading `CLAUDE.md` would reasonably conclude the git history is clean. Effort was +spent (a 251-commit rewrite, three restarted release pipelines, a mapping document) for a +result that a `git log` on any side branch undoes. + +root-cause pattern: **Rule declared repo-wide, applied to a subset — and the gap between +the two is documented in a third place, in different terms.** + +neckbeard mechanism: **Gap in neckbeard.** Nothing in `AGENTS.md`, `WORKFLOW.md`, +`schema.yaml` or `scripts/validate.py` concerns commit hygiene, author identity or history +rewriting; `docs/aar/2026-08-09-neckbeard-v1-creation.md` ("Git is the changelog") treats +git as a given, not as an artifact under governance. The nearest applicable rule is +`AGENTS.md:50-55` ("Never claim something works without evidence... Uncertainty is +reported, never swallowed"), which is a behavioural rule for an agent, not a check on the +repo. A field test finding worth carrying back: a framework that governs documents while +the project's most sensitive claims are about its *git history* leaves that surface +unguarded. diff --git a/analysis/findings/F-003-author-identity-unification-incomplete.md b/analysis/findings/F-003-author-identity-unification-incomplete.md new file mode 100644 index 0000000..da87d7c --- /dev/null +++ b/analysis/findings/F-003-author-identity-unification-incomplete.md @@ -0,0 +1,34 @@ +# F-003: Five author identities of one person remain, one with a malformed e-mail + +category: claim-vs-reality +confidence: high + +evidence: +- `shared/commit-zuordnung-2026-08-07.md:19-22` states that the rewrite unified author + identity: "bei einigen Commits zusätzlich die Autoren-Identität (drei Varianten + derselben Person auf eine vereinheitlicht)". +- Author fields still present across the six repos + (`analysis/data/timestamp_anonymisation.tsv`, column `author`): + `Thore Cimbal `, `Scrublord MacBad `, + `ScrublordMcBad `, `sorb `, + `sorB `. +- That is five variants, not the three the document says were collapsed into one. +- `sorB ` (2 commits on `ThreadNet-Web` main) is not a valid e-mail + address — the `@` is missing, `cfx@riot` became `cfxqriot`. +- The unification reached only the rewritten commits: `management` main shows a single + identity, while `axion1337.chat-gitops` main still carries 135 commits as + `Scrublord MacBad ` and 10 as `ScrublordMcBad`. + +impact: Same exposure class as F-002 and the same false sense of completion. In addition, +the malformed address makes those two commits unattributable by tooling that matches on +e-mail, and `Scrublord@Mac.Bad` leaks a machine name. Contributor statistics on the public +Gitea mirror show one person as four or five contributors. + +root-cause pattern: **Rule declared repo-wide, applied to a subset** — the same pattern as +F-002, in the same operation. Both were verified for the property that was easy to check +(SHA pairs matched) and not for the property the operation existed to achieve. + +neckbeard mechanism: **Gap in neckbeard**, as in F-002 — no commit or identity hygiene +exists in the framework. The closest structural analogue is `scripts/validate.py`, which +enforces that declared metadata matches reality for *documents* (`check_fields`, +`apply_rules`); nothing does the equivalent for commit metadata. diff --git a/analysis/findings/F-004-open-work-lives-only-in-host-markdown.md b/analysis/findings/F-004-open-work-lives-only-in-host-markdown.md new file mode 100644 index 0000000..3fdca53 --- /dev/null +++ b/analysis/findings/F-004-open-work-lives-only-in-host-markdown.md @@ -0,0 +1,46 @@ +# F-004: Open work items live only in host markdown, against the repo's own "no backlog markdown" rule + +category: process-drift +confidence: high + +evidence: +- The rule, twice stated: `CLAUDE.md:72-75` — "**Alles Offene ist ein Issue** … Kein neues + Backlog-Markdown anlegen; `hosts/`/`shared/` sind nur Bestand + Historie" — and + `README.md:47` — "Alle offenen Punkte sind **Issues in diesem Projekt**". +- Open next steps that exist only as prose in `hosts/` and `shared/`: + - `hosts/overmind.md:90` — "**Nächster Schritt:** `element-desktop-build` von rohana in + die Lab-Registry umziehen … bewusst zurückgestellt" (section OVERMIND-01, marked + "Status: erledigt"). + - `hosts/overmind.md:111-115` — "**Offen:** … Falls der Hang trotz EEE-off + neuer + Firmware wiederkehrt: gezielter ASPM-Fix statt globalem Kernel-Parameter". + - `hosts/cfgmon.md:148` — "**Nächster Schritt:** die drei manuellen Schritte oben, dann + → erledigt" (section CFGMON-11). + - `shared/branding.md:210` — a whole `## Offen` section. +- Section IDs in `hosts/`/`shared/` with **no** corresponding issue anywhere in the group + (checked against all 111 issues in `analysis/data/gitlab_issues.json`): + `OVERMIND-01`, `CFGMON-11`, `CFGMON-12`, `CFGMON-13`, `MATRIX-05`. + For contrast, `OVERMIND-02` -> management#4 and `LABNET-01` -> management#11 do exist. +- `hosts/overmind.md:146` even routes readers to a markdown-only item as if it were + tracked: "CFGMON-11 (Gitea-CI-Rückbau)". + +impact: An item like the `element-desktop-build` migration is invisible to the group board, +carries no milestone, no priority and no owner, and appears in no refinement. It is +deferred with a reason — a good reason — inside a file the process declares to be history. +`README.md:74` names the distinction between "gemacht" and "bewusst gelassen" as the most +frequent question; for these five IDs the answer exists in exactly one place and it is not +the one the process points at. + +root-cause pattern: **Two backlogs, one rule.** The rule says one system; the host +documents are the natural place to write while working on a host, so items land there and +the migration to an issue is a separate act of discipline that sometimes does not happen. + +neckbeard mechanism: Directly prevented by ADR-0002 +(`docs/adr/0002-in-repo-issues.md`, Decision: "In-repo Markdown issues +(`docs/issues/NNNN-slug.md`, status in frontmatter, generated `STATUS.md` as index)"). +Under it there is no gap between "writing in the doc" and "filing an issue" — both are +markdown files in the same tree, and `scripts/validate.py` enforces that an issue has a +`status` from `schema.yaml`'s enum `[open, in-progress, done, rejected]` (`check_fields`, +`schema.yaml:76-84`), so an open item cannot exist as a bold prose label. `scripts/gen_status.py` +then lists it in `STATUS.md` whether or not anyone remembered it. +Residual gap: nothing in neckbeard would stop a wiki page under `docs/wiki/` from carrying +an "Offen" section; the guard is `WORKFLOW.md:126` wiki lint, a human ritual. diff --git a/analysis/findings/F-005-dead-gitea-tracker-still-referenced.md b/analysis/findings/F-005-dead-gitea-tracker-still-referenced.md new file mode 100644 index 0000000..a3e30c5 --- /dev/null +++ b/analysis/findings/F-005-dead-gitea-tracker-still-referenced.md @@ -0,0 +1,44 @@ +# F-005: A live document routes the reader to the Gitea tracker that three documents declare dead + +category: claim-vs-reality +confidence: high + +evidence: +- The claim, stated three times and each time absolutely: + - `README.md:22-27` — "**Keine Ausnahmen mehr.** … der Gitea-Tracker ist leer … + **Alle Issues leben auf git.lab.**" + - `hosts/overmind.md:38-42` — "**Issues nicht mehr** … der Tracker ist leer. + **Ohne Ausnahme: Issues leben auf git.lab.**" + - `CLAUDE.md:49` — "**Issues leben auf git.lab.** Die alten Gitea-Issues sind + geschlossen und verweisen dorthin." +- `hosts/cfgmon.md:176` (section CFGMON-12) resolves its status against that tracker: + "**Status:** abgelöst durch [gitops#48](https://rohana.axion1337.de/sorb/axion1337.chat-gitops/issues/48) + (2026-08-01, sorb: HOHE Priorität …) — Plan-Skizze und die offene + Erreichbarkeits-Entscheidung git.lab-only vs. extern stehen dort". +- So the substance of an open decision is said to live in an issue on the tracker that is + declared empty. The link is the only pointer to it in the repo. +- The number is additionally unsafe: `CLAUDE.md:50-52` warns that gitops issue numbers + shifted in the migration ("z. B. Gitea#48 → GitLab#46") and that "alte „gitops#N"-Verweise + meinen die Gitea-Nummer". A reader who resolves `gitops#48` on git.lab lands on a + different issue than the one meant — and `analysis/data/links.tsv` records + `axion1337.chat-gitops#48` as an existing GitLab issue, so nothing looks broken. +- CFGMON-12 has no issue of its own anywhere in the group (F-004). + +impact: A high-priority decision ("HOHE Priorität", plus an open reachability question) is +reachable only through a link into a system the documentation says is retired, under a +number the documentation says is ambiguous. Both failure modes are silent: the link +resolves, and so does the wrong git.lab issue. + +root-cause pattern: **Decision executed in the tool, documentation not carried along** — +the migration was completed and announced, but the documents that pointed into the old +system were not swept. Compounded by **two backlogs, one rule** (F-004). + +neckbeard mechanism: Removed by construction under ADR-0002 +(`docs/adr/0002-in-repo-issues.md`): with issues as files in the repo, a reference to an +issue is a relative link, and `scripts/validate.py`'s `check_body_links` reports +"inline link target missing" when it does not resolve — a renumbering or a retired tracker +becomes a failing check instead of a working link to the wrong thing. ADR-0002 explicitly +lists this as the con of forge issues: "issue ↔ artifact links leave the repo". +**Gap in neckbeard:** `check_body_links` only validates repo-relative targets; external +URLs are format-checked at most (`schema.yaml:22-26` applies that only to frontmatter link +fields). A doc pointing at a dead external tracker stays green. diff --git a/analysis/findings/F-006-stale-branches-publish-pre-rewrite-history.md b/analysis/findings/F-006-stale-branches-publish-pre-rewrite-history.md new file mode 100644 index 0000000..48fc9d3 --- /dev/null +++ b/analysis/findings/F-006-stale-branches-publish-pre-rewrite-history.md @@ -0,0 +1,43 @@ +# F-006: Three abandoned branches keep publishing exactly what the rewrite removed from main + +category: dead-artifact +confidence: high + +evidence: +- `axion1337.chat-gitops` `origin/turn-secret-rotation-20260728-192656`: 41 commits not on + main, head `f30d2f5` dated 2026-07-28, **not merged** (`git merge-base --is-ancestor` -> + no). All 41 carry real clock times (00h–01h and 21h–23h heavy). They are the *pre-rewrite* + versions of commits the mapping table lists as replaced — 42 mapping rows resolve as + `ok-both-present` in `analysis/data/sha_refs.tsv`, meaning the old SHA is still reachable. +- The same branch exists on the public mirror: + `git ls-remote https://rohana.axion1337.de/sorb/axion1337.chat-gitops.git` -> + `f30d2f582ba14d85a7dec97c4db9bb2677ca824d refs/heads/turn-secret-rotation-20260728-192656`, + identical to git.lab. +- `threadnet-call` `origin/livekit`: 14 own commits with real clock times, head `c12a4116` + (2026-07-31 22:22), mirrored publicly with the same head. +- `axion1337.chat-gitops` `origin/wiki`: head `0ff598e`, 2026-05-14. `CLAUDE.md:63` already + describes it as "ein überholter Mai-Abzug von `docs/`", and management#19 ("DOC-02: + Veralteten `wiki`-Branch im gitops-Repo entfernen?") tracks it — open, `priority:low`, + no `status:` label, i.e. plain backlog. +- The rotation branch's own successor mechanism is live: the scheduled CI job + `canonize_rotation` exists at `.gitlab-ci.yml:51` in the gitops repo, as `CLAUDE.md:56-60` + describes. The branch predates it and was never cleaned up. + +impact: The single most expensive operation in this repo's history — a 251-commit rewrite +that restarted three release pipelines and needed its own mapping document — is undone for +42 of those commits by a branch nobody looks at, on a host that is public. The `wiki` branch +additionally offers a three-month-old copy of the documentation next to the current one, +which is the "zwei Wahrheiten über dieselbe Sache" failure `CLAUDE.md:94-97` names as worse +than an incomplete one. + +root-cause pattern: **Artifacts outlive their purpose without an owner.** All three branches +served a finished purpose; none had a defined end. The one that is noticed (`wiki`) sits in +the backlog without a status label, which is where low-priority hygiene goes to rest. + +neckbeard mechanism: **Gap in neckbeard.** The framework governs files inside a checkout, +not refs: nothing in `AGENTS.md`, `WORKFLOW.md` or `scripts/validate.py` sees a branch. +The nearest existing mechanisms are `WORKFLOW.md:122` (refinement item 2, "Backlog triage +over `docs/issues/`") and `WORKFLOW.md:126` (wiki lint, which hunts "orphan pages") — both +would need a branch equivalent to catch this. `schema.yaml`'s `warn_if_orphan` rule shows +the framework already accepts "reachable from nowhere" as a reportable condition for +documents; the field test shows refs need the same treatment. diff --git a/analysis/findings/F-007-mirror-scope-claims-contradict-each-other.md b/analysis/findings/F-007-mirror-scope-claims-contradict-each-other.md new file mode 100644 index 0000000..da7798a --- /dev/null +++ b/analysis/findings/F-007-mirror-scope-claims-contradict-each-other.md @@ -0,0 +1,47 @@ +# F-007: How many repos are mirrored has three different answers, and one of them is wrong + +category: claim-vs-reality +confidence: high + +evidence: +- `CLAUDE.md:36-37` — "**Gespiegelt wird nur die Gruppe `axion1337.chat`** (die **fünf** + Produkt-Repos und `management`)" — i.e. six repos. +- `hosts/overmind.md:27-31` — "Stand 2026-08-09 **sieben**: die **sechs** Produkt-Repos + (ThreadNet-Web, threadnet-call, thread-net-git, threadnet-operating, + axion1337.chat-gitops, seit heute auch `game-operating`) **und `management`**". +- Both files were last committed on the same day, 2026-08-09 + (`git log -1 main -- `), so this is not a lag between an old and a new statement; + the repo asserts five and six product repos simultaneously. +- Measured (`git ls-remote` against both hosts, heads of `main`): + - management, axion1337.chat-gitops, ThreadNet-Web, threadnet-call, thread-net-git, + threadnet-operating -> **all six in sync**, identical SHAs. + - `game-operating` -> git.lab `ead1272823`, `rohana.axion1337.de/sorb/game-operating` + -> **no repository**. The "seit heute auch `game-operating`" claim does not hold. + - `gameserver` -> git.lab `d5c6ccb2e9`, Gitea `48441a500f`, **diverged** — which is + exactly what `hosts/overmind.md:33-35` says and management#32 tracks. +- Caveat on the negative result: the mirror naming convention is `sorb/` for all + six verified repos; a `game-operating` mirror under a different name would not have + been found. Confidence high on the contradiction, medium on the specific cause. + +impact: The mirror set is the answer to "what can the Hetzner cluster still reach when the +lab is down" — the reason the two-host topology exists at all (`CLAUDE.md:26-33`). A repo +believed mirrored but not mirrored is a gap in exactly that guarantee, and the belief is +recorded in the file that is meant to be authoritative for host questions. +management#28 ("MIRROR-01: Ein Ausfall der Push-Mirrors bleibt unbemerkt") shows the risk +class is known; it sits in the backlog at `priority:low` with no status label. + +root-cause pattern: **Decision executed in the tool, documentation not carried along** — +here in the inverse direction: the document was updated ahead of the tool, and the number +in the *other* document was not touched at all. + +neckbeard mechanism: `WORKFLOW.md:136-138` (Knowledge Handling) is the governing rule: +"Contradictions are resolved or explicitly flagged — never left silently coexisting", with +the detection ritual at `WORKFLOW.md:126` (refinement item 4: "Wiki lint (content-level, +beyond `validate.py`): contradictions between pages, claims superseded by newer sources"). +`AGENTS.md:50-52` adds "Never claim something works without evidence". +**Partial gap:** the rule exists, the detection is a human ritual on a weekly cadence, and +`scripts/validate.py` checks structure and link targets only — two numbers contradicting +each other across two files is invisible to it. `AGENTS.md:101-103` ("If a deterministic job +lacks a script, propose one") points the right way, but "is this claim still true" is not +deterministic in general. The tractable subset — a claim of the form "N repos are mirrored" +— is checkable, and this field test wrote such a check ad hoc. diff --git a/analysis/findings/F-008-component-slugs-inconsistent.md b/analysis/findings/F-008-component-slugs-inconsistent.md new file mode 100644 index 0000000..d718965 --- /dev/null +++ b/analysis/findings/F-008-component-slugs-inconsistent.md @@ -0,0 +1,42 @@ +# F-008: The five components have four naming schemes, and one display name maps to a repo that shares no name with it + +category: structural-drift +confidence: high + +evidence: +- Slugs verified against git.lab with `git ls-remote` (see `analysis/SCOPE.md` §3): + `threadnet-call`, `thread-net-git`, `threadnet-operating`, `ThreadNet-Web`, + `axion1337.chat-gitops`. +- `thread-net-git` breaks the `threadnet-*` pattern of its siblings; + `https://git.lab/axion1337.chat/threadnet-git.git` returns "project could not be found". +- `ThreadNet-Web` is the only CamelCase slug. `ThreadNet-Web` and `threadnet-web` return + byte-identical ref lists (same project via GitLab's case-insensitive path handling), and + the repo's own documents use both plus a lowercase registry path + `registry.git.lab/axion1337.chat/threadnet-web/desktop-build` (`hosts/overmind.md:54`). + `hosts/matrix.md:20` uses the Gitea spelling `sorb/ThreadNet-Web`. +- "ThreadNet Server Suite" = `axion1337.chat-gitops` rests on a single sentence, + `CLAUDE.md:6`. The slug contains no ThreadNet element; nothing else in the repo repeats + the equation. This session had to ask the human to confirm it (Phase-0 STOP, question 3). +- `vision/threadnet.md:9-11` lists the product line as "ThreadNet-Web …, threadnet-call + …, thread-net-git, threadnet-operating" — four names in three casings, and the fifth + component is absent from the vision that defines the line. + +impact: Nothing in the repo lets a reader or an agent get from a display name to a +repository deterministically. This session could not, and the Phase-0 scope freeze existed +partly to resolve it. Every automation that iterates over "the ThreadNet repos" needs a +hand-maintained table, and the case-insensitive redirect hides the inconsistency until +something case-sensitive (a container path, a CI cache key, a `git clone` into a +case-sensitive filesystem) meets it. + +root-cause pattern: **Rule declared repo-wide, applied to a subset** — the branding +decision in `shared/branding.md` fixes what the *product* is called on every surface, and +was carried through thoroughly there, but repository names were never part of that sweep. + +neckbeard mechanism: **Gap in neckbeard**, with a near-miss worth noting. `schema.yaml` +enforces naming as a first-class rule for artifacts — `filename: "^\\d{4}-[a-z0-9-]+\\.md$"` +for ADRs and issues, `"^[a-z0-9-]+\\.md$"` for wiki pages — and `scripts/validate.py` reports +"filename does not match" plus "id does not match filename prefix". The framework therefore +already holds the position that names must be mechanically derivable. It applies that only +inside one repo; a multi-repo project has no equivalent, and neckbeard has no artifact type +that declares "these are the components and this is what they are called". Session 2 needs +one; today `analysis/SCOPE.md` §3 is the only such table that exists. diff --git a/analysis/findings/F-009-doc-attention-does-not-follow-work-mass.md b/analysis/findings/F-009-doc-attention-does-not-follow-work-mass.md new file mode 100644 index 0000000..18d0af4 --- /dev/null +++ b/analysis/findings/F-009-doc-attention-does-not-follow-work-mass.md @@ -0,0 +1,47 @@ +# F-009: Documentation attention and actual work mass point at different components + +category: structural-drift +confidence: medium + +evidence: +- Open issues per component (`analysis/data/gitlab_issues.json`): + `axion1337.chat-gitops` 35 · `management` 26 · `ThreadNet-Web` 9 · `threadnet-call` 1 · + `thread-net-git` 0 · `threadnet-operating` 0. +- Commit volume over all refs (`analysis/data/git_activity.tsv`): + `axion1337.chat-gitops` 269 · `ThreadNet-Web` 52 · `threadnet-operating` 21 · + `threadnet-call` 12 own · `thread-net-git` 11. +- Repository substance (`analysis/data/tree_*.txt`): `thread-net-git` holds **4 tracked + files** (`.gitignore`, `README.md`, `docker-compose.yml`, one file under `backup/`) and + one markdown document; last commit 2026-08-02, 7 days before the reference date. + `threadnet-operating` holds 27 files, 2 documents. +- Against that, `vision/threadnet.md:9-11` presents all four ThreadNet repos as equal + members of the product line, and `roadmap.md:50-62` gives the ThreadNet line six numbered + items, five of which concern `ThreadNet-Web` and none of which concern `thread-net-git` + or `threadnet-operating`. +- The component carrying half the open work, `axion1337.chat-gitops`, is named in the + vision document **not at all** and in `CLAUDE.md` once, parenthetically, as an equation + to a display name (`CLAUDE.md:6`). +- All 14 issues of the newly created M5 — Härtung milestone are in `axion1337.chat-gitops`. + +impact: A reader forming a mental model from `vision/` and `roadmap.md` will weight five +components roughly equally and will not learn that one of them holds half the backlog while +two are effectively dormant. Session-start reading therefore mis-primes exactly the +prioritisation that the roadmap exists to steer. This is a mismatch, not a defect: dormancy +may be entirely intended — but the documents do not say so, and `README.md:68-70` requires +each point to describe "den tatsächlichen Zustand". + +root-cause pattern: **Documents describe the intended shape, the tracker holds the actual +one, and nothing reconciles them.** Related to F-001 in mechanism: the tracker is where +reality accumulates, the documents are written once. + +neckbeard mechanism: `AGENTS.md:79` plus `scripts/gen_status.py`: `STATUS.md` is a generated +overview of open issues, active designs and recent ADRs, explicitly "do not edit by hand", +and `WORKFLOW.md:128` puts reviewing it for "anything stale or surprising" on the refinement +agenda. With ADR-0002's in-repo issues, work mass is countable from the tree, so the +imbalance would be visible in a generated artifact rather than inferable only from an API. +**Gap in neckbeard:** `gen_status.py` covers one repo. This project is six, and neckbeard +has no cross-repo status concept — the same missing "components" artifact as in F-008. + +confidence note: medium rather than high — the underlying counts are exact, but "attention +should follow work mass" is a judgement about intent, and dormant-by-design is a legitimate +answer the documents simply do not give. diff --git a/analysis/findings/F-010-stand-labels-lag-their-own-commits.md b/analysis/findings/F-010-stand-labels-lag-their-own-commits.md new file mode 100644 index 0000000..475e621 --- /dev/null +++ b/analysis/findings/F-010-stand-labels-lag-their-own-commits.md @@ -0,0 +1,53 @@ +# F-010: Hand-written "Stand" labels are older than the commits that touched the same file + +category: doc-drift +confidence: medium + +evidence: +- Label vs. last commit on `main` (`analysis/data/docs_inventory.tsv`, `git log -1`): + + | file | "Stand" label | last commit | + |---|---|---| + | `CLAUDE.md:18` | 2026-08-01 | 2026-08-09 | + | `roadmap.md:3` | 2026-08-06 | 2026-08-09 | + | `hosts/overmind.md:14` | 2026-07-31 | 2026-08-09 | + +- The labels are not merely old, they are contradicted inside their own file: + `hosts/overmind.md` carries the table label "**Stand** 2026-07-31" at line 14 and the + sentence "Stand 2026-08-09 **sieben**" at line 28. +- `CLAUDE.md` is labelled "Projektrealitäten (Stand 2026-08-01)" while containing a rule + section headed "Commit-Konventionen (seit 2026-08-07)" — six days newer than the label + above it. +- Scale of the surface: 40 documents, 813 extracted claim lines, of which 68 carry an + explicit date assertion (`analysis/data/claims.tsv`, trigger `date-claim`). +- The whole document set is young — every management doc is ≤ 8 days old + (`docs_inventory.tsv`, max `days_since_change` = 8) — so this is drift accumulating at + high speed, not neglect over time. + +impact: The label is what a reader uses to decide whether to trust a section, and here it +systematically under-reports freshness, which trains readers to distrust current content +and, worse, gives no signal at all when a section really is stale. In `roadmap.md` the +combination is actively misleading: "Stand 2026-08-06" over numbers that were already wrong +on 2026-08-09 (F-001). + +root-cause pattern: **Hand-maintained metadata about a file, kept inside the file.** +Git already knows the answer; the label is a second source of truth that must be updated by +hand and therefore is not. + +neckbeard mechanism: Prevented by `AGENTS.md:79` — `STATUS.md` is "Generated overview … +do not edit by hand", produced by `scripts/gen_status.py` — combined with +`AGENTS.md:101-103`: "Deterministic jobs (status generation, validation, link checks) are +done by scripts, not by you. If a deterministic job lacks a script, propose one instead of +doing it by inference." A file's freshness is exactly such a deterministic job. +`docs/aar/2026-08-09-neckbeard-v1-creation.md` reinforces it from experience: +"Deterministic jobs belong in scripts, not inference — this rule paid for itself repeatedly", +and "Git is the changelog. No separate log file." (`WORKFLOW.md:140`) is the same principle +applied to history. +Note for Session 2: `schema.yaml` requires a `date` field on adr, design and aar artifacts +(`kind: date`), which is a *creation/decision* date and legitimately hand-set — that is not +the same thing as a freshness label and should not be conflated when migrating. + +confidence note: medium — the dates are exact, but a "Stand" label may be intended as +"state of the described system as last verified", not "state of this text". Under that +reading the labels are defensible for `hosts/overmind.md`; they are not for +`roadmap.md`, whose own header says "Zahlen hier veralten, das Board nicht". diff --git a/analysis/findings/F-011-component-claude-md-claim-unmet.md b/analysis/findings/F-011-component-claude-md-claim-unmet.md new file mode 100644 index 0000000..008959a --- /dev/null +++ b/analysis/findings/F-011-component-claude-md-claim-unmet.md @@ -0,0 +1,44 @@ +# F-011: "Project repos have their own CLAUDE.mds" holds for one of five components + +category: claim-vs-reality +confidence: medium + +evidence: +- `CLAUDE.md:5-7` — "Projekt-Repos haben eigene CLAUDE.mds für ihre Spezifika (z. B. die + ESS-/Flux-Details in „ThreadNet Server Suite" = `axion1337.chat-gitops`) — bei Widerspruch + gilt für Arbeitsweise und Prozess **diese** Datei." +- Present in the five component checkouts (`analysis/data/tree_*.txt`): + `axion1337.chat-gitops/CLAUDE.md` — yes. `threadnet-call`, `thread-net-git`, + `threadnet-operating`, `ThreadNet-Web` — none. +- The conflict-resolution rule the sentence sets up ("bei Widerspruch gilt … **diese** + Datei") therefore has nothing to resolve in four of five repos, and a session opened + directly in one of those four gets no pointer to the canonical conventions at all. +- The one that exists is consistent with its claim: `CLAUDE.md:230-233` says the Karpathy + block was taken verbatim from the gitops CLAUDE.md and must not be edited. Verified — + the block is byte-identical in both files; the management copy only appends its own + closing note after it. That claim holds. + +impact: Four of five component repos have no session-start instructions. The conventions +that `CLAUDE.md:118` declares binding for "**alle** Repos der Gruppe" (commit style, +timestamp anonymisation, secrets handling) are unreachable from inside those repos — which +is a plausible contributing cause of F-002 and F-003, where exactly those four repos are +the ones the rules did not reach. + +root-cause pattern: **Rule declared repo-wide, applied to a subset** — and here the +distribution mechanism for the rules is itself the thing that was only partly applied. + +neckbeard mechanism: This is the exact problem ADR-0001 +(`docs/adr/0001-agents-md-canonical.md`) decides. Its Context names it outright: +"Maintaining per-harness copies of the rules would guarantee drift", and its Decision makes +`AGENTS.md` the single rule file with `CLAUDE.md` reduced to a one-line pointer — the +neckbeard repo's own `CLAUDE.md` is exactly that one line ("Read AGENTS.md — the canonical +instruction file for this repository. All rules live there."). Adopting it converts the +present claim into a checkable fact: each repo carries a pointer, the rules exist once. +**Gap in neckbeard:** ADR-0001 solves one-repo-many-harnesses; it does not address +many-repos-one-ruleset. Nothing in the framework says how five component repos share the +governing `AGENTS.md` — vendoring a copy re-creates the drift ADR-0001 rejects, and a link +to another repo breaks the portability ADR-0003 protects. Session 2 has to answer this, and +it is the sharpest framework question this field test produced. + +confidence note: medium — the sentence can be read as descriptive-in-general rather than as +a claim about all five repos, and it names only gitops as an example. diff --git a/analysis/findings/F-012-orphaned-sha-references.md b/analysis/findings/F-012-orphaned-sha-references.md new file mode 100644 index 0000000..c245777 --- /dev/null +++ b/analysis/findings/F-012-orphaned-sha-references.md @@ -0,0 +1,46 @@ +# F-012: Six commit references in the docs resolve nowhere, and nothing would have caught it + +category: doc-drift +confidence: high + +evidence: +- All SHA-shaped tokens in the 40 management documents were resolved against every ref of + all six repos and against the rewrite mapping (`analysis/scripts/inv_shas.py` -> + `analysis/data/sha_refs.tsv`): 22 resolve, **6 do not**. +- The six, with their nature established individually: + - `hosts/cfgmon.md:54` `dfe04c4a` and `verfahren/deploy-uebergabe.md:84` `dfe04c4` — + a commit pushed directly to Gitea and overwritten by the mirror. Unresolvable **by + design**; the surrounding text documents the loss ("vom Mirror überschrieben"). + - `verfahren/deploy-uebergabe.md:85` and + `verfahren/aar/2026-08-01-cve-pipeline-gitops47.md:13` `2b715ca` — same class, the + second documented overwrite ("2b715ca→0bd77e2"). + - `hosts/overmind.md:23` `7645a2b` — a commit in the `vendor/windows` repo, which the + human placed out of scope; not resolvable here, not a defect. + - `hosts/overmind.md:87` `5bc25447` — not a commit at all but a **container image tag** + ("Tags `5bc25447` + `stable`"); a false positive of the extractor, recorded as such. +- So of six, four are intentional records of lost commits and two are out-of-scope or + mis-typed as commits. **No accidental orphan was found** — and that is the finding worth + keeping: the mapping list did its job (F-015). +- What no mechanism provides: none of this was checkable before this session wrote a + script for it. `analysis/data/links.tsv` covers markdown link targets and reports 2 + broken links in 11,390 (both malformed upstream Element changelog entries), but a SHA in + prose is not a link and was never checked. + +impact: Low today, structurally high. The repo cites commits as evidence throughout — it is +the house style, and a good one (`README.md:68-70`, "woher stammt die Aussage?"). That style +depends on citations staying resolvable across exactly the kind of history operation this +project performed on 2026-08-07, and the only thing that kept it working was a document +someone remembered to write by hand. + +root-cause pattern: **Evidence-by-citation without a checker.** The convention is sound and +followed; its integrity rests on human diligence at rewrite time. + +neckbeard mechanism: **Gap in neckbeard.** `scripts/validate.py` checks link integrity in +two places — `check_links` for frontmatter link fields and `check_body_links` for inline +markdown links, erroring with "inline link target missing" — and `schema.yaml:19-20` +extends body-link checking to root-level prose via `link_only: ["*.md"]`. Commit SHAs cited +in prose are outside both. Given `AGENTS.md:101-103` ("Deterministic jobs … are done by +scripts … If a deterministic job lacks a script, propose one"), resolving a cited SHA is a +textbook deterministic job — `git cat-file -e` — and its absence is a real hole for any +project whose docs cite commits. `analysis/scripts/inv_shas.py` is a working reference +implementation. diff --git a/analysis/findings/F-013-mirror-topology-actually-holds.md b/analysis/findings/F-013-mirror-topology-actually-holds.md new file mode 100644 index 0000000..fb42cb6 --- /dev/null +++ b/analysis/findings/F-013-mirror-topology-actually-holds.md @@ -0,0 +1,49 @@ +# F-013: The mirror topology works exactly as documented — all six repos in sync + +category: works-well +confidence: high + +evidence: +- `main` heads compared between canonical git.lab and the Gitea mirror, both read live + with `git ls-remote`: + + | repo | git.lab | rohana/Gitea | | + |---|---|---|---| + | management | `2f012a6cd2` | `2f012a6cd2` | in sync | + | axion1337.chat-gitops | `151ef3c8d0` | `151ef3c8d0` | in sync | + | ThreadNet-Web | `d3bd5b20c2` | `d3bd5b20c2` | in sync | + | threadnet-call | `d13cce7337` | `d13cce7337` | in sync | + | thread-net-git | `2f4a15ce85` | `2f4a15ce85` | in sync | + | threadnet-operating | `32f89afebf` | `32f89afebf` | in sync | + +- The reasoning behind the topology is written down and is genuinely good: + `CLAUDE.md:26-33` explains *why* two locations exist rather than only asserting it — the + Hetzner cluster must rebuild when the lab is off — and pre-empts the tempting cleanup with + a named warning: "⚠️ **Die Flux-Quelle nicht „geradeziehen"** auf git.lab: Das sähe + aufgeräumter aus und würde die Verfügbarkeit der Produktion an das Lab koppeln". +- The failure mode is documented with its rescue procedure, not just prohibited: + `README.md:16-20` and `CLAUDE.md:45-48` — pull the `.patch` from Gitea, `git am` to + preserve authorship, push via git.lab. +- The one standing exception is explicit, justified, bounded, and has a live mechanism: + the TURN rotation CronJob (`CLAUDE.md:53-60`), canonised daily by the scheduled CI job + `canonize_rotation`, present at `.gitlab-ci.yml:51` in the gitops repo. The alarm design + is stated deliberately — "diese rote Pipeline **ist** der Alarm, einen zusätzlichen + Termin gibt es bewusst nicht." + +impact: This is the part of the current approach that must survive migration untouched. +The value is not the sync itself but the form: a decision with its reason, its +counter-argument, its rescue path, and its one exception each written where the next +session will look. + +root-cause pattern: **A decision recorded with its reasoning outlives the person who made +it.** Every claim in this cluster held up under measurement; the ones that failed elsewhere +in this report are the ones recorded as bare assertions. + +neckbeard mechanism: This is what `docs/adr/` is for. `AGENTS.md:81` — "Architecture +Decision Records — binding; never edited, only superseded" — and `AGENTS.md:89-90`, "Before +proposing options (Gate 2), read the relevant ADRs and AARs first — past decisions and +learnings are input, not trivia." The existing `decisions/0001-gitlab-kanonisch-push-mirror.md` +already is an ADR in all but schema; migrating it needs frontmatter per `schema.yaml:39-52` +(`type`, `id`, `status`, `date`) and nothing else. The "don't straighten this out" warning +maps to the ADR Consequences section, and `WORKFLOW.md:56` ("Options & trade-offs … pro/contra +each, chosen option, and why") is where the two-host reasoning belongs. diff --git a/analysis/findings/F-014-issue-hygiene-is-real.md b/analysis/findings/F-014-issue-hygiene-is-real.md new file mode 100644 index 0000000..6952852 --- /dev/null +++ b/analysis/findings/F-014-issue-hygiene-is-real.md @@ -0,0 +1,49 @@ +# F-014: The issue discipline the docs describe is actually lived — measurably + +category: works-well +confidence: high + +evidence: all measured against `analysis/data/gitlab_issues.json` (111 issues, 71 open). +- **Milestone duty** (`CLAUDE.md:98-103`, "Jedes Issue gehört zu genau einem Meilenstein"): + **0 of 71** open issues lack a milestone. Across all four active projects, in every one. +- **Exactly one status label** (`CLAUDE.md:76-78`, `README.md:60`): **0** issues carry more + than one `status:` label. +- **WIP limit 2** (`CLAUDE.md:77`, "**WIP-Limit 2** — auch sessionübergreifend zu + verteidigen"): `status:doing` = **0**. The limit is not merely respected, there is no + work parked as in-progress at all. +- **No priority in titles** (`CLAUDE.md:90-97`, cleaned up 2026-08-06 after 34 migrated + issues carried prefixes and two contradicted their own label): **0** open issues carry a + `[HIGH]`/`[MEDIUM]`/`[LOW]` prefix. Priority lives only in `priority:*` labels + (48 medium, 37 low, 12 high, 4 critical). +- **Legacy IDs preserved and never reused** (`README.md:64-66`, "IDs … werden **nie + wiederverwendet**; sie leben in Issue-Titeln weiter"): **23** issues carry a leading + legacy ID (`^ID:`), across **23 distinct** IDs — no ID identifies two issues. Three + further titles mention an ID belonging to another issue (`LABNET-02` in management#15, + #26 and #27), which is the scheme used as intended: per `CLAUDE.md:92-93` the IDs + "benennen den Gegenstand", so referring to one from another issue is a cross-reference, + not a collision. +- **Closed, not deleted** (`README.md:72-74`): 40 closed issues are present and readable + alongside the 71 open ones. +- Link hygiene in the management repo is likewise clean: of 161 links in its documents, + **0 broken** (`analysis/data/links.tsv`); the two broken links in the whole corpus are + malformed upstream Element changelog entries in `ThreadNet-Web`. + +impact: The rule set is not aspirational. Where a rule is mechanically checkable and the +tracker enforces it — a milestone field, a label — compliance is total. That is the +strongest single argument for the migration: this project already works the way neckbeard +assumes, and the failures found elsewhere in this report are concentrated exactly where no +mechanism enforces anything (prose, branches, commit metadata, cross-document consistency). + +root-cause pattern: **Where the tool can hold the rule, the rule holds.** The inverse of the +pattern behind F-001, F-004, F-005 and F-010. + +neckbeard mechanism: Preserved and extended by ADR-0002 +(`docs/adr/0002-in-repo-issues.md`) plus `schema.yaml:76-84`, which makes `status` an enum +(`[open, in-progress, done, rejected]`) that `scripts/validate.py` enforces via +`check_fields` — the file-level equivalent of "exactly one status label", but checkable in +CI rather than by convention. Note the direction of loss to plan for: neckbeard's issue +schema has **no milestone and no priority field**, and +`docs/aar/2026-08-09-neckbeard-v1-creation.md` lists "priority field on issues (YAGNI, +revisit via refinement)" among the ideas deliberately not adopted. This project uses both, +on 100% and 101 of 111 issues respectively. Recorded here as field-test evidence, not as a +proposal — see REPORT.md's gap list. diff --git a/analysis/findings/F-015-rewrite-mapping-is-sound.md b/analysis/findings/F-015-rewrite-mapping-is-sound.md new file mode 100644 index 0000000..58bf02c --- /dev/null +++ b/analysis/findings/F-015-rewrite-mapping-is-sound.md @@ -0,0 +1,43 @@ +# F-015: The rewrite mapping list does what it promises — 251 of 251 rows verified + +category: works-well +confidence: high + +evidence: `analysis/scripts/inv_shas.py` -> `analysis/data/sha_refs.tsv`, every row of +`shared/commit-zuordnung-2026-08-07.md` re-checked against the actual repositories. +- Row count matches the claim exactly: 117 (gitops) + 78 (management) + 47 (ThreadNet-Web) + + 9 (threadnet-call) = **251**, and `CLAUDE.md:136` says "251 Commits neue SHAs". +- Of the 251 pairs: **209 `ok`** (new SHA resolves, old one gone as expected) and + **42 `ok-both-present`** (new resolves, old still reachable — all 42 explained by the + stale branches in F-006, not by a mapping error). +- **0 inverted** (new missing while old resolves) and **0 unresolvable** (neither present). + There is no row in the table that does not describe a real commit pair. +- Consequently no accidental orphan reference exists in the docs: all six unresolvable SHA + citations have individual, benign explanations (F-012). +- The document is honest about its own boundaries in a way that measurably helped: + `shared/commit-zuordnung-2026-08-07.md:39-44` states what is *not* in the table + (pre-boundary commits, 147 in gitops, 3 in ThreadNet-Web) — which is what let this + session classify unresolved SHAs correctly instead of reporting them as breakage. +- It records the operational trap it hit rather than quietly fixing it + (`:24-37`): the tag force-push restarted three release pipelines, and the reason nothing + was overwritten is named as luck, not design — "**Das war Glück, keine Planung**" — with + the follow-up tracked as ThreadNet-Web#14. + +impact: A destructive, irreversible operation was made auditable after the fact by one +hand-written document, and the audit passes three days later. The unusual quality is the +self-criticism: the near-miss is written down as a near-miss, which is exactly the material +a future session needs and exactly what usually gets smoothed over. + +root-cause pattern: **A risky operation paired with a written reconstruction of what it +did.** Note the limit, recorded as F-004's sibling: the `backup-vor-rewrite` branches the +document names as its verification basis (`:14-17`) exist on **no** remote today, so the +mapping can no longer be re-derived — only, as here, spot-checked against surviving refs. + +neckbeard mechanism: `docs/aar/` is the home for this document type — `AGENTS.md:83`, +"Standalone After Action Reviews (incidents, major deviations only)", with the required +frontmatter at `schema.yaml:67-74` (`type`, `status` from `[open, harvested]`, `date`) and +the content shape at `WORKFLOW.md:84-89` (planned / actual / why the difference / +learnings, then harvest into the wiki). `WORKFLOW.md:105` makes it mandatory rather than +optional: "Incidents and major misdiagnoses get a standalone AAR in `docs/aar/`". The +`status: harvested` transition is the piece this project lacks — it writes AARs but has no +mechanism that marks a learning as absorbed. diff --git a/analysis/findings/F-016-self-documentation-is-honest.md b/analysis/findings/F-016-self-documentation-is-honest.md new file mode 100644 index 0000000..7f9553c --- /dev/null +++ b/analysis/findings/F-016-self-documentation-is-honest.md @@ -0,0 +1,49 @@ +# F-016: The repo names its own unresolved problems instead of presenting a clean face + +category: works-well +confidence: high + +evidence: +- Known problems written down *and* filed as issues, verified present in + `analysis/data/gitlab_issues.json`: + - `hosts/overmind.md:33-35` — "⚠️ `gameserver` … hat **keinen** Mirror … dort liegt auf + Gitea ein gleichnamiges Repo mit anderem Stand" -> management#32, open. **Verified + true by measurement**: git.lab `d5c6ccb2e9` vs Gitea `48441a500f`, diverged (F-007). + - `CLAUDE.md:63` — the gitops `wiki` branch is "ein überholter Mai-Abzug" -> management#19, + open. **Verified**: head `0ff598e`, 2026-05-14 (F-006). + - Mirror failure going unnoticed -> management#28 "MIRROR-01", open. + - Restore never rehearsed -> management#30, "Der Restore ist nie geprobt — Sicherungen + sind bisher eine Vermutung". + - `CLAUDE.md:143-147` — the timestamp rule "**schützt nur die Git-Historie**", with push + times, issue timestamps, pipelines and packages named as remaining exposure. Incomplete + (F-002) but volunteered. +- `CLAUDE.md:94-97` explains a rule by the damage its absence did, with numbers: 34 migrated + issues carried title prefixes, "davon **zwei mit einer anderen Aussage als ihr Label**", + and states the principle — "Zwei Wahrheiten über dieselbe Sache sind schlimmer als eine + unvollständige." +- `CLAUDE.md:149-158` ("Redlichkeit & gelebte Lehren") requires verified claims to be + separated from suspicion, states "Korrelation ≠ Kausalität — ein plausibler Verdacht ist + kein Befund", and closes with "Fehlschläge und übersprungene Schritte werden benannt, + nicht geglättet; „fertig" heißt verifiziert." +- `verfahren/retro/2026-08-09.md:70-71` records CI that was green while doing nothing + (`build_embedded` "lud **nie** ein Artefakt hoch") and a published npm package of 12.5 KB + instead of 12.8 MB — failures found and written down rather than quietly fixed. + +impact: This is why the present analysis was possible at all. Most of the drift in this +report was found by taking the repo's own statements seriously and checking them; that only +works because the statements are specific, dated and falsifiable. A repo that wrote +"Mirrors are configured" instead of "seven repos, these six product ones plus management" +would have yielded no findings and no confidence either way. + +root-cause pattern: **Specific, falsifiable claims are a feature.** Every finding in this +report is downstream of a claim precise enough to be wrong. + +neckbeard mechanism: This is `AGENTS.md:50-55` almost verbatim — "Never claim something +works without evidence: a test run, command output, a rendered result. 'Should work' is not +a status" and "Uncertainty is reported, never swallowed. Flag your shakiest calls." It +recurs at `WORKFLOW.md:68` (Gate 3, "Shakiest calls: name the decisions you are least +confident about") and `WORKFLOW.md:113-114` (every session ends by answering which choices +it is least confident about). `WORKFLOW.md:137-139` completes it: "If the wiki has no +confident answer, say so. Never file a low-confidence synthesis back as knowledge." +The habit already exists here; neckbeard gives it fixed places to live rather than relying +on the author's temperament.