Initial commit: codemap skill (architecture map + per-module code-quality audit)

This commit is contained in:
Xingyu Chen
2026-06-10 18:07:15 -07:00
commit 2d7c7d0afd
10 changed files with 1561 additions and 0 deletions
+103
View File
@@ -0,0 +1,103 @@
# `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.
```jsonc
{
"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).
+152
View File
@@ -0,0 +1,152 @@
# Audit Standard (canonical)
This is the fixed rubric. Every module audit must follow it verbatim so scores are
comparable across modules, runs, and projects. Do not improvise scoring.
## Scoring rubric (0100) → grade
| Score | Grade | Meaning |
|------:|:-----:|---------|
| 90100 | A | Clean, well-scoped, idiomatic. No material smells. |
| 7589 | B | Minor issues: a documented shim, mild bloat, a localized cast. |
| 6074 | C | Notable hacks/fallbacks, real bloat, or duplication that has a clear owner. |
| 4059 | D | Significant legacy/stubs/duplication, or a dual-format/protocol violation. |
| 039 | F | Broken, fake output, or an unfinished feature wired in as if done. |
Be rigorous and evidence-based, not generous. A module with one HIGH finding rarely
scores above 60; with only LOW findings it usually scores 80+.
## Smell taxonomy (the `tags`)
Use these exact tag strings. `clean` is the only positive tag; the rest are negative
(the map colors them red and counts them in the report).
- `monkeypatch` — runtime mutation of another module / stdlib / vendor; `setattr` on
foreign objects; `sys.modules` / `sys.meta_path` surgery; reassigning store actions.
- `fallback` — "try the real thing, then fake/degrade"; chained `a || b || c` /
`a ?? b` defaults that hide which value is real.
- `silent-except` / `silent-catch``except: pass`, bare `except`, empty `catch {}`
that swallow errors with no log/signal.
- `legacy` — deprecated/back-compat shims, retired vocabulary, dead-but-shipped code,
parallel "old + new" code paths kept side by side.
- `dual-format` — accepting both snake_case and camelCase (or two payload shapes) for
the same field; the classic `display_name || displayName` patch.
- `stub` / `placeholder``NotImplemented`, `TODO: implement`, dead buttons, demo
scripts, hardcoded sample data presented as real.
- `fake-output` — returns random/canned/hardcoded results where real computation is implied.
- `duplication` — logic copy-pasted from a sibling or that an existing shared
abstraction already covers.
- `bloat` / `god-component` — oversized file/function; many responsibilities in one unit.
- `glue` — thin, valueless pass-through / boilerplate forwarding: rows of one-line
wrappers that only forward args to another layer (e.g. dozens of `send({type:...})`
methods), an adapter that copies a payload field-for-field without transforming, a
store/function that only re-exports or delegates to another. The indirection earns
nothing. Distinct from `bloat` (size) and `duplication` (copy-paste): glue is about
forwarding that adds no value.
- `any-escape``as any`, `@ts-ignore`, untyped boundaries used to bypass the type system.
- `over-fit` — hardcoded to one case where a small generalization was expected.
- `clean` — no material issues.
Judgement rules:
- A *documented, bounded* compat shim that deliberately refuses to silently coerce is
`legacy` at most LOW — do not over-penalize disciplined shims.
- A fallback that is a real security control or numeric guard (e.g. identity matrix on
singular input, stripping untrusted shaders) is **not** a smell.
- Native-dependency gating that *raises or returns an error* when a lib is missing is
correct; only `fake-output` if it silently returns fabricated data.
- A `*Placeholder` name is not automatically a stub — read it; it may be a finished
read-only widget.
- A *single* thin delegator, or a genuine boundary normalizer that converts/validates
once, is fine — not `glue`. Flag `glue` only when pass-through wrappers **proliferate**
(many near-identical forwarders that should be collapsed, generated, or replaced by a
generic dispatch) or an adapter forwards with no transformation. Usually MED when it
proliferates, LOW for a one-off.
## Severity (each finding)
- `HIGH` — wrong/dangerous/fake, a protocol or security issue, or a god-file that is a
genuine maintenance hazard.
- `MED` — a real smell a maintainer should fix: a live dual-format patch, an un-migrated
duplicate, an unfinished-but-wired path.
- `LOW` — a documented shim, a cosmetic cast, benign bloat. Worth noting, not urgent.
Always cite `file:line` and quote/paraphrase the offending snippet. Never report a
grep hit as a problem without reading the surrounding code.
## Independent-subagent protocol (REQUIRED)
Every module's score MUST be produced by a separate subagent, never inline in the main
thread, and never reused across modules. One subagent audits one module against the
paths in its state entry. Spawn them in parallel (Explore or general-purpose).
### Subagent prompt template
> You are auditing CODE QUALITY of ONE functional module for an architecture audit.
> Module: **{label}** (`{id}`). Files: {paths}. Project root: {root}.
>
> Read the module's code (grep the markers below, then READ the surrounding code —
> never flag a grep hit you haven't read). Judge it against this rubric:
> {paste the "Scoring rubric", "Smell taxonomy", "Severity" sections above}
>
> Hunt specifically for: monkeypatch / stdlib mutation, fallback chains & silent
> excepts, legacy/deprecated/back-compat shims, dual-format (snake||camel) handling,
> stubs / fake output / unfinished-but-wired code, bloat/god-files, duplication of
> logic that exists elsewhere, thin valueless glue (proliferating pass-through wrappers
> / no-op adapters), and over-fitting. Also state whether the module is appropriately
> generic.
>
> Return ONLY this JSON (no prose):
> {"score": <0-100>, "grade": "<A|B|C|D|F>",
> "tags": ["<from the taxonomy>", ...],
> "findings": [{"sev":"HIGH|MED|LOW","loc":"file:line","text":"concrete issue + evidence"}, ...]}
> If clean, use tags ["clean"] and findings []. Be rigorous, not generous.
Use `schema` on the Agent call to force that JSON shape when available. Then feed each
result to `scripts/apply_audit.py --id <id> --json '<result>'`.
## Test-author protocol (the `test` command + the baseline step of `fix`)
A dedicated **test-author subagent** generates tests for a module. It is separate from
the auditor, fixer, and verifier.
- **Detect, don't invent.** Find the repo's test framework and location from existing
tests near the module (pytest / jest / vitest / go test / …); match their style and
placement. Never introduce a new framework or harness.
- **characterization mode** (default before a fix): capture the module's CURRENT
observable behavior — inputs→outputs, side effects, payload shapes — as assertions of
"same as today", not "correct". Target the public surface; don't pin private internals.
Use snapshot/golden tests only where the repo already does.
- **coverage mode**: cover the public API and the specific behaviors named in the
module's `findings`. Aim for meaningful branches, not line count.
- **Must be GREEN on the current, unmodified code before returning.** If a test you want
to write fails because of a real bug, FLAG it as a finding — do not assert the buggy
output as if it were the desired behavior.
- Tests are real, committed source (the regression net); never delete or weaken them to
move a number.
- Return JSON: `{"framework":"...","files":["..."],"locked":"<behaviors locked>",
"gaps":"<what is still uncovered>","flagged":[{"sev":"...","loc":"...","text":"..."}]}`.
## Acceptance / regression gate (the gate in `fix`)
An **acceptance/verifier subagent**, independent of the fixer, proves a fix introduced no
regression. It does NOT score quality — pass/fail only.
- Re-run the EXACT baseline test set captured before the fix (same commands), plus the
narrowest build/typecheck for the touched area.
- **PASS iff** every test that was green before is green after, AND no new build / type /
lint errors appeared. A baseline-green test that is now failing, errored, skipped,
deleted, or flaky counts as a regression → FAIL (you cannot remove a test to pass).
- New tests the fixer may have added are ignored (and the fixer should not add any).
- Return JSON: `{"pass": <bool>, "ran": "<commands>",
"regressions": [{"test":"...","was":"pass","now":"fail|error|missing","evidence":"..."}],
"evidence": "<short summary>"}`.
- **Gate rule:** no PASS → no re-audit and no rendered score improvement. Report the
failure with evidence; revert or hand back to the fixer.
## Cross-cutting themes
After all modules are scored, the orchestrator (main thread) writes 47
`reportThemes` into `modules.json` — patterns seen across modules (e.g. "dual-format
recurs in N handlers", "duplication between X and Y", "stub backend wired live"). Each
is `[headline, body]`. These are synthesis, not per-module scoring, so the main thread
writes them.