feat(desktop): the Factory model, where every plan stands now and what waits on you
Summary
- Factory v1, PR 2 of 3, on #2597, now merged.
renderer/desktop/factory-model.ts: a pure function from the plan list, main's Inbox read (#2597), and this Mac's call to the Factory tab's board. Nothing draws it yet; the view (PR 3) ships behind the Experimental flag. - Steps, derived rather than stored: Plan while a plan has no agents and was saved in the last day, or is on the call; Build while an agent works on it or its open pull request is still in checks (pending, failing, or a draft); Ship for a minute after one of its pull requests was seen turning merged.
- What waits: the Inbox's open items under Build, the longest waiting first, each with the agent stalled on it (an agent is stalled by holding an open item, not by a status); open pull requests with checks passing, or none to run, under Ship as "Ready to merge". Questions are the wait to take first, since an agent that asks is stopped. Nothing merges on its own.
- A pull request is told apart by its page where the service sends one, else its number, since two repositories' pull requests may share a number. The list row names at most three pull requests (open and draft first), so a plan with more than three open shows the three it names; widening that is a server change v1 avoids.
noteMergedcarries when each pull request was first seen merged from one read of the plan list to the next, since the list carries no merge instant: only a pull request seen standing and then merged is news.- No range and no totals: Factory is a live view (Dean, v9). No new fetch, IPC, act kind, table, or server work.
Evidence
- Platform-independent checks:
pnpm check:affectedexit 0 (typecheck, lint, knip, 500 desktop tests);./scripts/check.shexit 0. - Seven new tests in
factory-model.test.ts, through the module's exports. - macOS Electron verification (
./scripts/verify.sh):not runā nothing is drawn by this PR.
Visual evidence
- Fixture screenshots inspected:
not attached(no UI change).
Physical-device evidence
- Screenshot or screen recording:
not attached - Device/display configuration:
not recorded
Invariants
-
./scripts/check.shgreen; renderer/UI PRs also./scripts/verify.shwith evidence inspected. (CI) ā nothing drawn. - JSON Schema goldens unchanged (
LUKE_UPDATE_FIXTURESnot run, or diff explained line by line). (CI) - Every behavior change has, in this PR, the test that fails without it; no change-detector test added. (manual; root
AGENTS.md"Testing") - Gateway envelope goldens unchanged. (CI)
- No new
astype assertion outside the allowlisted files. (CI via anti-slop) - No
Effect.runPromise/runSync/runForkoutside the runtime edges and the shimstools/oxlint/anti-slop/effect-edges.jsonrecords. (CI viaanti-slop/no-run-promise-outside-edges) - No new
setTimeout/setInterval/new Promise/AbortController/fs.watchoutside the filestools/oxlint/anti-slop/effect-edges.jsonrecords. (CI viaanti-slop/no-raw-async-primitives) - No Effect, Stream, or Layer written as a statement and dropped; a description a caller walks past runs nothing. (CI via
pnpm discarded-effect) - Test count equals the pre-PR count or the delta is listed. (manual:
vitest run --reporter=json) ā +6 desktop tests. - Each hand-rolled file the PR replaces is deleted, or the part that remains is a permanent adaptor named in root
AGENTS.md's "The permanent adaptors" with the reason it stays. - Every
CLAUDE.md/AGENTS.mdsentence naming a changed part is edited; root pair stays byte-identical. (CI for pair existence; manual for wording) -
PRIVACY.mdunchanged, or the change is a product decision called out in the PR body. - Package
package.jsondeps match what the sources import by bare specifier;effectviacatalog:. (CI) - Barrel/door rule: no Node-reaching Effect module (
@effect/platform-node,effect/sql) behind a barrel the renderer or a web function opens. (CI: existing renderernode:grep plus a new grep for those specifiers in renderer bundles)
Notes
- Blockers or follow-up verification: None; rebased onto main after #2597 merged.
š¤ Generated with Claude Code
Summary by cubic
Adds the Factory model: a pure function that derives where every plan stands ā Plan, Build, or Ship ā from the plan list, main's Inbox read, and the active call. Nothing draws it yet; the view ships in the next PR.
Steps are derived, not stored. A plan stands in Plan while it has no agents and was saved within a day, or is on the call; in Build while an agent works on it or its pull request is still in checks (pending, failing, or draft); in Ship for a minute after one of its pull requests was seen to merge. What waits on you sits at the bottom of two steps: the Inbox's open items under Build, longest waiting first ā an agent is stalled by holding an open item, not by its status ā and pull requests with checks passing or none to run under Ship as ready to merge. Questions come first, since an agent that asks is stopped, and nothing merges on its own.
noteMerged carries when each pull request was first seen merged from one read of the plan list to the next, since the list carries no merge instant: only a pull request seen standing and then merged is news. Pull requests are told apart by their pages where the service sends one, else their numbers, since two repositories' pull requests may share a number; the list's row names at most three per plan. Questions carry no agent, only the plan and the item. No range or totals, since Factory is a live view, and no new fetch, IPC, act kind, table, or server work. Seven new tests cover the step derivation, wait ordering, page disambiguation, and merged tracking.