|
| 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