Repository navigation
Description
Redesign slice: Insights by model, plus Work view fixes (operator request, 2026-10-27)
The operator found Insights hard to read and navigate, and missing the insight they want most: how each LLM performs. Rebuild the Insights view in the approved forest-glass style (tokens and rules in docs/design/ui/redesign-2026-10-26/README.md) and fix the Work view problems in the same slice.
Insights, top to bottom:
-
Summary row of 4 stat tiles: reported cost this week and in total (with coverage, e.g. "reported for 293 of 475 attempts"), Molecules finished, median time to draft PR, and first-try green rate (checks passed on the first coding attempt).
-
By model (the main section): a table with one row per effective model × Atom role (analysis, coding, review, meta). Columns:
- attempts;
- Molecules;
- reported cost (total and median per attempt, with coverage);
- tokens in, out and cache-read;
- median wall-clock per attempt;
- outcome: for coding, the share whose checks passed on that attempt; for review, findings raised.
Sortable, with sort state in the URL (
?view=insights&sort=…). Every value comes only from this Lab's ledgers (the per-attempt usage lines already recorded); a missing value shows "not reported", never zero. -
Over time: a small weekly chart of reported cost and of Molecules finished, stacked by model. Built from inline SVG, no chart library, with a text table fallback for screen readers.
-
Where time goes: Active Atom time versus waiting for you versus waiting on checks, as one bar with labelled segments.
-
Cost per merged PR and Formula suggestions stay "Unavailable" with their current reasons, but drop to a small "Not yet available" footer instead of taking two large cards.
Readable values (fixes for what the operator saw):
- Money via
Intl.NumberFormat, 2 decimals, never round a nonzero amount to $0 (today it shows$560.197838). - Durations: hours and minutes only ("303 h 28 min"),
tabular-nums. - Definition lists aren't indented as nested blocks; label and value sit on one line in a two-column grid that reflows at 400 px.
Work view fixes:
- The lane filter bar clips its first chip on the left ("g 1" instead of "Running 1"). It must wrap or scroll inside itself with a visible start, never clip.
- A filtered grid with 1 tile leaves a huge empty panel. The grid sizes to its content, with a short empty-state line when there's nothing to show.
- "Earlier Molecules / Recent Molecules" axis labels align with the grid they describe.
Done when
- Tests (ui, deterministic, fixture Lab with several models and roles):
- the by-model rows aggregate correctly;
- missing cost stays "not reported" and coverage counts are right;
- sort is stable and in the URL;
- money formatting has no float noise;
- the chart has a text fallback;
- the lane bar never clips (a CSS contract test).
- Visual check: the operator checks Insights and Work at desktop and 400 px.
- Targeted checks:
go test ./internal/ui/....
UX rules for every redesign slice (from the 2026-10-26 UI review)
- Follow the approved mockup in
docs/design/ui/redesign-2026-10-26/(its README lists the tokens and rules), with the assets inlab/internal/ui/web/assets/. Reuse the.btnprimary, secondary and danger system and the glass panel from UI polish: composed Start Work controls, segmented lane bar, sharper glass (visual only) #241. - One primary action per card or row. Destructive actions (Retire, Stop Molecule, Stop loop) sit behind a disclosure and a confirmation that names the Molecule or loop. Never place them next to a primary action.
- State in the URL: view, selected Molecule, filter and search (for example
?view=inbox,?m=<id>,?filter=…&q=…) viahistory.pushState, so Back, reload and copied links work. Navigation uses real<a href>. - Forms: real
<form>s, so Enter submits. Inputs carryname,autocomplete="off"and an example placeholder ending in "…". A submit button stays enabled until the request starts, then shows progress. Errors appear inline, linked witharia-describedby, and focus moves to them. - No rebuild under the user: polling patches the DOM in place, keyed by id. Never rebuild a block that has focus or an input being typed in. Keep one persistent
aria-liveregion and update its text only when it changes. - Readable values:
- dates via
Intl.DateTimeFormatplus relative time; - money via
Intl.NumberFormat(one precision rule; small amounts never round to $0); - counts via
Intl.PluralRules; tabular-numsfor numbers;- never raw phase codes,
assay-…ormol-…ids, full digests or ISO timestamps in the main UI (short forms only, behind "details" with a copy button).
- dates via
- Plain language, second person, Title Case buttons: "Plan ready for your approval", "Coding · 18 min", "Ready to publish". Keep the primitives true: Lab, Molecule, Atom and Formula keep their names and meanings.
- Accessibility and touch:
- a skip link;
- one
<main>; - ordered headings;
- visible
:focus-visibleeverywhere; - targets at least 44 px on coarse pointers;
touch-action: manipulation;- reduced motion and forced colors honoured;
- no horizontal page scroll at 400 px.
Review checklist (read before coding)
The adversarial review checks these every time. Recent slices failed review on all of them, so build them in from the start:
- Bounds: sizes, counts, time and total work are bounded, and hitting a bound fails safe (incomplete or truncated, never silently accepted).
- Filesystem safety: paths cannot traverse. Use
LstatandO_NOFOLLOW, and check symlinks and ownership. Watch for TOCTOU races on shared dirs (/tmp). Only ever delete Forgecell-owned, marked paths. - Untrusted input: issue text, repository files, model and tool output, and ledgers can be malformed, huge or hostile. Validate them, never interpolate them into HTML or a shell, and never let them trigger retries or approvals.
- No local leaks: no absolute local paths, environment variables or credentials in output, logs, the UI or ledgers.
- Contract changes: a changed adapter invocation bumps the protocol, and approved digests still bind exactly what was shown.
- Tests: deterministic. Use no wall-clock budgets (use readiness markers or seams), write nothing into the user's real temp or home, and cover the failure path as well as the happy path.
Plan checks (for intake)
Check category must be one of regression, candidate or setup. Use targeted package tests only as plain go test commands (for example go test ./internal/<pkg>/...); the protected view adds -json itself when protected deltas are declared. The Formula baseline already runs the full suite once, so don't add another full go test ./... check, and don't repeat its go vet or gofmt checks. A plan may hold at most 16 checks in total, counting the 5 Formula baseline checks, so prefer one combined targeted command over one check per package.
Added 2026-10-27 (from #155)
-
Planning effort: in the by-model table and the summary, show clarifying questions per Molecule and planning (analysis) cost, from the ledgers.
-
Keep base tests compiling (added 2026-10-27): the protected view runs the base
_test.gofiles against your code. Never change the signature of an existing Go function, method or type that a base test file calls. Add a new one instead. A protected build failure cannot be declared as an expected delta. -
After UI foundation: split app.js/style.css into per-view modules (no behaviour change) so v1 UI slices run in parallel #262: this slice owns its own
web/js/<view>.jsmodule(s) andweb/css/<view>.css. Don't edit other views' modules; shared helpers go incore*.js.
Plan checks for this slice (2026-10-27)
- The operator's visual or browser check is a manual step after delivery, not a plan check. Don't add a check for it.
- Every plan check:
category: regressionorcandidate, withreviewedAcceptanceandindependentProvenanceleft empty. The analysis must never assert independent acceptance. - Use one combined targeted
go testcheck for the packages this slice changes.
Activity
DanielNetzer commentedon Oct 27, 2026
Added from #155: show clarifying questions per Molecule (and planning cost) in Insights, by model.
feat(ui): Insights by model — cost, tokens, time, first-try green per…
DanielNetzer commentedon Oct 27, 2026
Merged via #276.