feat: live architecture view in the dashboard - #47
Open
Robobc wants to merge 2 commits into
Open
Conversation
Adds an Architecture tab that draws the deployed platform from the same status.json the Monitor tab reads, and retires the Approach tab. The view is plain DOM + inline SVG with no dependencies, because the dashboard has to keep working over `python3 -m http.server` with no build step. Layout is deterministic (columns are layers, rows ordered by one barycentre pass), so the same status.json always draws the same picture and a narrated demo stays true. Three deliberate honesty constraints: - `state` is READ from monitor.py, never recomputed. monitor.py owns the one CloudFormation-status classifier; a second one in the UI was the bug the previous change removed. - A dashboard sees exactly ONE account. monitor.py now emits a `deployment` block (strategy, role, polled/platform/workload accounts) and the far side of a federated deployment is drawn "not observed" rather than given a guessed status. It is never counted as deployed or failed. - Observability is a per-card badge, not edges. TOPOLOGY keeps the real dependency (it mirrors app.py) and the filter lives at draw time, so the map and the picture disagree in one obvious place. Five lines converging on one card was the worst source of crossings. monitor.py also stops calling get_caller_identity() twice per poll and degrades to the full stack list when the contract cannot resolve a footprint, instead of blinding the dashboard. The Approach tab moves to dashboard/approach-tab.html — parked outside public/ so the static server cannot reach it, with instructions for putting it back. Monitor becomes the default tab. index.html drops 371 lines. Verified: - 33 headless assertions (DOM shim, real status.json + a federated fixture): every edge is a cubic bezier with no NaN, 5 edges survive the in-scope topology filter, out-of-scope stacks land in the tray and carry no edges, badges appear only on deployed stacks shipping to a deployed observability stack, the VPC box stays hidden until networking is deployed, a dragged card survives the next poll while an untouched one re-snaps, and the federated fixture yields two account boxes with one trust edge. - Fixed while testing: buildModel guarded status.json by truthiness only, so a malformed file with a string `stacks` passed the guard and Object.keys() walked its characters — one card per letter. The try/catch above could not help because nothing throws. Shape-checked now; mutating the guard back out makes the probe fail. - Live against the test rig (066523631817): reads 6 deployed + 4 out of scope, matching `deploy.sh verify`. - 155 tests pass; ruff clean on monitor.py.
The truthiness guard that let a string `stacks` through (one card per letter, and update()'s try/catch cannot catch it because nothing throws) now fails CI if it regresses. Mutating either check out makes it red.
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
Adds an Architecture tab that draws the deployed platform live, from the same
status.jsonthe Monitor tab already reads. Retires the Approach tab.Changes
dashboard/public/graph.js+graph.css(new) — the view. Plain DOM and inline SVG, zero dependencies, because the dashboard has to keep working overpython3 -m http.serverwith no build step. Layout is deterministic (columns are layers, rows ordered by a single barycentre pass), so the samestatus.jsonalways draws the same picture and a narrated demo stays true tomorrow. Drag a card and it stays where you drop it, including across polls; scroll to zoom, drag the background to pan.dashboard/monitor.py— emits adeploymentblock (strategy, role, polled/platform/workload accounts) so the view can be honest about multi-account deployments. Also stops callingsts:GetCallerIdentitytwice per poll, and degrades to the full stack list when the contract cannot resolve a footprint instead of blinding the dashboard.dashboard/public/index.html— Architecture tab wired in; Approach tab removed, Monitor is now the default. Drops 371 lines.dashboard/approach-tab.html(new) — the Approach tab, parked. Note it lives indashboard/, notdashboard/public/, so the static server cannot reach it. Header comment explains how to put it back.tests/test_dashboard.py— 7 tests pinning the view's invariants.Three deliberate constraints
stateis read, never recomputed.monitor.pyowns the one CloudFormation-status classifier. A second one in the browser was the exact bug #46 removed, so the view reads the emittedstateand degrades a missing one tonot-deployedrather than re-deriving it from the raw status string.A dashboard sees exactly one account. In a federated deployment the far side is not observable from here, so it is drawn
unobserved— dashed, no state colour — and never counted as deployed or failed. Guessing would be worse than admitting it.Observability is a per-card badge, not edges. Five stacks ship logs and traces to the observability stack; drawn as edges that is a fan-in straight through the middle of the picture and was the worst source of crossings.
TOPOLOGYkeeps the real dependency because it mirrorsapp.py, and the filter lives at draw time, so the map and the picture disagree in exactly one obvious place.Verified
status.jsonand a federated fixture: every edge is a cubic bezier with noNaN, five edges survive the in-scope topology filter, out-of-scope stacks land in the bottom tray and carry no edges, badges appear only on deployed stacks shipping to a deployed observability stack, the VPC box stays hidden until the networking stack is actually deployed, a dragged card survives the next poll while an untouched one re-snaps to its slot, and the federated fixture yields two account boxes with exactly one trust edge.buildModelguardedstatus.jsonby truthiness only, so a malformed file withstacksas a string passeds && s.stacksandObject.keys()then walked its characters — one card per letter. Thetry/catchabove it could not help, because nothing throws. Both blocks are shape-checked now, and the second commit pins it: mutating either check out turns CI red.deploy.sh verify.ruff checkandruff format --checkclean.Review notes
graph.jscarries long comments explaining the choices most likely to get "simplified" later — why DOM instead of<canvas>(a stack name is text: crisp at any zoom, selectable, reaches the accessibility tree), why there is no animation loop at all (every animation is CSS@keyframes, so idle CPU is zero andprefers-reduced-motionswitches the lot off in one block), and why the layout is one barycentre pass rather than full Sugiyama.