Repository navigation
Show a document's people why its Planner cannot start on a machine - #773
Merged
Merged
Conversation
A connector starts a document's Planner backend and starts it again whenever it exits early. When the backend could not start, for example because it refused its checkout, the reason reached only the connector's own log on that machine, and the document showed "Planner: starting" for as long as the loop went on. Its members, who are often not the machine's owner, had nothing to read. The connector now counts the launches in a row that exited before staying up and, after each one, posts to /api/connector/planner/failure: the document (by id, which the Planner credential names), how many times, how the backend ended and why. The reason is the last line it wrote to stderr that says why, so a closing "Exiting with code 1" notice never stands in for it, without terminal colors or a leading time, with credentials masked as for everything else the connector prints, the home directory shortened to ~ and cut to 300 characters. When a launch stays up for the healthy interval the connector tells Chopin that nothing is failing any more. It is a new route, not a protocol bump, because the server refuses a connector whose protocol is newer than its own. A server that does not know the route answers 404, which the connector takes to mean it never will and stops asking for that document, and a server that has the route ignores a connector that never calls it. Reporting never waits on the restart loop and is cut off after ten seconds. docs/chopin-cli.md says what people in the document then read. Assistant-model: Claude Opus 5.5 Assistant-workflow: inline Assistant-verification: GIT_CONFIG_GLOBAL=/dev/null bun test in apps/connector passed: 271 pass, 14 skip, 0 fail before the final edits, and src/planner.test.ts 20 pass, 0 fail after them Assistant-verification: mutation check passed: with the unsupported-server flag disabled the 404 test fails (3 reports instead of 1) and passes with it Assistant-verification: bun run ci and bun run types passed Co-authored-by: Alex Lavaee <lavaman131@github.com>
A machine's connector starts a document's Planner backend and starts it again whenever it exits early. Until now Chat said "Planner: starting on <machine>…" for as long as that went on, and the reason was only in the connector's log on that machine. The server takes the connector's report at POST /api/connector/planner/failure, only for a document it asked that machine to run (the connector names it by id, or by address, which is read with the machine's own token), and keeps the latest per document and machine in memory, as it keeps the rest of the Planner's attachment state. It is forgotten when the Planner attaches, when the connector says a launch stayed up, when the machine is no longer asked for the document (chosen elsewhere, disconnected or no longer shared) and with a restart. The reason is stripped of colors and control characters and kept to one line of at most 300 characters; the time is the server's own, not the connector's clock. From the second launch in a row, the "starting" state sent to the room carries the failure: how many launches, why, and when the last one exited. A single failure is a transient one and still just says starting. An @chopin request sent meanwhile is told why instead of "try again in a moment". Only the login is still named, never the machine. The report is a new route, not a connector protocol bump, so a server that does not know it simply answers 404 and a connector that never reports works as before. docs/agent-connection.md and docs/hosted-agent.md describe it. Assistant-model: Claude Opus 5.5 Assistant-workflow: inline Assistant-verification: GIT_CONFIG_GLOBAL=/dev/null bun test in apps/server passed: 3966 pass, 6 skip, 0 fail before the final edits, and src/harness/remote 118 pass, 0 fail after them Assistant-verification: red-before-green passed: the new planner-dispatch tests failed on the unchanged server (404, no machineId) and caught a crash on a report without a reason Assistant-verification: bun run ci and bun run types passed Co-authored-by: Alex Lavaee <lavaman131@github.com>
The line under the composer that says "Planner: starting on studio…" now says what is wrong once the machine's backend has failed to start more than once in a row. It is still the starting state, so data-planner-state stays "starting" and the line is still a polite status, but the dot turns red and the line has three: "Planner: can’t start on studio" in the danger colour, why in the ordinary secondary ink, and "Tried 3 times in a row, last at 06:29 PM. Still trying." in the quietest. The words keep the "Planner:" prefix every other state has. Everyone in the document reads it: the machine's owner sees their machine's name and a teammate sees "@mona’s machine", as before. The reason is text, never markup, and wraps, so on a phone the dot stays with the first line. The end-to-end test runs a real remote-Planner server with a fake connector: one failed launch changes nothing, the second says why to the owner and to a teammate with the document open, a teammate's @chopin message is told why instead of to try again in a moment, and the line goes once the Planner attaches. A second test checks it under the composer on a phone. Assistant-model: Claude Opus 5.5 Assistant-workflow: inline Assistant-verification: GIT_CONFIG_GLOBAL=/dev/null bun test in apps/web/src/chat passed: 227 pass, 0 fail Assistant-verification: GIT_CONFIG_GLOBAL=/dev/null bun run e2e e2e/planner-picker.e2e.ts passed: 8 passed, including the two new tests Assistant-verification: screenshots passed: looked at the owner, teammate and phone captures in /tmp/chopin-shots-planner-failure Assistant-verification: bun run ci passed, including the design contract and the impeccable check (no new findings), and bun run types passed Co-authored-by: Alex Lavaee <lavaman131@github.com>
lavaman131
force-pushed
the
planner-start-failure
branch
from
November 4, 2026 08:02
0afc973 to
bea856d
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.
When a machine's Planner backend keeps failing to start, the document now says why. Until now Chat said Planner: starting on studio… for as long as the connector's restart loop went on, and the reason (for example
unsafe-checkout: …) was only in the connector's log on that machine, which the document's members, often not the machine's owner, cannot read.What people see
From the second failed launch in a row, the line under the composer changes. It is still the starting state (
data-planner-state="starting", still a polite status), because the machine keeps trying:The machine's owner sees its name; a teammate in the same document sees @mona’s machine, as the starting line does today. One failed launch is treated as transient and changes nothing. An
@chopinmessage sent meanwhile is refused with the reason instead of "try again in a moment". Once the Planner attaches, or a launch stays up, it all goes.Screenshots from the end-to-end run (
CHOPIN_SHOTS):The machine's owner, desktop
A teammate with the document open, desktop
Under the composer on a phone
How it works
Three commits, one per layer.
apps/connector). It counts launches in a row that exited before staying up and posts after each toPOST /api/connector/planner/failure: the document (by id, which the Planner credential names), the count, how the backend ended and why. The reason is the last stderr line that says why: not blank, and not a line that only announces the exit (Exiting with code 1; …,Shutting down, …), with terminal colors and a leading timestamp removed. It is masked with the connector's existingredacted(the Planner credential, GitHub tokens,--envvalues, token-shaped strings), the home directory shown as~, and cut to 300 characters. When a launch stays up for the healthy interval it posts that nothing is failing. Reporting never waits on the restart loop and gives up after ten seconds.packages/protocol,apps/server). The server accepts the report only for a document it asked that machine to run, keeps the latest per document and machine in memory (like the rest of the Planner's attachment state) and forgets it when the Planner attaches, when the connector says a launch stayed up, when the machine is no longer asked for the document, and on restart.Session.PlannerAttachment'sstartinggains an optionalfailure: { attempts, reason, at }, sent to the room from the second launch on. The reason is sanitised again server-side (colors and control characters out, one line, 300 characters) andatis the server's own clock.apps/web,e2e). The line described above.Compatibility
failureis optional onstarting; an older client ignores it.Things to know
~, tokens masked). If that is too much for read-only viewers, it is one condition inplannerStatusinmain.ts.chopin statusis unchanged: it still shows the first stderr line. The line sent to Chopin is the last one that says why, because the first is often a banner.@chopinrefusal is covered end to end, and that waits the server's 30-second start window, so the new e2e test takes about 36 s.Verification
bun testinapps/connector(271 pass, 14 skip, 0 fail) andapps/server(3966 pass, 6 skip, 0 fail);apps/web/src/chat227 pass.@chopinmessage), web (the three lines, stillstarting, reason escaped, teammate's wording) and two e2e tests against a real remote-Planner server (desktop with a teammate, and phone).bun run e2e e2e/planner-picker.e2e.ts: all 8 pass, the 6 existing ones included.bun run ci(including the design contract and the impeccable check, no new findings) andbun run typespass.reason; the connector's 404 test fails with its guard disabled.Not covered
No real connector was run against a real backend that refuses its checkout; the connector side is tested with a script that prints the same shape of stderr (reason, then an exit notice).