5.2 KiB
modules.json — the state / source of truth
One file per project. The HTML and MD are pure projections of it (regenerated by
render.py); never hand-edit the outputs. Edit modules.json (or let the scripts and
subagents edit it) and re-render.
{
"meta": {
"project": "My App", // shown in the title (module NAMES are never translated)
"lang": "en", // UI display language: "en"|"zh" (default "en").
// localizes the chrome + report; module `desc`
// should be authored in this language. ids/labels stay.
"subtitle": "short tagline", // optional header sub-line (write in meta.lang)
"generatedAt": "2026-01-01",
"rev": "abc1234", // git rev these artifacts reflect (optional)
"htmlPath": "docs/architecture-map.html", // for reciprocal links
"mdPath": "docs/architecture-audit.md",
"spineDesc": "A user edits … → … → persistence.", // shown on the spine view
"tracked_loc": 184900, // filled by scan.py --write (union, de-duped)
"tracked_files": 980,
"locLine": "≈185k first-party LoC …" // optional override of the report line
},
"excludes": ["__pycache__","/node_modules/", "..."], // optional; sensible defaults if absent
"bands": [ // visual layers, top → bottom (data-flow order)
{"id":"festore","tier":"fe","t":"Frontend · Stores","d":"one store per domain"},
{"id":"wire1","wire":true,"t":"◀ WebSocket · HTTP ▶"}, // a divider, not a band
{"id":"becore","tier":"be","t":"Backend · Core","d":"scene model, protocol"}
],
"spine": ["p_viewport","editorStore","ws_svc","be_main","core_scene","persistence"],
"reportThemes": [
["Dual-format is the most-repeated violation", "snake||camel recurs in N handlers …"],
["Duplication is the dominant theme", "X and Y reimplement …"]
],
"modules": [
{
"id": "core_scene", // stable unique id (used in deps + edges)
"label": "Scene", // shown on the card
"band": "becore", // which band it sits in
"path": "core/scene.py", // human-readable location (shown in detail)
"paths": ["src/core/scene.py"], // globs scan.py counts (root-relative; may use ** wildcards)
"exclude": [], // optional extra excludes for this module
"coupling": "core", // low | med | high | core (manual / structural)
"deps": ["core_object","core_components"], // downstream: what this calls
"desc": "Central data structure …", // 1-line "what it does", shown on click;
// author in meta.lang (zh for this project)
"tests": ["server/.../tests/test_scene.py"], // globs for this module's tests (the
// regression net); NOT counted in the
// module's own audit scope / loc
"lastFix": { // optional: outcome of the most recent `fix`
"at":"2026-06-11","accepted":true,
"ran":"pytest tests/test_scene.py",
"scoreBefore":68,"scoreAfter":84
},
// ---- filled by scan.py --write ----
"loc": 1234,
"contentHash": "ab12…", // hash of current code
// ---- filled by apply_audit.py (one subagent's result) ----
"score": 88, "grade": "B",
"tags": ["legacy"],
"findings": [{"sev":"LOW","loc":"core/scene.py:72","text":"… evidence …"}],
"auditedHash": "ab12…", // contentHash at audit time → staleness check
"auditedAt": "2026-06-10",
"auditedRev": "3837998"
}
]
}
Field ownership
| Field | Written by | When |
|---|---|---|
meta.*, bands, spine, coupling, deps, desc, paths, label, id, band |
model (decomposition) | generate, and when structure changes |
loc, contentHash, meta.tracked_* |
scan.py --write |
every scan |
score, grade, tags, findings, auditedHash/At/Rev |
apply_audit.py (from an auditor subagent) |
each (re)audit |
tests |
test-author subagent | test, and the baseline step of fix |
lastFix |
model (after the acceptance gate) | each fix |
reportThemes |
model (synthesis) | after a full/partial audit |
Test files are excluded from a module's audit scope by default (so editing a test
does not mark the module stale and test LoC does not inflate the production-code score).
The tests field records them separately as the regression net.
Staleness
A module is stale when contentHash != auditedHash (its code changed since last
audit), unaudited when it has no score/auditedHash, empty when its paths
match no files (likely deleted → drop it or fix the globs). scan.py reports these;
only stale + unaudited modules need a fresh subagent.
Coupling vs score
coupling (low/med/high/core) is a structural property — how central the module is
(degree + role). score is a quality property — how clean the code is. They are
independent: a core module can be clean (A) and a low leaf can be broken (F).