Skip to content

acpmux: fork before a recorded prompt with durable retry identity - #27364

Merged
teamleaderleo merged 15 commits into
feat-cmux-nextfrom
lane/hb-fork-before
Nov 2, 2026
Merged

teamleaderleo merged 15 commits into
feat-cmux-nextfrom
lane/hb-fork-before

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Edit and Resend needs a child containing only the history before the selected prompt. acp.session.fork gains an authoritative beforePromptId boundary with persisted requestId retries. The true first prompt produces an empty configured child; later prompts use the completed preceding turn. The source transcript stays unchanged.

Leo's request:

well i just think we can improve it a f***ton more than it is now... it's slow it's bad it belabours the point in too many tooltips it's ugly in places it doesn't even work in places there's lots of functionality that needs to get in

The capability is acp.session.fork.beforePromptId. Unknown, ambiguous, steering, unreconstructable and conflicting requests fail explicitly. Partial creation never allocates a replacement child on retry. Existing remote guards still run, including the phone Full-access marker now preserved through canonical fork normalization.

Overlap audit supplied by the area coordinator: “beforePromptId” and “fork before prompt” matched no PR. “edit and resend” matched merged desktop work #19470, #19679, #20318, #18754, #19565, unrelated iOS work #27286/#27314 (untouched), and the companion mobile-host classification PR #27347. The VM broker does not support the search endpoint or pr-overlap GraphQL request form.

Validation:

  • Original red: 40852403033, test-only head 52a88bf; compilation passed, boundary/capability and phone guard regressions failed.
  • Review regressions red: 40859147358, head 773c055; inherited external history and missing earlier native answer were incorrectly accepted.
  • Prior green: 40860810273, head 02b8d67: clippy with warnings denied for acpmux and cmux-tui, 96 fork integration tests, the real phone Full-access regression, and protocol_ir_is_current passed; both packages compiled. Fail-fast command: cd cmux-tui; cargo test -p acpmux --test hub_integration fork_through::; cargo test -p acpmux --test remote_guard_codex_bridge canonical_fork_boundaries_keep_the_phones_full_access_requirement; cargo test -p acpmux --lib protocol_ir_is_current.
  • Generated-web lints: 40853156245, with generated implementation patch applied. All seven SDK generators and acpmux TS output checks passed 40858406959.
  • Protocol/inventory SDK test failure matches base exactly: 40859020378, test_live_raw_v12_layout_and_history_contracts_are_exact/new-pane-right expects a field map missing the existing optional side. Both head and base have 64 tests, one identical failure; remaining generation checks passed independently.
  • Independent Codex gpt-6-astra high/fast review: SHIP at 44beba2. The final repair uses the canonical main-chain terminal-answer predicate; thinking-only, sidechain, and nonterminal records cannot satisfy completeness. Red run 40992466031 at dc101c1 compiled and reproduced the flaw; three other fork-before tests passed. Final-head validation is running in 40993993386. Run40855130410 is not counted as green: a non-fail-fast wrapper concealed a stack abort; boxed futures repaired it and the final fail-fast suite passed.

Risk: strict completeness checks conservatively refuse adopted/imported, compacted or incomplete histories. Source metadata retains request reservations even when a child is purged. The additive fields preserve old-store deserialization and are stripped during transfer import. No policy is widened.

This cohesive change exceeds the usual 800-line target because the boundary must ship together with empty-child semantics, durable retry state, guard parity, native-history verification, generated protocol types and regression fixtures. Advertising a partial boundary without those guarantees would expose a misleading contract to mobile clients.

No capture: backend protocol, generated types and test fixtures only; this prerequisite changes no visible UI.

Agent session: agent session

@blacksmith-sh

blacksmith-sh Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Found 2 test failures on Blacksmith runners:

Failures

Test View Logs
test_every_compile_job_names_its_warm_sources (main.ThisTree.test_every_compile_job
_names_its_warm_sources)/
test_every_compile_job_names_its_warm_sources (main.ThisTree.test_every_compile_job
_names_its_warm_sources)
View Logs
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)/
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)
View Logs

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@github-actions github-actions Bot added the risk:low Risk tier (docs/ci/risk-tiers.md) label Oct 29, 2026
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 6ee2e72: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr27364 -f ref=lane/hb-fork-before -f platform=macos -f backend_mode=local

Gallery before/after for 6ee2e72: 16 states rendered, 0 images differ, 2966 more touched states not rendered. Images are in the run's artifact, not on this public PR; the independent review of this head reads them on its own, so the PR needs no hand-made screenshots of these states.

gh run download 41403728703 -R manaflow-ai/cmux -n gallery-advisory-27364-6ee2e72b5db1ea166042f87be2e829809bc50ade (then read gallery-review.json)

States
State Theme Status Diff Picked by
agent-pane.live-chat-watch/choice-alone Apple System Colors Light unchanged 0% imports methods.ts (1 hops)
agent-pane.live-chat-watch/choice-alone Apple System Colors unchanged 0% imports methods.ts (1 hops)
agent-pane.live-chat-watch/view-only Apple System Colors Light unchanged 0% imports methods.ts (1 hops)
agent-pane.live-chat-watch/view-only Apple System Colors unchanged 0% imports methods.ts (1 hops)
agent-pane.live-chat-watch/take-over-refused Apple System Colors Light unchanged 0% imports methods.ts (1 hops)
agent-pane.live-chat-watch/take-over-refused Apple System Colors unchanged 0% imports methods.ts (1 hops)
agent-pane.access-offer/turn-no-credits Apple System Colors Light unchanged 0% imports types.ts (2 hops)
agent-pane.access-offer/turn-no-credits Apple System Colors unchanged 0% imports types.ts (2 hops)
agent-pane.access-offer/turn-low-credits Apple System Colors Light unchanged 0% imports types.ts (2 hops)
agent-pane.access-offer/turn-low-credits Apple System Colors unchanged 0% imports types.ts (2 hops)
agent-pane.access-offer/turn-no-offer Apple System Colors Light unchanged 0% imports types.ts (2 hops)
agent-pane.access-offer/turn-no-offer Apple System Colors unchanged 0% imports types.ts (2 hops)
agent-pane.approval-edits/single Apple System Colors Light unchanged 0% imports methods.ts (2 hops)
agent-pane.approval-edits/single Apple System Colors unchanged 0% imports methods.ts (2 hops)
agent-pane.approval-edits/grouped Apple System Colors Light unchanged 0% imports methods.ts (2 hops)
agent-pane.approval-edits/grouped Apple System Colors unchanged 0% imports methods.ts (2 hops)
agent-pane.approval-edits/single-multiedit Apple System Colors Light unchanged 0% imports methods.ts (2 hops)
agent-pane.approval-edits/single-multiedit Apple System Colors unchanged 0% imports methods.ts (2 hops)
agent-pane.approval-edits/grouped-multiedit Apple System Colors Light unchanged 0% imports methods.ts (2 hops)
agent-pane.approval-edits/grouped-multiedit Apple System Colors unchanged 0% imports methods.ts (2 hops)
agent-pane.approval-edits/single-long Apple System Colors Light unchanged 0% imports methods.ts (2 hops)
agent-pane.approval-edits/single-long Apple System Colors unchanged 0% imports methods.ts (2 hops)
agent-pane.approval-edits/grouped-long Apple System Colors Light unchanged 0% imports methods.ts (2 hops)
agent-pane.approval-edits/grouped-long Apple System Colors unchanged 0% imports methods.ts (2 hops)
agent-pane.auth-health/signed-in Apple System Colors Light unchanged 0% imports methods.ts (2 hops)
agent-pane.auth-health/signed-in Apple System Colors unchanged 0% imports methods.ts (2 hops)
agent-pane.auth-health/signed-out Apple System Colors Light unchanged 0% imports methods.ts (2 hops)
agent-pane.auth-health/signed-out Apple System Colors unchanged 0% imports methods.ts (2 hops)
agent-pane.auth-health/expired Apple System Colors Light unchanged 0% imports methods.ts (2 hops)
agent-pane.auth-health/expired Apple System Colors unchanged 0% imports methods.ts (2 hops)
agent-pane.auth-health/unknown Apple System Colors Light unchanged 0% imports methods.ts (2 hops)
agent-pane.auth-health/unknown Apple System Colors unchanged 0% imports methods.ts (2 hops)

Pick other states with a Gallery: entry.id, entry.id/variant line in the PR body.

Passes: CI passes on 6ee2e72b5d.

CI passes on 6ee2e72b5d (run 41403728789 attempt 1).

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

web and size checks: green

Shipped in:

The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/41407469077 at 7b24abd failed: cmux-next checks (god files, concurrency, crash safety, l10n).
Those jobs last passed at 6660f71. This pull request is one of 5 merged since: #31842, #31934, #31925, #31968, #27364.
If the failure is in your change, fix forward on feat-cmux-next. Pull requests run only the tiers their paths reach (docs/ci/cmux-next-tiers.md); label a batch PR full-ci to run them all before merging.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-iyebib created for this PR by the cmux coordinator.

@github-actions github-actions Bot added risk:normal Risk tier (docs/ci/risk-tiers.md) and removed risk:low Risk tier (docs/ci/risk-tiers.md) labels Oct 29, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

