Skip to content

feat(cloud-agent-next): coalesce adjacent part deltas in outbox - #6274

Merged
eshurakov merged 3 commits into
mainfrom
eshurakov/grand-current
Sep 17, 2026
Merged

eshurakov merged 3 commits into
mainfrom
eshurakov/grand-current

Conversation

@eshurakov

Copy link
Copy Markdown
Contributor

Summary

The wrapper control-event outbox could only compact by superseding a snapshot entry keyed on an entity id. message.part.delta carries an increment, not a snapshot, so it had no key and could never be compacted: a delta burst grew the lane one entry per delta until admission failed and the event was dropped as queue_overflow at MAX_CONTROL_EVENT_OUTBOX_EVENTS.

  • Add an append/merge rule beside the supersede rule. Adjacent same-part deltas for field text merge by concatenating delta, keeping the tail entry's receiptId, sequence and preparedAt, so the existing receipt identity still describes the published frame.
  • Both rules share the in-flight tail guard, so an entry that a pending attempt will remove is never replaced.
  • A merged entry takes the newer member's deadlineAt, so an actively-growing group is not expired mid-burst; snapshot squash keeps its previous deadline, so supersede semantics are unchanged.
  • Merging is declined when the merged payload would exceed MAX_SANDBOX_CONTROL_FRAME_BYTES; the delta is appended as its own entry instead. At the entry cap that append can still be dropped as queue_overflow, which is correct because an over-frame replacement was never sendable.
  • Also attribute non-applied control events: the id-mismatch and child-lineage rejections now return through result() and emit session_event_result, and a caught batch halt emits one warn-level session_event_batch_halted with the halting item's identity and the skipped suffix shape. The halt diagnostic never reads the thrown value.
  • Merging is restricted to field text; no wire protocol, DO, SDK or schema change is involved.

Verification

No manual testing performed. Automated checks run on the branch:

  • bun test src/control/control-event-outbox.test.ts (wrapper): 76 pass, 0 fail
  • pnpm exec vitest run src/sandbox-session/session-message-queue.test.ts src/sandbox-control/diagnostics.test.ts: 362 pass, 0 fail

Visual Changes

N/A

Reviewer Notes

The deadline refresh for merged groups is deliberate: an actively-merged group is bounded by the outbox entry and byte limits instead of the 30s clock.

@kilo-code-bot

kilo-code-bot Bot commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

Full re-review after a force-push (previous head ee9f854 is not an ancestor of the current head, so no previous findings were carried forward): the outbox delta-merge predicate compares the complete non-delta property set for same-identity message.part.delta text events under the shared in-flight tail guard, byte and deadline accounting stay exact, and the batch-halt removal only attempts items that were previously dropped as unattempted.

Files Reviewed (11 files)
  • services/cloud-agent-next/src/sandbox-control/diagnostics.test.ts
  • services/cloud-agent-next/src/sandbox-control/session-forwarding.test.ts
  • services/cloud-agent-next/src/sandbox-control/session-forwarding.ts
  • services/cloud-agent-next/src/sandbox-session/SandboxSession.ts
  • services/cloud-agent-next/src/sandbox-session/session-message-queue.test.ts
  • services/cloud-agent-next/src/shared/sandbox-control-protocol.ts
  • services/cloud-agent-next/wrapper/src/control/control-event-outbox.test.ts
  • services/cloud-agent-next/wrapper/src/control/control-event-outbox.ts
  • services/cloud-agent-next/wrapper/src/control/control-event-transport.test.ts
  • services/cloud-agent-next/wrapper/src/control/sandbox-control-client.test.ts
  • services/cloud-agent-next/wrapper/src/control/sandbox-control-client.ts
Previous Review Summary (commit ee9f854)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit ee9f854)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Reviewed the outbox delta-merge rule and the new control-event diagnostics end to end; the merge predicate compares the full non-delta property set under a shared tail guard, byte accounting stays exact, and the halt diagnostic cannot surface the thrown value.

