analysis: add drift report and session handoff
REPORT.md groups the 16 findings by their four root-cause patterns, maps each pattern to the neckbeard mechanism that would have caught it, and lists the seven framework gaps the field test exposed. HANDOFF.md carries scope, reproduction, this session's decisions and the seven calls I am least confident about.
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
# HANDOFF.md — Session 1 → Session 2
|
||||
|
||||
Everything Session 2 needs, and nothing else. Session 2 designs and builds the
|
||||
neckbeard-based management system in a **new branch**, starting fresh from this file.
|
||||
|
||||
## Where things are
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| Analysis branch | `analysis/neckbeard-fieldtest`, branched from `main` at `2f012a6` |
|
||||
| Commits | `f6a9b9f` scope · `b8b8531` inventory · `959bf88` SHA + timestamps · `eaa00f0` findings · this file |
|
||||
| Deliverables | [SCOPE.md](SCOPE.md) · [REPORT.md](REPORT.md) · [findings/](findings/) (F-001…F-016) · [data/](data/) · [scripts/](scripts/) |
|
||||
| Read first | REPORT.md executive summary, then the pattern → mechanism → implication table |
|
||||
| Neckbeard reference | `v0.1.1` @ `823a08cac6b03a47d7e2f661200a49ac6e09d38d`, `main`, clean |
|
||||
|
||||
Nothing outside `analysis/` was modified on this branch. `main` is untouched.
|
||||
|
||||
## Reproducing the raw data from zero
|
||||
|
||||
```bash
|
||||
git clone https://git.lab/axion1337.chat/management.git
|
||||
cd management && git checkout analysis/neckbeard-fieldtest
|
||||
bash analysis/scripts/run_all.sh
|
||||
```
|
||||
|
||||
Clones the five component repos into `../components/` if absent, exports group issue
|
||||
metadata from git.lab, regenerates everything under `analysis/data/`. Bash + python3
|
||||
stdlib only, no pip installs. Requires lab/VPN access for the clone and the issue export;
|
||||
both skip cleanly without it and the rest still runs. Override the checkout location with
|
||||
`NB_WORKSPACE`.
|
||||
|
||||
**A second run on an unchanged tree must produce no diff.** Verified with
|
||||
`diff -r` after a full regeneration. No wall-clock time enters any output: "days since"
|
||||
is measured against the management repo's HEAD commit date (2026-08-09), not the clock.
|
||||
|
||||
`inv_repo.py` aborts the whole run if anything outside `analysis/` was modified. That
|
||||
guard was tested by deliberately dirtying `README.md`; it fires.
|
||||
|
||||
## Scope, as frozen at the Phase-0 STOP
|
||||
|
||||
Five components, slugs verified against git.lab with `git ls-remote`, human-confirmed:
|
||||
|
||||
| Display name | Repo slug |
|
||||
|---|---|
|
||||
| ThreadNet Call | `threadnet-call` |
|
||||
| ThreadNet Git | `thread-net-git` |
|
||||
| ThreadNet Operating | `threadnet-operating` |
|
||||
| ThreadNet Server Suite | `axion1337.chat-gitops` |
|
||||
| ThreadNet Web | `ThreadNet-Web` |
|
||||
|
||||
Out of scope as analysis targets: `game-operating`, `gameserver`, the `vendor` and
|
||||
`Archiv` subgroups. References into them are recorded as `points-outside-scope`.
|
||||
The human confirmed their own working copy points at canonical git.lab, not the mirror.
|
||||
|
||||
## Decisions taken this session, and why
|
||||
|
||||
1. **Both repos freshly cloned; push URL set to `DISABLED-no-push` on every clone**,
|
||||
including clones `run_all.sh` creates. The mandate forbids modifying originals; making
|
||||
it mechanically impossible beats remembering not to.
|
||||
2. **The management repo is inventoried at `main`, not at the analysis branch.** The first
|
||||
run counted this session's own commits and `analysis/` files as project reality (87
|
||||
commits instead of 86, 45 files instead of 44). An analysis that observes itself
|
||||
reports its own footprint as drift.
|
||||
3. **Commits follow the repo's own convention** (`CLAUDE.md:116-134`): English,
|
||||
conventional style, author *and* committer date at 12:00:00 UTC, plus the mandated
|
||||
`analysis:` prefix. Not anonymising would have been drift this session introduced.
|
||||
4. **The GitLab token is referenced by path, never read into output.** Per `CLAUDE.md:109`
|
||||
its value was not printed, logged or written anywhere; the export holds **metadata
|
||||
only** — no issue descriptions, no comments.
|
||||
5. **All group issues exported, open and closed**, rather than an arbitrary
|
||||
"recently closed" cutoff. The group is small (111 issues); a full export is
|
||||
deterministic and needs no justification for where the line was drawn.
|
||||
6. **`sha_refs.tsv` and `timestamp_anonymisation.tsv` were added** beyond the mandated file
|
||||
list, prompted by the human's question about the rebase mapping list. They carry the
|
||||
evidence for F-002, F-003, F-006, F-012 and F-015.
|
||||
7. **Two tooling bugs were found and fixed mid-flight**, both of which would have produced
|
||||
false conclusions: `git grep -E '\b…'` silently reports **zero** markers because git's
|
||||
ERE has no `\b` (real count: 543), and a `TZ` that is not set on the `git` process
|
||||
itself makes every commit look non-anonymised.
|
||||
8. **Link statuses stayed at the three mandated values**; the nuance moved into a `kind`
|
||||
column rather than inventing a fourth status.
|
||||
|
||||
## Where Session 2 should start
|
||||
|
||||
The pattern → mechanism → implication table in REPORT.md is the input. Two things gate
|
||||
everything else:
|
||||
|
||||
- **Question 1 in REPORT.md** — where the 71 open issues live after migration. ADR-0002
|
||||
Option C versus pure Option B changes the shape of the whole design.
|
||||
- **Neckbeard gap 1** — how five repos share one `AGENTS.md`. Unanswered, this blocks any
|
||||
multi-repo adoption.
|
||||
|
||||
Neckbeard's own rules for Session 2: `PROJECT.md` is absent from the management repo, so
|
||||
**Gate 0 fires there** (`AGENTS.md:57-63`) — it was suspended for this session only. The
|
||||
migration is size L, so `WORKFLOW.md` Gates 1–5 with a design doc in `docs/design/` apply.
|
||||
|
||||
## The decisions I am least confident about
|
||||
|
||||
In descending order of how much they could mislead Session 2.
|
||||
|
||||
1. **Claim extraction is trigger-based, not semantic.** `claims.tsv` holds 813 candidate
|
||||
lines matched by regex patterns, biased toward recall. I verified the claims the
|
||||
mandatory checks and the findings required — not all 813. A claim that is false but
|
||||
matched no trigger, or matched one and was not among the ones I chased, is not in this
|
||||
report. This is the largest hole in the analysis.
|
||||
2. **`git ls-remote` against `rohana.axion1337.de/sorb/<name>` is how I concluded
|
||||
`game-operating` has no mirror** (F-007). That rests on the naming convention holding,
|
||||
which I verified for six repos but cannot prove for the seventh. The contradiction
|
||||
between `CLAUDE.md:36` and `hosts/overmind.md:28` is solid; the cause is not.
|
||||
3. **F-009 and F-010 are judgement calls, marked `medium`.** "Doc attention should follow
|
||||
work mass" assumes dormancy is unintended, and a "Stand" label may legitimately mean
|
||||
"system state as last verified" rather than "state of this text". Both could be
|
||||
dismissed by an answer I do not have.
|
||||
4. **The severity I assigned to F-002/F-003.** I treated 237 commits with real clock times
|
||||
on a public mirror as the report's most consequential finding. That weighting is mine.
|
||||
If the exposure is acceptable to you, the finding shrinks to a documentation defect and
|
||||
the executive summary over-weights it.
|
||||
5. **F-011's confidence is `medium` because the sentence is ambiguous.** "Projekt-Repos
|
||||
haben eigene CLAUDE.mds" may be descriptive rather than a claim about all five. I read
|
||||
it as a claim because the sentence goes on to define conflict resolution against it.
|
||||
6. **I did not verify claims made inside issue bodies.** `CLAUDE.md:52` says the migration
|
||||
footnote *in the issue* is authoritative for shifted gitops numbers — so the one source
|
||||
that could settle F-005's numbering question is the one I deliberately did not export.
|
||||
7. **`markers.tsv` was produced and then barely used.** 543 markers, 538 of them inherited
|
||||
upstream. I recorded "management: 0 markers, checked, no drift found" and moved on. If
|
||||
technical debt in the components matters to Session 2, that file is unmined.
|
||||
@@ -0,0 +1,190 @@
|
||||
# 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 — publicly readable on the Gitea mirror,
|
||||
which this session verified is in sync. Two component repos were never rewritten at all.
|
||||
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 expose real hours | Stated privacy goal unmet, publicly; expensive operation largely undone |
|
||||
| [F-003](findings/F-003-author-identity-unification-incomplete.md) | 5 author identities of one person survive, one malformed | Same exposure; one person shows as 4–5 contributors publicly |
|
||||
| [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; `game-operating` claimed mirrored, is not | Gap in the availability guarantee the two-host topology exists for |
|
||||
| [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 |
|
||||
|
||||
### 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 public with 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
|
||||
|
||||
---
|
||||
|
||||
## 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/`?
|
||||
|
||||
---
|
||||
|
||||
## 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`.
|
||||
Reference in New Issue
Block a user