From a board showing 11 of 14 merged with member 31 in review/ and its
CI still running: the phase was advancing and every surface keyed to a
running agent said the board was idle. The tab title went back to the
plain project name, the live chip fell through to "you, working", and
the member the phase was waiting on wore "waiting on you" — which is
the opposite of true, since the phase merges it by itself on green.
The reading already exists client-side (phasesInFlight()), and the
snapshot already carries running/halted/stopped plus per-member states.
Nothing is missing but the question being asked, in three places that
answer it with runningAgents() instead.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Found on a board that was hosted by a shell that got killed: the phase
halted at the member whose agent went down with it, and no number of
presses of run phase could get past that member. What cleared it was
launching the member's work agent by hand and only then running the
phase, which is a two-step the board never mentions.
The runner already intends the opposite — _this_run() scopes the log so
that a new run may relaunch a member whose run died, and says so — but
_member_state() reads any existing branch as evidence the phase already
dealt with the card, and a run that died always leaves one. So the
intent is written down and unreachable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two small corrections found while checking 0.4-alpha's deploy.
wrangler.jsonc claimed the slashless form redirects with a 301; measured
against the live site it is a 307. The code is the host's choice rather
than anything this repo sets, so the post-deploy check now says to
confirm that it redirects at all — the property the site depends on —
and records the observed code beside it rather than asserting one.
Card 43 already describes the two test_boards_sync failures a team-mode
checkout sees, and still describes them correctly; only its pointer into
the test file had drifted — reload() sits at 598 now, not 481.
config.py:53-69 is still exact.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Runs 55 (the prompt says the run is one turn), then 54 (start_agent
refuses a phase card), then 46 (a board with no runnable commands says
so). No card depends on another; 55 is prompt-only and goes first, 54
and 46 both edit board.html so they run adjacent.
Also the first exercise of the Phases view: 56-59 landed after phase 53
finished, so hiding, the lane, the move refusal and the sweep have not
yet been watched on a live run.
complete_task works from the stem of the card it is completing, so a
finished phase leaves every member's worktree, local branch and remote
branch in place — measured on 53: three worktrees at 3.8M each and two
member branches still on origin. The sweep now removes them, with the
existing rule intact for a member that never merged: there is work in
that worktree, so it stays.
Today the runner merges each member into the phase branch as soon as CI
is green, which closes the member's PR and flattens the stack as it is
built: phase 53 handed back one +807 diff for two cards. Stop merging
during the run, chain each member's branch on the one before it, and let
the phase card sit on top. Carries one open question — how the stack
lands — which is a decision only the author can make.
56 takes phase members off the Board view (counts describe what is
visible; membership is the only thing hiding them, so done, archived or
an edited list gives them back). 57 draws them instead: a Phases view,
one swimlane per phase, the phase log under it, run-again where the halt
is. 58 refuses to move a phase card while a member has a live agent —
'hold the phase first' — and covers archive, which is the path that
would really have hurt. 59 sweeps merged members to done/ when the phase
merges, so an ending reads as an ending.
Card 47's agent ended its turn with 'the suite is still running; I'll
wait for the monitor', which in a one-shot claude -p run is the end of
the run — 314 lines of finished, passing work staged and never
committed. The prompt never states that the run is a single turn or that
uncommitted work dies with it.
/api/phase/run guards itself (phases._phase_card refuses a non-phase);
/api/agent/start has no phase check at all, so a stale tab launched an
ordinary work agent on card 53 and it implemented both members itself.
The gate that was missing is on the older feature — the usual shape:
a new capability guards its own front door and leaves the neighbour's
open.
Runs 52 (scroll position survives a redraw) then 47 (an archive chip on
the card). Neither depends on the other, so neither carries a Depends on
line — they are phased because they both edit board.html, and two agents
branched from main would collide in it. Sequencing gives the second one
the first one's work as its branch point.
renderBoard() wipes #board and rebuilds every column, so each .drop is a
new node with scrollTop 0 — and render() runs on every SSE frame, so the
board resets under you continuously while agents work. The log already
solves this for itself with S.logStick; the columns never got it.
A phase is a card with Type: Phase and a ## Cards section listing its
members in run order; members carry Depends on, which guards rather than
orders. It runs on its own branch, each member branched from the phase
tip so card two sees card one's work, merged back on green, one PR into
main at the end — the human gate moves from every card to the phase
boundary, and 'the board never merges' stays true of main.
The card warned that archiving does not commit and suggested sequencing
behind card 44. That landed before 0.3-alpha: archive_task goes out
through _relocate, attributed and committed under the same gate a move
is. Nothing blocks 47.
The tray works but the gesture is a drag across the whole board. Puts
the same glyph on the card's footer row, on backlog/to-do/done only,
arming on the first click as the other two-step actions do.
The landing page was carrying two large visuals stacked — a full
terminal in the hero and the board beneath it — which is what made it
read as busy. Now the hero is one third words and two thirds board: the
claim this page makes is a board, so the board is what it shows first
and shows large.
The terminal moves into a 50/50 section below, beside the copy that
explains what installing costs: one script, port 26071, two questions,
and the settings file it writes. The six doors are unchanged.
Smaller changes that follow from it: the headline takes a narrower step
(--t-hero-narrow, 40px) because it no longer has half a row; it loses
its hard <br> and wraps on its own; the CTA drops the time claim now
that a whole section makes it; and the caption under the shot becomes
one plain line rather than a tagged row.
The Sessions list shows agent names only for runs this board process
launched; anything replayed from disk loses its agent id and falls
through to the You branch of session_label(). Diagnosis and evidence in
the card.
11 and 15 were archived through the board, which renames the file and
stops there — the deletion from done/ and the new file in archive/ never
reached git, and the uncommitted deletion is what sync refuses to run
over. 36 carries an appended agent report, uncommitted for the same
reason. Card 44 writes both up.
The host uploads the assets directory whole, so a .md left in static/
becomes a public url — static/fonts/README.md was live, telling readers
how to refresh fonts they cannot write to. copy_static skips it, and
internal_targets skips it too: the link checker and the copier have to
agree, or a link to a skipped file would pass the build and 404 on the
site. The licences are .txt and still ship, which is the point of
committing them.
Card 43 records the other thing today's run turned up: the suite reads
the developer's own local/.env, so two sync tests fail here and pass in
CI.
37 sync resolves its remote like github.py does, and says so when it
cannot; 38 a card being merged wears the state and holds still; 39 the
tab says whether agents are working; 42 a long closing report keeps its
headline instead of its tail. 40 (the open-questions launch gate) is
archived, unmoved by the board and so never committed by one.
Both from the first downstream 0.2 update report: the vendored diff
left as homework in a clean-main workflow, and the TIME_WAIT port hop
that rewrote an explicit BOARD_PORT pin.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>