Skip to content

docs: audit everything, consolidate 18 skills into 2, resync the mdBook - #32

Merged
taddyb merged 4 commits into
masterfrom
worktree-docs-audit
Aug 1, 2026
Merged

docs: audit everything, consolidate 18 skills into 2, resync the mdBook#32
taddyb merged 4 commits into
masterfrom
worktree-docs-audit

Conversation

@taddyb

@taddyb taddyb commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Audits every .claude/skills/ package (9,371 lines), all 32 docs/ files, README.md, .claude/references/, and CLAUDE.md — then acts on what it found. Full report: docs/2026-07-30-docs-and-skills-audit.md.

Method: five parallel auditors, each required to verify every concrete claim against the repo rather than assess plausibility. Every path ls'd, every config key checked against src/config.rs, every cargo test --test X checked against tests/, every CLI flag grepped, every #[test] counted, every number cross-checked against the dated findings doc that owns it. Where docs disagreed, metrics were recomputed from .ddrs/runs/*/ rather than picking a side.

What was wrong

A config key that does not exist. kan_head.disaggregation.use_precip was documented in CLAUDE.md, src/config.rs's own comment, and config/sources/conus-hourly.yaml. It was removed in 334f0fe. Because CLAUDE.md is in context on every turn, this propagated faster than any one doc could be corrected.

Two documented entry-point commands hard-error. ddrs init exits 2; ddrs run --workflow eval demands a --from-run flag that exists nowhere in src/. Both were the documented first step in docs/setup.md and README.

The baseline number came from the wrong network. 0.689 / 0.723 appeared in 13 of 18 skills as the CONUS bar. It is a global MERIT number over 5,224 gauges; the CONUS bar is 0.6781 / 0.7172 on 2,365. That makes the widely-quoted +0.026 delta a cross-population subtraction (correct: +0.037). A separate population error in the 07-07/07-16 findings docs flips a verdict — hourly-lstm's "+0.022 NSE gain from routing" becomes −0.051 when the baseline is scored on the same gauges.

One doc invalidated six skills at once. The 2026-07-06 leakance NO-GO retired the "Phase B is required" framing; all six research skills still asserted it, three still carried executable instructions for the closed campaign. That duplication is why the staleness was uniform.