The protocol contract and inventory failures match base by test name and error. Comparison run https://github.com/manaflow-ai/cmux/actions/runs/40859020378 shows test_live_raw_v12_layout_and_history_contracts_are_exact / new-pane-right failing identically on b3ef063 and base3d89c41ab4578e9a10ee4533a6dcd2509861355f: the expected field map omits the existing optional side field. Neither the SDK schema nor that test is changed here. The remaining generated-output checks were run independently: all seven SDK generators and acpmux TypeScript output pass in https://github.com/manaflow-ai/cmux/actions/runs/40858406959.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by an agent session · session

…k-before

# Conflicts:
#	cmux-tui/crates/acpmux/docs/acpmux-schema.json
#	cmux-tui/crates/acpmux/src/hub/mod.rs
#	cmux-tui/crates/acpmux/src/hub/session.rs
#	cmux-tui/crates/acpmux/src/server/fork_through.rs
#	cmux-tui/crates/acpmux/src/server/requests.rs
#	cmux-tui/crates/acpmux/tests/fake_claude.py
#	cmux-tui/crates/acpmux/tests/remote_guard_codex_bridge.rs
#	webviews/src/agent-session/acpmux/protocol/generated/methods.ts
@teamleaderleo
teamleaderleo marked this pull request as ready for review November 2, 2026 06:35
@cursor

cursor Bot commented Nov 2, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (subagent claude-opus-5-5 medium): SHIP at f3034b8

Visual verdict: no UI in this diff

Checked the merge resolution with --remerge-diff. start_later is passed through fork_with_boundary, and the beforePromptId path passes false. All callers (requests, aside, btw) match the new signature. fork_lock and close_lock are both on Session and both initialized. fork_through strips beforePromptId, requestId and startLater. The bridge test keeps the before-prompt cases, fake_claude.py keeps both the usage reply and stop_reason, and the generated methods.ts has both ForkParams and MessageEvent. The source reservation keeps its guarantee under the ordered writer. The change is made in memory before write_meta (Wait::Durable) takes its version, and every later copy is taken from memory, so no stale copy can be written after the reservation becomes durable. The other direct store.save calls on chat metadata run only at load or import.

Follow-ups:

  • [follow-up] hub/fork.rs writes the child's fork_before.ready = true with a direct store.save(&ready) outside the ordered writer. A writer already running for the new child with an older copy could land after it. The trailing save_meta(&new) puts ready back on disk, but that call does not wait for durability, so a crash in that window makes retries return fork.incomplete (it fails safe: no duplicate child, no data loss). Setting ready in memory and calling write_meta(&new) + flush_session would close the window.
  • [follow-up] server/requests.rs:1579 is 112 columns, over max_width = 100. The rustfmt step only warns.

@teamleaderleo

teamleaderleo commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator Author

Review (subagent claude-opus-5-5 medium): SHIP at 3b59d4c
Visual verdict: no UI in this diff

The usage report is only appended from refresh_usage_stats_of, which runs after a turn ends (hub/turns.rs). So a fork that wrongly ran or changed a turn on the source would still add user_message/status/turn records, and those stay in the comparison. The native file check and the claude_history checks are unchanged. Every source-unchanged comparison in the file (four of them across three tests) now uses source_journal on both sides. The snapshot copy and the child-journal reads are not comparisons, so they correctly stay unfiltered. The truncated-prefix tail check still compares a prefix and then only allows stopped/exited/status, with both sides filtered the same way.

Follow-ups: none

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (subagent claude-opus-5-5 medium): SHIP at 6ee2e72

Visual verdict: no UI in this diff

Checked 3b59d4c..6ee2e72 only: forked and mux are built by json!({...}) object literals right before each write, so JsonSet::set takes the object branch and does the same insert that IndexMut did. The trait is in scope in both files: use cmux_json::JsonSet as _ in hub/fork.rs, where forked.set(...) was already used at the prior head, and use crate::no_panic::JsonExt in server/fork_through.rs, which already calls out.set. set has no #[must_use] and the workspace enables no unused_results, so dropping the bool raises no warning, the same as the existing call sites.

Follow-ups: none

This branch was previously deployed

3 inactive deployments
artifacts — 6ee2e72b Deployed Nov 2, 2026 by teamleaderleo via publish tree-addressed cmux-tui #99918
sentry-dsyms — 6ee2e72b Deployed Nov 2, 2026 by teamleaderleo via upload cmux-tui dSYMs to Sentry #99918
ci-routing-agent — 6ee2e72b Deployed Nov 2, 2026 by teamleaderleo via cmux-tui tree preflight #99918
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant