Skip to content

Commit faeab31

Browse files
committed
docs(audit): UI→API→Training end-to-end audit + closure spec
8 parallel Explore-agent audit comparing promised behaviour from VisualBuilderPlan/Spec/Raschka gallery promise against shipped code. 5 production-blocking gaps: 1. DataInspector text-input only (no file picker) 2. FlowCanvas isValidConnection accepted but App never passes it 3. No checkpoint history UI / ledger RPC 4. 5 Raschka gallery presets unwired (bricks exist) 5. smoke_zero1 CLI documented but unimplemented 3 medium-debt UX gaps + 2 test-coverage gaps documented. Clean lanes: Tokenizer (Lane 3 100%) and Optimizer/Schedule (Lane 7 100%) — both ready to ship as-is. Produced: - docs/UI-TO-TRAIN-AUDIT-2026-05-23.md (audit report) - docs/UI-TO-TRAIN-CLOSURE-SPEC.md (design + acceptance criteria) - 8 bd epics E-AUDIT-01..08 covering all gaps (P0/P1/P2/P3)
1 parent 29a58e8 commit faeab31

2 files changed

Lines changed: 386 additions & 0 deletions

File tree

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# UI → API → Training End-to-End Audit
2+
**Date**: 2026-05-23 14:45 GMT+2
3+
**Scope**: Honest comparison of promised-vs-shipped across 8 vertical lanes of the Visual Builder GUI.
4+
**Method**: 8 parallel `Explore` agents, each ≤80-line report mapping docs/specs/designs to actual code + test status.
5+
6+
## Executive summary
7+
8+
The system delivers the **core promise** end-to-end: a user can build a model from bricks, configure it, run training, and see loss. But there are **5 concrete production gaps** that block the full promise from the user description:
9+
10+
| # | Gap | Severity | Lane |
11+
|---|---|---|---|
12+
| 1 | **No real file upload** — DataInspector is text-input only, no `<input type="file">` | 🔴 BLOCKING | 4 |
13+
| 2 | **No edge validation** — FlowCanvas accepts `isValidConnection` prop but App never passes it; edges fail silently at verify | 🔴 BLOCKING | 2 |
14+
| 3 | **No checkpoint history UI** — no `ckpt.list` RPC, no picker widget; resumes require copy-paste paths | 🟡 HIGH | 6 |
15+
| 4 | **5 Raschka gallery presets unwired** — GPT-2 XL, Tiny Aya, xLSTM, Gemma 4 E2B/E4B (bricks exist, factories don't) | 🟡 HIGH | 1 |
16+
| 5 | **smoke_zero1 CLI missing** — documented but unimplemented; multi-Mac training is loopback-only | 🟡 HIGH | 8 |
17+
18+
Plus **3 medium-debt UX gaps**:
19+
20+
| # | Gap | Lane |
21+
|---|---|---|
22+
| 6 | B and S not exposed as train controls (embedded in preset) | 5 |
23+
| 7 | `loss_scaler.overflow_steps` nesting mismatch between backend (nested) and UI (`loss_scaler_overflows` flat) | 5 |
24+
| 8 | Compress/strict toggles missing from UI (backend supports `compress`, `ckpt_strict`, `opt_state_strict`) | 6 |
25+
26+
And **2 test-coverage gaps** (functionality works, regression doesn't pin it):
27+
28+
| # | Gap | Lane |
29+
|---|---|---|
30+
| 9 | E2E `readTrainExtras` only reads 7/16 promised extras keys | 5 |
31+
| 10 | No e2e test for manual edge connection (only drag-drop bricks) or adapter-chain UI | 2 |
32+
33+
**Lane 3 (Tokenizer)** and **Lane 7 (Optimizer)** are clean — no production gaps; tokenizer mutation is out-of-scope by design.
34+
35+
---
36+
37+
## Lane-by-lane summary (compressed)
38+
39+
### Lane 1 — Gallery coverage: **93% (66/71)**
40+
- 57 presets in `cppmega_v4/architectures/`, 57 in UI PRESETS array (dynamic via `architectures.list_presets` RPC).
41+
- 25 brick kinds in BLOCK_BUILDERS, 25+6 adapters draggable from `Palette.tsx`.
42+
- Tests: `tests/v4/test_galcov_stage_d.py` 203 passed, 15 xfail (locked gaps).
43+
- **Gap**: 5 Raschka entries lack preset factories:
44+
- #1 GPT-2 XL → needs `abs_pos_embed` preset
45+
- #44 Tiny Aya → `tiny_aya_parallel_specs()` exists but not in PRESETS dict
46+
- #50 xLSTM 7B → needs `mlstm` preset
47+
- #57 Gemma 4 E2B, #58 E4B → needs `per_layer_embed` preset
48+
- Bricks already exist for all five; only `presets.py` factory wiring missing.
49+
50+
### Lane 2 — Canvas drag/drop/connect/configure: **85%**
51+
- 428 vitest tests passing (drag, connect, dim_env, undo/redo, verify-on-edit).
52+
- E2E: `08_manual_drag_drop.spec.ts` (26 bricks) + `09_e2e_manual.spec.ts` (8 cross-product scenarios).
53+
- **Critical gap**: `FlowCanvas` accepts `isValidConnection?: IsValidConnection` (line 20) but `App.tsx:1215` never passes it. Edges silently fail shape contracts.
54+
- **Coverage gap**: no e2e exercises manual edge connection or `GotchasTab` suggest_adapters UI.
55+
56+
### Lane 3 — Tokenizer: **100% of in-scope promise**
57+
- 12 tokenizer presets (cppmega_v3, nanochat, gpt-4o, gpt-3.5, gpt-2, llama-3, mistral, gemma, qwen, deepseek, phi-3, claude).
58+
- Byte-exact roundtrip verified vs gb10 reference (`test_decode_parity_with_gb10_reference_receipt` PASS).
59+
- 3-panel playground compare, FIM/SPACE/NL special-id contract exposed.
60+
- 42/42 tests green.
61+
- **Out-of-scope**: vocab editing (read-only by design; user "modify tokenizer" expectation = preset switch, which works).
62+
63+
### Lane 4 — Data pipeline: **60% — CRITICAL GAP**
64+
- Backend complete: `data.preview_parquet`, `data.roundtrip_check`, glob/dir/manifest support, corpus_stats sidecar, real-token train consumption (parquet_path → data_source="parquet_tokenized").
65+
- 16 vitest tests passing.
66+
- E2E `18_real_data_convergence.spec.ts`: parquet + tokenizer + loss decay verified.
67+
- **Critical gap**: DataInspector path field is plain `<input type="text">` (`DataInspector.tsx:194-198`). No file picker, no upload widget. User cannot point at arbitrary local parquet — only fixture paths.
68+
- Secondary: no tokenizer compatibility check at preview time (only at train time → silent late failure).
69+
70+
### Lane 5 — Training loop UI: **88% — 14/16 extras keys surface**
71+
- All 16 promised train-extras keys surface in TrainExtrasOverlay (losses, losses_smoothed, val_losses, lr_trajectory, perplexity, bpb, dtype_state, fp8, fim, sharding, side_channels, per_brick_grad_norms, MoE 9-key, optimizer_kind, gradient_reduce_ms, weight_delta_norm).
72+
- All 10 promised train UI controls present except B and S (embedded in preset, not independent inputs).
73+
- 75 pytest stage_train tests pass.
74+
- **Gap 1**: B and S not exposed as train controls (workaround: spec edit pre-train).
75+
- **Gap 2**: `loss_scaler.overflow_steps` nesting mismatch (`stages.py:2245` nests under `loss_scaler` dict, UI expects flat `extras.loss_scaler_overflows`). Silent: overflow markers don't render.
76+
- **Gap 3**: Plasticity/MTP/IFIM/MHC extras flow through generic extras but no styled panel.
77+
- **Coverage gap**: `e2e/utils/train_extras.ts` only reads 7/16 keys.
78+
79+
### Lane 6 — Checkpoint management: **85%**
80+
- Backend complete: save/load, opt-state sidecar (just landed `05dcde8`), arch-hash validation, compression (none/int8/fp16/opt-fp16/both), sharded save/load, streaming load (peak RSS bound), backward compat (single-file + sharded + directory).
81+
- 40+ test files pass. M0.7 resumable round-trip PASS.
82+
- TopBar shows ckpt metadata (arch_hash, opt_kind, global_step) via debounced `ckpt.inspect` RPC.
83+
- **Gap 1**: No `ckpt.list_history` RPC, no UI picker dropdown — resumes need copy-paste.
84+
- **Gap 2**: Compression dropdown / `ckpt_strict` / `opt_state_strict` not surfaced in UI.
85+
- **Gap 3**: V7-H05 live mid-run checkpoint button wired in `TrainLiveControls`; backend WS queue not implemented (`onScheduleCheckpoint` callback fires but is no-op).
86+
- **Gap 4**: No peak-RSS regression test at real >1 GB scale.
87+
88+
### Lane 7 — Optimizer + Schedule: **100% — ready to ship**
89+
- 7 OptimKinds wired (AdamW, Muon, Lion, Lion8bit, Adam8bit, muon_adamw_hybrid, SGD) — all in `OPTIM_BUILTINS` + `OptimTab` KINDS array.
90+
- 6 ScheduleKinds wired (constant, linear_warmup, cosine, wsd, inv_sqrt, polynomial) — catalog'd with paper refs.
91+
- 7 ParamGroup matchers + regex:* wildcard.
92+
- `suggest_optim_groups` RPC + `AutoGroupButton` proven across 6 family presets.
93+
- 45/45 tests pass.
94+
- Sophia/Adafactor/Tiger/AdEMAMix explicitly deferred (P3 optional per E2E v2).
95+
96+
### Lane 8 — Distributed training: **75% — local sim done, multi-Mac stubbed**
97+
- 8 device kinds (h100_80gb, h200_141gb, a100_40gb/80gb, b100_80gb, gb10, tpu_v5p/v6e, m3_ultra).
98+
- 5 sharding factories + auto_shard 3-5 ranked proposals.
99+
- 17 gotcha rules (15 promised, +2 bonus: incompatible_comm_backend, slow_loopback_ring).
100+
- Full memory accounting (FP8/bf16/fp32 duplication, master fp32, FSDP peak, TP boundary).
101+
- ShardingTab UI with proposals + axis editor.
102+
- `fake_ranks` smoke + `gradient_reduce_ms` ✅.
103+
- ZeRO-1 wrapper using real `mx.distributed.all_sum`/`all_gather`.
104+
- 126 parallelism tests pass.
105+
- **Gap 1**: `smoke_zero1` CLI documented but unimplemented (`docs/distributed_zero1_smoke_procedure.md:170`).
106+
- **Gap 2**: Multi-mac launcher manual; no orchestration playbook (`docs/multimac_training.md` Phase 2 deferred to Stream F).
107+
- **Gap 3**: Loopback receipt only — no real cross-Mac ZeRO-1 receipt (peer-48 hardware not connected, external blocker).
108+
109+
---
110+
111+
## What this means
112+
113+
The **happy path works**:
114+
1. ✅ Drag a preset → 57/71 architectures (93%) auto-build
115+
2. ✅ Drag individual bricks → 25 kinds + 6 adapters draggable
116+
3. ✅ Connect them → React Flow edge creation works
117+
4. ✅ Configure params → BrickContextPanel + DimEnvEditor + verify-on-edit
118+
5.**Upload arbitrary parquet** — must copy paths into text field
119+
6. ✅ Preview parquet → DataInspector + channel filter + roundtrip badges
120+
7. ✅ Pick tokenizer → 12 presets, 3-panel compare, byte-exact roundtrip
121+
8. ✅ Train N steps → loss chart + 14/16 extras + abort + live LR
122+
9.**Resume from arbitrary checkpoint** — must copy paths into text field, no history list
123+
10. ✅ Pick optimizer + schedule → 7 + 6 wired with auto-group
124+
11. ⚠️ **Manage distributed training** — single-Mac + fake_ranks works, real multi-Mac is stubbed
125+
126+
The honest assessment: **the system is a working dev tool, not yet a polished operator UI**. Closing gaps 1–5 (file upload, edge validation, ckpt history, 5 missing presets, smoke_zero1) flips it to fully-promised behaviour.
127+
128+
---
129+
130+
## Recommended bd epics (8 epics, ~24 sub-tickets)
131+
132+
```
133+
E-AUDIT-01 [P0] Lane 4 — DataInspector file picker (BLOCKING)
134+
├─ 01.1 add <input type="file"> + onChange → FileReader → POST /upload
135+
├─ 01.2 backend tmp-file persistence + path return
136+
└─ 01.3 e2e: pick local fixture, verify preview renders
137+
138+
E-AUDIT-02 [P0] Lane 2 — Edge validation (BLOCKING)
139+
├─ 02.1 thread isValidConnection from App.tsx into FlowCanvas
140+
├─ 02.2 use shape_contract.is_compatible(src, dst) as the check
141+
└─ 02.3 e2e: drop incompatible bricks, attempt connect, assert rejected
142+
143+
E-AUDIT-03 [P1] Lane 6 — Checkpoint history UI
144+
├─ 03.1 ckpt.list_history RPC (scan dir, return [{path, mtime, arch_hash, step}])
145+
├─ 03.2 CheckpointHistoryDropdown component in TopBar
146+
├─ 03.3 compress dropdown + ckpt_strict + opt_state_strict checkboxes
147+
└─ 03.4 V7-H05 live mid-run checkpoint WS queue
148+
149+
E-AUDIT-04 [P1] Lane 1 — Close 5 gallery gaps
150+
├─ 04.1 abs_pos_embed preset (GPT-2 XL)
151+
├─ 04.2 tiny_aya_parallel wired into PRESETS dict
152+
├─ 04.3 mlstm preset (xLSTM 7B)
153+
└─ 04.4 per_layer_embed preset (Gemma 4 E2B + E4B)
154+
155+
E-AUDIT-05 [P1] Lane 8 — smoke_zero1 CLI
156+
├─ 05.1 cppmega_mlx.cli.smoke_zero1 entrypoint
157+
├─ 05.2 multi-mac launcher script (mlx.launch wrapper)
158+
└─ 05.3 loopback receipt regression test
159+
160+
E-AUDIT-06 [P2] Lane 5 — Train UI polish
161+
├─ 06.1 expose B + S as TrainOptionsPanel controls
162+
├─ 06.2 fix loss_scaler_overflows nesting in stages.py:2245
163+
└─ 06.3 Plasticity/MTP/IFIM/MHC extras panels in TrainExtrasOverlay
164+
165+
E-AUDIT-07 [P2] Lane 5+2 — E2E coverage gaps
166+
├─ 07.1 extend readTrainExtras to all 16 keys + e2e asserts
167+
├─ 07.2 e2e for manual ReactFlow edge connect
168+
└─ 07.3 e2e for GotchasTab suggest_adapters panel
169+
170+
E-AUDIT-08 [P3] Lane 4+6 — Late warnings
171+
├─ 08.1 tokenizer compatibility check at preview_parquet time
172+
├─ 08.2 peak-RSS regression at >1GB checkpoint
173+
└─ 08.3 multi-node throughput receipt (BLOCKED on peer-48 hardware)
174+
```
175+
176+
Total: 8 epics, 24 sub-tickets, ~3-5 dev-days each (except 08.3 external blocker).

0 commit comments

Comments
 (0)