Gates that cannot fail. cargo test --test sp8_gradcheck -- --ignored runs zero tests and exits 0 (nothing in that file is #[ignore]). Same for --lib training::checkpoint and --lib data::store::zarr::tests::…. mc_routes_linear_chain never existed. Test counts were also wrong — 16 not 8, 8 not 6.

What changed

Skills: 18 → 2. 9,371 → 2,359 lines.

  • ddrs-dev — build/code/run/debug, with references/{build-and-env, config, testing, traps, research-status}.md
  • ddrs-eval-plots — evaluate output, rewritten around .ddrs/runs/<id>/; the dead output/saved_models_*/ layout is gone

Dropped the H5/H6 plot references (both plot instruments the v2 audit refuted) and rescued two orphaned parity files. Editorial rules: don't duplicate CLAUDE.md; lead with the discriminating test, not the narrative; one authoritative numbers table with a do-not-use list; assert "all pass" instead of brittle counts. Each SKILL.md opens with a TOC indexing into its references.

The mdBook, 13 chapters. It was a 2026-06-08 snapshot — leakance, the disaggregation head, nnse-kge/kge, ddrs sources/import/status/gc, managed adjacency, the global stores, and --backend cpu were all invisible to it. Beyond the dead commands: outputs.md opened with "there is no global results directory" (everything lands under .ddrs/runs/<id>/); setup.md claimed the CPU path needs no CUDA (burn-cuda/cudarc are non-optional, so a CPU-only reader fails at cargo build); seven "MLP head" mentions violated invariant 5; p_spatial was called an exponent; perf.md had the Rust defaults inverted and PersistentScratch at 33 handles instead of 39, understating memory ~18%; DDRS_FORCE_GRAPHS=1 does not actually exercise graph capture.

CLAUDE.md and README.md corrected for all of the above, plus the disaggregation head and experiment.loss.kind — neither of which appeared in any user-facing doc.

Verification

mdbook build is clean. Zero MLP references outside the documented mlp: serde alias. Every remaining ddrs init mention is in a "this is dead" context. Every rewritten ddrs-eval-plots template was executed end-to-end against a real run, reproducing the committed parameter_convergence_stats.json values exactly.

Notes for review

  • One src/ change, comment-only (src/cuda_graph/scratch.rs docstring). Tier C gate run in full anyway: cargo check --lib clean, cargo test --lib 243 passed / 0 failed, cargo test all binaries ok, compare_ddr_sandbox ABSOLUTE MATCH (max abs 1.525879e-5 m³/s).
  • nse-batch / optimizer: adadelta are documented with an explicit "arrives with PR feat(training): optimizer micro-batching (gradient accumulation) with exact valid-count weighting #31" caveat; they do not exist on master.
  • .claude/references/ is left in place. It is a strict subset of docs/ and its newer mtime is a 2026-06-10 back-port, not newer knowledge — but deleting it means updating ~25 inbound links including one in src/sparse/mod.rs. Recommended as a follow-up in the report.

The V9 verdict is retracted

The last commit fixes the two source-side defects the audit found, and the second one is worth a reviewer's attention.

.claude/ARCHITECTURE.md recorded "V9 (graph vs no-graph bit-match): GREEN", evidenced by DDRS_FORCE_GRAPHS=1 compare_ddr_sandbox. That env var only selects the CUDA backend — and is read with .is_ok(), so DDRS_FORCE_GRAPHS=0 triggers it too. Capture requires all three of use_cuda_graphs && sparse_solver == Cuda && backend_is_cuda (src/routing/mmc.rs:289-294). The sandbox builds from Config::default() (src/sandbox.rs:88-89) = use_cuda_graphs: false + SparseSolver::Cpu, and fixtures/sandbox/config.csv sets neither toggle — it carries only geometry, ranges, and dt.

So the run that certified V9 exercised the CUDA backend with the CPU sparse solver and no capture. Corroborating: this PR's verification run reports max abs 1.525879e-5 m³/s, matching the 1.5e-5 in the historical V9 entry to the digit — that entry's run was this same CPU-solver path.

The ABSOLUTE MATCH is real and still certifies the backend. It does not certify the property V9 names. The CUDA-graph capture path currently has no gate. Both architecture docs now say UNVERIFIED with the reason; closing it needs a sandbox config that sets both toggles.

Also fixed: scratch.rs's docstring claimed 32 handles and all-n-sized buffers. Actual is 39 handles, of which 37 are n-sized and 2 nnz-sized — understating memory ~18% (~525 KB / ~44 MB → ~740 KB / ~51 MB). The inline "24 saved-state" is 23, now tied explicitly to mmc_op::NUM_SAVED_STATE.

🤖 Generated with Claude Code

taddyb and others added 4 commits July 30, 2026 21:54
Audited every `.claude/skills/` package (9,371 lines), all 32 `docs/` files,
README.md, `.claude/references/`, and CLAUDE.md by verifying each concrete claim
against source rather than assessing plausibility.

Findings (full report: docs/2026-07-30-docs-and-skills-audit.md):

- `kan_head.disaggregation.use_precip` does not exist. It is documented in
  CLAUDE.md, src/config.rs:113's comment, and config/sources/conus-hourly.yaml.
  Removed in 334f0fe; the head now always consumes precip.
- `ddrs init` (exit 2) and `ddrs run --workflow eval` (`--from-run` unimplemented)
  are documented as working in README.md, docs/, and CLAUDE.md. Both hard-error.
- The baseline `0.689 / 0.723` propagated into 13 of 18 skills as the CONUS bar.
  It is a global-MERIT 5,224-gauge number. The CONUS bar is 0.6781 / 0.7172 on
  2,365 gauges, making the widely-quoted +0.026 delta a cross-population
  subtraction (correct: +0.037).
- The 07-07 and 07-16 findings docs compare 3,211-gauge baselines against
  2,365-gauge trained medians. Population-matched, hourly-lstm's "+0.022 NSE gain
  from routing" reverses to -0.051.
- One superseding doc (2026-07-06 leakance NO-GO) invalidated the same
  "Phase B is required" paragraph in six skills; none were updated. Three still
  carried executable instructions for the closed campaign.
- Test counts were wrong (leakance_gradcheck 16 not 8, zeta_accum 8 not 6), and
  two gate commands in CLAUDE.md/docs run zero tests and exit 0.
- `.claude/references/` is a strict subset of `docs/`; its newer mtime is a
  2026-06-10 back-port of corrections `docs/` received on 2026-06-08.

Consolidation: 18 skills -> 2, 9,371 -> 2,359 lines (75% reduction).

- `ddrs-dev` (build/code/run/debug): SKILL.md + references/{build-and-env,
  config, testing, traps, research-status}.md
- `ddrs-eval-plots` (evaluate output): rewritten around `.ddrs/runs/<id>/`;
  the dead `output/saved_models_*/` layout is gone. Two dead-campaign references
  (H5 parameter_swap, H6 loss_landscape) removed since both plot instruments the
  v2 audit refuted; two orphaned parity_* files merged into parity.md and wired
  into the routing table.

Editorial rules applied: do not duplicate CLAUDE.md (in context every turn);
lead with the discriminating test, not the narrative; one authoritative numbers
table with gauge-set definitions and a do-not-use list, replacing five copies of
H1-H7; assert "all pass" instead of brittle test counts.

Every rewritten eval-plots template was executed end-to-end against a real run,
reproducing the committed parameter_convergence_stats.json values exactly.

docs/ and README.md fixes are enumerated as prioritized follow-ups in the report,
not applied here.

Co-Authored-By: Claude <noreply@anthropic.com>
Table of contents:
- ddrs-dev/SKILL.md gains a §Contents indexing each reference file's sections,
  so an agent can jump to the right file+section without opening all five.
- ddrs-eval-plots/SKILL.md likewise.
- Added §Contents to the four reference files that lacked one: config.md,
  research-status.md, parameter_map.md (455 lines), metrics.md. traps.md and
  parity.md already open with functional index tables.

CLAUDE.md corrections (verified against source):
- `kan_head.disaggregation.use_precip` does not exist — removed in 334f0fe.
  The disagg block's presence is what makes `aorc_precip` mandatory.
- `ddrs run --workflow eval` is not implemented (`--from-run` does not exist);
  `ddrs init` exits 2. Both were listed as working commands.
- `src/sparse.rs` -> `src/sparse/` (3 sites).
- `cargo test --test mmc mc_routes_linear_chain` names a test that does not
  exist -> `forward_reproducible`.
- Baseline cache key hashes BASELINE_ALGO_VERSION first; documented the
  headwater gauge filter and why it exists (513/3211 phantom zeros).
- Data-source table no longer marks netcdf/icechunk readers (TODO) —
  both are implemented.
- Added `kge` and `nse-batch` to the loss-kind list.
- `conus-hourly` is not `conus` plus one key; the groups target different hosts.
- Repointed `.claude/references/*` links at their `docs/` counterparts.
- Added a pointer to the two surviving skills.

README.md corrections:
- Same `--workflow eval` / `ddrs init` caveat.
- Workspace table was missing config.yaml, baseline/, plot/kan_parameters.nc,
  and the baselines cache; checkpoint contents now spelled out.
- Leakance formula was missing the losing-only clamp, which is ON by default,
  plus the impervious mask.
- Documented the disaggregation head (previously in no user-facing doc) and
  `experiment.loss.kind`.
- Documented `--backend cpu` and the six other `ddrs run` flags, and the
  `--workspace`-beside-config trap.

Co-Authored-By: Claude <noreply@anthropic.com>
The book was a 2026-06-08 snapshot. Everything landed since was invisible to
it: leakance, the precip disaggregation head, the nnse-kge/kge objectives,
`ddrs sources`/`import`/`status`/`gc`, managed adjacency, the global data
stores, and `--backend cpu`. Two documented entry-point commands hard-errored.

Fixed across 13 chapters, each claim re-verified against source:

Commands that did not work
- `ddrs init` (exits 2) removed from the getting-started path in setup.md and
  running.md; documented as a dead stub.
- `ddrs run --workflow eval` documented as unimplemented (`--from-run` does not
  exist); `train-and-test` and the legacy `eval` binary are the working paths.
- `cargo test --test sp8_gradcheck -- --ignored` ran zero tests and exited 0 —
  a gate that could not fail. Same for `--lib training::checkpoint` and
  `--lib data::store::zarr::tests::…`. `mc_routes_linear_chain` never existed.

Claims that were inverted or wrong
- outputs.md opened with "there is no global results directory"; everything
  lands under `.ddrs/runs/<id>/`. Rewritten around the real tree.
- setup.md claimed the CPU path needs no CUDA; burn-cuda and cudarc are
  non-optional, so a CPU-only reader fails at `cargo build`, not at runtime.
  Reframed as CPU *execution* via `--backend cpu`.
- Seven "MLP head" mentions in algorithm.md and intro.md violated invariant 5.
- algorithm.md called `p_spatial` an exponent; it is the coefficient.
- perf.md had the Rust defaults inverted (`Cpu`/`false`, not cuda/true),
  `PersistentScratch` at 33 handles (39 — a group of 6 backward handles was
  missing, understating memory ~18%), and a wrong K1 output list.
- `DDRS_FORCE_GRAPHS=1` does not exercise graph capture — it only selects the
  backend. Corrected in ddr-comparison.md and the dependent V9 claim in perf.md.
- baseline.md's cache key omitted the BASELINE_ALGO_VERSION salt and its gauge
  filter predated the headwater skip.
- burn-autograd.md knew two custom Backward ops; there are three (widths 2/5/8).
- inputs-formatting.md described `tau` as a substep count; it is the UTC→local
  trim-window phase offset and nothing in src/routing/ reads it.
- inputs-reading.md said five data sources; there are eleven store modules.
- architecture.md described a two-way timestep dispatch; it is three-way.

Coverage added
- The disaggregation head and leakance math, previously in no chapter.
- `experiment.loss`, `state_cache`, `kan_head.disaggregation`, the leakance
  params, and the four missing `parameter_ranges` keys.
- Managed adjacency in the reader chapters; the format-sniffing store enums.
- All `ddrs run`/`plan` flags, the global `--config`/`--workspace` pair and the
  workspace-beside-config trap, and the stale-binary trap.
- architecture.md's module map went from 9 of 15 top-level modules to all of
  them, with sub-tables for src/data/store/ and src/training/.
- nh-qprime-store-contract.md added to SUMMARY.md — README and CLAUDE.md both
  cite it, but it was not published.

Also caveated `nse-batch`/`adadelta` in CLAUDE.md and README.md: they arrive
with PR #31 and do not exist on master.

`mdbook build` is clean. Verified: zero MLP references outside the documented
`mlp:` serde alias, and every remaining `ddrs init` mention is in a
"this is dead" context.

Co-Authored-By: Claude <noreply@anthropic.com>
…9 claim

Two source-side defects surfaced by the documentation audit.

1. `src/cuda_graph/scratch.rs` module docstring (comment-only).
   Claimed "32 Handles total" and "All buffers are `[n × f32]`". Counted
   against the struct: 39 handles — 3 forward I/O, 6 static-input mirrors,
   1 pattern diag_mask, 23 saved-state, 1 backward input, 5 backward
   outputs. Two of them (`state_a_values`, `pattern_diag_mask`) are
   nnz-sized, not n-sized, so 37 are `[n_segments]`.

   The memory figures were understated ~18%: ~525 KB / ~44 MB become
   ~740 KB / ~51 MB, plus `2 × nnz × 4` bytes. An inline comment also said
   "24 saved-state outputs" where the group holds 23; it is now tied
   explicitly to `mmc_op::NUM_SAVED_STATE` so the two stay in lockstep.
   `docs/reference/perf.md` already carries the corrected numbers.

2. The V9 "graph vs no-graph bit-match: GREEN" verdict is retracted as
   UNVERIFIED in `.claude/ARCHITECTURE.md` and `docs/architecture.md`.

   The recorded evidence is `DDRS_FORCE_GRAPHS=1 compare_ddr_sandbox`, but
   that env var only selects the CUDA backend (and is read with `.is_ok()`,
   so `=0` triggers it too). Capture requires all three of
   `use_cuda_graphs && sparse_solver == Cuda && backend_is_cuda`
   (`src/routing/mmc.rs:289-294`); the sandbox builds from
   `Config::default()` (`src/sandbox.rs:88-89`) = `use_cuda_graphs: false`
   + `SparseSolver::Cpu`, and `fixtures/sandbox/config.csv` sets neither
   toggle — it carries only geometry, ranges, and dt. So the run exercised
   the CUDA backend with the CPU sparse solver and no capture.

   Corroborating: today's run reports max abs 1.525879e-5 m³/s, matching
   the 1.5e-5 in the historical V9 entry to the digit — that entry's run
   was this same CPU-solver path. The ABSOLUTE MATCH is real and still
   certifies the backend; it does not certify the property V9 names. The
   CUDA-graph capture path currently has no gate. Closing it needs a
   sandbox config that sets both toggles.

Tier C gate (comment-only src/ change, but run in full):
  cargo check --lib                          clean
  cargo test --lib                           243 passed, 0 failed
  cargo test                                 all binaries ok, 0 failed
  cargo run --release --example compare_ddr_sandbox
                                             ABSOLUTE MATCH, max abs 1.525879e-5 m³/s

Co-Authored-By: Claude <noreply@anthropic.com>
@taddyb
taddyb merged commit 8d8e328 into master Aug 1, 2026
2 checks passed
@taddyb
taddyb deleted the worktree-docs-audit branch August 1, 2026 02:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant