Repository navigation
fix: preserve unaccepted work while keeping active-turn controls reachable - #731
Conversation
bandzalkin
left a comment
There was a problem hiding this comment.
Architectural review → fix round
Scope: Reviewed #731 from merge base 8921c8ce8e5b78d4264a5e286880df87c74dc8a9 through correction commit ef1964426990d55474dc1276fcbaae5390326897, including protocol, ACP adapter, execution, regression, documentation, and changelog changes. Outcome: structured busy rejection applies backpressure without terminating the borrowed autonomous session or exhausting the delivery.
Constraints: Only RequestError(-32003, data.reason=session_busy) proves non-acceptance. Unknown or accepted work keeps ordinary timeout/cancellation semantics. ACP owns that proof; ExecutionContext owns watchdog, delivery retry, stop/play, and shutdown. Local contact events have no REST row to recover. Bootstrap/restoration provenance is removed with session cleanup.
Decisions: Keep a single total adapter deadline, fresh collector/emitter per request attempt, and a typed CancelledError carrying proven non-acceptance. The runtime converts only its own watchdog cancellation into deferral and preserves shutdown/control priority. Retain deferred local events at their FIFO position instead of inventing durable rows or consuming them. This is smaller than duplicating ACP error recognition in the runtime or creating another retry queue.
Findings and proof: A1 rejected-attempt contamination, A2 watchdog budget loss, and local-event loss were confirmed and corrected; cleanup provenance and shutdown races were checked. No standalone blocker remains. Fresh gate: 6,315 passed / 684 skipped; focused ACP/control tests 80 passed; all pre-commit hooks and both lock checks passed; baseline E2E collection 526 items / 1 skipped; markdown snippets 23 passed. Standalone real ACP socketpair smoke demonstrated watchdog deferral, same-session recovery, and an accepted retry's visible answer after unrelated autonomous tool output.
Architectural verdict: APPROVED for #731 independently. Generic OMP 18.6.0 errors remain ordinary errors; structured 18.6.1 rejection is supported. Combined integration with #729 is HELD: its live external-effect recorder commits rejected-attempt effects to the shared ledger before prompt success. The minimal staging correction belongs in #729, not a second policy in #731. This is not remote CI or merge approval.
Squashed from band-ai#731 at a4d966f. Upstream-PR: band-ai#731
Squashed from band-ai#754 at 3dc3a7a, resolved over band-ai#731's session-busy retry loop: the emitter drops the retired mention argument, and band-ai#731's busy-recovery tests post their reply through the Band tool (or assert the closing thought when no Band tool is injected). Upstream-PR: band-ai#754
Squashed from band-ai#731 at a4d966f, resolved over upstream's band-ai#754: the busy-retry loop builds the emitter without the retired mention argument, the busy-recovery tests reply through the Band tool (FakeACPAgent.reply) or assert the closing thought when no Band tool is injected, and docs/acp.md keeps both the busy-session and the 4.x-to-5.x upgrade sections. Upstream-PR: band-ai#731
Squashed from band-ai#731 at a4d966f, resolved over upstream's band-ai#754: the busy-retry loop builds the emitter without the retired mention argument, the busy-recovery tests reply through the Band tool (FakeACPAgent.reply) or assert the closing thought when no Band tool is injected, and docs/acp.md keeps both the busy-session and the 4.x-to-5.x upgrade sections. Upstream-PR: band-ai#731
Squashed from band-ai#731 at a4d966f, resolved over upstream's band-ai#754: the busy-retry loop builds the emitter without the retired mention argument, the busy-recovery tests reply through the Band tool (FakeACPAgent.reply) or assert the closing thought when no Band tool is injected, and docs/acp.md keeps both the busy-session and the 4.x-to-5.x upgrade sections. Upstream-PR: band-ai#731
Squashed from band-ai#731 at a4d966f, resolved over upstream's band-ai#754: the busy-retry loop builds the emitter without the retired mention argument, the busy-recovery tests reply through the Band tool (FakeACPAgent.reply) or assert the closing thought when no Band tool is injected, and docs/acp.md keeps both the busy-session and the 4.x-to-5.x upgrade sections. Upstream-PR: band-ai#731
Squashed from band-ai#731 at a4d966f, resolved over upstream's band-ai#754: the busy-retry loop builds the emitter without the retired mention argument, the busy-recovery tests reply through the Band tool (FakeACPAgent.reply) or assert the closing thought when no Band tool is injected, and docs/acp.md keeps both the busy-session and the 4.x-to-5.x upgrade sections. Upstream-PR: band-ai#731
Squashed from band-ai#731 at a4d966f, resolved over upstream's band-ai#754: the busy-retry loop builds the emitter without the retired mention argument, the busy-recovery tests reply through the Band tool (FakeACPAgent.reply) or assert the closing thought when no Band tool is injected, and docs/acp.md keeps both the busy-session and the 4.x-to-5.x upgrade sections. Upstream-PR: band-ai#731
Squashed from band-ai#731 at a4d966f, resolved over upstream's band-ai#754: the busy-retry loop builds the emitter without the retired mention argument, the busy-recovery tests reply through the Band tool (FakeACPAgent.reply) or assert the closing thought when no Band tool is injected, and docs/acp.md keeps both the busy-session and the 4.x-to-5.x upgrade sections. Upstream-PR: band-ai#731
Squashed from band-ai#731 at a4d966f, resolved over upstream's band-ai#754: the busy-retry loop builds the emitter without the retired mention argument, the busy-recovery tests reply through the Band tool (FakeACPAgent.reply) or assert the closing thought when no Band tool is injected, and docs/acp.md keeps both the busy-session and the 4.x-to-5.x upgrade sections. Upstream-PR: band-ai#731
Squashed from band-ai#731 at a4d966f, resolved over upstream's band-ai#754: the busy-retry loop builds the emitter without the retired mention argument, the busy-recovery tests reply through the Band tool (FakeACPAgent.reply) or assert the closing thought when no Band tool is injected, and docs/acp.md keeps both the busy-session and the 4.x-to-5.x upgrade sections. Upstream-PR: band-ai#731
a4d966f to
092bbfe
Compare
Squashed from band-ai#731 at 092bbfe; retains upstream auxiliary-claim test imports. Upstream-PR: band-ai#731
Squashed from band-ai#731 at 092bbfe; retains upstream auxiliary-claim test imports. Upstream-PR: band-ai#731
…hable Rebuild INT-1754 from main with one rejection signal, shared control handling, and the existing room scheduler. Preserve context and ACP sessions across proven non-acceptance.
c121aab to
9856902
Compare
AlexanderZ-Band
left a comment
There was a problem hiding this comment.
Two findings: missing runtime rejection diagnostics and REST lookup ownership. The remaining four review groups and the independent Logical Bugs skeptic found no confirmed defects. The findings will be addressed through the verified fix workflow.
AlexanderZ-Band
left a comment
There was a problem hiding this comment.
Reviewed against INT-1754 and its finalized plan. One nonblocking hygiene nit; no confirmed design, runtime, test-quality, edge-flow, or logical-bug findings.
A busy adapter currently consumes ordinary work without executing it, or treats a structured ACP rejection as a failed turn and tears down the session. This replacement keeps proven unaccepted work outstanding while allowing approval, status, and question controls to reach already accepted work.
Implements INT-1754. Rebuilt from current main; replaces the previous implementation of this PR.
Behavior
InputNotAcceptedsignal covers pre-send local occupancy and ACP's exact-32003/reason=session_busyrejection. It bypasses turn judgment, failure acknowledgement, and execution-failure retry charges. Transport uncertainty keeps its existing failure behavior.NOT_ACCEPTEDwithout terminal acknowledgement or history drain. A control behind older work cannot drain that work or reopen a terminal duplicate.No
band-sdk-coreAPI or dependency changes. TypeScript adapter migration remains a followup. This does not promise exactly-once execution across restarts or generic attribution of unsolicited provider work.Verification
a86ede24fd6c867f36117b6bdfe964ac69e4d1dfpassed the full Ubuntu/Windows Python 3.11–3.13 matrix, including separate CrewAI/Parlant jobs, packaging, and the core coverage gate: 27 successful checks. Only the schedule-only weekly coverage report was skipped.The review fixes add DEBUG diagnostics at the shared rejection transition and keep actionable-message lookup with its lifecycle page accessor. Both new real HTTP-boundary logging regressions failed before the fix and pass afterward. The preprocessing/Slack review fixes preserve configured filtering and transformations on control delivery without committing model context, and forward the same control hook through both Slack wrapper ingress paths. Normal delivery preprocesses once. Runtime regressions now use real Agent dispatch instead of duplicating it in a helper. All 9 new regressions fail on the preceding PR head and pass with these fixes; the focused preprocessing/Slack/Agent suite passes 342 tests. CI for that preceding head completed with 27 successful checks and only the schedule-only weekly coverage report skipped.
The latest review centralized one-shot failure-detail bounding and the empty-message fallback in its existing acknowledgement path. Preceding head
093161cdf8b5e22065c35faad18460f2c9d0fdd8passes the full local gate: 7,882 passed, 170 skipped, Ruff lint/format, Pyrefly, 28 documentation checks, and isolated extras-free wheel smoke. The final cleanup ate614a405ac54af4d6f86774533bd20da54e0bb82removes redundant preprocessing comments and leaves the Python AST unchanged. Its full local gate also passes: 7,882 passed, 170 skipped, Ruff lint/format, and Pyrefly. GitHub CI for this final head passes the full Ubuntu/Windows Python 3.11–3.13 matrix, isolated CrewAI/Parlant jobs, packaging, lint, and coverage. The schedule-only weekly coverage report is not a live acceptance gate.Live evidence and blockers
Actual OMP 18.2.6 and released 18.8.9 naturally entered autonomous work through a supported extension. A real ACP prompt received the exact structured busy rejection, preserved its session without reporting failure, and a later prompt succeeded on that same session. This proves the provider/ACP recovery boundary; it is not platform scheduler acceptance.
Added live A/B/C/D acceptance cells for Claude SDK, Codex, and OpenCode. Their runs did not reach the scenario: Claude/Codex were blocked by platform 403
plan_required(Enterprise subscription required). After verifying an isolated OpenCode 1.18.4 server had Bash permission set toask, provisioning failed with platform 500 and WebSocket handshake failures (request_id=7db65f61778980ab644c439b7500628b). All created resources were subsequently deleted and verified absent. Platform live acceptance remains blocked, not passed.