Files Reviewed (5 files)
  • services/cloud-agent-next/wrapper/src/control/control-event-outbox.ts
  • services/cloud-agent-next/wrapper/src/control/control-event-outbox.test.ts
  • services/cloud-agent-next/src/sandbox-session/SandboxSession.ts
  • services/cloud-agent-next/src/sandbox-session/session-message-queue.test.ts
  • services/cloud-agent-next/src/sandbox-control/diagnostics.test.ts

Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0

Review guidance: REVIEW.md from base branch main

…ed batch items

Three rejection paths in applySandboxControlEvent returned a bare
{ applied: false } and emitted no diagnostic, and a caught exception while
applying a batch item emitted nothing, so an event that did not apply could
not be attributed from logs alone.

Return the id-mismatch and child-lineage rejections through the existing
result() helper so they emit session_event_result, and emit one warn-level
session_event_batch_item_failed per caught batch item with its identity and
index.

A caught item records that item as unknown and the batch continues, so one
bad event can no longer discard the rest of the batch. Terminal events such
as session.turn.close and session.idle are therefore still applied when an
earlier item throws.

The item diagnostic never reads the thrown value and is built inside a
containing try/catch, so it cannot leak payload content or change the batch
result. Applied, rejected and pre-RPC unattempted outcomes and retry
semantics are unchanged.
…outbox

The outbox had one compaction rule, and it was a supersede rule keyed on an
entity id. message.part.delta carries an increment rather than a snapshot, so
it produced no key and could never be compacted: a delta burst grew the lane
one entry per delta until admission failed and the event was dropped with
queue_overflow at MAX_CONTROL_EVENT_OUTBOX_EVENTS.

Add an append rule beside the supersede rule. Adjacent same-part deltas for
field 'text' merge by concatenating delta, keeping the tail entry's receiptId,
sequence and preparedAt so the existing receipt identity still describes the
published frame. Both rules share the in-flight tail guard, so an entry that a
pending attempt will remove is never replaced.

A merged entry takes the newer member's deadlineAt rather than the older one.
Retaining the older deadline would expire a still-growing group and lose its
fresh text, which survives today because the newer delta would carry its own
deadline. The refresh is deliberate: an actively-merged group is bounded by the
outbox entry and byte limits instead of the 30s clock. Snapshot squash keeps
its previous deadline, so supersede semantics are unchanged.

Merging is declined when the merged payload would exceed
MAX_SANDBOX_CONTROL_FRAME_BYTES, and the delta is appended as its own entry
instead. That fallback is not unconditionally lossless: at the entry cap the
append can still be dropped as queue_overflow, which is correct because an
over-frame replacement was never sendable.

Merging is restricted to field 'text'; no wire protocol, DO, SDK or schema
change is involved.
…ation deadline

The per-session forward queue admitted at most 32 in-flight operations, so a
burst of batch frames, each carrying up to SANDBOX_EVENT_BATCH_MAX_ITEMS
events, could exhaust it and drop later frames.

Bound the forward queue with SANDBOX_CONTROL_FORWARD_OPERATION_LIMIT = 2048.
The existing frame budget (MAX_SESSION_FORWARD_BYTES) remains the memory
bound, and SANDBOX_CONTROL_OPERATION_LIMIT stays at 32 where it still guards
stop receipts and recovery arrays.

Raise MAX_CONTROL_EVENT_OUTBOX_EVENTS from 256 to 2048 so the wrapper outbox
and its receipt tracking share one entry budget, and raise
PUBLICATION_DEADLINE_MS from 30s to 60s so an in-flight publication is not
expired by a short reconnect.
@eshurakov
eshurakov force-pushed the eshurakov/grand-current branch from ee9f854 to 134561a Compare September 17, 2026 18:47
outcomes.push({ receiptId: item.receiptId, status: 'unattempted' });
continue;
}
for (const [index, item] of input.items.entries()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bot: Continuing after an unknown item can apply same-session events out of order.

Suggested fix: Restore the halt guard after the catch: leave the throwing item as unknown, mark every remaining item unattempted, and emit one bounded session_event_batch_halted diagnostic for the failed item plus suffix shape. This keeps later deltas/snapshots/completions from being applied after a predecessor whose mutation outcome is indeterminate. The changed test at session-message-queue.test.ts:2226-2275 should again assert that the suffix is unattempted rather than applied.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants