Skip to content

fix(agent): bound managed staging by reclaiming superseded deltas - #4610

Merged
Yeachan-Heo merged 2 commits into
Yeachan-Heo:devfrom
chlee1001:fix/managed-provisional-buffer-quadratic
Aug 18, 2026
Merged

fix(agent): bound managed staging by reclaiming superseded deltas#4610
Yeachan-Heo merged 2 commits into
Yeachan-Heo:devfrom
chlee1001:fix/managed-provisional-buffer-quadratic

Conversation

@chlee1001

@chlee1001 chlee1001 commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

What

Managed fallback stages a whole attempt in ManagedAttemptTransaction so a discarded one stays unobservable. Every staged streaming frame carries the WHOLE accumulated partial twice — once as message, once as assistantMessageEvent.partial — so staged bytes grow with the square of the response length.

Reaching the cap now reclaims the staged *_delta increments first; only a batch that still cannot fit fails. Each increment's complete value is re-published by its block's *_end frame and by the terminal message_end / done frames, and those are retained, so the replayed sequence still delivers the full turn.

Unchanged by design:

  • nothing is published early — the batch stays all-or-nothing, so a discarded attempt remains unobservable
  • the local overflow still carries no transport facts, so it never consumes or rotates the fallback chain
  • a single oversized event keeps its pre-clone rejection (witnessReads === 1 contract)
  • per-frame event-time distinctness is untouched (replays mutating provider partials as event-time snapshots and the degraded-snapshot sibling still pass unmodified)

Why

A reasoning-heavy turn of a few thousand tokens crossed the 16 MiB cap and killed the run with Managed fallback attempt exceeded the provisional event buffer limit, even though no single event came close to the cap and the attempt itself was healthy.

Measured on 0.13.3 before the fix, driving the real agentLoop with a mock provider:

stream before after
4-char deltas, 7,200 chars ok ok
4-char deltas, 8,000 chars (~2k tokens) dies ok
8-char deltas, 11,200 chars dies ok
4-char deltas, 80,000 chars (20,000 deltas, also over the 10,000-event cap) dies ok
same stream with fallbackManaged: false ok ok

Field case: session with profile chain zai/glm-5.2:medium -> commandcode-goat/meta/muse-spark-1.2-contributor. Three consecutive turns died on this error; the turns that succeeded were 1,636 and 1,731 output tokens, and the dead ones streamed 45-70s before reporting usage=0.

Related, but neither covers this:

Testing

Added completes a long managed stream by reclaiming superseded increments instead of failing: 200 x 1 KiB increments stage ~40 MiB uncompacted. It fails on the parent commit with the exact user-facing string, and passes with the fix:

Received: "Managed fallback attempt exceeded the provisional event buffer limit"
(fail) managed attempt transaction > completes a long managed stream by reclaiming superseded increments instead of failing

It also pins that the fallback chain is never consumed (outcomeCalls === 0), that increments were actually reclaimed (fewer replayed text_delta than pushed), and that the retained path still delivers the block's complete content (text_start / text_end present, text_end.content is the full text).

  • bun test packages/agent/test/managed-attempt-transaction.test.ts -> 55 pass / 0 fail (all 54 pre-existing assertions unchanged)
  • bun test packages/agent/test/ -> 783 pass / 0 fail
  • bun --cwd=packages/agent run check -> biome + tsc clean

Scope note on the root bun run check:ts: it does not pass on a pristine dev worktree either, before this change — packages/coding-agent/src/internal-urls/gjc-protocol.ts(21,51): error TS2307: Cannot find module './docs-index.generated' (generated module absent until generate-docs-index runs). A second failure, telegram-daemon-generation-guard.test.ts reporting ENOENT for a file that exists, appears only under the parallel run and passes standalone in the same tree. Neither touches packages/agent.

GJC verdict

gajae.pr-review-verdict.v1 merge-approved sha256:d8d9671d17c84116ae9c22c90f36f348cf8d4df4131cdfd7a3c257bd2b931962 reviewer:architect reviewer-id:Yeachan-Heo evidence:independent adversarial review; repro on parent c83ffe3d fails with exact user-facing string, head passes; bun test packages/agent/test/ 783/0 on cc48e54b and on fix-forward f83d08b596; bun --cwd=packages/agent run check clean; changelog-history-guard pass; exact-head APPROVED review 2026-08-18T00:23:34Z

  • Target branch is dev
  • bun check passes — scoped bun --cwd=packages/agent run check is clean; the root check is red on pristine dev for the unrelated reasons above
  • Tested locally
  • CHANGELOG updated (if user-facing)
  • Verdict above matches the exact PR head (f83d08b), not an earlier commit

Maintainer fix-forward (2026-08-18): dev rolled 0.14.0 after this PR's base, so merging the original head verbatim would have placed the new changelog bullet inside the released ## [0.14.0] section. Head is advanced by one merge commit (f83d08b596dcccff5a6e070ee1ecf3da065f0cea) merging dev 6696988b6d in and resolving packages/agent/CHANGELOG.md so the bullet sits under ## [Unreleased] (diff vs dev: exactly one insertion; changelog-history-guard passes). The original contributor commit cc48e54b0d is preserved verbatim as the merge's first parent — code and tests are untouched. Digest above is recomputed for the new exact head with the gate's own command (git diff --binary --full-index --no-ext-diff <merge-base>...<head>).

Every frame staged by the managed attempt transaction carries the whole
accumulated partial twice (as `message` and as
`assistantMessageEvent.partial`), so staged bytes grow quadratically with
the streamed response length. A reasoning-heavy turn of a few thousand
tokens therefore exhausted the 16 MiB provisional cap and terminated the
run with `Managed fallback attempt exceeded the provisional event buffer
limit`, even though no single event came close to the cap and the attempt
itself was healthy. Raising the cap only moves the threshold, because the
growth is quadratic.

Reaching the cap now reclaims the staged `*_delta` increments first. Each
increment's complete value is re-published by its block's retained `*_end`
frame and by the terminal `message_end` / `done` frames, so the retained
replay still delivers the full turn. Only a batch that still cannot fit
after reclamation fails.

Attempt semantics are unchanged: nothing is published early, so a
discarded attempt stays unobservable; the local overflow still carries no
transport facts and never consumes the fallback chain; and a single
oversized event keeps its pre-clone rejection.
Reconstruct PR Yeachan-Heo#4610 onto dev 6696988: keep the managed-staging compaction fix's changelog entry under [Unreleased]; dev rolled 0.14.0 after the PR base, so the auto-merge would otherwise land the new bullet inside the released 0.14.0 section.

@Yeachan-Heo Yeachan-Heo left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Independent adversarial review of PR #4610 (fix(agent): bound managed staging by reclaiming superseded deltas).

Defect independently reproduced: applied only the PR's regression test to parent commit c83ffe3 and it fails with the exact user-facing string Managed fallback attempt exceeded the provisional event buffer limit; on the fix head it passes. Quadratic staged-byte growth (each staged frame carries the whole accumulated partial twice) is real, and managed fallback is the default session path whenever a fallback chain has >= 2 entries, so this kills ordinary long reasoning turns.

Correctness audit of the compaction design: all four reclaimed delta types (text_delta, thinking_delta, reasoning_summary_delta, toolcall_delta) have their complete value re-published by retained frames — text_end/thinking_end/reasoning_summary_end carry full content, toolcall_end carries the full parsed tool call, and terminal done/message_end carry the full message (verified in packages/agent/src/proxy.ts). The committed message is built from the live provider partial, never from staged frames, so no content can be lost. Lossless staging path untouched. Attempt atomicity preserved: compaction never publishes, only frees accounting.

Verification on exact submitted head cc48e54: bun test packages/agent/test/ 783 pass / 0 fail (clean env; the single remote-compaction failure seen in a polluted shell is ambient OPENAI_BASE_URL leakage, unrelated and passing standalone), bun --cwd=packages/agent run check (biome + tsc) clean.

Verification on fix-forward head f83d08b (merge of cc48e54 into dev 6696988): agent suite 783/783, package check clean, bun scripts/changelog-history-guard.ts pass, targeted managed-attempt-transaction/agent-loop/verify-pr-verdict tests 112/112.

Maintainer fix-forward applied under maintainerCanModify (one merge commit, no code changes): dev rolled 0.14.0 after the PR base, so the original head's changelog entry would land inside the released section on merge. The merge resolves packages/agent/CHANGELOG.md so the new bullet sits under ## [Unreleased]; git diff origin/dev f83d08b5 -- packages/agent/CHANGELOG.md is exactly one insertion. Contributor commit cc48e54 is preserved verbatim as the first parent.

Advisory (non-blocking, strictly better than today's hard failure): on threshold-crossing turns the replayed delta stream becomes a subsequence, so chunk-folding consumers (e.g. ACP agent_message_chunk) see a suffix-only live stream for those turns; full content is still delivered by the retained *_end/message_end frames, and those turns previously failed the entire run.


[repo owner's gaebal-gajae (clawdbot) 🦞]

@Yeachan-Heo
Yeachan-Heo merged commit 44d7b6e into Yeachan-Heo:dev Aug 18, 2026
33 of 41 checks passed
Yeachan-Heo pushed a commit to Veritas-7/gajae-code that referenced this pull request Aug 18, 2026
…ble via env

Managed fallback stages streamed events in a provisional buffer whose caps
were hardcoded (10,000 events / 16 MiB). Reasoning-heavy streaming can trip
the cap during transient provider failures, and the resulting
ManagedAttemptBufferOverflowError terminates the whole agent turn — in gjc
team runs this leaves workers dead at the prompt (Yeachan-Heo#4618).

Expose both caps as operator knobs, read once per transaction:

- GJC_FALLBACK_MAX_STAGED_EVENTS (default 10000)
- GJC_FALLBACK_MAX_STAGED_BYTES (default 16 MiB)

Rebuilt onto current dev by the maintainer from the original submission
(a050ca4), resolving the overlap with
Yeachan-Heo#4610 (superseded-delta reclamation) semantically:

- keep the exported MANAGED_ATTEMPT_MAX_STAGED_* constants as the canonical
  defaults and feed them to $envpos from @gajae-code/utils, so exponents,
  hex, and unsafe integers can no longer silently unbind the memory guard
  (positive integer, digits only; anything else silently falls back to the
  default)
- read the caps through field initializers; the reclamation logic from
  Yeachan-Heo#4610 is untouched and still runs before the configurable caps reject a
  batch
- #wouldOverflow is shared by managed and non-managed lossless staging, so
  the knobs bound the provisional transaction in both modes; in non-managed
  sessions the cap only decides how much reasoning buffers before the batch
  flushes and streams through (Yeachan-Heo#4601)
- port the env tests without as-any casts: events-cap trip, bytes-cap trip,
  "0" -> default, and 3e0/0x3 digits-only rejection; scrub both env keys
  in afterEach so baseline tests stay host-env independent
- document both knobs in the agent/runtime toggles section with the
  dual-mode scope and silent-fallback contract; add the agent CHANGELOG
  [Unreleased] entry alongside the Yeachan-Heo#4610 sibling entry

Lore-id: 4602-fixforward
Constraint: managed overflow stays fatal/non-retryable (1b4fc60); knobs move only the threshold
Constraint: lossless flush-on-overflow (Yeachan-Heo#4601) and superseded-delta reclamation (Yeachan-Heo#4610) unchanged
Tested: bun test packages/agent/test/managed-attempt-transaction.test.ts (59 pass)
Tested: bun test packages/coding-agent/test/agent-session-fallback-attempt-transaction.test.ts (20 pass)
Tested: bun --cwd=packages/agent run check; bun --cwd=packages/agent run test (793 pass)
Tested: verify-gjc-state-writers --fail; changelog-history-guard; git diff --check
Confidence: high
Scope-risk: narrow
Reversibility: easy

Co-authored-by: Veritas-7 <koreacmc.kr@gmail.com>
Yeachan-Heo pushed a commit to Veritas-7/gajae-code that referenced this pull request Aug 18, 2026
…ble via env

Managed fallback stages streamed events in a provisional buffer whose caps
were hardcoded (10,000 events / 16 MiB). Reasoning-heavy streaming can trip
the cap during transient provider failures, and the resulting
ManagedAttemptBufferOverflowError terminates the whole agent turn — in gjc
team runs this leaves workers dead at the prompt (Yeachan-Heo#4618).

Expose both caps as operator knobs, read once per transaction:

- GJC_FALLBACK_MAX_STAGED_EVENTS (default 10000)
- GJC_FALLBACK_MAX_STAGED_BYTES (default 16 MiB)

Rebuilt onto current dev by the maintainer from the original submission
(a050ca4), resolving the overlap with
Yeachan-Heo#4610 (superseded-delta reclamation) semantically:

- keep the exported MANAGED_ATTEMPT_MAX_STAGED_* constants as the canonical
  defaults and feed them to $envpos from @gajae-code/utils, so exponents,
  hex, and unsafe integers can no longer silently unbind the memory guard
  (positive integer, digits only; anything else silently falls back to the
  default)
- read the caps through field initializers; the reclamation logic from
  Yeachan-Heo#4610 is untouched and still runs before the configurable caps reject a
  batch
- #wouldOverflow is shared by managed and non-managed lossless staging, so
  the knobs bound the provisional transaction in both modes; in non-managed
  sessions the cap only decides how much reasoning buffers before the batch
  flushes and streams through (Yeachan-Heo#4601)
- port the env tests without as-any casts: events-cap trip, bytes-cap trip,
  "0" -> default, and 3e0/0x3 digits-only rejection; scrub both env keys
  in afterEach so baseline tests stay host-env independent
- document both knobs in the agent/runtime toggles section with the
  dual-mode scope and silent-fallback contract; add the agent CHANGELOG
  [Unreleased] entry alongside the Yeachan-Heo#4610 sibling entry

Lore-id: 4602-fixforward
Constraint: managed overflow stays fatal/non-retryable (1b4fc60); knobs move only the threshold
Constraint: lossless flush-on-overflow (Yeachan-Heo#4601) and superseded-delta reclamation (Yeachan-Heo#4610) unchanged
Tested: bun test packages/agent/test/managed-attempt-transaction.test.ts (59 pass)
Tested: bun test packages/coding-agent/test/agent-session-fallback-attempt-transaction.test.ts (20 pass)
Tested: bun --cwd=packages/agent run check; bun --cwd=packages/agent run test (793 pass)
Tested: verify-gjc-state-writers --fail; changelog-history-guard; git diff --check
Confidence: high
Scope-risk: narrow
Reversibility: easy

Co-authored-by: Veritas-7 <koreacmc.kr@gmail.com>
Yeachan-Heo pushed a commit to Veritas-7/gajae-code that referenced this pull request Aug 18, 2026
…ble via env

Managed fallback stages streamed events in a provisional buffer whose caps
were hardcoded (10,000 events / 16 MiB). Reasoning-heavy streaming can trip
the cap during transient provider failures, and the resulting
ManagedAttemptBufferOverflowError terminates the whole agent turn — in gjc
team runs this leaves workers dead at the prompt (Yeachan-Heo#4618).

Expose both caps as operator knobs, read once per transaction:

- GJC_FALLBACK_MAX_STAGED_EVENTS (default 10000)
- GJC_FALLBACK_MAX_STAGED_BYTES (default 16 MiB)

Rebuilt onto current dev by the maintainer from the original submission
(a050ca4), resolving the overlap with
Yeachan-Heo#4610 (superseded-delta reclamation) semantically:

- keep the exported MANAGED_ATTEMPT_MAX_STAGED_* constants as the canonical
  defaults and feed them to $envpos from @gajae-code/utils, so exponents,
  hex, and unsafe integers can no longer silently unbind the memory guard
  (positive integer, digits only; anything else silently falls back to the
  default)
- read the caps through field initializers; the reclamation logic from
  Yeachan-Heo#4610 is untouched and still runs before the configurable caps reject a
  batch
- #wouldOverflow is shared by managed and non-managed lossless staging, so
  the knobs bound the provisional transaction in both modes; in non-managed
  sessions the cap only decides how much reasoning buffers before the batch
  flushes and streams through (Yeachan-Heo#4601)
- port the env tests without as-any casts: events-cap trip, bytes-cap trip,
  "0" -> default, and 3e0/0x3 digits-only rejection; scrub both env keys
  in afterEach so baseline tests stay host-env independent
- document both knobs in the agent/runtime toggles section with the
  dual-mode scope and silent-fallback contract; add the agent CHANGELOG
  [Unreleased] entry alongside the Yeachan-Heo#4610 sibling entry

Lore-id: 4602-fixforward
Constraint: managed overflow stays fatal/non-retryable (1b4fc60); knobs move only the threshold
Constraint: lossless flush-on-overflow (Yeachan-Heo#4601) and superseded-delta reclamation (Yeachan-Heo#4610) unchanged
Tested: bun test packages/agent/test/managed-attempt-transaction.test.ts (59 pass)
Tested: bun test packages/coding-agent/test/agent-session-fallback-attempt-transaction.test.ts (20 pass)
Tested: bun --cwd=packages/agent run check; bun --cwd=packages/agent run test (793 pass)
Tested: verify-gjc-state-writers --fail; changelog-history-guard; git diff --check
Confidence: high
Scope-risk: narrow
Reversibility: easy

Co-authored-by: Veritas-7 <koreacmc.kr@gmail.com>
Yeachan-Heo pushed a commit to Veritas-7/gajae-code that referenced this pull request Aug 18, 2026
…ble via env

Managed fallback stages streamed events in a provisional buffer whose caps
were hardcoded (10,000 events / 16 MiB). Reasoning-heavy streaming can trip
the cap during transient provider failures, and the resulting
ManagedAttemptBufferOverflowError terminates the whole agent turn — in gjc
team runs this leaves workers dead at the prompt (Yeachan-Heo#4618).

Expose both caps as operator knobs, read once per transaction:

- GJC_FALLBACK_MAX_STAGED_EVENTS (default 10000)
- GJC_FALLBACK_MAX_STAGED_BYTES (default 16 MiB)

Rebuilt onto current dev by the maintainer from the original submission
(a050ca4), resolving the overlap with
Yeachan-Heo#4610 (superseded-delta reclamation) semantically:

- keep the exported MANAGED_ATTEMPT_MAX_STAGED_* constants as the canonical
  defaults and feed them to $envpos from @gajae-code/utils, so exponents,
  hex, and unsafe integers can no longer silently unbind the memory guard
  (positive integer, digits only; anything else silently falls back to the
  default)
- read the caps through field initializers; the reclamation logic from
  Yeachan-Heo#4610 is untouched and still runs before the configurable caps reject a
  batch
- #wouldOverflow is shared by managed and non-managed lossless staging, so
  the knobs bound the provisional transaction in both modes; in non-managed
  sessions the cap only decides how much reasoning buffers before the batch
  flushes and streams through (Yeachan-Heo#4601)
- port the env tests without as-any casts: events-cap trip, bytes-cap trip,
  "0" -> default, and 3e0/0x3 digits-only rejection; scrub both env keys
  in afterEach so baseline tests stay host-env independent
- document both knobs in the agent/runtime toggles section with the
  dual-mode scope and silent-fallback contract; add the agent CHANGELOG
  [Unreleased] entry alongside the Yeachan-Heo#4610 sibling entry

Lore-id: 4602-fixforward
Constraint: managed overflow stays fatal/non-retryable (1b4fc60); knobs move only the threshold
Constraint: lossless flush-on-overflow (Yeachan-Heo#4601) and superseded-delta reclamation (Yeachan-Heo#4610) unchanged
Tested: bun test packages/agent/test/managed-attempt-transaction.test.ts (59 pass)
Tested: bun test packages/coding-agent/test/agent-session-fallback-attempt-transaction.test.ts (20 pass)
Tested: bun --cwd=packages/agent run check; bun --cwd=packages/agent run test (793 pass)
Tested: verify-gjc-state-writers --fail; changelog-history-guard; git diff --check
Confidence: high
Scope-risk: narrow
Reversibility: easy

Co-authored-by: Veritas-7 <koreacmc.kr@gmail.com>
Yeachan-Heo pushed a commit that referenced this pull request Aug 18, 2026
…ow (#4618)

ManagedAttemptBufferOverflowError surfaced as one static sentence, so a
subagent killed by the provisional staging cap was indistinguishable from
a provider or context-window failure — the exact misread reported in
recordored." and the error text carried no stage, counts, or limits.

The overflow now reports its shape everywhere it can reach:

- agent: the typed error carries stage, staged event/byte counts at
  rejection, and both caps; the message keeps its stable prefix (session
  retry policy prefix-classifies on it) and appends a shape-only
  parenthetical stating this is a local staging-buffer limit that
  reproduces on re-issue, not a provider/context-window failure. Baked
  into the error itself because the non-retryable local exit path
  surfaces the thrown error, not the managedFailureMessage wrapper.
- coding-agent: the executor retains a bounded, redaction-safe
  localErrorSummary (closed kind set, sanitized summary) from the
  subagent's terminal assistant error; receipt preview, errorSummary,
  subagent tool output, and the await renderer name the local kind and
  carry the diagnostic instead of the generic error preview.

Does not touch cap configurability (#4602) or superseded-delta
reclamation (#4610).

Lore-id: 4618-buffer-diagnostics
Constraint: message prefix must stay byte-identical for session prefix classification
Constraint: diagnostics must be shape-only (no provider/prompt text can reach a parent receipt)
Constraint: do not duplicate #4602 configurability or #4610 delta reclamation
Rejected: enriching managedFailureMessage only | the non-retryable local exit surfaces the thrown error, not the wrapper
Rejected: enlarging the caps | workaround path ships with #4602
Confidence: high
Scope-risk: moderate
Reversibility: trivial
Tested: byte-cap + event-cap surfaced diagnostics (agent), propagation, redaction, foreign-kind degradation, generic-error fallback isolation (coding-agent)
Not-tested: live provider delta-storm reproduction
Closes: #4618
Yeachan-Heo pushed a commit to Veritas-7/gajae-code that referenced this pull request Aug 18, 2026
…ble via env

Managed fallback stages streamed events in a provisional buffer whose caps
were hardcoded (10,000 events / 16 MiB). Reasoning-heavy streaming can trip
the cap during transient provider failures, and the resulting
ManagedAttemptBufferOverflowError terminates the whole agent turn — in gjc
team runs this leaves workers dead at the prompt (Yeachan-Heo#4618).

Expose both caps as operator knobs, read once per transaction:

- GJC_FALLBACK_MAX_STAGED_EVENTS (default 10000, ceiling 10000000)
- GJC_FALLBACK_MAX_STAGED_BYTES (default 16 MiB, ceiling 4 GiB)

Rebuilt onto current dev by the maintainer from the original submission
(a050ca4), resolving the overlap with
Yeachan-Heo#4610 (superseded-delta reclamation) semantically:

- keep the exported MANAGED_ATTEMPT_MAX_STAGED_* constants as the canonical
  defaults and feed them to $envpos from @gajae-code/utils, so exponents,
  hex, and unsafe integers can no longer silently unbind the memory guard
  (positive integer, digits only; anything else silently falls back to the
  default)
- read the caps through field initializers; the reclamation logic from
  Yeachan-Heo#4610 is untouched and still runs before the configurable caps reject a
  batch
- #wouldOverflow is shared by managed and non-managed lossless staging, so
  the knobs bound the provisional transaction in both modes; in non-managed
  sessions the cap only decides how much reasoning buffers before the batch
  flushes and streams through (Yeachan-Heo#4601)
- port the env tests without as-any casts: events-cap trip, bytes-cap trip,
  "0" -> default, and 3e0/0x3 digits-only rejection; scrub both env keys
  in afterEach so baseline tests stay host-env independent
- document both knobs in the agent/runtime toggles section with the
  dual-mode scope and silent-fallback contract; add the agent CHANGELOG
  [Unreleased] entry alongside the Yeachan-Heo#4610 sibling entry

Lore-id: 4602-fixforward
Constraint: managed overflow stays fatal/non-retryable (1b4fc60); knobs move only the threshold
Constraint: hard ceilings clamp above-ceiling overrides with a warning (review: the guard must never be disableable; GJC_SESSION_CONTEXT_BUDGET_BYTES convention)
Constraint: lossless flush-on-overflow (Yeachan-Heo#4601) and superseded-delta reclamation (Yeachan-Heo#4610) unchanged
Tested: bun test packages/agent/test/managed-attempt-transaction.test.ts (61 pass, incl. ceiling clamp + zero/negative/non-numeric fallback)
Tested: bun test packages/coding-agent/test/agent-session-fallback-attempt-transaction.test.ts (20 pass)
Tested: bun --cwd=packages/agent run check; bun --cwd=packages/agent run test (793 pass)
Tested: verify-gjc-state-writers --fail; changelog-history-guard; git diff --check
Confidence: high
Scope-risk: narrow
Reversibility: easy

Co-authored-by: Veritas-7 <koreacmc.kr@gmail.com>
Yeachan-Heo pushed a commit that referenced this pull request Aug 18, 2026
…ow (#4618)

ManagedAttemptBufferOverflowError surfaced as one static sentence, so a
subagent killed by the provisional staging cap was indistinguishable from
a provider or context-window failure — the exact misread reported in
recordored." and the error text carried no stage, counts, or limits.

The overflow now reports its shape everywhere it can reach:

- agent: the typed error carries stage, staged event/byte counts at
  rejection, and both caps; the message keeps its stable prefix (session
  retry policy prefix-classifies on it) and appends a shape-only
  parenthetical stating this is a local staging-buffer limit that
  reproduces on re-issue, not a provider/context-window failure. Baked
  into the error itself because the non-retryable local exit path
  surfaces the thrown error, not the managedFailureMessage wrapper.
- coding-agent: the executor retains a bounded, redaction-safe
  localErrorSummary (closed kind set, sanitized summary) from the
  subagent's terminal assistant error; receipt preview, errorSummary,
  subagent tool output, and the await renderer name the local kind and
  carry the diagnostic instead of the generic error preview.

Does not touch cap configurability (#4602) or superseded-delta
reclamation (#4610).

Lore-id: 4618-buffer-diagnostics
Constraint: message prefix must stay byte-identical for session prefix classification
Constraint: diagnostics must be shape-only (no provider/prompt text can reach a parent receipt)
Constraint: do not duplicate #4602 configurability or #4610 delta reclamation
Rejected: enriching managedFailureMessage only | the non-retryable local exit surfaces the thrown error, not the wrapper
Rejected: enlarging the caps | workaround path ships with #4602
Confidence: high
Scope-risk: moderate
Reversibility: trivial
Tested: byte-cap + event-cap surfaced diagnostics (agent), propagation, redaction, foreign-kind degradation, generic-error fallback isolation (coding-agent)
Not-tested: live provider delta-storm reproduction
Closes: #4618
Yeachan-Heo pushed a commit to Veritas-7/gajae-code that referenced this pull request Aug 18, 2026
…ble via env

Managed fallback stages streamed events in a provisional buffer whose caps
were hardcoded (10,000 events / 16 MiB). Reasoning-heavy streaming can trip
the cap during transient provider failures, and the resulting
ManagedAttemptBufferOverflowError terminates the whole agent turn — in gjc
team runs this leaves workers dead at the prompt (Yeachan-Heo#4618).

Expose both caps as operator knobs, read once per transaction:

- GJC_FALLBACK_MAX_STAGED_EVENTS (default 10000, ceiling 10000000)
- GJC_FALLBACK_MAX_STAGED_BYTES (default 16 MiB, ceiling 4 GiB)

Rebuilt onto current dev by the maintainer from the original submission
(a050ca4), resolving the overlap with
Yeachan-Heo#4610 (superseded-delta reclamation) semantically:

- keep the exported MANAGED_ATTEMPT_MAX_STAGED_* constants as the canonical
  defaults and feed them to $envpos from @gajae-code/utils, so exponents,
  hex, and unsafe integers can no longer silently unbind the memory guard
  (positive integer, digits only; anything else silently falls back to the
  default)
- read the caps through field initializers; the reclamation logic from
  Yeachan-Heo#4610 is untouched and still runs before the configurable caps reject a
  batch
- #wouldOverflow is shared by managed and non-managed lossless staging, so
  the knobs bound the provisional transaction in both modes; in non-managed
  sessions the cap only decides how much reasoning buffers before the batch
  flushes and streams through (Yeachan-Heo#4601)
- port the env tests without as-any casts: events-cap trip, bytes-cap trip,
  "0" -> default, and 3e0/0x3 digits-only rejection; scrub both env keys
  in afterEach so baseline tests stay host-env independent
- document both knobs in the agent/runtime toggles section with the
  dual-mode scope and silent-fallback contract; add the agent CHANGELOG
  [Unreleased] entry alongside the Yeachan-Heo#4610 sibling entry

Lore-id: 4602-fixforward
Constraint: managed overflow stays fatal/non-retryable (1b4fc60); knobs move only the threshold
Constraint: hard ceilings clamp above-ceiling overrides with a warning (review: the guard must never be disableable; GJC_SESSION_CONTEXT_BUDGET_BYTES convention)
Constraint: lossless flush-on-overflow (Yeachan-Heo#4601) and superseded-delta reclamation (Yeachan-Heo#4610) unchanged
Tested: bun test packages/agent/test/managed-attempt-transaction.test.ts (61 pass, incl. ceiling clamp + zero/negative/non-numeric fallback)
Tested: bun test packages/coding-agent/test/agent-session-fallback-attempt-transaction.test.ts (20 pass)
Tested: bun --cwd=packages/agent run check; bun --cwd=packages/agent run test (793 pass)
Tested: verify-gjc-state-writers --fail; changelog-history-guard; git diff --check
Confidence: high
Scope-risk: narrow
Reversibility: easy

Co-authored-by: Veritas-7 <koreacmc.kr@gmail.com>
Yeachan-Heo pushed a commit to Veritas-7/gajae-code that referenced this pull request Aug 18, 2026
…ble via env

Managed fallback stages streamed events in a provisional buffer whose caps
were hardcoded (10,000 events / 16 MiB). Reasoning-heavy streaming can trip
the cap during transient provider failures, and the resulting
ManagedAttemptBufferOverflowError terminates the whole agent turn — in gjc
team runs this leaves workers dead at the prompt (Yeachan-Heo#4618).

Expose both caps as operator knobs, read once per transaction:

- GJC_FALLBACK_MAX_STAGED_EVENTS (default 10000, ceiling 10000000)
- GJC_FALLBACK_MAX_STAGED_BYTES (default 16 MiB, ceiling 4 GiB)

Rebuilt onto current dev by the maintainer from the original submission
(a050ca4), resolving the overlap with
Yeachan-Heo#4610 (superseded-delta reclamation) semantically:

- keep the exported MANAGED_ATTEMPT_MAX_STAGED_* constants as the canonical
  defaults and feed them to $envpos from @gajae-code/utils, so exponents,
  hex, and unsafe integers can no longer silently unbind the memory guard
  (positive integer, digits only; anything else silently falls back to the
  default)
- read the caps through field initializers; the reclamation logic from
  Yeachan-Heo#4610 is untouched and still runs before the configurable caps reject a
  batch
- #wouldOverflow is shared by managed and non-managed lossless staging, so
  the knobs bound the provisional transaction in both modes; in non-managed
  sessions the cap only decides how much reasoning buffers before the batch
  flushes and streams through (Yeachan-Heo#4601)
- port the env tests without as-any casts: events-cap trip, bytes-cap trip,
  "0" -> default, and 3e0/0x3 digits-only rejection; scrub both env keys
  in afterEach so baseline tests stay host-env independent
- document both knobs in the agent/runtime toggles section with the
  dual-mode scope and silent-fallback contract; add the agent CHANGELOG
  [Unreleased] entry alongside the Yeachan-Heo#4610 sibling entry

Lore-id: 4602-fixforward
Constraint: managed overflow stays fatal/non-retryable (1b4fc60); knobs move only the threshold
Constraint: hard ceilings clamp above-ceiling overrides with a warning (review: the guard must never be disableable; GJC_SESSION_CONTEXT_BUDGET_BYTES convention)
Constraint: lossless flush-on-overflow (Yeachan-Heo#4601) and superseded-delta reclamation (Yeachan-Heo#4610) unchanged
Tested: bun test packages/agent/test/managed-attempt-transaction.test.ts (61 pass, incl. ceiling clamp + zero/negative/non-numeric fallback)
Tested: bun test packages/coding-agent/test/agent-session-fallback-attempt-transaction.test.ts (20 pass)
Tested: bun --cwd=packages/agent run check; bun --cwd=packages/agent run test (793 pass)
Tested: verify-gjc-state-writers --fail; changelog-history-guard; git diff --check
Confidence: high
Scope-risk: narrow
Reversibility: easy

Co-authored-by: Veritas-7 <koreacmc.kr@gmail.com>
pull Bot pushed a commit to nenyatech-mirror/gajae-code that referenced this pull request Aug 18, 2026
…achan-Heo#4610)

Managed fallback staged every streaming frame with the WHOLE accumulated partial carried twice (once as message, once as assistantMessageEvent.partial), so staged bytes grew quadratically with response length; a reasoning-heavy turn of a few thousand tokens crossed the 16 MiB provisional cap and killed the run with 'Managed fallback attempt exceeded the provisional event buffer limit' even though the attempt itself was healthy.

Reaching the cap now reclaims the staged *_delta increments first — each one's complete value is re-published by its block's retained *_end frame and by the terminal message_end/done frames — and only a batch that still cannot fit fails. Nothing is published early (discarded attempts stay unobservable), the overflow still carries no transport facts (fallback chain never consumed), and a single oversized event keeps its pre-clone rejection. Lossless staging is untouched.

Original fix and regression test by @chlee1001 (cc48e54); maintainer fix-forward merged dev 6696988 in to keep the changelog entry under [Unreleased] after the 0.14.0 roll (changelog-history-guard verified; released section byte-identical). Verified: regression test fails on parent c83ffe3 with the exact user-facing string and passes on head; bun test packages/agent/test/ 783/0; bun --cwd=packages/agent run check clean; Dev CI green on f83d08b.

Co-authored-by: Chaehyeon Lee <chlee1001@users.noreply.github.com>
(cherry picked from commit 44d7b6e)
Yeachan-Heo pushed a commit that referenced this pull request Aug 18, 2026
…ow (#4618)

ManagedAttemptBufferOverflowError surfaced as one static sentence, so a
subagent killed by the provisional staging cap was indistinguishable from
a provider or context-window failure — the exact misread reported in
recordored." and the error text carried no stage, counts, or limits.

The overflow now reports its shape everywhere it can reach:

- agent: the typed error carries stage, staged event/byte counts at
  rejection, and both caps; the message keeps its stable prefix (session
  retry policy prefix-classifies on it) and appends a shape-only
  parenthetical stating this is a local staging-buffer limit that
  reproduces on re-issue, not a provider/context-window failure. Baked
  into the error itself because the non-retryable local exit path
  surfaces the thrown error, not the managedFailureMessage wrapper.
- coding-agent: the executor retains a bounded, redaction-safe
  localErrorSummary (closed kind set, sanitized summary) from the
  subagent's terminal assistant error; receipt preview, errorSummary,
  subagent tool output, and the await renderer name the local kind and
  carry the diagnostic instead of the generic error preview.

Does not touch cap configurability (#4602) or superseded-delta
reclamation (#4610).

Lore-id: 4618-buffer-diagnostics
Constraint: message prefix must stay byte-identical for session prefix classification
Constraint: diagnostics must be shape-only (no provider/prompt text can reach a parent receipt)
Constraint: do not duplicate #4602 configurability or #4610 delta reclamation
Rejected: enriching managedFailureMessage only | the non-retryable local exit surfaces the thrown error, not the wrapper
Rejected: enlarging the caps | workaround path ships with #4602
Confidence: high
Scope-risk: moderate
Reversibility: trivial
Tested: byte-cap + event-cap surfaced diagnostics (agent), propagation, redaction, foreign-kind degradation, generic-error fallback isolation (coding-agent)
Not-tested: live provider delta-storm reproduction
Closes: #4618
Yeachan-Heo pushed a commit to Veritas-7/gajae-code that referenced this pull request Aug 18, 2026
…ble via env

Managed fallback stages streamed events in a provisional buffer whose caps
were hardcoded (10,000 events / 16 MiB). Reasoning-heavy streaming can trip
the cap during transient provider failures, and the resulting
ManagedAttemptBufferOverflowError terminates the whole agent turn — in gjc
team runs this leaves workers dead at the prompt (Yeachan-Heo#4618).

Expose both caps as operator knobs, read once per transaction:

- GJC_FALLBACK_MAX_STAGED_EVENTS (default 10000, ceiling 2000000)
- GJC_FALLBACK_MAX_STAGED_BYTES (default 16 MiB, ceiling 1 GiB)

Rebuilt onto current dev by the maintainer from the original submission
(a050ca4), resolving the overlap with

- keep the exported MANAGED_ATTEMPT_MAX_STAGED_* constants as the canonical
  defaults and feed them to $envpos from @gajae-code/utils, so exponents,
  hex, and unsafe integers can no longer silently unbind the memory guard
  (positive integer, digits only; anything else silently falls back to the
  default)
- read the caps through field initializers; the reclamation logic from
  Yeachan-Heo#4610 is untouched and still runs before the configurable caps reject a
  batch
- #wouldOverflow is shared by managed and non-managed lossless staging, so
  the knobs bound the provisional transaction in both modes; in non-managed
  sessions the cap only decides how much reasoning buffers before the batch
  flushes and streams through (Yeachan-Heo#4601)
- port the env tests without as-any casts: events-cap trip, bytes-cap trip,
  "0" -> default, and 3e0/0x3 digits-only rejection; scrub both env keys
  in afterEach so baseline tests stay host-env independent
- document both knobs in the agent/runtime toggles section with the
  dual-mode scope and silent-fallback contract; add the agent CHANGELOG
  [Unreleased] entry alongside the Yeachan-Heo#4610 sibling entry

Lore-id: 4602-fixforward
Constraint: managed overflow stays fatal/non-retryable (1b4fc60); knobs move only the threshold
Constraint: hard ceilings clamp above-ceiling overrides with a warning (review: the guard must never be disableable; GJC_SESSION_CONTEXT_BUDGET_BYTES convention)
Constraint: every retained batch item is measured and charged BEFORE retention — stageAssistantMessageEvent now counts its assistant pair, so actual retention cannot exceed the caps and the typed overflow fires before the allocation that would OOM (review 2)
Constraint: lossless flush-on-overflow (Yeachan-Heo#4601) and superseded-delta reclamation (Yeachan-Heo#4610) unchanged
Tested: bun test packages/agent/test/managed-attempt-transaction.test.ts (62 pass, incl. exact-at-ceiling + above-ceiling clamp, charged-batch adversarial growth, zero/negative/non-numeric fallback)
Tested: bun test packages/coding-agent/test/agent-session-fallback-attempt-transaction.test.ts (20 pass)
Tested: bun --cwd=packages/agent run check; bun --cwd=packages/agent run test (793 pass)
Tested: verify-gjc-state-writers --fail; changelog-history-guard; git diff --check
Confidence: high
Scope-risk: narrow
Reversibility: easy

Co-authored-by: Veritas-7 <koreacmc.kr@gmail.com>
Yeachan-Heo pushed a commit that referenced this pull request Aug 18, 2026
…ow (#4618)

ManagedAttemptBufferOverflowError surfaced as one static sentence, so a
subagent killed by the provisional staging cap was indistinguishable from
a provider or context-window failure — the exact misread reported in
recordored." and the error text carried no stage, counts, or limits.

The overflow now reports its shape everywhere it can reach:

- agent: the typed error carries stage, staged event/byte counts at
  rejection, and both caps; the message keeps its stable prefix (session
  retry policy prefix-classifies on it) and appends a shape-only
  parenthetical stating this is a local staging-buffer limit that
  reproduces on re-issue, not a provider/context-window failure. Baked
  into the error itself because the non-retryable local exit path
  surfaces the thrown error, not the managedFailureMessage wrapper.
- coding-agent: the executor retains a bounded, redaction-safe
  localErrorSummary (closed kind set, sanitized summary) from the
  subagent's terminal assistant error; receipt preview, errorSummary,
  subagent tool output, and the await renderer name the local kind and
  carry the diagnostic instead of the generic error preview.

Does not touch cap configurability (#4602) or superseded-delta
reclamation (#4610).

Lore-id: 4618-buffer-diagnostics
Constraint: message prefix must stay byte-identical for session prefix classification
Constraint: diagnostics must be shape-only (no provider/prompt text can reach a parent receipt)
Constraint: do not duplicate #4602 configurability or #4610 delta reclamation
Rejected: enriching managedFailureMessage only | the non-retryable local exit surfaces the thrown error, not the wrapper
Rejected: enlarging the caps | workaround path ships with #4602
Confidence: high
Scope-risk: moderate
Reversibility: trivial
Tested: byte-cap + event-cap surfaced diagnostics (agent), propagation, redaction, foreign-kind degradation, generic-error fallback isolation (coding-agent)
Not-tested: live provider delta-storm reproduction
Closes: #4618
Yeachan-Heo pushed a commit to Veritas-7/gajae-code that referenced this pull request Aug 18, 2026
…ble via env

Managed fallback stages streamed events in a provisional buffer whose caps
were hardcoded (10,000 events / 16 MiB). Reasoning-heavy streaming can trip
the cap during transient provider failures, and the resulting
ManagedAttemptBufferOverflowError terminates the whole agent turn — in gjc
team runs this leaves workers dead at the prompt (Yeachan-Heo#4618).

Expose both caps as operator knobs, read once per transaction:

- GJC_FALLBACK_MAX_STAGED_EVENTS (default 10000, ceiling 2000000)
- GJC_FALLBACK_MAX_STAGED_BYTES (default 16 MiB, ceiling 1 GiB)

Rebuilt onto current dev by the maintainer from the original submission
(a050ca4), resolving the overlap with

- keep the exported MANAGED_ATTEMPT_MAX_STAGED_* constants as the canonical
  defaults and feed them to $envpos from @gajae-code/utils, so exponents,
  hex, and unsafe integers can no longer silently unbind the memory guard
  (positive integer, digits only; anything else silently falls back to the
  default)
- read the caps through field initializers; the reclamation logic from
  Yeachan-Heo#4610 is untouched and still runs before the configurable caps reject a
  batch
- #wouldOverflow is shared by managed and non-managed lossless staging, so
  the knobs bound the provisional transaction in both modes; in non-managed
  sessions the cap only decides how much reasoning buffers before the batch
  flushes and streams through (Yeachan-Heo#4601)
- port the env tests without as-any casts: events-cap trip, bytes-cap trip,
  "0" -> default, and 3e0/0x3 digits-only rejection; scrub both env keys
  in afterEach so baseline tests stay host-env independent
- document both knobs in the agent/runtime toggles section with the
  dual-mode scope and silent-fallback contract; add the agent CHANGELOG
  [Unreleased] entry alongside the Yeachan-Heo#4610 sibling entry

Lore-id: 4602-fixforward
Constraint: managed overflow stays fatal/non-retryable (1b4fc60); knobs move only the threshold
Constraint: hard ceilings clamp above-ceiling overrides with a warning (review: the guard must never be disableable; GJC_SESSION_CONTEXT_BUDGET_BYTES convention)
Constraint: every retained batch item is measured and charged BEFORE retention — stageAssistantMessageEvent now counts its assistant pair, so actual retention cannot exceed the caps and the typed overflow fires before the allocation that would OOM (review 2)
Constraint: lossless flush-on-overflow (Yeachan-Heo#4601) and superseded-delta reclamation (Yeachan-Heo#4610) unchanged
Tested: bun test packages/agent/test/managed-attempt-transaction.test.ts (62 pass, incl. exact-at-ceiling + above-ceiling clamp, charged-batch adversarial growth, zero/negative/non-numeric fallback)
Tested: bun test packages/coding-agent/test/agent-session-fallback-attempt-transaction.test.ts (20 pass)
Tested: bun --cwd=packages/agent run check; bun --cwd=packages/agent run test (793 pass)
Tested: verify-gjc-state-writers --fail; changelog-history-guard; git diff --check
Confidence: high
Scope-risk: narrow
Reversibility: easy

Co-authored-by: Veritas-7 <koreacmc.kr@gmail.com>
Yeachan-Heo pushed a commit to Veritas-7/gajae-code that referenced this pull request Aug 18, 2026
…ble via env

Managed fallback stages streamed events in a provisional buffer whose caps
were hardcoded (10,000 events / 16 MiB). Reasoning-heavy streaming can trip
the cap during transient provider failures, and the resulting
ManagedAttemptBufferOverflowError terminates the whole agent turn — in gjc
team runs this leaves workers dead at the prompt (Yeachan-Heo#4618).

Expose both caps as operator knobs, read once per transaction:

- GJC_FALLBACK_MAX_STAGED_EVENTS (default 10000, ceiling 2000000)
- GJC_FALLBACK_MAX_STAGED_BYTES (default 16 MiB, ceiling 1 GiB)

Rebuilt onto current dev by the maintainer from the original submission
(a050ca4), resolving the overlap with

- keep the exported MANAGED_ATTEMPT_MAX_STAGED_* constants as the canonical
  defaults and feed them to $envpos from @gajae-code/utils, so exponents,
  hex, and unsafe integers can no longer silently unbind the memory guard
  (positive integer, digits only; anything else silently falls back to the
  default)
- read the caps through field initializers; the reclamation logic from
  Yeachan-Heo#4610 is untouched and still runs before the configurable caps reject a
  batch
- #wouldOverflow is shared by managed and non-managed lossless staging, so
  the knobs bound the provisional transaction in both modes; in non-managed
  sessions the cap only decides how much reasoning buffers before the batch
  flushes and streams through (Yeachan-Heo#4601)
- port the env tests without as-any casts: events-cap trip, bytes-cap trip,
  "0" -> default, and 3e0/0x3 digits-only rejection; scrub both env keys
  in afterEach so baseline tests stay host-env independent
- document both knobs in the agent/runtime toggles section with the
  dual-mode scope and silent-fallback contract; add the agent CHANGELOG
  [Unreleased] entry alongside the Yeachan-Heo#4610 sibling entry

Lore-id: 4602-fixforward
Constraint: managed overflow stays fatal/non-retryable (1b4fc60); knobs move only the threshold
Constraint: hard ceilings clamp above-ceiling overrides with a warning (review: the guard must never be disableable; GJC_SESSION_CONTEXT_BUDGET_BYTES convention)
Constraint: every retained batch item is measured and charged BEFORE retention — stageAssistantMessageEvent now counts its assistant pair, so actual retention cannot exceed the caps and the typed overflow fires before the allocation that would OOM (review 2)
Constraint: lossless flush-on-overflow (Yeachan-Heo#4601) and superseded-delta reclamation (Yeachan-Heo#4610) unchanged
Tested: bun test packages/agent/test/managed-attempt-transaction.test.ts (62 pass, incl. exact-at-ceiling + above-ceiling clamp, charged-batch adversarial growth, zero/negative/non-numeric fallback)
Tested: bun test packages/coding-agent/test/agent-session-fallback-attempt-transaction.test.ts (20 pass)
Tested: bun --cwd=packages/agent run check; bun --cwd=packages/agent run test (793 pass)
Tested: verify-gjc-state-writers --fail; changelog-history-guard; git diff --check
Confidence: high
Scope-risk: narrow
Reversibility: easy

Co-authored-by: Veritas-7 <koreacmc.kr@gmail.com>
Yeachan-Heo pushed a commit that referenced this pull request Aug 19, 2026
…ow (#4618)

ManagedAttemptBufferOverflowError surfaced as one static sentence, so a
subagent killed by the provisional staging cap was indistinguishable from
a provider or context-window failure — the exact misread reported in
recordored." and the error text carried no stage, counts, or limits.

The overflow now reports its shape everywhere it can reach:

- agent: the typed error carries stage, staged event/byte counts at
  rejection, and both caps; the message keeps its stable prefix (session
  retry policy prefix-classifies on it) and appends a shape-only
  parenthetical stating this is a local staging-buffer limit that
  reproduces on re-issue, not a provider/context-window failure. Baked
  into the error itself because the non-retryable local exit path
  surfaces the thrown error, not the managedFailureMessage wrapper.
- coding-agent: the executor retains a bounded, redaction-safe
  localErrorSummary (closed kind set, sanitized summary) from the
  subagent's terminal assistant error; receipt preview, errorSummary,
  subagent tool output, and the await renderer name the local kind and
  carry the diagnostic instead of the generic error preview.

Does not touch cap configurability (#4602) or superseded-delta
reclamation (#4610).

Lore-id: 4618-buffer-diagnostics
Constraint: message prefix must stay byte-identical for session prefix classification
Constraint: diagnostics must be shape-only (no provider/prompt text can reach a parent receipt)
Constraint: do not duplicate #4602 configurability or #4610 delta reclamation
Rejected: enriching managedFailureMessage only | the non-retryable local exit surfaces the thrown error, not the wrapper
Rejected: enlarging the caps | workaround path ships with #4602
Confidence: high
Scope-risk: moderate
Reversibility: trivial
Tested: byte-cap + event-cap surfaced diagnostics (agent), propagation, redaction, foreign-kind degradation, generic-error fallback isolation (coding-agent)
Not-tested: live provider delta-storm reproduction
Closes: #4618
Yeachan-Heo pushed a commit that referenced this pull request Aug 20, 2026
…ow (#4618)

ManagedAttemptBufferOverflowError surfaced as one static sentence, so a
subagent killed by the provisional staging cap was indistinguishable from
a provider or context-window failure — the exact misread reported in
recordored." and the error text carried no stage, counts, or limits.

The overflow now reports its shape everywhere it can reach:

- agent: the typed error carries stage, staged event/byte counts at
  rejection, and both caps; the message keeps its stable prefix (session
  retry policy prefix-classifies on it) and appends a shape-only
  parenthetical stating this is a local staging-buffer limit that
  reproduces on re-issue, not a provider/context-window failure. Baked
  into the error itself because the non-retryable local exit path
  surfaces the thrown error, not the managedFailureMessage wrapper.
- coding-agent: the executor retains a bounded, redaction-safe
  localErrorSummary (closed kind set, sanitized summary) from the
  subagent's terminal assistant error; receipt preview, errorSummary,
  subagent tool output, and the await renderer name the local kind and
  carry the diagnostic instead of the generic error preview.

Does not touch cap configurability (#4602) or superseded-delta
reclamation (#4610).

Lore-id: 4618-buffer-diagnostics
Constraint: message prefix must stay byte-identical for session prefix classification
Constraint: diagnostics must be shape-only (no provider/prompt text can reach a parent receipt)
Constraint: do not duplicate #4602 configurability or #4610 delta reclamation
Rejected: enriching managedFailureMessage only | the non-retryable local exit surfaces the thrown error, not the wrapper
Rejected: enlarging the caps | workaround path ships with #4602
Confidence: high
Scope-risk: moderate
Reversibility: trivial
Tested: byte-cap + event-cap surfaced diagnostics (agent), propagation, redaction, foreign-kind degradation, generic-error fallback isolation (coding-agent)
Not-tested: live provider delta-storm reproduction
Closes: #4618
Yeachan-Heo pushed a commit that referenced this pull request Aug 20, 2026
…ow (#4618)

ManagedAttemptBufferOverflowError surfaced as one static sentence, so a
subagent killed by the provisional staging cap was indistinguishable from
a provider or context-window failure — the exact misread reported in
recordored." and the error text carried no stage, counts, or limits.

The overflow now reports its shape everywhere it can reach:

- agent: the typed error carries stage, staged event/byte counts at
  rejection, and both caps; the message keeps its stable prefix (session
  retry policy prefix-classifies on it) and appends a shape-only
  parenthetical stating this is a local staging-buffer limit that
  reproduces on re-issue, not a provider/context-window failure. Baked
  into the error itself because the non-retryable local exit path
  surfaces the thrown error, not the managedFailureMessage wrapper.
- coding-agent: the executor retains a bounded, redaction-safe
  localErrorSummary (closed kind set, sanitized summary) from the
  subagent's terminal assistant error; receipt preview, errorSummary,
  subagent tool output, and the await renderer name the local kind and
  carry the diagnostic instead of the generic error preview.

Does not touch cap configurability (#4602) or superseded-delta
reclamation (#4610).

Lore-id: 4618-buffer-diagnostics
Constraint: message prefix must stay byte-identical for session prefix classification
Constraint: diagnostics must be shape-only (no provider/prompt text can reach a parent receipt)
Constraint: do not duplicate #4602 configurability or #4610 delta reclamation
Rejected: enriching managedFailureMessage only | the non-retryable local exit surfaces the thrown error, not the wrapper
Rejected: enlarging the caps | workaround path ships with #4602
Confidence: high
Scope-risk: moderate
Reversibility: trivial
Tested: byte-cap + event-cap surfaced diagnostics (agent), propagation, redaction, foreign-kind degradation, generic-error fallback isolation (coding-agent)
Not-tested: live provider delta-storm reproduction
Closes: #4618
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