Repository navigation
Hub: an Overview of every project, to see at a glance that each is moving - #223
Conversation
…ving A tab after the box's Terminal and before the projects, and the hub's landing page when the address names nothing else. A card per project: - whether it is building, moving, waiting on the owner, stalled, idle, parked or not answering; what needs a look sorts first - its kit release (amber when behind the newest kit on the machine), its Inbox (a click opens it), workers mid-ticket, and when the fleet last wrote anything - tickets merged of planned, as a bar - what needs attention: the box alert, questions with no default holding up work, open work with nothing moving for 2 h, workers silent over an hour, open incidents, a drain - twelve weeks of the fleet's daily activity, GitHub-style The data is a pulse in each project's hello, computed from the log in one pass; the hub and the gateway pass it through as they did the rest. A dashboard on an older kit has no pulse, and its card says to update. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T5z3hdiDu7TwHcW5jpP6do
A project is fully blocked when every open ticket waits on the owner: named in the --blocks of an open question with no default, or depending on one that is. Its card says "Fully blocked" in red and it sorts first, whatever else is running. Partly blocked is some of them: the card keeps what the project is doing (Building, Moving) and adds an amber "Partly blocked" beside it. Either way the progress bar shows the held tickets in amber after the merged ones, and the attention line says how many of how many wait on how many answers. The headline leads with fully blocked projects and counts partly blocked ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T5z3hdiDu7TwHcW5jpP6do
…every project - Each card names the approved goal first in priority, with its tickets merged of planned and how many other goals are open. A project with no approved goal says so. - Each card has Run, Drain and Park (Park asks to confirm), and the page has Park all (confirmed) and Resume all while any project is held. - The hub still posts no owner action. It asks the project's own dashboard, in its frame, by message; the dashboard posts the fleet action to its own origin, as a click there would. The dashboard takes the message only from its parent, and only when the parent is another origin, which frame-ancestors limits to the hub. Three ops, each once per nonce, and the answer goes back to that parent alone. The log's reason says it came from the hub's Overview. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T5z3hdiDu7TwHcW5jpP6do
The pulse asks whether each ticket has merged. Without the read cache that was two rev-parse spawns per unmerged ticket: 2.2 s for 200 open tickets, every 10 s, per project. With it, 0.18 s (0.20 s at 1000). Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T5z3hdiDu7TwHcW5jpP6do
…; a parked goal's tickets are not stalled Two wrong reads, both reproduced: - an approved goal with no tickets yet read "idle" (the card said "Waiting for a new goal"), however long nobody had planned it. It is open work: moving, then stalled. - one goal parked by the owner (Upkeep still running, so the fleet is not parked) read "moving", then a red "stalled" after 2 h. Its tickets wait by choice: they no longer count as work that could move, nor as what a question blocks; the card says they are on hold. Also: the goal named is a running one before a parked one; a question that holds no ticket (an incident, unplanned work) is counted apart from the ones that do; the hub's "Waiting on you" state, which nothing sent, is now sent for an unplanned goal held by a question with no default. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T5z3hdiDu7TwHcW5jpP6do
… under anything but the top page index.html is also the page at /view/. On a box the gateway lets the owner's wrapper on the public name frame a granted viewer, so there "a parent on another origin" is not only the hub. The wrapper runs no script today; the bridge no longer rests on that. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T5z3hdiDu7TwHcW5jpP6do
…ashboards left running unseen - The page is rebuilt on every press and every 10 s, and focus went with it: Park then Confirm park could not be done from the keyboard. Whatever had focus keeps it. - After a park that worked the card went on showing Run for up to 10 s (a hello's age), with Park enabled again. The card shows what its dashboard said it set until the hello agrees; the dashboard reads its hello again after every owner action. - Park all loaded every project's dashboard in a hidden frame and left it there, each reading /api/data every 10 s. A frame made only to ask is dropped when it answers. - A hello that isn't shaped like one (attention not a list) threw in the middle of the paint and took the whole Overview with it: now its own card says so. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T5z3hdiDu7TwHcW5jpP6do
…an't Park by keyboard, Park all, Resume all; then a dashboard's own page, the viewer under the hub, another local page and a dashboard in its own tab each ask and are not heard. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T5z3hdiDu7TwHcW5jpP6do
… fleet Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T5z3hdiDu7TwHcW5jpP6do
…lo sends Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T5z3hdiDu7TwHcW5jpP6do
hhff
left a comment
There was a problem hiding this comment.
Adversarial review of the Overview. 7 commits pushed on top (9af633a..e23a928), no force-push.
Confirmed and fixed
| sev | where | what | fix |
|---|---|---|---|
| high | devteam.mjs cmdHello / helloPulse |
two git rev-parse spawns per unmerged ticket on every hello. 200 open tickets: 2.2 s vs 0.14 s on main, every 10 s per project. the comment said "no git" |
9af633a turns on the read cache in cmdHello: 0.18 s at 200, 0.20 s at 1000 |
| high | helloPulse state |
an approved goal with no tickets read idle ("Waiting for a new goal") forever, even with nobody planning it |
0b99745: counts as open work, so moving then stalled |
| high | helloPulse state |
one goal parked by the owner (Upkeep still running, so fleet mode is run) read moving, then red stalled after 2 h |
0b99745: tickets under a parked or let-go goal are not work that can move or be blocked; card says they are on hold |
| med | index.html bridge | listener also installed at /view/. on a box the gateway adds the public-name wrapper as a frame ancestor of a granted viewer, so "a cross-origin parent is the hub" was false there. not exploitable today only because the wrapper has no script |
df58acc: not in the viewer, and only directly under the top page |
| med | hub.html paintOverview |
every press and every 10 s rebuilt the page and dropped focus. Park then Confirm park was impossible by keyboard | 53099b1: focus kept across repaints |
| med | hub.html setFleet |
after a park that worked, the card showed Run (Park enabled again) for up to 10 s | 53099b1: card shows what the dashboard said it set until hello agrees (30 s cap); dashboard re-reads hello after any owner action |
| med | hub.html frameFor |
Park all loaded every dashboard in a hidden frame and left it polling /api/data every 10 s |
53099b1: a frame made only to ask is dropped once it answers |
| low | hub.html overviewCard |
a hello with attention not a list threw mid-paint and blanked the whole Overview |
53099b1 per-card catch; e23a928 caps the mosaic |
| low | hub.html STATES.waiting |
state the kit never sent | 0b99745: sent for an unplanned goal held by a no-default question |
| low | README | still said the hub "takes no action" | 7cffe97 |
Also in 0b99745: goal pick prefers a running goal over a parked one; questions that hold no ticket (incident, unplanned work) counted apart.
Bridge checks that held: frame-ancestors as served ('self' + hub; gateway maps the hub port to the box name); a dashboard cannot frame another dashboard; same-origin parent, null origin, opener and top-level self-messages all refused; nonce replay only reachable by the parent; reply targetOrigin is the sender's origin; hub checks source window and origin of the reply. If earlier script throws the listener is never installed, which fails closed (hub says no answer after 20 s). Review pages and artifact frames are not index.html.
Left for the owner
- On a laptop, whatever serves 127.0.0.1:4320 can now run, drain or park every fleet with no click, if the owner opens it. Before this PR it could only frame dashboards. An agent that takes the port while the hub's dashboard restarts would qualify. Documented in the README; a real fix needs the dashboard to authenticate the hub.
- Default landing on a box is now Overview, not Terminal.
- Hub's 20 s timeout message blames an older kit even when the dashboard is just slow.
- Blocking follows
depends_ononly, not contract providers or superseded deps. - A project named
overvieworterminalcollides with those hashes. - "Working" counts tickets with a live phase, not tmux sessions.
Tests
test/hub-overview.test.mjs: 3 pass. New pulse test for both state bugs. New Chrome test: Park by keyboard, Park all, Resume all, then four askers that must not be heard (dashboard to itself, viewer under the hub, another local page, dashboard in its own tab) and the hub that must. Fails against the pre-fix index.html and hub.html.- dashboard
the hub|pages parse: 2 pass. bounds 3 pass. speed 8 pass. - gateway: 66 pass, 1 fail ("a preview that is down, ambiguous or unknown..."), same on main.
- fleet-park: 2 fail, same two on main (tmux in this sandbox).
Note: commits carry the session's own co-author trailer, not the one named in the task.
Generated by Claude Code
|
Re-reviewed at e23a928, which adds the Overview's Run, Drain and Park bridge:
On Node 24, merged with main, |
The hub gets an Overview tab, so you can see in one look that every project is still moving, even when you owe some of them answers. It sits after the box's Terminal and before the project tabs, and it's what the hub opens on unless the address names a tab (
#terminalor a project).A card per project
+means local changes.The headline reads "Everything is moving", "N fully blocked on you" or "N need a look", followed by how many projects are moving, how many are partly blocked, and how many answers you owe.
How the state is worked out (
helloPulse, from the log in one pass):--blocksof an open question with no default, or depends on one that is, however far down.Plumbing
hello, which the dashboard already serves to the hub. The hub and the cloud gateway pass it through unchanged, so there's no new endpoint and nothing new to authorize.Checked
test/hub-overview.test.mjswalks a project from idle to moving, then fully blocked (including a dependent ticket), then partly blocked, then building while still partly blocked.https://claude.ai/code/session_01T5z3hdiDu7TwHcW5jpP6do
Generated by Claude Code