Skip to content

Commit 6225f20

Browse files
committed
feat(v4-8): RewritersTab → extras.model_summary.rewriters_applied
Closes V4-8 / cppmega-mlx-ais. Closes G7 from V4 audit. Backend (_summarize_model): - model_summary.rewriters_applied = list of rewriter names from ctx.spec.rewriters. Surfaces what UI chained so e2e can assert. UI fix (App.tsx): - Real bug: onRewriterApply was never wired, so the conditional 'Apply chain' button (data-testid=rewriter-apply) never rendered even though RewritersTab supports it. Tests had no way to trigger a re-verify after chain mutation. Now wired to scheduleVerify(). E2E 22_rewriter_propagation.spec.ts: 3 parametrised scenarios for MTPRewriter / IFIMRewriter / MHCRewriter. Each adds the rewriter, verifies the chip appears, clicks Apply, runs Train, asserts the rewriter name appears in extras.model_summary.rewriters_applied. 3/3 green.
1 parent 3aba787 commit 6225f20

3 files changed

Lines changed: 52 additions & 0 deletions

File tree

cppmega_v4/runner/stages.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,10 @@ def _pget(node: Any, key: str, default: Any) -> Any:
696696
loss = getattr(spec, "loss", None)
697697
if loss is not None:
698698
loss_kind = getattr(loss, "kind", "cross_entropy")
699+
# V4-8: surface which rewriters the UI chained so e2e can assert
700+
# MTP/IFIM/MHC selection actually reached the backend spec.
701+
rewriters = getattr(spec, "rewriters", []) or []
702+
rewriters_applied = [getattr(r, "name", str(r)) for r in rewriters]
699703
return {
700704
"mlp_activation": _pget(mlp_node, "activation", "swiglu"),
701705
"attention_pre_norm": _pget(attn_node, "pre_norm", "none"),
@@ -705,6 +709,7 @@ def _pget(node: Any, key: str, default: Any) -> Any:
705709
"optimizer_kind": optimizer_kind,
706710
"schedule_kind": schedule_kind,
707711
"loss_kind": loss_kind,
712+
"rewriters_applied": rewriters_applied,
708713
"num_brick_kinds": len({n.kind for n in nodes}),
709714
}
710715

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// V4-8: RewritersTab chain reaches stage_train via spec.rewriters →
2+
// extras.model_summary.rewriters_applied. Closes G7 from V4 audit.
3+
4+
import { test, expect } from "@playwright/test";
5+
import { gotoApp, selectPreset, closeModal } from "../fixtures";
6+
import { readTrainExtras } from "../utils/train_extras";
7+
8+
const REWRITERS = ["MTPRewriter", "IFIMRewriter", "MHCRewriter"];
9+
10+
for (const rw of REWRITERS) {
11+
test(`V4-8: rewriter '${rw}' propagates to extras.model_summary`,
12+
async ({ page }) => {
13+
test.setTimeout(60_000);
14+
await gotoApp(page);
15+
await selectPreset(page, "llama3_8b");
16+
17+
await page.getByTestId("sidebar-tab-rewriters").click();
18+
await page.getByTestId("rewriters-tab").waitFor();
19+
await page.getByTestId(`rewriter-add-${rw}`).click();
20+
// Chip should appear
21+
await expect(page.getByTestId("rewriter-chip-0")).toContainText(rw);
22+
await page.getByTestId("rewriter-apply").click();
23+
24+
await page.getByTestId("run-pipeline-toggle").click();
25+
await page.getByTestId("run-pipeline-train").click();
26+
const modal = page.getByTestId("run-result-modal");
27+
await modal.waitFor({ timeout: 60_000 });
28+
const extras = await readTrainExtras(page);
29+
30+
// Top-level extras has the list (array DOM testid pattern)
31+
const rwListRoot = page.locator(
32+
"[data-testid^='run-result-extras-train-model_summary-rewriters_applied']");
33+
const count = await rwListRoot.count();
34+
// model_summary.rewriters_applied renders as nested object → dl entry
35+
// OR as array → ol. Either way the chosen rewriter name must appear.
36+
// Easier: assert top-level extras renders the array via the recursive
37+
// ExtrasEntry pattern (model_summary is an object → values rendered
38+
// as JSON.stringify when nested). Check via JSON parse of cell text.
39+
const msEntry = await page.getByTestId(
40+
"run-result-extras-train-model_summary-rewriters_applied").textContent();
41+
expect(msEntry).toContain(rw);
42+
expect(extras.losses.every(l => Number.isFinite(l))).toBe(true);
43+
44+
await closeModal(page);
45+
});
46+
}

vbgui/src/App.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ export function App(): JSX.Element {
400400
dispatch({ type: "rewriters.remove", index: i })}
401401
onRewriterReorder={(f, t) =>
402402
dispatch({ type: "rewriters.reorder", from: f, to: t })}
403+
onRewriterApply={() => void scheduleVerify()}
403404
onShardingChange={(s) =>
404405
dispatch({ type: "sharding.set", sharding: s })}
405406
onShardingAccept={handleShardingAccept}

0 commit comments

Comments
 (0)