Repository navigation
cockpit v3: steering end to end on the live node API (milestone 2 integration) - #218
Merged
Merged
Conversation
Milestone 2's web seams now read the server: every steering route (preview, apply, Undo, Needs you, Find, last look) is on the live source, and what did not match the S9/S10/S12/S13 server is fixed: - Previews draw the server's own shapes: the moved or added node sits dashed in the column it lands in (the server lists it under ghosts), "Wait: ..." sentences read as labelled lines, a plan's code prefix is left out of warnings, one arrow between before and after, and Apply stays off when the server says the viewer may only look. - Add child sends what it waits on as depends_on: [ref] with depends_why, lands in First unless it waits on a sibling, and says the column the server placed it in. - An answer that applied a proposal (Apply C-16) has its Undo (the proposal's own) in the toast and beside the node's verbs. - A verb's card in its node's thread offers its Undo by token, also after a reload; the server's undone card names the token it undid. - The node chat reads the per-node threads (?nodes=1) for its children's news; on a phone a verb from the full-screen chat closes it and opens the preview in view. - Team's first pick never sends a preview with no changes (400); team rows size by the panel's width, not the window's. - Asks read as words (a person's Markdown), chips end in an ellipsis. - Server: Start now no longer warns about met links it already had, the factory team says "all idle" instead of "0 running", and Name it says it files under a stored node of its own level. The e2e seeds the base env and a held Google Ads integration, and tests/e2e_ui/factory_v3/test_v3_steering.py drives each verb, Needs you, Find, the factory tree, every lens and the phone against a real server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A verb filed as a proposal and applied at once posted the same proposal card twice in its node's thread (filed, then applied). The node chat now shows the newest as the live card and the earlier one as its line; the Room's own threads are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…server keeps one
- POST /v1/factory/decisions/{id}/undo takes back an Apply on a projects
proposal's decision: the proposal's own Undo runs, then it waits for a
person again under a fresh decision (as reopen leaves one), so the work held
for it waits again (a hold the sweep let lapse comes back and its PL is told)
and the ask is in Needs you again. The answered decision stays answered.
- The web offers an answer's Undo only when the proposal it applied is applied
with an undo_until (never a rules, tuning or code change), until that time on
the server's clock; Undo calls the new route and says where the ask is now.
- An answer the server stored but whose proposal failed to apply says so
("D-50 answered; applying C-17 failed: ..."), with no Undo; the failure body
carries the reason.
- A verb card's Undo shows only to the person who applied it (meta.by_user)
or an owner, and only an open Undo ticks its clock.
- ?nodes=1 lists at most the newest 50 node threads.
- The e2e sweep exempts icons only inside controls; the seed's C-17 and C-18
add real rules, and a new e2e applies one from the factory tree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5 of 13 tasks
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.
Related issue
Closes # (cockpit v3 milestone 2 integration, "Steer at the node";
notes/factory-v3/final/plan.md§1–§3)Summary
Milestone 2's pieces landed separately (#213 S8–S10, #214 W6/W8/W10, #215 S11/S12, #216 W7/W9, #217 S13), but the web still read none of the steering routes:
SERVED_STEERwas empty, so on a live factory every verb said "this server cannot preview it yet". This PR switches every route on and fixes what did not match once the web read the real server. Then it drives each verb, Needs you, Find, the factory tree, the lenses and the phone end to end, against a local server seeded like Luka's factory.ELI5: before, pressing "Start now" on a live factory did nothing. Now it shows the real plan (where the panel moves among its siblings, what its wait becomes, who approves). Apply does it, and Undo takes it back from three places: the toast, the "Undo (n min left)" button beside the node's verbs, and the verb's card in the node's chat. Applying C-16 from a status line can be undone too, and that Undo really puts things back: C-16 waits for a person again under a fresh ask, T-16 is held for it again, and the ask is back in Needs you.
Plan bullets → what this PR does
W6. Verb previews and Undo, wired (
v3/nodeSource.ts,v3/nodeWire.ts,v3/verbs/,v3/nodeSteer.ts)SERVED_STEERlistspreview,apply,undo,needsYou,findandseen, and the live source carries all of them.columns_after.ghostswith the column it lands in. A moved node keeps its own state there. The mini columns used to ignoreghosts, so neither the ghost nor the struck place showed.previewColumnsnow draws those ghosts dashed in their column. A proposal's ghost with no column is the page's own and stays apart.effectsarrive as sentences ("Wait: …", "Order: …", "Depends on: …"). A one- or two-word lead now becomes the line's label.depends_on_done: …). The code is left out.→ sample-main (here)) no longer get a second arrow.can_apply: falsekeeps Apply off and says who applies it (an owner's verb seen by an editor).depends_on: [ref]withdepends_why: {ref: reason}. The old single string was a 400. A new child defaults to First, which is where the server places a child that waits on nothing. The pull-forward banner names the column the server placed it in, and the server's sentence that repeats the banner is not shown twice.appliedwith anundo_until, until that time on the server's clock. Undo callsPOST /v1/factory/decisions/{id}/undo(new, below). It is offered in the toast and beside the verbs, from the status line and from Needs you.preview_appliedcard in the node's thread offers "Undo (n min left)" by its token, so the Undo survives a reload, to the person who applied it (meta.by_user) or an owner. The card that Undo posts now names the token (meta.undo_token, server), so the applied card stops offering it.useTeamPreviewsent its first preview with the settled-but-empty body, so the first pick got a 400 (send changes). It now waits for the changes. The member rows size by the panel's own width (container query). Beside the 40 % chat column, the vendor and model pickers had collapsed to zero.W8. Sheets on the live routes (
v3/sheets/V3Sheets.tsx, palette)askWords).W10. Since last look:
PUT …/n/{ref}/seenis sent after 3 s on the live source.W5 / S11. The node chat
GET chat/threads?nodes=1, the follow-up named in cockpit v3: threads per node and structural verbs with preview, apply and Undo (S11, S12) #215). Read marks update both thread lists.S12 / S13 server fixes (
node_verbs.py,nodes.py)preview_appliedcard names the token it undid.W9. Factory tree, W7. Lenses: covered end to end (below). The e2e seed now has a base env.
W11 (part): steering end to end (
tests/e2e_ui/factory_v3/test_v3_steering.py, new)base-env's env reported ready with smoke OK.needs you: Apply C-16 (D-n), T-16's line is what it was before, and Needs you lists the fresh ask (not D-45).PR-9876 · met; Undo restores the line.feature:I-1and in the chat column.who_may: an owner; Apply; the chip is inherited by the project and its task; build-tier-drafts-3 is untouched.$a/h → about $b/h; Apply is a definition version; Undo re-pins.T-16,#9876andC-16each open their node.checks.pyholds the sweep both e2e modules use. An icon inside a control (button, link, chip) is a glyph, not a line between nodes; an icon anywhere else on the node page still counts.Review fixes (round 2)
POST /v1/factory/decisions/{id}/undo(proposals.undo_answer, HUMAN_ORIGIN, EDIT; MANAGE for an owner-class proposal): the proposal's own Undo runs (same checks;undowas split into_undo_checksand_take_back, behaviour unchanged), then the proposal goes back topendingunder a fresh mirrored decision withbased_onread again, no grace timer and a 72 h window from now. Holds on it that the sweep let lapse since it applied come back (tasks.hold_again,task.held,[Factory notice · HOLD BACK · T-n]to the PL). The proposer is told[Factory proposal · C-n back to pending …]. The web calls it, and the toast says where the ask is now. The sample engine does the same: a fresh D-52, and what waited on D-45 waits on it. The e2e checks after Undo that the status line ends atneeds you: Apply C-16 (D-…)with the fresh id, that C-16 is pending under it, that T-16's line is what it was before, and that Needs you lists the fresh ask and not D-45.liveNodeSource.answernow readsGET …/proposals/{C-n}after an Apply and returns the Undo only for anappliedprojects proposal with anundo_until.expiresAtcomes fromundo_untilthrough the shell's clock offset. New unit tests cover a rules proposal (no Undo), a projects update (Undo until itsundo_until), and Reject (no proposal read).preview_appliedcards carryby_user(node_verbs._card, thechat.pywhitelist,PreviewAppliedMeta). The card offers Undo only to that person or an owner (the same rule asundoLeft).AppliedOfand ticks only while its own Undo is open.appliedandrenderCardchange only with the messages, the viewer or the undo function.?nodes=1unbounded. At most the newest 50 node threads (NODE_THREADS_MAX), with a server test.BODY_CHECKSnow skips a lucide icon only inside a control (button, a, [role="button"], [data-testid="v3-chip"]). In the chat column the Room's cards and the chat's icons stay out, as before. All 18 e2e pass with the tighter sweep.reason. The toast saysD-50 answered; applying C-17 failed: the definition already has these values, refreshes the pages and offers no Undo. The seed's C-17 and C-18 now add real rules. A new e2e applies C-17 from the factory tree's Needs you: it becomes a definition version, no Undo is offered, and the ask leaves the list.Deviations
sample-mainin tests.FORBIDDEN_SAMPLE_TOKENSforbids the real branch name in fixtures. The autonomy test covers the same thing on the seed's base.useTeamPreviewno longer sends a preview with no changes. v2's team editor loses only a failing request.RoomCardpassespreview_appliedto the node renderer only when cockpit v3 provides one.useRoomThreadsandfetchRoomThreadstake an optionalnodes.POST …/proposals/{ref}/undois unchanged (still endsundone).who_mayandcan_apply, because the e2e server is single-user. The editor's 403 is covered by cockpit v3: autonomy and auto-merge per subtree (S13) #217's server tests.These are follow-ups.
omnigent/runner,omnigent/tools,omnigent/policiesoromnigent/factory.py). The new route and card field are server-only and additive: an older web ignoresby_userandreason.Test Plan
Worktree on
staging@ 74d87c8 (unchanged since),OMNIGENT_SKIP_WEB_UI=true CI=1, final head:npm run buildinweb/, thenuv run --frozen pytest tests/e2e_ui/factory_v3 --ui-skip-build --browser-channel chrome→ 18 passed (7 existing + 11 steering), with the tightened icon sweep.uv run --frozen pytest -q -n 8 tests/server/factory tests/examples/test_factory_sample_tokens.py tests/runner/test_factory_node_tool.py tests/server/test_openapi_drift.py→ 4539 passed. New in this round:test_undo_answer.py: Undo of an Apply puts the charter back, leaves the proposal pending under a fresh decision (old one stays answered), puts back the hold the sweep let lapse and tells the PL and the proposer; the fresh ask applies again; an open ask, an unknown id and a closed window are refused; a Reject or a second Undo is refused; someone without access cannot.test_node_threads.py:?nodes=1caps the node threads; thepreview_appliedcard carriesby_user.test_human_origin.py: the new write route carries HUMAN_ORIGIN (10 routes).test_node_verbs.py(Start now's met links, the undone card's token, Add's list with reasons, Name it's wording),test_nodes.py(no "0 running").web/):tsc -b,npm run lint,npm run format:checkclean.vitest run src/components/factory src/pages/factory src/lib→ 237 files, 4193 tests passed. New in this round:v3/answerUndo.live.test.ts: Undo offered for an applied projects change until itsundo_until; none for a rules proposal, an expired or failed one, or a Reject; Undo posts/decisions/{row_id}/undoand names the fresh ask; a refusal that still answered reads as "answered; applying failed".v3/steerLive.test.tsx: Undo on the status line brings backneeds you: Apply C-16 (D-52), T-16 waits on D-52, Needs you lists it; a rule's answer offers no Undo.NodeChat.test.tsx: a verb card's Undo shows only to the person who applied it (or an owner).exfil-scan.py,secret-scan.py): pass.Pre-commit checks(ruff-format on staging's own files, the iOS swift-format config, pyrefly),E2E UI Required(maintainer waiver),stores-crdbandstores-mysql(schema), andE2E Tests(pi-native, claude-sdk and k8s harness journeys). Theregex.execlines the exfil scan flagged are nowString.match.pre-commit run --files <changed>: ruff, prettier, oxlint, web tsc and the hygiene hooks pass. pyrefly reports the 28 errors already on staging, none in changed code.How to try it on a live factory: open it with
?cockpit=v3.sand read the preview. Apply, then use the Undo beside the verbs.aand type the title of a held item: it is pulled forward. Then pressu.tand pick another model for one member: the cost line appears.T-16,#9876orC-16.Demo
Captures from the seeded local server at 1440 (light and dark) and 390: https://claude.ai/artifact/ESKbtnfjzptJLskEwCuC6z (private; ask Luka for access). Screenshots are not committed (repo rule), and the CLI cannot upload attachments. The captures are in
wt/v3-tmp/v3-m2-integrate/shots/.Type of change
Test coverage
Coverage notes
Manual: every verb, Needs you, Find, the factory tree, the lenses and the phone chat were driven by hand in Chrome on a server seeded with
tests/e2e_ui/factory_v3/seed.py, at 1440 and 390, in light and dark. That run found the mismatches fixed here: the ghosts not drawn, the team's empty first preview, the phone preview opening behind the chat, the duplicate proposal cards and the "0 running" line. The e2e now covers each of them.Changelog
Cockpit v3 can steer a live factory: verb previews, Apply and Undo, Needs you, Find and the last look now read the server, and an applied verb can be undone from its card for 10 minutes; undoing an applied decision brings the ask back.
🤖 Generated with Claude Code