Repository navigation
Conversation
linhdmn
added this pull request to stack #38
October 5, 2026 00:36
…onents `assets/assistant-ui/dashboard.js` had no builder after 633c1e2 repointed `web/build.mjs` at `web/entry.tsx` and dropped its `outfile` line, while keeping the artefact for the standalone opt-in. The fold also moved the self-mount and the SSE transport out of `web/app.tsx` into the host-only entry, so nothing in the tree could build a working standalone bundle any more — and every component added since (`08f1cb5` metrics, `237ea70` proposals) lands in `web/app.tsx`, which is `client.js`'s input and not `dashboard.js`'s. Measured: the committed artefact served the loopback page mounting its thread, workspace tree and run list with `pane-metrics: 0` and `pane-proposals: 0`, against a snapshot carrying both. Same server, same snapshot, bundle built from today's `web/standalone.tsx`: both panes drawn. `web/standalone.tsx` mounts today's `DashboardApp` over the three endpoints the loopback server already serves, through the same `DashboardSource` seam the host entry uses, with React bundled rather than external — the opposite of the host entry, for the opposite reason (no other React on this page). `web/build.mjs` writes both artefacts from one shared esbuild literal, differing only in `external`, and `web/standalone.tsx` joins `SOURCE_INPUTS` so the staleness hash covers the loopback page: it was the half of the check that let the artefact drift for ten days without a word. Two checks, because either alone is a comment. `test/assistant-ui.test.ts` asserts the builder writes `dashboard.js` from that entry and that the hash covers it — CI, bare clone, no browser. `test/e2e-standalone-panes.mjs` drives the real `startDashboard` in real Chromium and asserts both panes appear once the server has something to show. Verified it fails on the old artefact: that bundle mounts the page and reports both panes absent. The e2e's metrics fixture asks `summarize()` for its own numbers rather than hand-writing them — a hand-built `MetricsSummary` threw `Cannot read properties of undefined (reading 'length')` in `MetricsPanel`, because `alerts` and each axis' `latest`/`samples` are required fields and a fixture remembering only the interesting ones produces a shape the server never emits.
The dead-export check flagged it, and it was right: the helper is used at the tool boundary below and nothing outside src/plugin.ts imports it, so the export was a surface with no user.
linhdmn
force-pushed
the
fix/standalone-restore
branch
from
October 5, 2026 03:52
c8e621f to
f74c554
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
The opt-in loopback page (
dashboard.standalone: true) served a component set frozen at 2026-09-23.Commit
633c1e2folded the dashboard into the DSH UI: it repointedweb/build.mjsatweb/entry.tsx, dropped theoutfile: …, 'dashboard.js'line, and moved the self-mount plus the SSE transport out ofweb/app.tsxinto the host-only entry — while keepingdashboard.jsinassets/, because the standalone opt-in was meant to keep working. After that fold no source in the tree could build a working standalone bundle. Every component added since (08f1cb5metrics,237ea70proposals) lands inweb/app.tsx, which isclient.js's input and notdashboard.js's.The page was not broken, which is why nothing failed: it mounted, rendered its approval thread, workspace tree and run list, and answered decisions. It had no MEASUREMENTS pane and no PROPOSALS pane — the point of watching a run on a loopback page with no harness UI beside it.
And
make dashboard-bundlecould not fix it, because the builder did not write that file at all.Measured, not reasoned
Same server, same snapshot (one carrying
metricsandrecommendations), two bundles, real Chromium:pane-metricspane-proposalsdashboard.js(2026-09-23)web/standalone.tsxThe staleness check missed it for the same structural reason:
web/standalone.tsxwas not an input of anything, because there was no such file. Run the builder and it does not touch the artefact; change the page and the hash does not move. Both halves are individually defensible and jointly invisible.The fix
web/standalone.tsx(135 lines) mounts today'sDashboardAppover the three endpoints the loopback server already serves —/api/events(SSE),/api/state,POST /api/approvals/:id— through the sameDashboardSourceseam the host entry uses. React is bundled here rather than external, which is the opposite of the host entry and for the opposite reason: there is no other React on this page.status()is deliberately absent, whichuseBriefsEnabledtreats as UNKNOWN and renders a failed brief rather than hiding it.web/build.mjswrites both artefacts from one shared esbuild literal, differing only inexternal.web/standalone.tsxjoinsSOURCE_INPUTS, so the staleness hash now covers the loopback page too.test/assistant-ui.test.tsasserts the builder writesdashboard.jsfrom that entry and that the hash covers it — CI, bare clone, no browser.test/e2e-standalone-panes.mjsdrives the realstartDashboardin real Chromium and asserts both panes appear once the server has something to show.The e2e was verified to fail on the old artefact: it mounts the page and reports both panes absent.
One finding inside the finding
A hand-written
MetricsSummarythrewCannot read properties of undefined (reading 'length')insideMetricsPanel:alerts, and each axis'latestandsamples, are required fields, and a fixture that remembers only the interesting ones produces a shape the server never emits. The test now askssummarize()for its own numbers from five invented records — shorter, and the only version that cannot drift from the real shape silently.Verified
make test— 726/726make check— green, all drift checks (52 KNOWN-ISSUES sections agreeing, actuator tables identical in 3 copies, no dead exports)make e2e-standalone-panes— mounted, both panes drawn, zero console/network errors.githooks/pre-commit --all— security scan okKNOWN-ISSUES §1cf records the defect, the reason the fold created it, and why both existing checks were blind to it.