Skip to content

Commit 76db953

Browse files
committed
docs(architecture): add E-2 graph audit with Engine/Trainer split
Why: post-commit Graphify audit for the real Stage 1+2 data acquisition/labeling run, confirming engine/trainer isolation (Invariant 8) structurally, not just by source inspection. What: before/after node+edge deltas (Engine Architecture unchanged, 1584/1584, +0/-0; Trainer Architecture +55/-9), bridge-node candidates matching exactly this PR's new symbols (acquire_stage1_lichess.py's functions, validate_dataset_manifest()) and nothing else, frozen boundary verdict UNCHANGED. Narrative documents and explains one observed side effect: the post-commit hook's own code-only/no-LLM scope pruned NNUE_PRD.md's 3 semantic `references` edges to ADR-006/007/010 when that file's content changed, with no LLM pass available to regenerate them -- verified directly against both graphs' edge lists, not a real change to the PRD's prose or its actual ADR citations. Left out: nothing -- audit only, no code changes. Refs #202 Phase: 15 — nnue
1 parent 44dce25 commit 76db953

1 file changed

Lines changed: 180 additions & 0 deletions

File tree

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# Architecture Graph Audit — E-2: Real Stage 1+2 Data Acquisition/Labeling Run
2+
3+
- Before commit: `15e021a1291dba63d8eebf1ef27d128f1656b073`
4+
- After commit: `44dce258678ee496b580d95f4d70085e0f09b7f8`
5+
- Before: 3303 nodes, 7100 edges
6+
- After: 3354 nodes, 7185 edges
7+
- Node delta: +60 / -9
8+
- Edge delta: +97 / -12
9+
10+
## Architecture Split
11+
_Scoping summary only — the detailed sections below (centrality, degree, boundary report, etc.) remain whole-graph, since those measures are not meaningful computed on a subgraph alone._
12+
13+
## Engine Architecture
14+
- Before: 1584 nodes; After: 1584 nodes
15+
- Node delta: +0 / -0
16+
17+
## Trainer Architecture
18+
- Before: 432 nodes; After: 478 nodes
19+
- Node delta: +55 / -9
20+
21+
## Top 10 nodes by betweenness centrality change
22+
- `Board` (engine_core_src_main_java_coeusyk_game_chess_core_models_board_board): 0.0035 -> 0.0034 (-0.0001)
23+
- `MovesGenerator` (engine_core_src_main_java_coeusyk_game_chess_core_movegen_movesgenerator_movesgenerator): 0.0009 -> 0.0009 (-0.0000)
24+
- `TunerPosition` (engine_tuner_src_main_java_coeusyk_game_chess_tuner_tunerposition_tunerposition): 0.0008 -> 0.0008 (-0.0000)
25+
- `NNUE_PRD.md` (docs_nnue_prd): 0.0000 -> 0.0000 (-0.0000)
26+
- `LabelledPosition` (engine_tuner_src_main_java_coeusyk_game_chess_tuner_labelledposition_labelledposition): 0.0006 -> 0.0006 (-0.0000)
27+
- `.iterativeDeepening()` (engine_core_src_main_java_coeusyk_game_chess_core_search_searcher_searcher_iterativedeepening): 0.0006 -> 0.0006 (-0.0000)
28+
- `.searchRoot()` (engine_core_src_main_java_coeusyk_game_chess_core_search_searcher_searcher_searchroot): 0.0005 -> 0.0005 (-0.0000)
29+
- `Task 14.7 WDL Self-Play Pilot` (changelog_task_14_7_wdl_selfplay_pilot): 0.0000 -> 0.0000 (-0.0000)
30+
- `.searchDepth()` (engine_core_src_main_java_coeusyk_game_chess_core_search_searcher_searcher_searchdepth): 0.0005 -> 0.0005 (-0.0000)
31+
- `.from()` (engine_tuner_src_main_java_coeusyk_game_chess_tuner_tunerposition_tunerposition_from): 0.0004 -> 0.0004 (-0.0000)
32+
33+
## Top 10 nodes by degree change
34+
- `NNUE_PRD.md` (docs_nnue_prd): 5 -> 2 (-3)
35+
- `ADR-006-self-written-pytorch-trainer.md` (docs_adr_adr_006_self_written_pytorch_trainer): 2 -> 1 (-1)
36+
- `ADR-010-trainer-repository-location.md` (docs_adr_adr_010_trainer_repository_location): 2 -> 1 (-1)
37+
- `ADR-007-staged-training-data.md` (docs_adr_adr_007_staged_training_data): 2 -> 1 (-1)
38+
39+
## Newly introduced architectural bridge-node candidates
40+
_New nodes ranked by betweenness centrality in the after-graph (>0). Heuristic, not a graphify-defined threshold._
41+
- `acquire()` (trainer_scripts_acquire_stage1_lichess_acquire): betweenness centrality 0.0000
42+
- `_iter_records()` (trainer_scripts_acquire_stage1_lichess_iter_records): betweenness centrality 0.0000
43+
- `acquire_stage1_lichess.py` (trainer_scripts_acquire_stage1_lichess): betweenness centrality 0.0000
44+
- `_to_record()` (trainer_scripts_acquire_stage1_lichess_to_record): betweenness centrality 0.0000
45+
- `test_acquire_stage1_lichess.py` (trainer_tests_scripts_test_acquire_stage1_lichess): betweenness centrality 0.0000
46+
- `stream_records()` (trainer_scripts_acquire_stage1_lichess_stream_records): betweenness centrality 0.0000
47+
- `validate_dataset_manifest()` (trainer_trainer_dataset_manifest_schema_validate_dataset_manifest): betweenness centrality 0.0000
48+
- `_open_source_stream()` (trainer_scripts_acquire_stage1_lichess_open_source_stream): betweenness centrality 0.0000
49+
- `_write_fixture()` (trainer_tests_scripts_test_acquire_stage1_lichess_write_fixture): betweenness centrality 0.0000
50+
- ``stockfish-label-e2-real.json` — provenance of each value` (trainer_configs_stockfish_label_e2_real_stockfish_label_e2_real_json_provenance_of_each_value): betweenness centrality 0.0000
51+
52+
## Newly introduced dependency cycles
53+
_Detected via strongly-connected-components (existence check, not full cycle enumeration)._
54+
- None
55+
56+
## Cross-module dependency changes
57+
- None
58+
59+
## Community changes
60+
_Community IDs are not stable across separate graphify runs — flagged via cohort-overlap (Jaccard < 0.5) among nodes present in both snapshots, not raw ID equality._
61+
- **490 of 3294 common nodes (15%) flagged — this volume is typical Louvain re-clustering instability under any graph perturbation, not evidence of real coupling change. Read this section by checking whether the specific files this PR touched appear below, not by the raw count.**
62+
- `MoveOrderer.java` (engine_core_src_main_java_coeusyk_game_chess_core_search_moveorderer): cohort overlap 0.01
63+
- `.getZobristHash()` (engine_core_src_main_java_coeusyk_game_chess_core_models_board_board_getzobristhash): cohort overlap 0.01
64+
- `.bruteForceNegamax()` (engine_core_src_test_java_coeusyk_game_chess_core_search_searchertest_searchertest_bruteforcenegamax): cohort overlap 0.01
65+
- `Piece.java` (engine_core_src_main_java_coeusyk_game_chess_core_models_piece): cohort overlap 0.01
66+
- `.evaluateTerminal()` (engine_core_src_main_java_coeusyk_game_chess_core_search_searcher_searcher_evaluateterminal): cohort overlap 0.01
67+
- `.enableTTStats()` (engine_core_src_main_java_coeusyk_game_chess_core_search_searcher_searcher_enablettstats): cohort overlap 0.01
68+
- `ClassicalEvaluator.java` (engine_core_src_main_java_coeusyk_game_chess_core_eval_classicalevaluator): cohort overlap 0.01
69+
- `.explainEval()` (engine_core_src_main_java_coeusyk_game_chess_core_eval_evaluator_evaluator_explaineval): cohort overlap 0.01
70+
- `.singularityGuardRequiresDepthAndQualifiedTtEntry()` (engine_core_src_test_java_coeusyk_game_chess_core_search_searchertest_searchertest_singularityguardrequiresdepthandqualifiedttentry): cohort overlap 0.01
71+
- `Evaluator.java` (engine_core_src_main_java_coeusyk_game_chess_core_eval_evaluator): cohort overlap 0.01
72+
- `KingSafety.java` (engine_core_src_main_java_coeusyk_game_chess_core_eval_kingsafety): cohort overlap 0.01
73+
- `.setEvaluatorStrategy()` (engine_core_src_main_java_coeusyk_game_chess_core_search_searcher_searcher_setevaluatorstrategy): cohort overlap 0.01
74+
- `ClassicalEvaluator` (engine_core_src_main_java_coeusyk_game_chess_core_eval_classicalevaluator_classicalevaluator): cohort overlap 0.01
75+
- `StaticExchangeEvaluator.java` (engine_core_src_main_java_coeusyk_game_chess_core_search_staticexchangeevaluator): cohort overlap 0.02
76+
- `.contemptScore()` (engine_core_src_main_java_coeusyk_game_chess_core_search_searcher_searcher_contemptscore): cohort overlap 0.02
77+
- ... and 475 more
78+
79+
## New God Nodes (top 15 by degree)
80+
- None
81+
82+
## Architectural cohesion
83+
- maintained (modularity 0.7850 -> 0.7869, delta +0.0019)
84+
85+
## Architectural Boundary Report
86+
_`production` = src/main/*.java outside `DEBUG_ONLY_MAIN_CLASSES`; `debug` = NnueOracle.java (ADR-002). Test files are excluded — test-to-production coupling is normal and not a boundary risk. Edges are reported at whichever node granularity graphify attaches them to (class/method), grouped by owning file._
87+
88+
### production -> debug dependencies
89+
- No change
90+
91+
### debug -> production dependencies
92+
- No change
93+
94+
### cross-module dependency changes
95+
_See "Cross-module dependency changes" above._
96+
97+
### EvaluatorStrategy coupling changes
98+
- No change
99+
100+
### Searcher coupling changes
101+
- No change
102+
103+
### NnueEvaluator coupling changes
104+
- No change
105+
106+
### FeatureExtractor coupling changes
107+
- No change
108+
109+
### NnueNetwork coupling changes
110+
- No change
111+
112+
### Frozen boundary verdict
113+
- UNCHANGED — no unapproved production -> debug edges introduced.
114+
115+
## Narrative
116+
117+
E-2's real content shows up exactly where expected and nowhere else. The graph's
118+
independent confirmation of this issue's Non-Scope: **Engine Architecture is
119+
unchanged (1584 -> 1584, +0/-0)** — zero Java files were touched, matching "no
120+
changes to `TextDatasetProvider`'s or `stockfish_label.py`'s own logic" and no
121+
Stage 3/self-play work. All real movement is in **Trainer Architecture (432 -> 478,
122+
+55/-9, net +46)**.
123+
124+
The "newly introduced architectural bridge-node candidates" are precisely this
125+
issue's new deliverables and nothing else: `acquire()`, `_iter_records()`,
126+
`_to_record()`, `_open_source_stream()`, `stream_records()` (all
127+
`acquire_stage1_lichess.py`, the new Stage 1 acquisition driver),
128+
`validate_dataset_manifest()` (the new dataset-manifest validator), plus their
129+
test-scope counterparts (`test_acquire_stage1_lichess.py`, `_write_fixture()`) and
130+
the new `stockfish-label-e2-real.json` provenance doc node. No unexplained
131+
additions — every new bridge-node candidate maps directly to a file this commit
132+
actually added.
133+
134+
**Degree-change table (`NNUE_PRD.md`, `ADR-006`/`ADR-007`/`ADR-010`, all -1 to -3):
135+
a known, expected side effect of the post-commit hook's own documented scope, not
136+
a real architectural regression.** Verified directly (not inferred from the table
137+
alone): before this commit, `docs_nnue_prd` carried 3 `references` edges to those
138+
three ADRs, extracted by an earlier *semantic* (LLM) pass. The installed
139+
post-commit hook rebuilds "code files only, no LLM needed" (its own header
140+
comment) — when it detected `NNUE_PRD.md` had changed, it correctly pruned that
141+
file's stale node data but has no LLM pass available to regenerate the semantic
142+
`references` edges, leaving the after-graph with only the 2 structurally-derivable
143+
edges (the inbound reference from the changelog, and the file's own `contains`
144+
edge to its title node). The PRD's actual prose still cites all three ADRs
145+
unchanged (`git diff` for this commit touches exactly one line, the Open Question 1
146+
resolution) — this is the graph's semantic layer for one file going stale, not a
147+
change in the document's real content or any real decoupling from those ADRs. A
148+
future full or `--update` run with semantic extraction enabled (as this session did
149+
manually, mid-review, before the shrink-guard correctly refused to merge a
150+
scope-mismatched incremental result — see this issue's completion report) would
151+
restore these edges; the code-only hook alone cannot and was never expected to.
152+
153+
No newly introduced dependency cycles, no cross-module dependency changes, no new
154+
God nodes. The Architectural Boundary Report is unanimous "No change" across every
155+
tracked row, including all `FROZEN_BOUNDARY_CLASSES`, and the frozen boundary
156+
verdict is **UNCHANGED** — this is the graph's independent confirmation of
157+
Invariant 8 (engine/trainer isolation) holding through this issue, on top of
158+
Invariant 1 (`DatasetProvider` isolation) and Invariant 6 (provenance chain) already
159+
verified directly (not just via the graph) elsewhere in this issue's completion
160+
report: `acquire_stage1_lichess.py` produces a manifest via
161+
`validate_dataset_manifest()`, never imports another `DatasetProvider`, and no edge
162+
from any of its new nodes to `TextDatasetProvider`/`StockfishLabeledProvider`
163+
appears anywhere in the after-graph.
164+
165+
Modularity moved by a small, positive amount (0.7850 -> 0.7869, delta +0.0019) —
166+
within the same noise band every prior Phase D/E audit has established, and if
167+
anything slightly *more* cohesive, not less. The community-churn section (490 of
168+
3294 common nodes, 15%, flagged) was checked against this PR's actual file list
169+
before being dismissed as noise — the listed churned nodes (`MoveOrderer.java`,
170+
`Piece.java`, `KingSafety.java`, `StaticExchangeEvaluator.java`, etc.) are
171+
pre-existing, unrelated engine-core classes, matching every prior audit's pattern
172+
of Louvain re-clustering instability rather than real coupling change.
173+
174+
Overall: an additive-only commit whose graph footprint is exactly its stated
175+
scope — nine new Python/doc nodes in Trainer Architecture, zero Engine Architecture
176+
change, zero boundary changes, zero cycles, zero cross-module drift, and one
177+
identified (not hidden) side effect of the code-only post-commit hook's own scope
178+
on a single pre-existing doc node, fully explained above rather than left as an
179+
unremarked anomaly in the degree-change table.
180+

0 commit comments

Comments
 (0)