The human answered the report's open questions: the game-operating mirror exists (a controlled re-probe shows Gitea hides repo existence behind an auth prompt, so the anonymous negative was inconclusive -- withdrawn in F-007); component dormancy is intentional and staged (F-009 addendum); any F-002/F-003 remediation must ship an old->new Zuordnung in the proven style of commit-zuordnung-2026-08-07 (F-002).
232 lines
18 KiB
Markdown
232 lines
18 KiB
Markdown
# REPORT.md — Neckbeard field test on the axion1337.chat management repo
|
||
|
||
Session 1 of 2, analysis only. Measured against neckbeard **v0.1.1**
|
||
(`823a08cac6b03a47d7e2f661200a49ac6e09d38d`, `main`, clean) as pinned in
|
||
[SCOPE.md](SCOPE.md). Raw data reproducible from zero with
|
||
`bash analysis/scripts/run_all.sh`; 16 findings in [findings/](findings/).
|
||
|
||
---
|
||
|
||
## Executive summary
|
||
|
||
The management repo is 11 days old, holds 44 files and 86 commits, and steers five
|
||
component repos plus itself. Its home-grown approach is **not decayed — it is unevenly
|
||
enforced**. Where a tool can hold a rule, the rule holds perfectly: every one of 71 open
|
||
issues has exactly one milestone and at most one status label, the WIP limit is respected,
|
||
no legacy ID is reused across 23 issues, and the management repo's 161 document links
|
||
contain zero broken targets. Where nothing enforces anything — prose, git refs, commit
|
||
metadata, agreement between two files — the same rule set fails, and it fails in the same
|
||
four ways every time.
|
||
|
||
The most consequential finding is not documentation drift. The 2026-08-07 history rewrite
|
||
set 251 commits to 12:00 UTC so that personal working hours could not be read out of the
|
||
history. That goal is met in **one of six repos**. 237 commits by the project's own
|
||
identities still carry real clock times, including 41 on an abandoned branch in
|
||
`axion1337.chat-gitops` clustered at 21:00–01:00. Two component repos were never rewritten
|
||
at all. Both hosts are private today, so nothing has leaked; the cost is that the
|
||
protection is believed to be in place and is not, so any future decision to push outward —
|
||
to GitHub, or by opening a project — would be taken on a false premise, and history once
|
||
pushed cannot be recalled. The rule's own caveat in `CLAUDE.md:143` lists push times, issue
|
||
timestamps and pipelines as residual exposure, but not the git history itself, so a reader
|
||
concludes the opposite of what is true. See [F-002](findings/F-002-timestamp-anonymisation-covers-one-of-six-repos.md),
|
||
[F-003](findings/F-003-author-identity-unification-incomplete.md),
|
||
[F-006](findings/F-006-stale-branches-publish-pre-rewrite-history.md).
|
||
|
||
Second: a decision that was made, executed and is already load-bearing exists in no
|
||
steering document. Milestone **M5 — Härtung** was created on 2026-08-09 with 14 issues moved
|
||
out of M1. `roadmap.md`, committed the same day, still poses it as an open question and
|
||
still prints the pre-split distribution; `CLAUDE.md:98` still binds every issue to "M1–M4";
|
||
no ADR covers it, though the repo's own rules make one mandatory for process decisions. An
|
||
agent following the canonical file would silently undo the split.
|
||
See [F-001](findings/F-001-milestone-m5-decided-but-absent-from-steering-docs.md).
|
||
|
||
What must survive migration is substantial and specific. The mirror topology is documented
|
||
with its reasoning, its counter-argument, its rescue procedure and its single justified
|
||
exception — and all six mirrors measure in sync. The rewrite mapping list verifies 251 of
|
||
251 rows against the live repositories, with zero contradictions. The repo names its own
|
||
unresolved problems, files them as issues, and records a near-miss as luck rather than
|
||
design. That candour is why this analysis was possible at all: every finding here is
|
||
downstream of a claim precise enough to be wrong.
|
||
|
||
**Bottom line for Session 2.** This project already works the way neckbeard assumes. The
|
||
migration's value is not new discipline but moving the existing discipline from places
|
||
where only a human can check it into places where a script can. Four framework gaps stand
|
||
in the way, listed below; the sharpest is that ADR-0001 solves one-repo-many-harnesses and
|
||
this project is many-repos-one-ruleset.
|
||
|
||
---
|
||
|
||
## Findings by root-cause pattern, most impactful first
|
||
|
||
### Pattern B — A rule is declared repo-wide and applied to a subset
|
||
|
||
The declaration and the application live in different places, and nothing compares them.
|
||
|
||
| Finding | | Impact |
|
||
|---|---|---|
|
||
| [F-002](findings/F-002-timestamp-anonymisation-covers-one-of-six-repos.md) | Anonymisation reaches 1 of 6 repos; 237 commits carry real hours | Stated privacy goal unmet while believed met; blocks any safe future push outward |
|
||
| [F-003](findings/F-003-author-identity-unification-incomplete.md) | 5 author identities of one person survive, one malformed | Same exposure class; one person renders as 4–5 contributors |
|
||
| [F-011](findings/F-011-component-claude-md-claim-unmet.md) | 4 of 5 components have no `CLAUDE.md` | The distribution channel for the rules is itself only partly applied — a plausible cause of F-002/F-003 |
|
||
| [F-008](findings/F-008-component-slugs-inconsistent.md) | Five components, four naming schemes | No deterministic path from display name to repo; this session had to ask |
|
||
|
||
### Pattern A — A decision is executed in the tool; the documentation is not carried along
|
||
|
||
| Finding | | Impact |
|
||
|---|---|---|
|
||
| [F-001](findings/F-001-milestone-m5-decided-but-absent-from-steering-docs.md) | M5 decided and populated; docs still call it open | Every new session is mis-primed by the canonical file |
|
||
| [F-007](findings/F-007-mirror-scope-claims-contradict-each-other.md) | Mirror count stated as five and six on the same day (the `game-operating` negative was withdrawn post-analysis — mirror exists, not anonymously readable) | Two canonical documents assert different repo counts simultaneously |
|
||
| [F-005](findings/F-005-dead-gitea-tracker-still-referenced.md) | Live doc routes to the tracker three docs declare dead, under an ambiguous number | A high-priority open decision is reachable only through a retired system |
|
||
| [F-010](findings/F-010-stand-labels-lag-their-own-commits.md) | Hand-written "Stand" labels older than their own file's last commit | Trains readers to distrust current content; gives no signal when content really is stale |
|
||
| [F-017](findings/F-017-prose-asserts-states-already-resolved.md) | Prose asserts states the tracker already resolved: a closed issue called open, a "pending" decision whose premise was executed 60 lines earlier | Sentences a reader would act on; found only by the systematic claim sweep |
|
||
|
||
### Pattern C — Two backlogs, one rule
|
||
|
||
| Finding | | Impact |
|
||
|---|---|---|
|
||
| [F-004](findings/F-004-open-work-lives-only-in-host-markdown.md) | Open next steps only in `hosts/`; OVERMIND-01, CFGMON-11/12/13, MATRIX-05 have no issue | Items invisible to board, milestone, priority and refinement |
|
||
| [F-009](findings/F-009-doc-attention-does-not-follow-work-mass.md) | gitops holds half the backlog and is absent from the vision | Session-start reading mis-weights prioritisation |
|
||
|
||
### Pattern D — Artifacts outlive their purpose without an owner
|
||
|
||
| Finding | | Impact |
|
||
|---|---|---|
|
||
| [F-006](findings/F-006-stale-branches-publish-pre-rewrite-history.md) | 3 abandoned branches, one carrying 41 pre-rewrite commits; `wiki` branch is a 3-month-old parallel truth | Undoes the rewrite for 42 commits; two truths about the same docs |
|
||
| [F-012](findings/F-012-orphaned-sha-references.md) | 6 unresolvable SHA citations, all benign — but nothing could check them | Evidence-by-citation depends entirely on human diligence at rewrite time |
|
||
|
||
### What works and must be preserved
|
||
|
||
| Finding | | Why it must survive |
|
||
|---|---|---|
|
||
| [F-014](findings/F-014-issue-hygiene-is-real.md) | Milestone duty 100%, one status label 100%, WIP limit held, no ID reuse, 0 broken links | Proof the team already works the way neckbeard assumes |
|
||
| [F-013](findings/F-013-mirror-topology-actually-holds.md) | All six mirrors in sync; decision recorded with reason, counter-argument, rescue path, one bounded exception | The form is the value: this is an ADR in all but frontmatter |
|
||
| [F-015](findings/F-015-rewrite-mapping-is-sound.md) | 251/251 mapping rows verified, 0 contradictions; near-miss recorded as luck | Shows a destructive operation made auditable by hand |
|
||
| [F-016](findings/F-016-self-documentation-is-honest.md) | Known problems named and filed; "zwei Wahrheiten … schlimmer als eine unvollständige" | Falsifiable claims are what made this analysis possible |
|
||
|
||
---
|
||
|
||
## Pattern → neckbeard mechanism → migration implication
|
||
|
||
| Pattern | Neckbeard mechanism (v0.1.1) | Implication for Session 2 |
|
||
|---|---|---|
|
||
| **B** — rule declared repo-wide, applied to a subset | **Largely a gap.** ADR-0001 (`docs/adr/0001-agents-md-canonical.md`) removes per-harness duplication *within* one repo; `schema.yaml` filename patterns + `validate.py` ("filename does not match", "id does not match filename prefix") show the framework already holds that names must be mechanically derivable | Decide **how five repos share one `AGENTS.md`** before anything else — vendoring copies re-creates the drift ADR-0001 rejects; a cross-repo link breaks ADR-0003 portability. Then introduce a components artifact that names each repo's canonical slug, so F-008 becomes checkable |
|
||
| **A** — decision executed, docs not carried along | `AGENTS.md:79` + `scripts/gen_status.py`: `STATUS.md` is generated, "do not edit by hand". `AGENTS.md:81`: ADRs binding, "never edited, only superseded". `WORKFLOW.md:128`: STATUS review on the refinement agenda. `WORKFLOW.md:136-138`: "Contradictions are resolved or explicitly flagged — never left silently coexisting" | Replace every hand-written count and "Stand" label with generated output. Port `decisions/0001-0009` to `docs/adr/` with `schema.yaml` frontmatter — they are already ADRs in substance. **Then file the missing one for M5.** |
|
||
| **C** — two backlogs, one rule | ADR-0002 (`docs/adr/0002-in-repo-issues.md`): issues as `docs/issues/NNNN-slug.md`, status in frontmatter, `STATUS.md` as index; `schema.yaml:76-84` enum `[open, in-progress, done, rejected]` enforced by `validate.py` `check_fields` | The **biggest decision of Session 2**: 71 open issues currently live in GitLab with milestones, `priority:*` labels and a group board. ADR-0002 Option C (repo canonical, mirrored to the forge) exists precisely for this and is the only option that does not throw away F-014's proven discipline. Do not migrate by deleting the board |
|
||
| **D** — artifacts outlive their purpose | **Gap for refs.** `schema.yaml`'s `warn_if_orphan` shows "reachable from nowhere" is already an accepted reportable condition — for documents. `WORKFLOW.md:122,126`: refinement backlog triage and wiki lint | Add a branch/ref hygiene step to the refinement ritual, and a SHA-resolution check (`analysis/scripts/inv_shas.py` is a working reference implementation) |
|
||
|
||
---
|
||
|
||
## Neckbeard gaps this field test exposed
|
||
|
||
Listed only, not filed as issues in the neckbeard repo — that is a separate act.
|
||
|
||
1. **Many repos, one ruleset.** ADR-0001 decides one-repo-many-harnesses. Nothing says how
|
||
a five-component project shares a governing `AGENTS.md` without either vendoring copies
|
||
(the drift ADR-0001 rejects) or cross-repo links (which ADR-0003 portability disallows).
|
||
Sharpest gap found. → F-011
|
||
2. **No components artifact.** No artifact type declares "these are the repos and these are
|
||
their canonical names", so slug drift and cross-repo status are unrepresentable.
|
||
`gen_status.py` covers one repo. → F-008, F-009
|
||
3. **No milestone or delivery-bucket concept.** `schema.yaml` has no field grouping issues
|
||
by what they pay into. This project uses milestones on 100% of open issues. → F-001
|
||
4. **`validate.py` does not resolve commit SHAs cited in prose.** `check_body_links` covers
|
||
markdown link targets only. Resolving a cited SHA is a textbook deterministic job under
|
||
`AGENTS.md:101-103`. → F-012
|
||
5. **No git-level hygiene at all** — commit metadata, author identity, branch lifetime are
|
||
outside the framework's field of view, while in this project they carry its most
|
||
sensitive claims. → F-002, F-003, F-006
|
||
6. **External link targets are never checked.** A document pointing at a retired external
|
||
tracker stays green. → F-005
|
||
7. **Field-test evidence on a deliberately rejected idea.** The creation AAR lists "priority
|
||
field on issues (YAGNI, revisit via refinement)" among ideas not adopted. This project
|
||
carries `priority:*` on 101 of 111 issues and treats it as distinct from the milestone
|
||
("`priority:*` sagt **wie dringend**, der Meilenstein sagt **worauf es einzahlt**",
|
||
`CLAUDE.md:99-101`). Recorded as evidence for the refinement that ADR-flagged revisit,
|
||
**not** re-proposed here. → F-014
|
||
|
||
---
|
||
|
||
## Appendix — the systematic claim verification
|
||
|
||
`analysis/scripts/verify_claims.py` gave every one of the 813 extracted claim rows a
|
||
mechanical disposition (`analysis/data/claims_verification.tsv`): **205 checked-ok**
|
||
(a path, issue reference or state assertion verified against tree or tracker),
|
||
**207 informational** (tokens classed as runtime/net/image/forge references — correctly
|
||
outside the analysed trees), **360 prose-or-runtime** (no mechanically checkable token;
|
||
their semantic truth remains unchecked, stated as a limit, not passed silently),
|
||
**13 in code blocks**, **28 flagged** for hand adjudication.
|
||
|
||
The 28 flags resolve as: **10** references into out-of-scope repos (homelab/wiki,
|
||
wiki-bookstack, vendor, the retired gitops wiki) — consistent with their own context;
|
||
**7** host/runtime artifacts that correctly are not in any tree (`lab.conf`,
|
||
`runner-data/`, an untracked `.npmrc` the doc itself calls untracked, npm tarball
|
||
contents); **3** historically removed files whose removal the surrounding text records;
|
||
**2** enumerations of a hypothetical revert, not claims; **1** tokenizer artifact
|
||
(`text/html`); **3** bare/ambiguous issue references; **2** genuine drift → **F-017**.
|
||
Bonus verification: all of `roadmap.md`'s gitops references (#25, #45, #46, #47, #48,
|
||
#49) match their GitLab titles — post-migration references are consistently
|
||
GitLab-numbered, strengthening F-014.
|
||
|
||
## Open questions for the human
|
||
|
||
1. **Where do the 71 open issues go?** ADR-0002 Option C (repo canonical, mirrored to
|
||
GitLab) preserves the board, the milestones and the labels that F-014 shows are working.
|
||
Pure Option B is cleaner and loses all three. This decides the shape of Session 2.
|
||
2. **F-002/F-003 are a live exposure, not a documentation defect.** Do you want the
|
||
remediation treated as an incident now — separately from and ahead of the migration?
|
||
This session recorded it and changed nothing, per mandate.
|
||
3. **`game-operating` mirror**: is it absent, or does it mirror under a name other than
|
||
`sorb/game-operating`? The negative result rests on the naming convention.
|
||
4. **Are `thread-net-git` (4 files) and `threadnet-operating` (0 issues, 7 days idle)
|
||
dormant by design?** If yes, the vision document should say so; if no, they are
|
||
under-tracked. Either way the docs currently imply five equal product lines.
|
||
5. **The M5 ADR** — file it as ADR-0010 in the current scheme now, or let it land as the
|
||
first ADR in the migrated `docs/adr/`?
|
||
|
||
---
|
||
|
||
### Answers received at session close (2026-08-10)
|
||
|
||
1. *(Issue location)* — deferred to Session 2, as proposed.
|
||
2. *(F-002/F-003 remediation)* — binding constraint recorded: any history rewrite must
|
||
ship an old→new **Zuordnung** in the style of `shared/commit-zuordnung-2026-08-07.md`
|
||
(the pattern F-015 verified). Timing remains with the human / Session 2.
|
||
3. *(game-operating mirror)* — **exists**, per the human; the anonymous negative was
|
||
withdrawn as inconclusive (Gitea hides existence behind an auth prompt — see F-007
|
||
addendum). Not ThreadNet-related beyond planned monitoring inclusion.
|
||
4. *(Dormant components)* — **intentional and staged**: base feature set first, then
|
||
monitoring and security build-out; deliberately not getting lost in polish. Recorded
|
||
in the F-009 addendum; no repo document states it yet.
|
||
5. *(M5 ADR)* — drafted as `analysis/drafts/0010-haertung-eigener-meilenstein.md`;
|
||
placed on local `main` as `decisions/0010-haertung-eigener-meilenstein.md` (banner
|
||
stripped) at session close. Push of `main` pending; the draft stays in the analysis
|
||
record as the field-test paper trail.
|
||
|
||
## Non-goals — what this analysis deliberately did not examine
|
||
|
||
- **No design doc in the target repo.** Deliberate deviation from `WORKFLOW.md` size-L
|
||
Gates 1–5: the migration design belongs to Session 2. Analysis precedes adoption.
|
||
- **Gate 0 suspended.** `PROJECT.md` is absent from the management repo, which under
|
||
`AGENTS.md:57-63` would be the init trigger. Suspended by the session mandate; recorded
|
||
as an observation, not a task.
|
||
- **Component code read structurally only** — trees, manifests, CI files, entry points.
|
||
No depth reading; no finding here required it.
|
||
- **Upstream fork history not analysed as project drift.** `threadnet-call` and
|
||
`ThreadNet-Web` carry thousands of Element/Matrix commits and 538 of the 543
|
||
TODO/FIXME/HACK markers found. Those are inherited, not steering artifacts. The
|
||
management repo itself contains **0 markers** — checked, no drift found.
|
||
- **Issue descriptions and comments were not exported.** `gitlab_issues.json` holds
|
||
metadata only, by design. Claims made *inside* issue bodies are therefore unverified —
|
||
including the migration footnotes `CLAUDE.md:52` says are authoritative for shifted
|
||
gitops numbers.
|
||
- **Out-of-scope repos** — `game-operating`, `gameserver`, the `vendor` and `Archiv`
|
||
subgroups — analysed only where a management-repo claim referred to them. Their contents
|
||
were not examined.
|
||
- **The `homelab` group** (`docs`, `wiki`, `wiki-bookstack`) and **axionwiki.lab** were not
|
||
examined; cross-references to them are recorded as `points-outside-scope` in `links.tsv`.
|
||
- **CI behaviour was not exercised**, only configuration presence (e.g. `canonize_rotation`
|
||
verified to exist at `.gitlab-ci.yml:51` in gitops; not observed running).
|
||
- **The human's own working copy** could not be inspected. The human confirmed at the
|
||
Phase-0 STOP that it points at git.lab.
|
||
- **Nothing was fixed.** No file outside `analysis/` was modified; `inv_repo.py` aborts the
|
||
run if any was, and the guard was tested by deliberately dirtying `README.md`.
|