Skip to content

Bound Workbench producer / completed-envelope render history end to end #681

Closed

Description

@ScriptedAlchemy

Priority and scope

P2 — memory and response-size reliability. Follow-up to #666 and #600. Coordinate with production streaming #686, but keep streaming latency and retained-history bounds as separate acceptance criteria.

Audited commit: b435f7b9179271cbff81d3e40d14ee342cbd65dd.

Origin: owner-requested deep-dive, 2026-09-06. Expanded with the complete producer/final/history findings.

Evidence level: source inspection establishes that the replay limit does not bound all retained invocation data. The reviewer has not reproduced an out-of-memory failure or claimed that every renderer has no other internal limit.

Verified gap

The 256-render-event bound applies to one live replay buffer, not the whole invocation lifecycle:

  • route-invocation-production.ts: renderCompiled() pushes render events into an array and returns that collection.
  • route-invocation-child.ts: the completed child result carries its event collection through IPC.
  • route-invocation-service.ts: successful invocations retain events: child.events; completed history and the final stream envelope retain that result. #publishStream() only evicts live render messages.

The final envelope can therefore restore the history that replay eviction discarded. Limiting the number of completed invocations does not establish a bound on retained events or bytes inside each invocation.

Required behavior

Use one documented retention policy across producer collection, child IPC, live replay, completed invocations, history reads, final stream envelopes, and browser replay. Keep the latest/final document separately from disposable intermediate history. Preserve outcome, correlation, and an explicit truncation indication.

Address retained bytes as well as event counts. Handle oversized final documents separately and explicitly; do not silently truncate valid results or introduce an unjustified universal plugin-result limit merely to cap intermediate history.

Acceptance

  • Produce substantially more than 256 events through an actual compiled child, not only a mocked renderChild callback.
  • Assert producer-retained events and completed invocation.events remain bounded.
  • Assert GET/read/history and final-stream responses do not rehydrate the full discarded history.
  • Preserve a single truthful truncation indication and the correct final document/outcome/correlation.
  • Exercise retained-byte behavior with large intermediate snapshots, not only many tiny events.
  • Reconnect after eviction and verify a coherent latest document or an explicit replay limitation.
  • Cancel after the shell event has been evicted and after a long progress sequence; retain intelligible partial evidence and correct cancellation status.
  • Error, cancellation, and completion paths release disposable producer/IPC buffers and preserve process-tree cleanup.
  • Preserve existing live replay behavior; a replay-only test is not sufficient proof of end-to-end bounds.

Test owners

  • packages/agent-bundle/tests/route-invocation-service.test.ts
  • packages/agent-bundle/tests/route-invocation-dev-server.test.ts
  • packages/workbench/tests/invocation-model.test.ts
  • packages/workbench/tests/audiobook-curator.acceptance.e2e.test.ts

Non-goals

No durable trace database, remote telemetry, new orchestration layer, or changes to plugin business behavior. Executable selection is #680; production Flight delivery is #686.

Activity

  1. ScriptedAlchemy commented on Sep 6, 2026

    @ScriptedAlchemy
    OwnerAuthor

    Coordination with #686 (streaming) — #681 owns retention, #686 owns Flight delivery.

    Retention policy lands in one place: RENDER_EVENT_RETENTION + retainRenderEvent in packages/agent-bundle/src/dev/routes/route-invocation-result.ts (re-exported from contracts/invocations.ts for the Workbench). Newest 256 render events, ≤ 1 MiB of JSON, oldest-first eviction, newest event never evicted. Applied by the render child (renderCompiled), the child's IPC reply, the service's live-replay window, the completed envelope (events + evictedEvents), and the Workbench live buffer. The latest document is tracked outside the window so cancellation keeps it after the shell was evicted.

    Ask for #686: when the MCP/event worker starts forwarding Flight chunks, keep feeding publishRender/the dispatcher one event at a time and do not add a second buffer — the service already bounds what it retains, and #stream in route-invocation-routes.ts now paces the replay by socket drain (the live-consumer queue limits still apply to live messages). Slow-consumer policy for live delivery stays #686's call; retention is settled here.

  2. ScriptedAlchemy commented on Sep 6, 2026

    @ScriptedAlchemy
    OwnerAuthor

    Coordination from #686 / #718: the generated MCP/event Flight workers now post chunk/end/error instead of one buffered complete. On the Workbench side nothing new is retained — chunks feed the existing dispatcher and events still go through publishRender one at a time, so retainRenderEvent (#699) bounds them unchanged whichever PR lands first (no overlapping hunks in route-invocation-production.ts; #718 only drops complete from the worker message set and adds a stream cancel hook). Slow live consumers stay bounded by createFlightDemand and the #stream drain pacing; no new queue.

  3. ScriptedAlchemy commented on Sep 6, 2026

    @ScriptedAlchemy
    OwnerAuthor

    Duplicate resolved: #699 closed, #715 survives as the single retention policy (route-invocation-render-history.ts: newest 256 events and ≤ 2 MiB serialized, pinned newest event and newest document-bearing event; applied to the child/IPC producer, service replay, completed/cancelled/failed envelopes, GET/read, history, final, and the Workbench live window). #699's unique tests — real compiled-child reconnect after the shell was evicted and cancel after eviction, history-ring eviction, pinned-newest module test, full-window HTTP replay — were ported into #715. #718 (#686 streaming) was told how to resolve against it.

  4. added a commit that references this issue on Sep 6, 2026
    3ddbead
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions