docs: publish OOM audit continuation evidence

This commit is contained in:
m4air
2026-09-19 01:07:46 -07:00
parent a37282bb1d
commit a3c2d81ac0
40 changed files with 3992 additions and 0 deletions
@@ -0,0 +1,133 @@
# Memory leak audit continuation — 2026-09-19
## Scope and checkpoint
Resumed the earlier audit with `memory-leak-audit` and `memory-leak-debugging`,
using parallel backend, renderer and lifecycle reviews. The selection rule was
to prefer cleanup that preserves behavior, identify substantial tradeoffs, and
leave areas with active PRs alone.
The original `OrcaWin/np-oom-scan` branch contained the historical patch stack,
including already published changes. It remains preserved. This worktree now
uses `OrcaWin/np-oom-resume-2026-09-19`, based on `origin/main` at
`6a7d86ef50dd699c23353b2e64ba261a9fb3344c`. The 35 pre-existing staged audit files
were preserved. No production fix from this continuation is retained, and no
PR was opened, updated or merged.
## Findings deferred because of active PRs
| Finding | Retention mechanism | Candidate correction and remaining review | Active area |
| ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Native-chat clipboard previews outlive the composer | `use-native-chat-composer-attachments.ts` revokes Blob URLs on remove/clear/drop, but has no unmount cleanup. Its scope cache deliberately strips preview URLs, so remount cannot release the old registrations. | Release owned Blob URLs when their composer retires. Preserve settled path/connection cache entries, pending-save behavior and StrictMode replay. Do not add an attachment quota as part of cleanup. | [#21483](https://github.com/stablyai/orca/pull/21483) edits the hook; [#17797](https://github.com/stablyai/orca/pull/17797) also changes attachment ownership. |
| Relay responses eagerly allocate base64 for every chunk | `git-response-stream.ts` builds a complete encoded array before the acknowledged sender admits chunks. A paused sender retains the unsent encoded response. | Encode each admitted chunk from the payload. Check actual retention and throughput against the existing response framing, ordering and admission behavior. This removes redundant eager encoding, not the payload or every transport queue. | [#11061](https://github.com/stablyai/orca/pull/11061) edits the implementation and ownership tests. |
| Scrcpy retains diagnostics that it never reports | `scrcpy-stream-session.ts` concatenates server stdout/stderr for the process lifetime; the exit diagnostic only uses `serverLog.slice(0, 1000).trim()`. | Retain an owned prefix of the same first 1,000 UTF-16 units. Preserve chunk decoding and the exact exit diagnostic. Full logs beyond that prefix are already unobservable through this consumer. | [#10548](https://github.com/stablyai/orca/pull/10548) edits this file, its test and the video registry. |
| Browser page chrome inset metadata survives explicit close | `browser-page-viewport.ts` stores per-page inset values. Recovery intentionally needs them, while explicit close can retire them. | Tie deletion to explicit page retirement. Preserve recovery and replacement guest ownership. Values are small metadata; no material OOM impact was measured. | [#20764](https://github.com/stablyai/orca/pull/20764) edits `webview-registry.ts`, the relevant retirement owner. |
An additional relay presence leak is also deferred to
[#10548](https://github.com/stablyai/orca/pull/10548):
`workspace-session-handler.ts` applies its 45-second client expiry only to the
namespace currently queried. Abandoned namespaces, including empty maps,
remain in `clientsByNamespace`. Sweeping other namespaces could release that
metadata, but sweeping every namespace on every heartbeat adds work and was
not accepted as universally cost-free. The historical prototype commit
`b812912d8d` was not brought onto this branch. The PR changes both the handler
and its test, verified through the REST file list (page 11, 100 files per page).
The overlap check is about the files being changed, not a claim that those PRs
already fix each finding. Read-only PR state and exact heads are recorded in
[the checkpoint](memory-leak-resume-2026-09-19/pr-checkpoint.json).
## Rejected and unproven leads
- **AI Vault scanner shutdown:** experimental ready-waiter rejection and
retirement tracking were discarded. The shared production scanner has no
`dispose()` caller beyond the test reset, and its child handles parent IPC
disconnect. No continuing allocation growth was demonstrated. A kill-request
deadline is not physical-exit evidence. Quit integration also overlaps
[#18205](https://github.com/stablyai/orca/pull/18205).
- **Pairing hydration waiters:** survival across pairing churn can be
intentional; changes would need ownership evidence and overlap
[#21175](https://github.com/stablyai/orca/pull/21175).
- **Structured-session status owners:** persistent owner/snapshot entries are
an audit lead, not enough evidence to remove state or add reader-side rules.
- **Unsent attachment volume:** one mounted composer can retain many unsent
images. A new count/byte quota changes accepted user input and is distinct
from releasing previews after unmount. No quota was introduced.
## Coverage without a new confirmed fix
The renderer pass reviewed direct `createObjectURL`, `createImageBitmap`, Blob
and canvas/data-URL owners. Feedback drafts release previews on remove, clear
and unmount. Editor image caches have entry/byte bounds and leases; browser and
emulator streams release replaced/stale/current frames; the pet cache evicts
URLs and closes bitmaps. These controls do not prove that arbitrary image
workloads have a fixed total memory cost.
The additional backend pass checked subprocess-output accumulation,
abort-listener cleanup, plugin verification/panel ownership, advertised URL
buffers, observability retention and desktop snapshot storage. Examples of
existing protections include plugin verification reset on refresh, bounded
panel sessions, bounded Git sampling buckets, and screenshot removal from
cached desktop snapshots. No independent, behavior-preserving OOM correction
was established by this targeted pass. This is not an exhaustive whole-program
proof of bounded allocation.
## Prior PR status refreshed
Of the 26 PRs still open at the September 17 handoff, nine have since merged:
[#20908](https://github.com/stablyai/orca/pull/20908),
[#20909](https://github.com/stablyai/orca/pull/20909),
[#21001](https://github.com/stablyai/orca/pull/21001),
[#21005](https://github.com/stablyai/orca/pull/21005),
[#21006](https://github.com/stablyai/orca/pull/21006),
[#21009](https://github.com/stablyai/orca/pull/21009),
[#21024](https://github.com/stablyai/orca/pull/21024),
[#21128](https://github.com/stablyai/orca/pull/21128), and
[#21167](https://github.com/stablyai/orca/pull/21167).
The other 17 remain open, as does the later cleanup extraction
[#21401](https://github.com/stablyai/orca/pull/21401).
The [September 18 tradeoff review](memory-pr-tradeoff-review-2026-09-18.md)
remains the implementation/evidence reference for those PRs. Their current CI
and merge readiness were not re-certified here. In particular, terminal
backpressure can stall a producer, CDP limits can disconnect a slow client,
speech limits can stop dictation, and terminal cache limits can add repeated
work. Those are meaningful policies, not cost-free lifecycle cleanup.
## Evidence limits and next work
The [real-hook reproduction](memory-leak-resume-2026-09-19/native-chat-preview-retention.test.tsx)
imports the production composer attachment hook and mounts it in happy-dom.
Ten mount/begin/resolve/unmount cycles leave ten 1 KiB Blob URLs registered
(10,240 bytes); one pending unmount leaves an eleventh (11,264 bytes total).
Remount restores the settled path with no preview URL. The remove and clear
controls release their 1,024 and 2,048 bytes respectively. The fixture revokes
all remaining URLs afterward. These are registered Blob sizes through Node's
URL registry, not Chromium RSS or heap measurements.
Set `ORCA_BACKGROUND_LAUNCH=1` and run
`pnpm exec vitest run --config docs/audits/memory-leak-resume-2026-09-19/vitest.config.ts`.
The packaged fixture passes one evidence test, explicitly asserting current
retention; it is not a claim that a fix passes a regression test. Its configuration
keeps it outside the ordinary test suite. Source hashes and results are in
[the reproduction record](memory-leak-resume-2026-09-19/preview-retention-result.json).
Formatting and the focused evidence test pass. The changed-code quality check
has no findings in the new artifacts, but fails on four findings in the
pre-existing staged September 18 evidence: `curly` in
`readers/stream-projection-control.cjs:16` and
`readers/readfile-growth-control.cjs:14`, and `prefer-template` in the latter
at lines 59 and 75. Those earlier artifacts remain untouched. No full app
typecheck or cross-platform UI validation is claimed for this documentation-only
continuation.
Chrome heap-debugging tools are unavailable in this session. No raw heap
snapshot was loaded and no affected-host capture was collected. Static paths
and controlled reproductions do not establish the cause of incident #19831.
No visible Electron app was launched; tests use `ORCA_BACKGROUND_LAUNCH=1`.
The next independent fix should be selected after the overlapping PRs settle,
starting with composer preview ownership or the unused scrcpy log suffix.
Any relay optimization still needs stalled-consumer allocation measurements
and output/throughput parity. The scanner shutdown prototype is rejected
evidence, not a patch ready to revive.
@@ -0,0 +1,207 @@
// Audit evidence: asserts the current leak, not desired regression-test behavior.
// @vitest-environment happy-dom
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { Blob, resolveObjectURL } from 'node:buffer'
import { URL as NodeURL } from 'node:url'
import { act, createElement, useEffect, useRef, useState } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import {
clearNativeChatAttachmentCacheForTests,
readNativeChatAttachmentCache,
useNativeChatComposerAttachments
} from '../../../src/renderer/src/components/native-chat/use-native-chat-composer-attachments'
import type { NativeChatResolvedTarget } from '../../../src/renderer/src/components/native-chat/native-chat-composer-target'
vi.mock('@/i18n/i18n', () => ({
translate: (_key: string, fallback: string) => fallback
}))
vi.mock('@/runtime/runtime-terminal-inspection', () => ({
isRemoteRuntimePtyId: () => false
}))
const target: NativeChatResolvedTarget = {
ptyId: 'pty-1',
settings: { activeRuntimeEnvironmentId: null }
}
const CYCLE_COUNT = 10
const BLOB_BYTES = 1024
type AttachmentApi = ReturnType<typeof useNativeChatComposerAttachments>
type RegistryProbe = {
retainedBytes: () => number
cleanup: () => void
}
let activeRegistry: RegistryProbe | null = null
function Probe({
scopeKey,
onReady
}: {
scopeKey: string
onReady: (api: AttachmentApi) => void
}): React.JSX.Element {
const [caret, setCaret] = useState(0)
const [draft, setDraft] = useState('')
const [notice, setNotice] = useState<string | null>(null)
const textareaRef = useRef<HTMLTextAreaElement>(null)
const api = useNativeChatComposerAttachments({
attachmentScopeKey: scopeKey,
caret,
disabled: false,
isComposing: () => false,
resolveTarget: () => target,
textareaRef,
setCaret,
setDraft: (updater) => setDraft((previous) => updater(previous)),
setNotice
})
useEffect(() => onReady(api), [api, onReady])
void draft
void notice
return createElement('textarea', { ref: textareaRef })
}
async function mountProbe(scopeKey: string): Promise<{ root: Root; api: () => AttachmentApi }> {
const container = document.createElement('div')
document.body.append(container)
const root = createRoot(container)
let latest: AttachmentApi | null = null
const onReady = (api: AttachmentApi): void => {
latest = api
}
await act(async () => {
root.render(createElement(Probe, { scopeKey, onReady }))
})
if (!latest) {
throw new Error('temporary attachment probe did not mount')
}
return {
root,
api: () => {
if (!latest) {
throw new Error('temporary attachment probe is unmounted')
}
return latest
}
}
}
function installUrlRegistryProbe(): RegistryProbe {
const retainedUrls = new Set<string>()
const browserUrl = globalThis.URL
const create = NodeURL.createObjectURL.bind(NodeURL)
const revoke = NodeURL.revokeObjectURL.bind(NodeURL)
vi.spyOn(browserUrl, 'createObjectURL').mockImplementation((blob: Blob) => {
const url = create(blob)
retainedUrls.add(url)
return url
})
vi.spyOn(browserUrl, 'revokeObjectURL').mockImplementation((url: string) => {
retainedUrls.delete(url)
revoke(url)
})
return {
retainedBytes: () =>
[...retainedUrls].reduce((total, url) => total + (resolveObjectURL(url)?.size ?? 0), 0),
cleanup: () => {
for (const url of retainedUrls) {
revoke(url)
}
retainedUrls.clear()
}
}
}
function makePreviewUrl(): string {
return globalThis.URL.createObjectURL(new Blob([Buffer.alloc(BLOB_BYTES)]))
}
function requireAttachmentId(id: string | null): string {
if (!id) {
throw new Error('temporary attachment probe did not return an id')
}
return id
}
describe('native-chat Blob URL ownership evidence', () => {
beforeEach(() => {
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true)
})
afterEach(() => {
activeRegistry?.cleanup()
activeRegistry = null
clearNativeChatAttachmentCacheForTests()
document.body.replaceChildren()
vi.restoreAllMocks()
vi.unstubAllGlobals()
})
it('measures pending and settled unmount retention against removal controls', async () => {
const registry = installUrlRegistryProbe()
activeRegistry = registry
for (let cycle = 0; cycle < CYCLE_COUNT; cycle += 1) {
const probe = await mountProbe(`settled-${cycle}`)
let id: string | null = null
await act(async () => {
id = probe.api().beginPendingImageAttachment(makePreviewUrl())
probe
.api()
.resolvePendingImageAttachment(requireAttachmentId(id), `/tmp/settled-${cycle}.png`)
})
act(() => probe.root.unmount())
}
const settledUnmountRetainedBytes = registry.retainedBytes()
expect(settledUnmountRetainedBytes).toBe(CYCLE_COUNT * BLOB_BYTES)
const remounted = await mountProbe('settled-0')
const remountedCache = readNativeChatAttachmentCache('settled-0')
expect(remounted.api().imageAttachments).toMatchObject([{ path: '/tmp/settled-0.png' }])
expect(remountedCache.every((attachment) => attachment.previewUrl === undefined)).toBe(true)
act(() => remounted.root.unmount())
const pending = await mountProbe('pending')
await act(async () => {
pending.api().beginPendingImageAttachment(makePreviewUrl())
})
act(() => pending.root.unmount())
const pendingUnmountRetainedBytes = registry.retainedBytes()
expect(pendingUnmountRetainedBytes).toBe((CYCLE_COUNT + 1) * BLOB_BYTES)
const remove = await mountProbe('remove')
let removeId: string | null = null
await act(async () => {
removeId = remove.api().beginPendingImageAttachment(makePreviewUrl())
remove.api().resolvePendingImageAttachment(requireAttachmentId(removeId), '/tmp/remove.png')
})
const beforeRemove = registry.retainedBytes()
act(() => remove.api().removeImageAttachment(requireAttachmentId(removeId)))
expect(registry.retainedBytes()).toBe(beforeRemove - BLOB_BYTES)
const afterRemove = registry.retainedBytes()
act(() => remove.root.unmount())
const clear = await mountProbe('clear')
await act(async () => {
clear.api().beginPendingImageAttachment(makePreviewUrl())
clear.api().beginPendingImageAttachment(makePreviewUrl())
})
const beforeClear = registry.retainedBytes()
act(() => clear.api().clearImageAttachments())
expect(registry.retainedBytes()).toBe(beforeClear - 2 * BLOB_BYTES)
const afterClear = registry.retainedBytes()
act(() => clear.root.unmount())
console.log(
JSON.stringify({
cycleCount: CYCLE_COUNT,
blobBytesPerCycle: BLOB_BYTES,
settledUnmountRetainedBytes,
pendingUnmountRetainedBytes,
remountedCachePreviewUrls: remountedCache.map(
(attachment) => attachment.previewUrl ?? null
),
removeControlRevokedBytes: beforeRemove - afterRemove,
clearControlRevokedBytes: beforeClear - afterClear
})
)
})
})
@@ -0,0 +1,438 @@
{
"queriedAtUtc": "2026-09-19T07:33:26.644328+00:00",
"repository": "stablyai/orca",
"baseline": "6a7d86ef50dd699c23353b2e64ba261a9fb3344c",
"priorHeldPrsAndLaterCleanup": [
{
"number": 20908,
"title": "fix(renderer): dispose global listeners during HMR",
"url": "https://github.com/stablyai/orca/pull/20908",
"state": "MERGED",
"headRefName": "np-oom-scan-renderer-hmr",
"headRefOid": "0848c34790482d9cebdfc66b83caa15d79113d3c",
"baseRefName": "main",
"mergedAt": "2026-09-18T06:40:00Z",
"updatedAt": "2026-09-18T06:40:00Z"
},
{
"number": 20909,
"title": "fix(main,preload): tear down renderer relay and preload listeners",
"url": "https://github.com/stablyai/orca/pull/20909",
"state": "MERGED",
"headRefName": "np-oom-scan-relay-preload",
"headRefOid": "c8f4d66de45e79660a2bfc38f06a2d0828161ede",
"baseRefName": "main",
"mergedAt": "2026-09-18T07:18:20Z",
"updatedAt": "2026-09-18T07:18:20Z"
},
{
"number": 20947,
"title": "fix(daemon): pause producers when stream backlogs grow",
"url": "https://github.com/stablyai/orca/pull/20947",
"state": "OPEN",
"headRefName": "np-oom-scan-daemon-stream-backpressure",
"headRefOid": "ba4fbe5cf42a66a5da69b4797f62af9bc6ad1ed7",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-19T04:41:56Z"
},
{
"number": 20949,
"title": "fix(browser): bound CDP output for stalled clients",
"url": "https://github.com/stablyai/orca/pull/20949",
"state": "OPEN",
"headRefName": "np-oom-scan-cdp-backpressure",
"headRefOid": "d12d1e0a06f3ced9425e98f3593e0864ef16830b",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-19T03:18:23Z"
},
{
"number": 20955,
"title": "Fix terminal hyperlink metadata retention during redraws",
"url": "https://github.com/stablyai/orca/pull/20955",
"state": "OPEN",
"headRefName": "np-oom-scan-osc-link-retirement",
"headRefOid": "fb724f630cbaecdf359a36c702c19361637b9160",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-19T05:35:08Z"
},
{
"number": 20963,
"title": "Bound AI Vault transcript record assembly before allocation",
"url": "https://github.com/stablyai/orca/pull/20963",
"state": "OPEN",
"headRefName": "np-oom-scan-transcript-record-budget",
"headRefOid": "4beab0c60cdb9c80c124b37d4b43c3863b1a38c8",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-19T03:18:26Z"
},
{
"number": 20965,
"title": "Bound invisible WebGL glyph cache entries",
"url": "https://github.com/stablyai/orca/pull/20965",
"state": "OPEN",
"headRefName": "np-oom-scan-webgl-empty-glyph-cache",
"headRefOid": "678e34cb553324a0cf1ef0825ec570e13cb1e5b2",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-19T04:21:15Z"
},
{
"number": 20976,
"title": "Enforce the legacy transcript import budget while reading",
"url": "https://github.com/stablyai/orca/pull/20976",
"state": "OPEN",
"headRefName": "np-oom-scan-legacy-import-source-budget",
"headRefOid": "8138b484eaf2e3efa656d1066eb24be63e40435c",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-19T03:18:28Z"
},
{
"number": 20981,
"title": "Bound terminal contrast-color caches",
"url": "https://github.com/stablyai/orca/pull/20981",
"state": "OPEN",
"headRefName": "np-oom-scan-contrast-cache",
"headRefOid": "00ed3625f818cb54526556569038f0d5ad8ed8bc",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-19T04:21:15Z"
},
{
"number": 20992,
"title": "fix(terminal): release erased cell backing strings",
"url": "https://github.com/stablyai/orca/pull/20992",
"state": "OPEN",
"headRefName": "np-oom-scan-terminal-cell-retention",
"headRefOid": "ef527dbf73a66a84b005a63e6778ba21f93320c5",
"baseRefName": "np-oom-scan-contrast-cache",
"mergedAt": null,
"updatedAt": "2026-09-19T05:58:32Z"
},
{
"number": 21001,
"title": "fix(terminal): retire explicitly closed pending split connections",
"url": "https://github.com/stablyai/orca/pull/21001",
"state": "MERGED",
"headRefName": "np-oom-scan-pending-split-close",
"headRefOid": "7df25d10810e6915346782005cee0efe9c89b5a6",
"baseRefName": "main",
"mergedAt": "2026-09-18T06:52:01Z",
"updatedAt": "2026-09-18T06:52:02Z"
},
{
"number": 21005,
"title": "fix(terminal): retire captured remote handles when pending panes close",
"url": "https://github.com/stablyai/orca/pull/21005",
"state": "MERGED",
"headRefName": "np-oom-scan-pending-runtime-close",
"headRefOid": "b28fec317801b4b7086207db64cb0f41e30140db",
"baseRefName": "main",
"mergedAt": "2026-09-18T09:13:11Z",
"updatedAt": "2026-09-18T09:13:12Z"
},
{
"number": 21006,
"title": "fix(sessions): cancel transcript acquisition during host teardown",
"url": "https://github.com/stablyai/orca/pull/21006",
"state": "MERGED",
"headRefName": "np-oom-scan-tui-transcript-acquisition",
"headRefOid": "746baae52bb51acbdcf0e3a7a0f7134ef3274a15",
"baseRefName": "main",
"mergedAt": "2026-09-18T08:10:32Z",
"updatedAt": "2026-09-18T08:10:33Z"
},
{
"number": 21009,
"title": "fix(log-tail): retire watches with their renderer lifetime",
"url": "https://github.com/stablyai/orca/pull/21009",
"state": "MERGED",
"headRefName": "np-oom-scan-local-log-tail",
"headRefOid": "d251ec248f1ebbaa78b7bdae84469920e2ef05e7",
"baseRefName": "main",
"mergedAt": "2026-09-18T07:02:03Z",
"updatedAt": "2026-09-18T07:02:04Z"
},
{
"number": 21014,
"title": "fix(runtime): reject stale inventory after PTY lifecycle changes",
"url": "https://github.com/stablyai/orca/pull/21014",
"state": "OPEN",
"headRefName": "np-oom-scan-stale-pty-inventory",
"headRefOid": "f940d76335473d7d2c91abf124b4092d233e53b2",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-19T06:41:24Z"
},
{
"number": 21020,
"title": "fix(runtime): persist acknowledged terminal tab retirement",
"url": "https://github.com/stablyai/orca/pull/21020",
"state": "OPEN",
"headRefName": "np-oom-scan-acknowledged-tab-retirement",
"headRefOid": "c5c2b6d745226f778584dc9c8b4a89bce3d8e6c0",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-19T06:41:24Z"
},
{
"number": 21021,
"title": "fix(claude): enforce history window quota while reading",
"url": "https://github.com/stablyai/orca/pull/21021",
"state": "OPEN",
"headRefName": "np-oom-scan-claude-history-window-budget",
"headRefOid": "f59ada2703e064024afb7dc493a8428cf78b0130",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-19T05:31:50Z"
},
{
"number": 21024,
"title": "fix(claude): stream transcript ancestry proofs",
"url": "https://github.com/stablyai/orca/pull/21024",
"state": "MERGED",
"headRefName": "np-oom-scan-claude-branch-streaming",
"headRefOid": "3d50ef26ac76933fc094b7a9ea25837e14860c05",
"baseRefName": "main",
"mergedAt": "2026-09-19T06:39:16Z",
"updatedAt": "2026-09-19T06:39:18Z"
},
{
"number": 21112,
"title": "fix: stop xterm reflow retaining and overwriting trimmed rows",
"url": "https://github.com/stablyai/orca/pull/21112",
"state": "OPEN",
"headRefName": "np-oom-scan-xterm-reflow-retention",
"headRefOid": "061913804c35af189d00f8a9574dcb226b971ba6",
"baseRefName": "np-oom-scan-terminal-cell-retention",
"mergedAt": null,
"updatedAt": "2026-09-17T09:31:15Z"
},
{
"number": 21113,
"title": "fix: persist closing never-started local terminal tabs",
"url": "https://github.com/stablyai/orca/pull/21113",
"state": "OPEN",
"headRefName": "np-oom-scan-local-empty-tab-retirement",
"headRefOid": "718ead7ea9f6296d69ceb7d1460a3579116fe85f",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-17T02:35:46Z"
},
{
"number": 21128,
"title": "fix: read crash diagnostics without loading whole dumps into memory",
"url": "https://github.com/stablyai/orca/pull/21128",
"state": "MERGED",
"headRefName": "np-oom-scan-crashpad-read-limit",
"headRefOid": "01b4001ad077b81582e1b93ac41cc74610fffde4",
"baseRefName": "main",
"mergedAt": "2026-09-19T06:39:52Z",
"updatedAt": "2026-09-19T06:39:54Z"
},
{
"number": 21129,
"title": "fix: bound audio queued behind local speech recognition",
"url": "https://github.com/stablyai/orca/pull/21129",
"state": "OPEN",
"headRefName": "np-oom-scan-speech-audio-budget",
"headRefOid": "7f0e6846d08918e85b642014f3264a81bfb76d9a",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-19T04:26:02Z"
},
{
"number": 21167,
"title": "fix: avoid retaining foreign SSH file frames before metadata",
"url": "https://github.com/stablyai/orca/pull/21167",
"state": "MERGED",
"headRefName": "np-oom-scan-ssh-file-metadata",
"headRefOid": "5e9614cd847f8ff4b6857e7e96b85da76bc06822",
"baseRefName": "main",
"mergedAt": "2026-09-18T06:59:42Z",
"updatedAt": "2026-09-18T06:59:43Z"
},
{
"number": 21175,
"title": "fix: retire unowned paired-host session partitions on GUI removal",
"url": "https://github.com/stablyai/orca/pull/21175",
"state": "OPEN",
"headRefName": "np-oom-scan-paired-host-session-retirement",
"headRefOid": "231edf2deab38bbf859edc2efea7deab845107db",
"baseRefName": "np-oom-scan-local-empty-tab-retirement",
"mergedAt": null,
"updatedAt": "2026-09-19T05:46:27Z"
},
{
"number": 21178,
"title": "fix: retire closed editor models from the app shell",
"url": "https://github.com/stablyai/orca/pull/21178",
"state": "OPEN",
"headRefName": "np-oom-scan-closed-editor-models",
"headRefOid": "e9ee5f595b40ca987875197d1faaf1781624b2a4",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-19T04:33:56Z"
},
{
"number": 21185,
"title": "fix(plugins): release diagnostic logs after successful uninstall",
"url": "https://github.com/stablyai/orca/pull/21185",
"state": "OPEN",
"headRefName": "np-oom-scan-plugin-log-retirement",
"headRefOid": "9a1686f4ed83d140868a7998bc36f266631bf2ba",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-19T04:36:34Z"
},
{
"number": 21401,
"title": "fix(daemon): retire disconnected stream refill owners",
"url": "https://github.com/stablyai/orca/pull/21401",
"state": "OPEN",
"headRefName": "np-oom-scan-daemon-refill-retirement",
"headRefOid": "d01363acb769306788de24b97154919e7531ef03",
"baseRefName": "main",
"mergedAt": null,
"updatedAt": "2026-09-18T07:48:30Z"
}
],
"overlappingPrs": [
{
"number": 10548,
"title": "feat(memory-safety): bound OOM-prone ingress across transports, parsers and scans",
"url": "https://github.com/stablyai/orca/pull/10548",
"state": "OPEN",
"headRefName": "oom-rescoped",
"headRefOid": "4be5bcd756219607ec13685ee1f81eeb3da27e98",
"updatedAt": "2026-07-30T20:07:52Z",
"overlappingPaths": [
"src/main/emulator/android/scrcpy-stream-session.ts",
"src/main/emulator/android/scrcpy-stream-session.test.ts",
"src/main/emulator/scrcpy-video-registry.ts",
"src/main/emulator/scrcpy-video-registry-memory.test.ts",
"src/relay/workspace-session-handler.ts",
"src/relay/workspace-session-handler.test.ts"
],
"verification": "REST pull files pages 5 and 11, per_page 100"
},
{
"number": 11061,
"title": "fix(memory): bound relay protocol accumulation",
"url": "https://github.com/stablyai/orca/pull/11061",
"state": "OPEN",
"headRefName": "oom-slice-11-relay-protocol",
"headRefOid": "c37e2355fd1005fce591a30872b12e04d0a86040",
"updatedAt": "2026-07-28T05:02:41Z",
"overlappingPaths": [
"src/relay/git-response-stream.ts",
"src/relay/git-response-stream-ownership.test.ts"
],
"verification": "GraphQL pullRequest.files; complete connection"
},
{
"number": 20764,
"title": "fix(browser-pane): guard webview.remove() against a dead guest",
"url": "https://github.com/stablyai/orca/pull/20764",
"state": "OPEN",
"headRefName": "fix/webview-remove-dead-guest-freeze",
"headRefOid": "2ca8295e5da86eb5741581b5c16c551dc8be1d55",
"updatedAt": "2026-09-17T14:52:30Z",
"overlappingPaths": [
"src/renderer/src/components/browser-pane/host-guest/webview-registry.ts"
],
"verification": "GraphQL pullRequest.files; complete connection"
},
{
"number": 18205,
"title": "fix(quit): reap owned helpers before app exit",
"url": "https://github.com/stablyai/orca/pull/18205",
"state": "OPEN",
"headRefName": "fix/quit-orphaned-processes",
"headRefOid": "90dcad0c63f96b88f7f15e380603c088e8c91a9d",
"updatedAt": "2026-09-07T14:53:49Z",
"overlappingPaths": ["src/main/startup/main-process-quit.ts"],
"verification": "GraphQL pullRequest.files; complete connection"
},
{
"number": 21483,
"title": "feat: attach explorer files as native-chat context",
"url": "https://github.com/stablyai/orca/pull/21483",
"state": "OPEN",
"headRefName": "fix/explorer-attach-as-context",
"headRefOid": "26028cc65e669ecec6b2a93b054ce14dd0de11ef",
"updatedAt": "2026-09-18T17:29:01Z",
"overlappingPaths": [
"src/renderer/src/components/native-chat/use-native-chat-composer-attachments.ts"
],
"verification": "GraphQL pullRequest.files; complete connection"
},
{
"number": 17797,
"title": "feat(native-chat): local attachments in the composer on Remote Orca Server panes",
"url": "https://github.com/stablyai/orca/pull/17797",
"state": "OPEN",
"headRefName": "cmer/Allow-local-attachment-with-remote-server-and-or-ssh-session",
"headRefOid": "48ece5fee69cd7aba593f4b7085461b7c2661829",
"updatedAt": "2026-09-01T04:03:45Z",
"overlappingPaths": [
"src/renderer/src/components/native-chat/use-native-chat-composer-attachments.ts"
],
"verification": "GraphQL pullRequest.files; complete connection"
}
],
"sourceFingerprints": [
{
"path": "src/main/emulator/android/scrcpy-stream-session.test.ts",
"sha256": "2e48eaee949129347d2379f54bbf996af98cda4bb0f621dcf2adfc8de8abb88c"
},
{
"path": "src/main/emulator/android/scrcpy-stream-session.ts",
"sha256": "b3159cb9e6c852441932c3ab8da034ac49fb87a51cdd7d1190363c2adefe6cd7"
},
{
"path": "src/main/emulator/scrcpy-video-registry.ts",
"sha256": "6548a16d2d8f4d4a90eede0b0eef039d8f045622238c1111b6b1083cc0120294"
},
{
"path": "src/main/startup/main-process-quit.ts",
"sha256": "2489de89112102db092d8e5fec7fc11805a9aed0a06833671659622bf06b15c8"
},
{
"path": "src/relay/git-response-stream-ownership.test.ts",
"sha256": "5d9821f0b6ed9fae5afe10b5323de84865d204077b2a2ba597f0757b0cf555c9"
},
{
"path": "src/relay/git-response-stream.ts",
"sha256": "953495aa5255d262e4cd4c6417d4b2d1f1391bb1b9a86f020e866ad8d6b58bbc"
},
{
"path": "src/renderer/src/components/browser-pane/host-guest/browser-page-viewport.ts",
"sha256": "3f3c9cc1f9eb9f1075442321a661a4b08b95bee4cdd03185d6f1d86d19d3196b"
},
{
"path": "src/renderer/src/components/browser-pane/host-guest/webview-registry.ts",
"sha256": "d8bfe19423725fcbd1da765d2b161211b90f82211a4f28c2b1f0726f834ef5eb"
},
{
"path": "src/renderer/src/components/native-chat/use-native-chat-composer-attachments.ts",
"sha256": "834694d55d72785c921099a00f83d5904c7e0ca27876b4baecaa0d099992abb1"
},
{
"path": "src/renderer/src/components/native-chat/use-native-chat-composer-paste.ts",
"sha256": "0e0ba9317407acd29d8be7488ba63638d5382f1793db213032927061582de891"
},
{
"path": "src/relay/workspace-session-handler.ts",
"sha256": "88f467ba21522f9c00531433a020b9d718e8f6c93773d960cc44e9d95b2ef408"
},
{
"path": "src/relay/workspace-session-handler.test.ts",
"sha256": "82aea25097d58a7946ffffedede9e27675158728621104ea6caef729f76e8172"
}
]
}
@@ -0,0 +1,61 @@
{
"kind": "Current production behavior reproduced; no fix retained",
"testedAtUtc": "2026-09-19T07:46:22.231674+00:00",
"baselineCommit": "6a7d86ef50dd699c23353b2e64ba261a9fb3344c",
"node": "v26.6.0",
"environment": {
"ORCA_BACKGROUND_LAUNCH": "1",
"DOM": "happy-dom",
"blobRegistry": "node:url URL and node:buffer Blob / resolveObjectURL"
},
"command": "ORCA_BACKGROUND_LAUNCH=1 ./node_modules/.bin/vitest run --config docs/audits/memory-leak-resume-2026-09-19/vitest.config.ts --reporter=verbose",
"testFilesPassed": 1,
"testsPassed": 1,
"measurements": {
"cycleCount": 10,
"blobBytesPerCycle": 1024,
"settledUnmountRetainedBytes": 10240,
"pendingUnmountRetainedBytes": 11264,
"remountedCachePreviewUrls": [null],
"removeControlRevokedBytes": 1024,
"clearControlRevokedBytes": 2048
},
"sourceFingerprints": [
{
"path": "docs/audits/memory-leak-resume-2026-09-19/native-chat-preview-retention.test.tsx",
"sha256": "ba296c6c15637755608beddc4e9c97a776581d76a95833c140100f0cd5cbb45a"
},
{
"path": "docs/audits/memory-leak-resume-2026-09-19/vitest.config.ts",
"sha256": "aa764369711d5014aa9d495f45586509ff4c235640384a7b15830cc10a302460"
},
{
"path": "src/renderer/src/components/native-chat/use-native-chat-composer-attachments.ts",
"sha256": "834694d55d72785c921099a00f83d5904c7e0ca27876b4baecaa0d099992abb1"
},
{
"path": "src/renderer/src/components/native-chat/use-native-chat-resolved-path-attachments.ts",
"sha256": "41fe633a12d78f826d22171f18174a05ea52c1f843429119522e9cf4516dd9db"
},
{
"path": "src/renderer/src/components/native-chat/native-chat-composer-scope-cache.ts",
"sha256": "f9b63a9e6e8d55d483406c13573d6db95223052e60a61515e96a084aa94a5e93"
}
],
"limits": [
"The actual production attachment hook is exercised; the paste event and IPC save are not.",
"The browser URL methods delegate to the Node URL registry, so these sizes are not Chromium heap/RSS measurements.",
"No StrictMode, late-save fix, user-facing UI, or affected-host incident attribution is claimed.",
"Assertions describe the existing leak and are isolated from the ordinary test suite.",
"The harness revokes its remaining registrations at teardown."
],
"codeQuality": {
"newArtifactFindings": 0,
"gatePassed": false,
"preExistingStagedEvidenceFindings": 4,
"files": [
"docs/audits/memory-pr-tradeoff-review-2026-09-18/readers/readfile-growth-control.cjs",
"docs/audits/memory-pr-tradeoff-review-2026-09-18/readers/stream-projection-control.cjs"
]
}
}
@@ -0,0 +1,10 @@
import { defineConfig } from 'vitest/config'
import baseConfig from '../../../config/vitest.config'
export default defineConfig({
...baseConfig,
test: {
...baseConfig.test,
include: ['docs/audits/memory-leak-resume-2026-09-19/native-chat-preview-retention.test.tsx']
}
})
@@ -0,0 +1,75 @@
# Memory PR tradeoff review — 2026-09-18
## Scope and result
Three parallel agents and the primary reviewer revisited all 17 PRs held for behavior or performance tradeoffs. Nine size-only holds were outside this pass. No PR was merged.
We found a separate lifecycle fix with no identified user-facing tradeoff, removed unnecessary behavior changes from two existing PRs, and corrected one overly broad warning. A promising terminal hyperlink optimization was rejected after repeated benchmarks exposed new density-dependent regressions. None of the remaining full PRs is represented as universally cost-free.
## All 17 decisions
| PR | Outcome | Remaining behavior or performance cost |
| --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| [#20947](https://github.com/stablyai/orca/pull/20947) daemon stream backlog | Separate cleanup extracted as [#21401](https://github.com/stablyai/orca/pull/21401) | The original backpressure PR can still pause live PTY producers. |
| [#20949](https://github.com/stablyai/orca/pull/20949) CDP queue | No verified replacement | Slow clients can be disconnected; general CDP events/results have no lossless replay owner. |
| [#20955](https://github.com/stablyai/orca/pull/20955) hyperlink retirement | Faster sparse prototype rejected after dense regressions | Periodic cleanup work remains. |
| [#20963](https://github.com/stablyai/orca/pull/20963) transcript record budget | No verified replacement | Complete records over 10 MiB are rejected and can leave a session incomplete. |
| [#20965](https://github.com/stablyai/orca/pull/20965) invisible glyph cache | No verified replacement | Evicted keys need recomputation on revisit. |
| [#20976](https://github.com/stablyai/orca/pull/20976) legacy import budget | No verified replacement | An import growing past 16 MiB can fail. |
| [#20981](https://github.com/stablyai/orca/pull/20981) contrast cache | No verified replacement | Evicted colors need recomputation on revisit. |
| [#20992](https://github.com/stablyai/orca/pull/20992) erased backing strings | No reliable faster replacement | Five cleanup variants, including the published implementation, did not establish removal of the parser penalty. |
| [#21014](https://github.com/stablyai/orca/pull/21014) stale PTY inventory | No safe replacement | Lifecycle races can require retry; treating stale inventory as current could affect successor processes. |
| [#21020](https://github.com/stablyai/orca/pull/21020) acknowledged tab retirement | No safe replacement | A stale/unconfirmed close can require retry; accepting it could close new work or falsely claim success. |
| [#21021](https://github.com/stablyai/orca/pull/21021) history budget | No verified replacement | Growth past the existing 16 MiB quota can fail reconciliation. |
| [#21024](https://github.com/stablyai/orca/pull/21024) streamed ancestry proof | No verified replacement | Markers appended beyond the initial read extent can require retry. |
| [#21128](https://github.com/stablyai/orca/pull/21128) crash dump reader | Updated: preserve native opened-prefix behavior | Dumps already over 64 MiB at descriptor stat remain rejected, including earlier growth/replacement. |
| [#21129](https://github.com/stablyai/orca/pull/21129) speech backlog | No verified replacement | Overload stops capture and can lose speech/final output; stopping a live microphone cannot preserve future audio. |
| [#21175](https://github.com/stablyai/orca/pull/21175) removed host partitions | Normal GUI warning withdrawn after source/identity controls | Direct stale-ID IPC/manual restoration was not proven equivalent; prerequisite and review gates remain. |
| [#21178](https://github.com/stablyai/orca/pull/21178) closed editor models | Updated: preserve existing bounded view caches | Large-file, raw Windows-drive URI and budget-evicted undo can still be lost. |
| [#21185](https://github.com/stablyai/orca/pull/21185) plugin log retirement | No verified replacement | Uninstalled-plugin history is removed; preserving every retired ring restores unbounded owner retention. |
## Published code
### #21401: retired daemon refill ownership
64 production lines and 122 test lines changed; the PR contains no audit bundle. Clearing a disconnected client now releases its refill token immediately. A late socket callback cannot flush or disarm a replacement using the same client ID. It reuses the existing `DaemonStreamHeldRefill` implementation; live queue/backpressure policy and protocol frames are unchanged.
Exact main baseline fails three of four lifecycle controls, including 200 retained client IDs. The candidate passes 31 tests across three suites, both lint configurations, and focused TypeScript 7 checks over its roots and 247 exact-source imports. All 303 evaluated test-source hashes were verified. Socket-owned callback allocations themselves remain governed by socket completion.
### #21128: remove an unnecessary crash-dump refusal
The caller opts into reading the initial nonempty regular-file extent. Growth after descriptor stat no longer rejects that valid prefix or causes growth-copy allocations. The default helper behavior and synchronous reader are unchanged. Shrinking files return only initialized bytes; zero-size sources still use bounded EOF reads.
56 tests across five suites pass; unchanged production fails the two new controls. Four-file ordinary/anti-slop lint, focused TypeScript 7 and independent review pass. Final tested-to-published difference is one explanatory comment. This is not an atomic snapshot against in-place rewriting and does not eliminate the descriptor-time size policy.
### #21178: preserve view state while releasing models
The app-shell lifetime now retires models without wiping the existing scroll, selection, diff and PDF caches. Their existing 20-entry policies remain; this is an entry bound, not a strict byte bound. Explicit combined model/cache disposal callers retain their behavior. Registry generation, exact model identity, live/reopened/shared URI ownership and attachment/detachment fences remain unchanged.
43 tests across eight suites, five-path ordinary/anti-slop lint and scoped TypeScript pass. Independent review found no ownership regression. Full web typecheck reports one inherited unused import in `NativeChatMessageList.windowing.test.tsx:12`, byte-identical to the earlier PR head. The final publication adds only a comment correction after those checks.
Real Monaco controls narrow the previous undo warning: small POSIX/file-URI reopen can retain undo via Monaco's existing 20 MiB closed-file budget, with a 10 MiB file-size eligibility limit and matching content. Raw Windows-drive URIs and large-file/budget cases still lose undo. These are programmatic model controls, not visible UI validation.
### #20955: optimization deliberately not published
The sparse extended-cell prototype made plain/sparse sweeps substantially faster, but its first form regressed dense rows. A density heuristic reduced that problem; repeated runs still found roughly 1.01.3% slowdown on densely linked rows with an unlinked midpoint, and a 5.9% slowdown for one prefix-density case in one run (the other two were faster). The user requested removal of tradeoffs, so this workload-dependent substitution was rejected. The original PR is unchanged.
Correctness controls preserve live links, saved attributes, wide/combined cells and erased cells; independent review additionally requested a dictionary-shape guard for private xterm metadata. Passing those controls does not erase the measured performance cost. The experimental sources, all benchmark runs and review notes remain local evidence.
## Why several alternatives did not qualify
- **Live queues:** finite retention cannot preserve unlimited undelivered input, uninterrupted producer progress and bounded resources simultaneously. Terminal snapshots/history have bounded windows and omit transient events. CDP `ReturnAsStream` only helps specific requested results. Disk spill moves cost to storage and I/O; graceful speech draining still stops future capture and cannot drain a permanently hung decoder.
- **Cache bounds:** exact published cache-method controls revisit 4,097 distinct keys. The old cache has zero revisit misses; the 4,096-entry cache has 4,097. This proves a repeated-work case, not GPU/rasterization latency. A different eviction policy cannot promise a hit for every unbounded revisit sequence.
- **JSON projection:** the existing streaming parser is useful for container retention, but selected paths and partial tokens still retain a complete ignored scalar. Two controls each retain all 12 MiB of an ignored string. Existing full-record callbacks and message/journal arrays need a deeper streaming contract before removing the admission guards safely. Moving the existing Codex prefix classifier ahead of assembly is a plausible partial improvement for known ignored record types, but remains unverified: framing, consumer, offset and unterminated-tail parity are required, and the general cap would remain.
- **File extent:** real Node 26.6 and Electron 43.7 / Node 24.21 controls show nonempty Buffer reads stop at their initial extent; large UTF-8 reads can include concurrent appends. The binary crash fix therefore does not justify dismissing the UTF-8 ancestry retry. Following a growing stream until EOF can add unbounded work, latency or graph growth.
- **History consistency:** exact prompt text/fingerprints and complete ancestry matter to reconciliation. A bounded prefix cannot establish that an unobserved message is absent. Streaming decoders/transactional journal or graph redesigns remain possible research directions; no parity-proven local replacement was found here.
- **Removed hosts:** ordinary remove/re-add creates a new UUID even before #21175, so the old partition was already unreachable through that new host. Updating an existing pairing preserves its UUID; profile moves carry owning repositories and stay guarded; mounted removed-host views already purge on catalog updates. This supports withdrawing the normal-GUI warning, not a claim about every manually restored identity.
- **Plugin history:** a preserve-history/rotate-token experiment fences late callbacks but retains all eight tested retired 200-row rings. Published cleanup releases all eight. The existing bounded security audit log has different content and cannot substitute for arbitrary plugin stdout history.
## Evidence and limits
Exact published-head controls also pass for #20947 (35), #20949 (6, including real localhost sockets), #21129 (15), #21014 (18), #21020 (11), and #21175 (16 retirement tests plus pairing controls). Negative controls and rejected alternatives remain documented; they are not counted as successful fixes.
The [evidence index](memory-pr-tradeoff-review-2026-09-18/evidence-index.json) records exact commits, local artifact paths and SHA-256 hashes. The permanent regression tests are in their individual PRs. Detailed local evidence is under `notes/tradeoff-removal/{queues,xterm,lifecycle,readers}`; it is intentionally not copied wholesale into implementation PRs.
All tests/apps used `ORCA_BACKGROUND_LAUNCH=1`; Electron ran only as Node for the native read control. No visible app was launched. Full cross-platform, SSH mixed-version, native speech, GPU and affected-host validation are not claimed. No host capture exists for #19831; these are code mechanisms and behavior controls, not incident attribution. Published heads were verified open at the expected commits. CI for #21401, #21128 and #21178 was pending at the final checkpoint; the unchanged #20955 and #21175 heads already had failing CI. Current PR CI remains a merge gate.
@@ -0,0 +1,454 @@
{
"scope": "All17 tradeoff holds; source controls and rejected experiments. Large evaluated-source graphs remain local, hashed here. Source code/permanent tests are retrievable through named PR commits.",
"published": {
"21401": "d01363acb769306788de24b97154919e7531ef03",
"21128": "09dbe227547fadaec8d9163f35fd127b0dc1c3ed",
"21178": "44fe1887bbbf2aae8957fff988a9a673f63a3b8c"
},
"records": [
{
"source": "notes/tradeoff-removal/readers/report.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/readers/report.json",
"sourceSha256": "9bb6b131ac37c9ec9f85e65d6a4598620cfa63007b92c24e8ae7d5b4a5f661b2",
"sourceBytes": 5040,
"archivedSha256": "9090d0b9b6c47f61d807bf989ef4428445e7dee58aea6c77a360c3905c9c9c62",
"archivedBytes": 5008
},
{
"source": "notes/tradeoff-removal/readers/readfile-growth-control.cjs",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/readers/readfile-growth-control.cjs",
"sourceSha256": "398e4d24261b8bbc4784a9c47f852b73e9deaf5efecf5296b057732c287854a9",
"sourceBytes": 2137,
"archivedSha256": "5819f4824370ce09bfc21b0ed9e47ad705503ed19bd0b74779d0296b6242b62d",
"archivedBytes": 2383
},
{
"source": "notes/tradeoff-removal/readers/readfile-growth-node.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/readers/readfile-growth-node.json",
"sourceSha256": "00822175101999ee86227a7a2c2395b94aee1c8baaf9fd4ab1431a694c70c828",
"sourceBytes": 1779,
"archivedSha256": "00822175101999ee86227a7a2c2395b94aee1c8baaf9fd4ab1431a694c70c828",
"archivedBytes": 1779
},
{
"source": "notes/tradeoff-removal/readers/readfile-growth-electron.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/readers/readfile-growth-electron.json",
"sourceSha256": "159f2c4d5caa481ca95c5bf5d01104f2ad332cfa6d4a7220f966462725738167",
"sourceBytes": 1827,
"archivedSha256": "159f2c4d5caa481ca95c5bf5d01104f2ad332cfa6d4a7220f966462725738167",
"archivedBytes": 1827
},
{
"source": "notes/tradeoff-removal/readers/stream-projection-control.cjs",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/readers/stream-projection-control.cjs",
"sourceSha256": "8c07a51e82beb092fa8ee3ab89c74892fed01f8773bb9ed59c555e23376c494e",
"sourceBytes": 1110,
"archivedSha256": "db66c80bfa300761d25a3c8f25c98fd1d375b3ffff664715a6b0b995e948c53e",
"archivedBytes": 1178
},
{
"source": "notes/tradeoff-removal/readers/stream-projection-control.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/readers/stream-projection-control.json",
"sourceSha256": "1c0e2d30868f01db6782d5ffa4e4d6ffe29d53f60f28b98647907ebe9c6cfd2d",
"sourceBytes": 509,
"archivedSha256": "46904d16611ce66d531b518537bbcfa39383a5af71a20e8b28413da31559f25a",
"archivedBytes": 477
},
{
"source": "notes/tradeoff-removal/readers/21128/independent-review-queues.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/readers/21128/independent-review-queues.json",
"sourceSha256": "4c35e2a4f682e29f79e55263ceb6c1b5404bc486e357756816161dae13e24709",
"sourceBytes": 3714,
"archivedSha256": "4c35e2a4f682e29f79e55263ceb6c1b5404bc486e357756816161dae13e24709",
"archivedBytes": 3714
},
{
"source": "notes/tradeoff-removal/queues/summary.md",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/queues/summary.md",
"sourceSha256": "59d94b46c463d000580388da6cd617791bbf2e6c22d79b868b5be6f3a32fc548",
"sourceBytes": 3385,
"archivedSha256": "1e22c4e9453013245cc2a4a29e4bb171a1608c7cb62219b14564deb7fac1c62a",
"archivedBytes": 4077
},
{
"source": "notes/tradeoff-removal/queues/20947/report.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/queues/20947/report.json",
"sourceSha256": "16a2e80bf57cae47e42eba9e90408ab35eb026b744e6667fb003a0a317d88ddc",
"sourceBytes": 4828,
"archivedSha256": "16a2e80bf57cae47e42eba9e90408ab35eb026b744e6667fb003a0a317d88ddc",
"archivedBytes": 4828
},
{
"source": "notes/tradeoff-removal/queues/20949/report.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/queues/20949/report.json",
"sourceSha256": "253d6392fd0f7ba3b8be1a85101172d3c1ec595386f5f8b2af6917fe6b2053f8",
"sourceBytes": 3990,
"archivedSha256": "253d6392fd0f7ba3b8be1a85101172d3c1ec595386f5f8b2af6917fe6b2053f8",
"archivedBytes": 3990
},
{
"source": "notes/tradeoff-removal/queues/21129/report.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/queues/21129/report.json",
"sourceSha256": "e62e643ccc1740694859ab5650cb51b1138d1a560638e94adad4cfd95528d09d",
"sourceBytes": 4526,
"archivedSha256": "e62e643ccc1740694859ab5650cb51b1138d1a560638e94adad4cfd95528d09d",
"archivedBytes": 4526
},
{
"source": "notes/tradeoff-removal/queues/20947/root-provenance.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/queues/20947/root-provenance.json",
"sourceSha256": "d541072a0aef7b10db42802bb592196187e803525344e35b7efe516ee81eb31c",
"sourceBytes": 239,
"archivedSha256": "d541072a0aef7b10db42802bb592196187e803525344e35b7efe516ee81eb31c",
"archivedBytes": 239
},
{
"source": "notes/tradeoff-removal/lifecycle/summary.md",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/lifecycle/summary.md",
"sourceSha256": "7adbd4e0a6eed360a18daca1d15d328f32c579d12bb49dfca67f9fb57793efee",
"sourceBytes": 2252,
"archivedSha256": "78604dab157b6017c33f35e849450abcd664b9dd8cae70f1f0d05510b978d505",
"archivedBytes": 2978
},
{
"source": "notes/tradeoff-removal/lifecycle/21014.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/lifecycle/21014.json",
"sourceSha256": "43ce897b9b230868dcf91a64a43d9f4655bad7de2197218e4bc5a0cda6eea768",
"sourceBytes": 2497,
"archivedSha256": "43ce897b9b230868dcf91a64a43d9f4655bad7de2197218e4bc5a0cda6eea768",
"archivedBytes": 2497
},
{
"source": "notes/tradeoff-removal/lifecycle/21020.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/lifecycle/21020.json",
"sourceSha256": "957e211f1a222b8282e3feda0f5773c5366d3145e14c7cd7c4d5b318494a2bb8",
"sourceBytes": 2053,
"archivedSha256": "957e211f1a222b8282e3feda0f5773c5366d3145e14c7cd7c4d5b318494a2bb8",
"archivedBytes": 2053
},
{
"source": "notes/tradeoff-removal/lifecycle/21175.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/lifecycle/21175.json",
"sourceSha256": "9b3aeec149fb865bad188b554c9471ad2bbd35a1850479fc21f45716bfeb2725",
"sourceBytes": 3942,
"archivedSha256": "9b3aeec149fb865bad188b554c9471ad2bbd35a1850479fc21f45716bfeb2725",
"archivedBytes": 3942
},
{
"source": "notes/tradeoff-removal/lifecycle/21178.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/lifecycle/21178.json",
"sourceSha256": "d68e7d3b36849954b1df3f6ecd08b824bce2b6b6fb3a6f2f6c7932ae9336da27",
"sourceBytes": 5318,
"archivedSha256": "d68e7d3b36849954b1df3f6ecd08b824bce2b6b6fb3a6f2f6c7932ae9336da27",
"archivedBytes": 5318
},
{
"source": "notes/tradeoff-removal/lifecycle/21185.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/lifecycle/21185.json",
"sourceSha256": "c4dc64ed1f6fdf13bf093095086f67833c69dbcbfa68be44837bbbb02948b237",
"sourceBytes": 2923,
"archivedSha256": "c4dc64ed1f6fdf13bf093095086f67833c69dbcbfa68be44837bbbb02948b237",
"archivedBytes": 2923
},
{
"source": "notes/tradeoff-removal/lifecycle/21178-independent-review-queues.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/lifecycle/21178-independent-review-queues.json",
"sourceSha256": "81c57554e42d23176ce7be5632d0423ad9a931fb66e18c14923011ebc9522048",
"sourceBytes": 4753,
"archivedSha256": "81c57554e42d23176ce7be5632d0423ad9a931fb66e18c14923011ebc9522048",
"archivedBytes": 4753
},
{
"source": "notes/tradeoff-removal/current.json",
"archived": null,
"sourceSha256": "6df0889b3348b8d3cb857201d5c10403d539ef826c01f6df942aa0264f9e5b4c",
"sourceBytes": 13283
},
{
"source": "notes/tradeoff-removal/publication-before.json",
"archived": null,
"sourceSha256": "839c205b7b6f426efb1b285c2d21d96f32da660c3bc30941601f08d6b6180b90",
"sourceBytes": 7495
},
{
"source": "notes/tradeoff-removal/publication-checkpoint.json",
"archived": null,
"sourceSha256": "c8f098052fb4c7bc2dbc8f968405fbb50f099ae88897ab8d9375b3398fd60462",
"sourceBytes": 1605
},
{
"source": "notes/tradeoff-removal/queues/20947/root-candidate.json",
"archived": null,
"sourceSha256": "23986fdd16a2c622578b9662979f909e71b0b74f1a06f40e4aa1fab546319a70",
"sourceBytes": 1505
},
{
"source": "notes/tradeoff-removal/queues/20947/root-candidate-graph.json",
"archived": null,
"sourceSha256": "c15edc81113861b83db86f0b82fe65d474fc3d257b41936d2864a1cacf413aed",
"sourceBytes": 47163
},
{
"source": "notes/tradeoff-removal/queues/20947/root-candidate-tests.log",
"archived": null,
"sourceSha256": "15538b068b20ede903c7e79cae934da158afa6752407b219c9ea1ccd12bddcf3",
"sourceBytes": 236
},
{
"source": "notes/tradeoff-removal/queues/20947/typecheck-graph.json",
"archived": null,
"sourceSha256": "9319326e2bb07beb967ee24404ab6d7686d78b2dd28acb77cb034c8c1415266a",
"sourceBytes": 37774
},
{
"source": "notes/tradeoff-removal/queues/20947/typecheck-ts7.log",
"archived": null,
"sourceSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"sourceBytes": 0
},
{
"source": "notes/tradeoff-removal/readers/21128/candidate.json",
"archived": null,
"sourceSha256": "14b37a4295e36d74a0c7260ebffcc1df8b50e337b58db7574e0484bc0eda932e",
"sourceBytes": 796
},
{
"source": "notes/tradeoff-removal/readers/21128/loaded-graph.json",
"archived": null,
"sourceSha256": "19d50edb596d01c0097565914451d36b1907377ff23db6efaaaccacb5fdab777",
"sourceBytes": 2478
},
{
"source": "notes/tradeoff-removal/readers/21128/tests.log",
"archived": null,
"sourceSha256": "3c80efda9f237230f952f321b490e9cb69b229c67c0aed17371bc2181cbfb18f",
"sourceBytes": 233
},
{
"source": "notes/tradeoff-removal/readers/21128/control-tests.log",
"archived": null,
"sourceSha256": "00d9da4465b174440f4c8e48fb46452e1be9a6ca2ac28aff6aeb2b3220f436bb",
"sourceBytes": 2286
},
{
"source": "notes/tradeoff-removal/readers/21128/control-graph.json",
"archived": null,
"sourceSha256": "9ff0de553cdd83c71198c2e78a1c28bb3ae1080b2a747c31ce68ac00b98aa280",
"sourceBytes": 1982
},
{
"source": "notes/tradeoff-removal/readers/21128/lint.json",
"archived": null,
"sourceSha256": "e75f44f9fe88320cfa775af0233a601fa04191365e92fa7eee160e23aa2b5dc9",
"sourceBytes": 196
},
{
"source": "notes/tradeoff-removal/readers/21128/anti-slop.json",
"archived": null,
"sourceSha256": "7e6703d61964dd85c408624160614e00d4e21e0aa24bd4c5127972a24c35cbae",
"sourceBytes": 194
},
{
"source": "notes/tradeoff-removal/readers/21128/typecheck.log",
"archived": null,
"sourceSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"sourceBytes": 0
},
{
"source": "notes/tradeoff-removal/lifecycle/evidence-manifest.json",
"archived": null,
"sourceSha256": "639bade6bf8f2c293b8b50ee981b9e81560b45fb168a8db177d694a753bd0cbe",
"sourceBytes": 11729
},
{
"source": "notes/tradeoff-removal/lifecycle/21178-final-graph.json",
"archived": null,
"sourceSha256": "6c5d1ebcfba01e768dbc3e8274389e88aef37dc897a7c0f7695150afa3a19cc9",
"sourceBytes": 171167
},
{
"source": "notes/tradeoff-removal/lifecycle/21178-final-tests.log",
"archived": null,
"sourceSha256": "43496c8c6e45e27dc2671d57448cfdaa1d84780c0f934f664fc689a2e95eb8dd",
"sourceBytes": 239
},
{
"source": "notes/tradeoff-removal/lifecycle/21178-publish.json",
"archived": null,
"sourceSha256": "96da215c4273f859d628563844ca4acb511906bc308568d6e5e304b9063b7f5e",
"sourceBytes": 259
},
{
"source": "notes/tradeoff-removal/queues/provenance-check.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/queues/provenance-check.json",
"sourceSha256": "f5193d45d04ebabd5738e96b0033e8d137e302d9bce0f7029523a5bcd8722bbe",
"sourceBytes": 640,
"archivedSha256": "f5193d45d04ebabd5738e96b0033e8d137e302d9bce0f7029523a5bcd8722bbe",
"archivedBytes": 640
},
{
"source": "notes/tradeoff-removal/queues/20947/candidate-manifest.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/queues/20947/candidate-manifest.json",
"sourceSha256": "9b6e3034f25284b4a6f713a6a97505c73c9f1c1aed11085661ec7048c9c03168",
"sourceBytes": 1377,
"archivedSha256": "9b6e3034f25284b4a6f713a6a97505c73c9f1c1aed11085661ec7048c9c03168",
"archivedBytes": 1377
},
{
"source": "notes/tradeoff-removal/queues/20947/cleanup-only.patch",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/queues/20947/cleanup-only.patch",
"sourceSha256": "d350e666ab9da15f35a5bf911c1a5f8414b394dc31583649686166bb4e539618",
"sourceBytes": 8434,
"archivedSha256": "d350e666ab9da15f35a5bf911c1a5f8414b394dc31583649686166bb4e539618",
"archivedBytes": 8434
},
{
"source": "notes/tradeoff-removal/xterm/20955-independent-review-queues.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/xterm/20955-independent-review-queues.json",
"sourceSha256": "5601ba9b008290fb1dc70be56be1abaa6df8903084a9b21cb6fc6c4417718928",
"sourceBytes": 3792,
"archivedSha256": "5601ba9b008290fb1dc70be56be1abaa6df8903084a9b21cb6fc6c4417718928",
"archivedBytes": 3792
},
{
"source": "notes/tradeoff-removal/xterm/20965-verdict.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/xterm/20965-verdict.json",
"sourceSha256": "e3d2304cab90f51173ba7f7a222bd562440ca6241b7d8a3ee3d9ff1e6d8b8663",
"sourceBytes": 4379,
"archivedSha256": "e3d2304cab90f51173ba7f7a222bd562440ca6241b7d8a3ee3d9ff1e6d8b8663",
"archivedBytes": 4379
},
{
"source": "notes/tradeoff-removal/xterm/20981-verdict.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/xterm/20981-verdict.json",
"sourceSha256": "35e338f0abb3363fac9a07e6b1ba6d3fbe477e6dc1f1a4963b38927eddd8a783",
"sourceBytes": 4819,
"archivedSha256": "35e338f0abb3363fac9a07e6b1ba6d3fbe477e6dc1f1a4963b38927eddd8a783",
"archivedBytes": 4819
},
{
"source": "notes/tradeoff-removal/xterm/20992-verdict.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/xterm/20992-verdict.json",
"sourceSha256": "07473c72b01fa148f1b2d12ec8c0ed2ba4c431eb5de40a23977298e8de71315d",
"sourceBytes": 6562,
"archivedSha256": "07473c72b01fa148f1b2d12ec8c0ed2ba4c431eb5de40a23977298e8de71315d",
"archivedBytes": 6562
},
{
"source": "notes/tradeoff-removal/xterm/cache-revisit-results.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/xterm/cache-revisit-results.json",
"sourceSha256": "98f96f928e624dcd3f964738298d14ed23431f6658b286d891678214b7ad0d59",
"sourceBytes": 3682,
"archivedSha256": "98f96f928e624dcd3f964738298d14ed23431f6658b286d891678214b7ad0d59",
"archivedBytes": 3682
},
{
"source": "notes/tradeoff-removal/xterm/bufferline-source-results.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/xterm/bufferline-source-results.json",
"sourceSha256": "27acaa73c54d66fb1fec3873e01e65994f51f982d9a8667fd2b97dd2840bd8bf",
"sourceBytes": 6412,
"archivedSha256": "cd101949ee1ff5fbe858b6fd4232602da2efa93a8f4bdde7e560cb7a4fb4c801",
"archivedBytes": 5764
},
{
"source": "notes/tradeoff-removal/publication-final.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/publication-final.json",
"sourceSha256": "008c2f9ccb41f76a9b582e7d9e884e72481f982b4a725fa86445f45864714b9f",
"sourceBytes": 2284,
"archivedSha256": "008c2f9ccb41f76a9b582e7d9e884e72481f982b4a725fa86445f45864714b9f",
"archivedBytes": 2284
},
{
"source": "notes/tradeoff-removal/xterm/osc-sweep-prefix-initial.json",
"archived": null,
"sourceSha256": "02d5ae5016e0db13794e0375e2190c760e289a11cf26d5d2c2cca37cd3586b8c",
"sourceBytes": 9341
},
{
"source": "notes/tradeoff-removal/xterm/osc-sweep-repeat-1.json",
"archived": null,
"sourceSha256": "a8997945dca137076f660b13a95838829440d2e3364358d7e9c1bacd7c1b11c6",
"sourceBytes": 14627
},
{
"source": "notes/tradeoff-removal/xterm/osc-sweep-repeat-2.json",
"archived": null,
"sourceSha256": "1989eb65cf04a04f0a00b3f2c869da1f2b599133c929827c4fa8d6d652e825c8",
"sourceBytes": 14661
},
{
"source": "notes/tradeoff-removal/xterm/osc-sweep-repeat-3.json",
"archived": null,
"sourceSha256": "791031302c0fcb2f0683c2734e6e6eaadcfe12430214b097f5d6c96082dc9dff",
"sourceBytes": 14599
},
{
"source": "notes/tradeoff-removal/xterm/terminal-osc-link-retirement-benchmarked.ts",
"archived": null,
"sourceSha256": "6609eb53c0bf79d9330f1051e870924da8f8e8663f5a90bff3a9f437311744a4",
"sourceBytes": 4403
},
{
"source": "notes/tradeoff-removal/xterm/terminal-osc-link-retirement.ts",
"archived": null,
"sourceSha256": "9be36d6c51fb830cbe01aff6bcdf961c596d788af20ec5fe75ca956f9e21ba3a",
"sourceBytes": 4484
},
{
"source": "notes/tradeoff-removal/xterm/osc-validation-final.log",
"archived": null,
"sourceSha256": "f58f7474e96872a78312e54f6b17731370e0eb32770d9a0aa2f4e99599d2e050",
"sourceBytes": 7114
},
{
"source": "notes/tradeoff-removal/xterm/osc-sweep-benchmark.mjs",
"archived": null,
"sourceSha256": "aadda4262daa44f0b578e44cdf2ec3d73e1beb15aaf377086609fed3ee8d100e",
"sourceBytes": 4430
},
{
"source": "notes/tradeoff-removal/xterm/bufferline-source-experiment.cjs",
"archived": null,
"sourceSha256": "d6aa881c4d7562ab42951df648712de275de78f55efd8974e5284481c508aed9",
"sourceBytes": 8999
},
{
"source": "notes/tradeoff-removal/xterm/cache-revisit-proof.cjs",
"archived": null,
"sourceSha256": "52b676ed2058a2ae603bc254ab8e047752aee2e9bb697f2138f53607a4db100b",
"sourceBytes": 4962
},
{
"source": "notes/tradeoff-removal/xterm/20955-verdict.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/xterm/20955-verdict.json",
"sourceSha256": "ea0c5fbf99c7c860abeec9d6fadc42668b4a22976511f2246453dfda8b5beb81",
"sourceBytes": 13086,
"archivedSha256": "dbde45f0f11a10301803ec4852f8f657bf000119075dc1b79538484dde44e1b2",
"archivedBytes": 12646
},
{
"source": "notes/tradeoff-removal/xterm/summary.md",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/xterm/summary.md",
"sourceSha256": "b7e3a608964581d983d1811219d56b0ca7eaa59044dc3102bdcb148ea34069d5",
"sourceBytes": 1809,
"archivedSha256": "4fb63ccdb4bb84d740b80b15649b9f959bd8d17f45d4dc61731de1f79592a4ee",
"archivedBytes": 3067
},
{
"source": "notes/tradeoff-removal/xterm/proof-manifest.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/xterm/proof-manifest.json",
"sourceSha256": "58ece455cc1d1199ef14b631b0d75fe2a3066cd3222b5629cc7c41f5031f2ca8",
"sourceBytes": 6594,
"archivedSha256": "c79eed8014a2f59cc4fd7bd0b072613070535c6d52e6adf2c3e692c983cdf20f",
"archivedBytes": 6574
},
{
"source": "notes/tradeoff-removal/xterm/osc-exploratory-observations.json",
"archived": "docs/audits/memory-pr-tradeoff-review-2026-09-18/xterm/osc-exploratory-observations.json",
"sourceSha256": "4579414714f47ae9aa54bd8b7aa665a15a76a4f1003de71e2a75d14767771f85",
"sourceBytes": 1301,
"archivedSha256": "4579414714f47ae9aa54bd8b7aa665a15a76a4f1003de71e2a75d14767771f85",
"archivedBytes": 1301
}
]
}
@@ -0,0 +1,43 @@
{
"pr": 21014,
"url": "https://github.com/stablyai/orca/pull/21014",
"publishedHead": "099f3396524554fc6725a7f0b727434dc7369527",
"classification": "residual_cost_no_low_risk_behavior_preserving_replacement",
"verdict": "Keep the lifecycle generation fence. A continuously changing PTY inventory can still require retry or return unavailable.",
"tradeoff": "A lifecycle change on the target execution host invalidates an in-flight census. One retry shares the original deadline; further churn or missing fresh evidence can produce terminal_liveness_unavailable.",
"existingMechanisms": [
"Aggregate and provider-specific generations already avoid invalidation by unrelated known execution hosts.",
"Captured physical incarnations distinguish predecessor exits from successor processes.",
"The bounded retry already admits a refreshed census when it fits the original deadline."
],
"alternatives": [
{
"approach": "Accept the earlier inventory",
"rejectedBecause": "Can restore a retired predecessor or remove newly admitted successor PTYs; stale evidence does not prove exited."
},
{
"approach": "Retry until a stable inventory arrives",
"rejectedBecause": "Introduces potentially unbounded latency and repeated host RPC work."
},
{
"approach": "Serialize lifecycle changes behind the census",
"rejectedBecause": "Delays spawn/exit processing; changes ownership timing and does not establish unreachable-host freshness."
},
{
"approach": "Overlay every concurrent per-PTY lifecycle event onto the old response",
"rejectedBecause": "Could reduce some same-host retries, but requires additional observation custody and complete event/incarnation coverage. Legacy or unavailable hosts still cannot provide missing facts. This is a larger protocol/ownership design, not a demonstrated zero-cost replacement."
}
],
"tests": [
{
"head": "099f3396524554fc6725a7f0b727434dc7369527",
"passed": 18,
"suites": 2,
"log": "21014-tests.log",
"graph": "21014-graph.json",
"coverage": "Predecessor/successor identity, legacy unstamped IDs, unknown-start spawn, ignored predecessor exit, host scoping, aggregate/target order, and one retry deadline."
}
],
"candidateCommit": null,
"executionBoundary": "Local/SSH host-scoped fixtures passed. Unavailable contact stays unverifiable; it is never converted to exited. No live SSH host was exercised."
}
@@ -0,0 +1,39 @@
{
"pr": 21020,
"url": "https://github.com/stablyai/orca/pull/21020",
"publishedHead": "ee8d1c0c4a4fd87e09d24895c0525497006dc5a9",
"classification": "residual_cost_no_low_risk_behavior_preserving_replacement",
"verdict": "Keep the post-acknowledgement identity check. A close racing a replacement or new leaf can still require a fresh user action.",
"tradeoff": "The original close can be refused as stale-terminal if the acknowledged tab now names a new creation/generation, successor physical incarnation, or new leaf. The current snapshot is republished.",
"existingMechanisms": [
"The acknowledgement captures host, tab creation/generation, leaves, PTYs, physical incarnations, and observed snapshot identity.",
"Removal of original exited leaves is already tolerated; not every harmless mutation is rejected.",
"Commit rechecks pin policy and preserves newer successor state."
],
"alternatives": [
{
"approach": "Blindly retry close on the same tab ID",
"rejectedBecause": "May close a newly created tab or newly running leaf that the original action did not authorize."
},
{
"approach": "Return closed=true while retaining a replacement",
"rejectedBecause": "Misreports retirement and can make callers remove current mirrored state."
},
{
"approach": "Keep retrying until identity stabilizes",
"rejectedBecause": "Adds latency or hangs under churn; any finite retry still has the same race."
}
],
"tests": [
{
"head": "ee8d1c0c4a4fd87e09d24895c0525497006dc5a9",
"passed": 11,
"suites": 1,
"log": "21020-tests.log",
"graph": "21020-graph.json",
"coverage": "Reused IDs/generations, physical split exits and promotion, persisted successors, pin races, dormant SSH kill IDs, and partial snapshots with a new sibling."
}
],
"candidateCommit": null,
"executionBoundary": "Host and physical identity are preserved. A stop request is not proof of exited. SSH fixtures passed; no live SSH host was exercised."
}
@@ -0,0 +1,57 @@
{
"pr": 21175,
"url": "https://github.com/stablyai/orca/pull/21175",
"publishedHead": "c86d273251cad3c9bc4a731651443659dab7e6d1",
"classification": "earlier_normal_flow_warning_withdrawn_with_explicit_scope",
"verdict": "The earlier warning that normal remove/re-pair loses a previously reusable cache is unsupported by the checked flows. No source change is needed to remove that warning.",
"tradeoff": "The PR does delete an unowned retired environment-ID mirror. Direct stale-ID session reads and manual restoration of an old catalog UUID can observe that deletion. Those cases are outside the demonstrated normal catalog-driven re-pair flow.",
"provenFacts": [
"Before and after the PR, addEnvironmentFromPairingCode mints randomUUID even when name and pairing offer are identical. The removed environment namespace is not reused.",
"updateEnvironmentFromPairingCode preserves the UUID only for a currently existing environment. Disconnect and in-place pairing update do not invoke this removal path.",
"Searched supported store, IPC, CLI, and VM resume paths. No supported import/restore API accepting a removed environment UUID was found. This does not promise manual backup compatibility.",
"Profile moves carry workspace sessions with their owning repository; copies omit those sessions. The main-owned repository/folder namespace guard preserves those partitions.",
"Main IPC and renderer removal actions refuse removing the active server. After successful removal, the catalog reload already purges removed-host repos, tabs, and session ownership from mounted renderer state.",
"The renderer mutation, catalog, runtime-status, and purge paths were unchanged by this PR. A stale in-flight request or direct session:get for the retired host ID remains an observable boundary."
],
"checkedPaths": [
"src/shared/runtime-environment-store.ts",
"src/main/ipc/runtime-environment-session-retirement.test.ts",
"src/main/orca-profiles/profile-project-transfer.ts",
"src/main/orca-profiles/profile-project-transfer-payload.ts",
"src/renderer/src/components/settings/use-runtime-environment-mutation-actions.ts",
"src/renderer/src/components/settings/use-runtime-environment-catalog.ts",
"src/renderer/src/store/slices/runtime-status.ts",
"src/renderer/src/store/slices/worktrees/teardown/purge-stale-runtime-host-state.ts"
],
"alternatives": [
{
"approach": "Retain every removed namespace for possible future reuse",
"rejectedBecause": "Retains the orphaned mirrors while ordinary supported re-pair does not consume them. A manual restore/archive feature would require an explicit retention and migration policy."
}
],
"tests": [
{
"head": "291b4ddd6f1c1af480169885e0fda7f9c78ff053",
"passed": 1,
"log": "21175-before-pairing-tests.log",
"graph": "21175-before-pairing-graph.json",
"coverage": "Actual file store: identical remove/re-add gets a new host UUID; in-place update preserves UUID."
},
{
"head": "c86d273251cad3c9bc4a731651443659dab7e6d1",
"passed": 1,
"log": "21175-pairing-tests.log",
"graph": "21175-pairing-graph.json",
"coverage": "Same baseline control at the published PR head."
},
{
"head": "c86d273251cad3c9bc4a731651443659dab7e6d1",
"passed": 16,
"log": "21175-retirement-tests.log",
"graph": "21175-retirement-graph.json",
"coverage": "Actual published retirement tests: local/SSH writes, disconnect/same-ID update preservation, new-ID isolation, legacy partitions, late writers, repeated remove/reload, and failure handling."
}
],
"candidateCommit": null,
"executionBoundary": "Unpair is explicit catalog ownership removal, not evidence that remote processes exited. Main-owned Git and folder namespace guards remain. Mounted-view behavior was traced in source, not exercised in a visible app."
}
@@ -0,0 +1,52 @@
{
"reviewer": "/root/merge_ci_dependencies",
"base": "29820ed587cab4f2ab31a9306ca2180355b3e745",
"head": "48d4af652e5a24758077bc9eaa81e05be1f1a08e",
"decision": "No blocking correctness or ownership regression found in the final follow-up. Preserving the existing bounded view caches does not weaken model retirement.",
"scope": "Independent read-only review of final delta, controller lifecycle, disposal helpers, cache writer sites, installed Monaco view-state representation and saved final validation. No test reruns or source/ref mutations.",
"productionChangedLines": 23,
"findings": [
"The extracted disposeClosedEditorModels body is byte-for-byte identical to the published disposeClosedEditorTabs model-retirement body. The original disposeClosedEditorTabs export remains as a compatibility wrapper that still performs both model disposal and cache cleanup.",
"The lifecycle controller now invokes only model retirement. Registry generation fences, exact captured-model identity, shared/reopened URI ownership checks, attached-model defer/detach callbacks, stale callback invalidation and subscription teardown are unchanged.",
"The cold-registry path previously only removed cache entries; returning early now preserves those values without importing Monaco, acquiring model ownership or leaving any model-retirement operation undone.",
"Production writers use the existing setWithLRU with its default 20-entry cap for scroll, selection, PDF and diff state. Restoring those entries introduces no new quota, producer backlog or model registry owner.",
"Scroll/PDF state consists of numerical positions and selections are coordinate objects. Installed Monaco diff saveViewState serializes both editor view states plus collapsed-region ranges; the cached modelState is not the live diff model.",
"Existing cache bounds are by entry count, not a strict byte ceiling: a view state can contain multiple selections or collapsed regions. This follow-up preserves that pre-existing behavior and should not be described as a hard memory byte bound."
],
"validationReviewed": {
"finalLog": "notes/tradeoff-removal/lifecycle/21178-final-tests.log",
"finalTestCount": "43 tests / 8 files pass",
"sourceGraph": "notes/tradeoff-removal/lifecycle/21178-final-graph.json",
"sourceGraphHead": "48d4af652e5a24758077bc9eaa81e05be1f1a08e",
"candidateRegressionTest": "The notes copy of closed-editor-view-state-retention.test.ts is byte-identical to the final commit; its tests demonstrate model disposal, preserved views, 20-entry LRU across 40 retired models and existing Monaco undo limits.",
"lint": "Saved final lint log is empty; parent/lifecycle agent owns exit-code record.",
"typecheck": "Saved full renderer typecheck reports only NativeChatMessageList.windowing.test.ts TS6196 unused NativeChatMessage. Do not call this a clean full typecheck without separately accounting for that inherited failure.",
"changedSourceHashes": [
{
"path": "src/renderer/src/components/editor/closed-editor-model-lifetime.test.ts",
"sha256": "068e3671310904a246e25195b33442f4136cc8e460f704f7e96d8833701fea81"
},
{
"path": "src/renderer/src/components/editor/closed-editor-model-registry.test.ts",
"sha256": "03cb972d8453968224654146734a52e396c7e9ddf518cfa1af95cccf9f20d2ff"
},
{
"path": "src/renderer/src/components/editor/closed-editor-tab-controller.ts",
"sha256": "2c173f4c3fc44c4e7f65bccaaaf44411ad0c01e4dd2558718cc7cceda264c180"
},
{
"path": "src/renderer/src/components/editor/closed-editor-tab-disposal.ts",
"sha256": "320b609399a770ba373bada4592ca19793e2dc376acac68a2cce5d14328c49fd"
},
{
"path": "src/renderer/src/components/editor/closed-editor-view-state-retention.test.ts",
"sha256": "22d36aadf8b759be33d42b8ad0e48a1cce6a368a8773307d7f12978ef7dc78f3"
}
]
},
"nonBlockingNotes": [
"The comment above the newly extracted disposeClosedEditorModels still says it releases view-state cache entries; update wording if convenient because that function now only retires models.",
"The registry callback local name pendingCaches now denotes pending closed-file descriptors only; a naming cleanup is optional and has no correctness effect."
],
"remainingUserTradeoff": "This improves close/reopen scroll, selection, PDF and diff-view continuity. It does not remove Monaco undo-history limitations: saved undo beyond Monaco's retention size or unsupported URI forms can still disappear after model disposal. Keep that caveat when judging the whole original #21178, rather than describing this follow-up as eliminating every tradeoff."
}
@@ -0,0 +1,89 @@
{
"pr": 21178,
"url": "https://github.com/stablyai/orca/pull/21178",
"publishedHead": "29820ed587cab4f2ab31a9306ca2180355b3e745",
"classification": "partial_tradeoff_removal_proven_residual_undo_cost",
"verdict": "Candidate preserves existing bounded reopen view state while still disposing closed Monaco models. Undo retention is better than the earlier warning suggested, but it is not unlimited or uniform across URI forms.",
"candidateCommit": "48d4af652e5a24758077bc9eaa81e05be1f1a08e",
"candidateParent": "29820ed587cab4f2ab31a9306ca2180355b3e745",
"candidateTree": "ef080c6b56e810e1895b2378bfc775407783ca9a",
"productionChangedLoc": 23,
"totalChangedLoc": 165,
"filesChanged": 5,
"removedTradeoff": "Closing the final owner no longer discards the existing bounded scroll, selection, PDF position, or diff-view caches merely to dispose the model. The existing 20-entry-per-cache LRU still applies.",
"implementation": "Reuse the existing disposal implementation via disposeClosedEditorModels; the app-shell controller uses model-only cleanup. Keep the original full disposal wrapper for direct callers. Cold-registry cleanup no longer erases view caches.",
"existingMechanisms": [
"All checked production writes to the four view caches already use setWithLRU with the existing 20-entry limit.",
"Installed Monaco ModelService retains eligible closed-file undo outside the disposed model, with its existing 20 MiB closed-history budget and 10 MiB SHA/file eligibility limit.",
"Real Monaco controls preserve small POSIX/file-URI undo across dispose/recreate when content and URI match."
],
"residualTradeoffs": [
"Raw Windows drive paths passed to URI.parse use a drive-letter scheme and fail Monaco closed-file undo eligibility. The cross-platform parser behavior was measured; native Windows was not run.",
"The measured file above 10 MiB loses undo on disposal. Monaco also has an existing 20 MiB aggregate closed-file undo budget and content/URI matching conditions.",
"The cache retains only its existing 20 entries per cache; closing more files does not create unlimited reopen-state retention.",
"No promise is made that every prior live-model undo history survives. Keeping unlimited old histories would reintroduce retained data or require a new product retention policy."
],
"alternatives": [
{
"approach": "Preserve existing bounded view caches",
"result": "Implemented and proved against the published PR control."
},
{
"approach": "Depend on Monaco existing closed-file undo restoration",
"result": "Verified for supported URI/content cases, explicitly bounded and not sufficient to erase all undo tradeoffs."
},
{
"approach": "Globally migrate raw Windows model paths to file URIs",
"rejectedBecause": "Changes model identity across multiple owners, diff variants, and reuse lookups. This needs coordinated cross-platform identity migration, not a safe one-line change inside cleanup."
},
{
"approach": "Keep models or archive all undo data after close",
"rejectedBecause": "Retains the original unbounded data or moves it to new unbounded storage."
}
],
"tests": [
{
"head": "29820ed587cab4f2ab31a9306ca2180355b3e745",
"passed": 3,
"expectedFailures": 2,
"log": "21178-published-tests.log",
"graph": "21178-published-graph.json",
"coverage": "Published PR control fails view-state retention and existing-LRU preservation; three small URI undo measurements pass."
},
{
"head": "48d4af652e5a24758077bc9eaa81e05be1f1a08e",
"passed": 43,
"suites": 8,
"log": "21178-final-tests.log",
"graph": "21178-final-graph.json",
"coverage": "Real Monaco lifecycle, detach/reopen races, shared/live ownership, registry fencing, cache sweeps, retained bounded view state, 40 model closures with only 20 cached positions, and undo URI/large-file limits."
}
],
"validation": {
"ordinaryLint": {
"result": "pass",
"paths": 5,
"log": "21178-final-lint.log"
},
"antiSlop": {
"result": "pass",
"paths": 5,
"log": "21178-anti-slop.log"
},
"scopedTypecheck": {
"result": "pass",
"log": "21178-scoped-typecheck.log",
"config": "21178-typecheck-tree/config/tsconfig.lifecycle-review.json",
"scope": "All five changed paths and transitive imports, exact candidate sources, original web compiler settings with explicit Node/Electron ambient types needed when narrowing entry files."
},
"fullWebTypecheck": {
"result": "one unrelated pre-existing diagnostic",
"log": "21178-typecheck.log",
"diagnostic": "NativeChatMessageList.windowing.test.tsx:12 TS6196 unused NativeChatMessage import; this entire file is unchanged from published head."
},
"diffCheck": "pass",
"sourceVerification": "source-verification.json"
},
"publicationStatus": "Unpublished candidate for root review. Primary source/index untouched; no push or merge.",
"executionBoundary": "Renderer ownership remains independent of Git versus folder workspaces and does not infer remote process state. Real Monaco ran headlessly under happy-dom; no native Windows or live SSH session was exercised."
}
@@ -0,0 +1,47 @@
{
"pr": 21185,
"url": "https://github.com/stablyai/orca/pull/21185",
"publishedHead": "7ac04b01a2c97451fd5e2df3af79745bac36a1cc",
"classification": "residual_retention_policy_cost_alternative_tested_and_rejected",
"verdict": "Successful uninstall must release obsolete plugin log rings to fix this retention. Preserving every old plugin-key history keeps the retained data; no zero-cost replacement was demonstrated.",
"tradeoff": "Old worker-log rows disappear after successful uninstall and are unavailable if the same plugin key is later reinstalled. Failed uninstall keeps the history. Late callbacks from retired producers are fenced.",
"existingMechanisms": [
"The buffer caps each plugin ring at 200 rows but has no global bound across removed plugin keys.",
"The ordinary renderer log hook already drops uninstalled plugin keys; direct getLogs and later same-key reinstall are where old history can matter.",
"PluginAuditLog already rotates at 10 MiB, but records security/mutation events rather than the worker-output log rows. It is not an existing lossless archive of this data."
],
"rejectedCandidateCommit": "7c9ba477a654a49a18576075139a3221eecf5f97",
"rejectedCandidatePurpose": "Feasibility control only: rotate the producer token on clear, retaining the lines. It preserves old history and fences late writers, but all eight removed rings remain reachable.",
"alternatives": [
{
"approach": "Rotate producer token but keep historical lines",
"rejectedBecause": "Actual GC control retains 8/8 removed 200-row rings, compared with 0/8 for the published fix."
},
{
"approach": "Write all history to a new archive",
"rejectedBecause": "Adds unbounded disk retention unless a new eviction policy is chosen; persistence is not free lossless removal of the tradeoff."
},
{
"approach": "Global LRU, weak references, or audit-log reuse",
"rejectedBecause": "Introduces observable eviction or nondeterministic loss, or changes the existing audit stream content/retention policy."
}
],
"tests": [
{
"head": "7ac04b01a2c97451fd5e2df3af79745bac36a1cc",
"passed": 2,
"log": "21185-published-tests.log",
"graph": "21185-published-graph.json",
"coverage": "Old producer callbacks fenced, new capture works, retired history removed, 0/8 removed rings survive forced GC."
},
{
"head": "7c9ba477a654a49a18576075139a3221eecf5f97",
"passed": 2,
"log": "21185-alternative-tests.log",
"graph": "21185-alternative-graph.json",
"coverage": "Old producer callbacks fenced and old history retained, but all 8/8 removed rings with 200 rows each survive forced GC."
}
],
"candidateCommit": null,
"executionBoundary": "No remote execution state is inferred. The rejected alternative was isolated in Git objects; it must not be published as a memory fix."
}
@@ -0,0 +1,24 @@
# Lifecycle tradeoff review
| PR | Result | Remaining user-visible cost |
| ------ | ------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| #21014 | Keep existing safety fence; 18 tests pass. | PTY inventory churn can require retry or report unavailable; missing host evidence cannot safely be treated as exited. |
| #21020 | Keep post-acknowledgement identity check; 11 tests pass. | A close racing a new tab/leaf/incarnation can require a fresh action. |
| #21175 | Withdraw the earlier normal remove/re-pair warning; no code change. | Explicit unpair deletes an unowned retired-ID mirror. Stale-ID direct reads and manual old-UUID restoration remain outside the demonstrated normal flow. |
| #21178 | Partial removal implemented: preserve existing bounded view caches while disposing models. | Monaco closed-file undo remains subject to its size budget, URI eligibility, and content match; raw Windows drive URI and >10 MiB controls lose undo. |
| #21185 | Preserve-history alternative tested and rejected. | Successful uninstall loses old worker logs. Keeping them retains all removed-key rings; an archive/eviction policy would introduce another cost. |
## Publishable candidate for root review
`48d4af652e5a24758077bc9eaa81e05be1f1a08e` is parented directly on #21178 head `29820ed587cab4f2ab31a9306ca2180355b3e745`.
- Five changed paths; 23 production changed lines, 165 total changed lines.
- 43 tests across eight suites pass at this exact candidate.
- Ordinary lint, anti-slop, scoped TypeScript, and diff whitespace check pass.
- Full web TypeScript reports one unrelated, unchanged unused import in `NativeChatMessageList.windowing.test.tsx:12`; this is disclosed rather than called a full pass.
- All candidate exports match Git objects. Eleven test graphs contain 8,496 distinct verified head/path source records. The exact-source typecheck snapshot contains 22,435 verified files.
- Dependencies are the installed workspace versions. Tests used background launch; no desktop window was shown. No native Windows, live SSH, or affected-host session was exercised.
`7c9ba477a654a49a18576075139a3221eecf5f97` is a **rejected #21185 feasibility control**, not a publication candidate.
No source worktree/index changes, pushes, PR mutations, or merges were performed by this task.
@@ -0,0 +1,97 @@
{
"p21401": {
"number": 21401,
"url": "https://github.com/stablyai/orca/pull/21401",
"state": "OPEN",
"headRefName": "np-oom-scan-daemon-refill-retirement",
"headRefOid": "d01363acb769306788de24b97154919e7531ef03",
"baseRefName": "main",
"commits": {
"nodes": [
{
"commit": {
"statusCheckRollup": {
"state": "PENDING"
}
}
}
]
}
},
"p21128": {
"number": 21128,
"url": "https://github.com/stablyai/orca/pull/21128",
"state": "OPEN",
"headRefName": "np-oom-scan-crashpad-read-limit",
"headRefOid": "09dbe227547fadaec8d9163f35fd127b0dc1c3ed",
"baseRefName": "main",
"commits": {
"nodes": [
{
"commit": {
"statusCheckRollup": {
"state": "PENDING"
}
}
}
]
}
},
"p21178": {
"number": 21178,
"url": "https://github.com/stablyai/orca/pull/21178",
"state": "OPEN",
"headRefName": "np-oom-scan-closed-editor-models",
"headRefOid": "44fe1887bbbf2aae8957fff988a9a673f63a3b8c",
"baseRefName": "main",
"commits": {
"nodes": [
{
"commit": {
"statusCheckRollup": {
"state": "PENDING"
}
}
}
]
}
},
"p21175": {
"number": 21175,
"url": "https://github.com/stablyai/orca/pull/21175",
"state": "OPEN",
"headRefName": "np-oom-scan-paired-host-session-retirement",
"headRefOid": "c86d273251cad3c9bc4a731651443659dab7e6d1",
"baseRefName": "np-oom-scan-local-empty-tab-retirement",
"commits": {
"nodes": [
{
"commit": {
"statusCheckRollup": {
"state": "FAILURE"
}
}
}
]
}
},
"p20955": {
"number": 20955,
"url": "https://github.com/stablyai/orca/pull/20955",
"state": "OPEN",
"headRefName": "np-oom-scan-osc-link-retirement",
"headRefOid": "5e984fd09326c41a596863a3dee6607d3a1024ad",
"baseRefName": "main",
"commits": {
"nodes": [
{
"commit": {
"statusCheckRollup": {
"state": "FAILURE"
}
}
}
]
}
}
}
@@ -0,0 +1,38 @@
{
"base": "99071175698dead2566d613bc52393b5e3c373a0",
"scope": "Separate cleanup-only fix; does not replace #20947 live-backlog backpressure policy",
"files": [
{
"path": "src/main/daemon/daemon-stream-data-batcher.ts",
"added": 9,
"deleted": 20,
"changed": 29,
"test": false,
"sha256": "fccd4796f511a959f76c2d2b29985457da2a946766f673caa15da4d87ae0f3b9",
"baseSha256": "958a01e69c8e24f6eeebe44d0ba0e4e3fe50cb27e7c2302ee8582827633ee26f"
},
{
"path": "src/main/daemon/daemon-stream-held-refill.ts",
"added": 35,
"deleted": 0,
"changed": 35,
"test": false,
"sha256": "9af9434c1e2d11576fe4f4fcb315dd857078c9c27f717f36b60f367ac3ccd5e5",
"baseSha256": null
},
{
"path": "src/main/daemon/daemon-stream-refill-retirement.test.ts",
"added": 122,
"deleted": 0,
"changed": 122,
"test": true,
"sha256": "e5fa9a6482b1e98e6095b27a0c530a4f3fa9bea38246e0da743c291814b161eb",
"baseSha256": null
}
],
"productionChangedLines": 64,
"testChangedLines": 122,
"candidateTestProjection": "Published test copy changes only relative source import from the tested notes fixture",
"typecheck": "Not yet run; parent should run candidate validation before publication",
"patch": "notes/tradeoff-removal/queues/20947/cleanup-only.patch"
}
@@ -0,0 +1,225 @@
--- a/src/main/daemon/daemon-stream-data-batcher.ts
+++ b/src/main/daemon/daemon-stream-data-batcher.ts
@@ -1,11 +1,8 @@
import type { Socket } from 'node:net'
import { encodeNdjson, NDJSON_MAX_LINE_BYTES } from './ndjson'
import { recordDaemonStreamBacklogEvent } from './daemon-stream-backlog-probe'
-import {
- clampToSafeSplitIndex,
- encodeStreamDataEvent,
- writeStreamDataEvents
-} from './daemon-stream-data-split'
+import { clampToSafeSplitIndex, writeStreamDataEvents } from './daemon-stream-data-split'
+import { DaemonStreamHeldRefill } from './daemon-stream-held-refill'
import type { PendingStreamDataBatch } from './daemon-stream-keep-tail-drop'
import type { DaemonEvent } from './types'
import { appendDaemonStreamData, type DaemonStreamEnqueueOptions } from './daemon-stream-data-entry'
@@ -44,6 +41,7 @@
export class DaemonStreamDataBatcher {
private pendingByClient = new Map<string, PendingStreamDataBatch>()
+ private readonly heldRefill = new DaemonStreamHeldRefill((clientId) => this.flush(clientId))
private getClient: (clientId: string) => StreamDataClient | undefined
private maxLineBytes: number
private onAfterSocketWrite: (() => void) | undefined
@@ -229,24 +227,14 @@
if (retained.length > 0) {
batch.queue = retained
// 'drain' only fires when the buffer fully empties (one gate-depth/turn = seconds for multi-MB backlogs); arm a no-op data event whose flush callback re-flushes while bytes are still in flight.
- this.armHeldQueueRefill(socket, clientId, retained[0].sessionId)
+ if (!socket.destroyed) {
+ this.heldRefill.arm(clientId, retained[0].sessionId, (line, complete) =>
+ socket.write(line, complete)
+ )
+ }
return
}
this.pendingByClient.delete(clientId)
- }
-
- private refillArmedClients = new Set<string>()
-
- private armHeldQueueRefill(socket: Socket, clientId: string, sessionId: string): void {
- if (this.refillArmedClients.has(clientId) || socket.destroyed) {
- return
- }
- this.refillArmedClients.add(clientId)
- // Must be a real protocol no-op line, not an empty write: an empty write's callback fires immediately, defeating the in-flight re-flush.
- socket.write(encodeStreamDataEvent(sessionId, ''), () => {
- this.refillArmedClients.delete(clientId)
- this.flush(clientId)
- })
}
private queuedCharsForSession(
@@ -324,6 +312,7 @@
}
clear(clientId?: string): void {
+ this.heldRefill.clear(clientId)
const batches =
clientId === undefined
? Array.from(this.pendingByClient.entries())
--- /dev/null
+++ b/src/main/daemon/daemon-stream-held-refill.ts
@@ -0,0 +1,35 @@
+import { encodeStreamDataEvent } from './daemon-stream-data-split'
+
+export class DaemonStreamHeldRefill {
+ private readonly armed = new Map<string, symbol>()
+
+ constructor(private readonly flush: (clientId: string) => void) {}
+
+ arm(
+ clientId: string,
+ sessionId: string,
+ write: (line: string, complete: () => void) => void
+ ): void {
+ if (this.armed.has(clientId)) {
+ return
+ }
+ const refill = Symbol()
+ this.armed.set(clientId, refill)
+ // A real no-op frame waits for preceding writes; an empty write can complete immediately.
+ write(encodeStreamDataEvent(sessionId, ''), () => {
+ if (this.armed.get(clientId) !== refill) {
+ return
+ }
+ this.armed.delete(clientId)
+ this.flush(clientId)
+ })
+ }
+
+ clear(clientId?: string): void {
+ if (clientId === undefined) {
+ this.armed.clear()
+ } else {
+ this.armed.delete(clientId)
+ }
+ }
+}
--- /dev/null
+++ b/src/main/daemon/daemon-stream-refill-retirement.test.ts
@@ -0,0 +1,122 @@
+import { Socket } from 'node:net'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+import { DaemonStreamDataBatcher } from './daemon-stream-data-batcher'
+
+function makeSocket() {
+ const socket = new Socket()
+ const completions: (() => void)[] = []
+ const writes: string[] = []
+ const buffered = vi.spyOn(socket, 'writableLength', 'get').mockReturnValue(128 * 1024)
+ vi.spyOn(socket, 'write').mockImplementation((...args) => {
+ writes.push(String(args[0]))
+ const complete = args.at(-1)
+ if (typeof complete === 'function') {
+ completions.push(() => complete())
+ }
+ return false
+ })
+ return { socket, completions, writes, buffered }
+}
+
+function refillOwnerCount(batcher: DaemonStreamDataBatcher): number {
+ const instance: unknown = batcher
+ if (typeof instance !== 'object' || instance === null) {
+ throw new Error('Missing batcher instance')
+ }
+ const owner = 'heldRefill' in instance ? instance.heldRefill : instance
+ if (typeof owner !== 'object' || owner === null) {
+ throw new Error('Missing refill owner')
+ }
+ const entries =
+ 'armed' in owner
+ ? owner.armed
+ : 'refillArmedClients' in owner
+ ? owner.refillArmedClients
+ : undefined
+ if (entries instanceof Map || entries instanceof Set) {
+ return entries.size
+ }
+ throw new Error('Missing refill ownership collection')
+}
+
+describe('retired daemon stream refill owners', () => {
+ beforeEach(() => vi.useFakeTimers())
+ afterEach(() => {
+ vi.clearAllTimers()
+ vi.useRealTimers()
+ vi.restoreAllMocks()
+ })
+
+ it('releases every disconnected client id before socket callbacks settle', () => {
+ const transport = makeSocket()
+ const batcher = new DaemonStreamDataBatcher(() => ({ streamSocket: transport.socket }))
+ for (let index = 0; index < 200; index += 1) {
+ const clientId = `retired-client-${index}`
+ batcher.enqueue(clientId, 'session', 'x'.repeat(8192))
+ batcher.flush(clientId)
+ batcher.clear(clientId)
+ expect(batcher.queuedCharsForClient(clientId)).toBe(0)
+ }
+ expect(transport.completions).toHaveLength(200)
+ expect(refillOwnerCount(batcher)).toBe(0)
+ })
+
+ it('prevents a retired completion from flushing or disarming a replacement client', () => {
+ const old = makeSocket()
+ const replacement = makeSocket()
+ let current = old
+ const batcher = new DaemonStreamDataBatcher(() => ({ streamSocket: current.socket }))
+ batcher.enqueue('client', 'session', 'old'.repeat(4096))
+ batcher.flush('client')
+ batcher.clear('client')
+ current = replacement
+ batcher.enqueue('client', 'session', 'new'.repeat(4096))
+ batcher.flush('client')
+ const flush = vi.spyOn(batcher, 'flush')
+ old.completions[0]()
+ expect(flush).not.toHaveBeenCalled()
+ expect(replacement.completions).toHaveLength(1)
+ expect(refillOwnerCount(batcher)).toBe(1)
+ replacement.buffered.mockReturnValue(0)
+ replacement.completions[0]()
+ expect(flush).toHaveBeenCalledOnce()
+ expect(batcher.queuedCharsForClient('client')).toBe(0)
+ expect(refillOwnerCount(batcher)).toBe(0)
+ })
+
+ it('preserves complete live output and releases its owner when writes drain', () => {
+ const transport = makeSocket()
+ const batcher = new DaemonStreamDataBatcher(() => ({ streamSocket: transport.socket }))
+ const output = 'ordinary-live-output\n'.repeat(1024)
+ batcher.enqueue('client', 'session', output)
+ batcher.flush('client')
+ expect(batcher.queuedCharsForClient('client')).toBe(output.length)
+ transport.buffered.mockReturnValue(0)
+ transport.completions[0]()
+ const delivered = transport.writes
+ .map((line) => JSON.parse(line))
+ .filter((event) => event.event === 'data')
+ .map((event) => event.payload.data)
+ .join('')
+ expect(delivered).toBe(output)
+ expect(batcher.queuedCharsForClient('client')).toBe(0)
+ expect(refillOwnerCount(batcher)).toBe(0)
+ })
+
+ it('clears all owner metadata and ignores all late completions at shutdown', () => {
+ const transport = makeSocket()
+ const batcher = new DaemonStreamDataBatcher(() => ({ streamSocket: transport.socket }))
+ for (const client of ['one', 'two']) {
+ batcher.enqueue(client, 'session', 'x'.repeat(8192))
+ batcher.flush(client)
+ }
+ batcher.clear()
+ const flush = vi.spyOn(batcher, 'flush')
+ for (const complete of transport.completions) {
+ complete()
+ }
+ expect(flush).not.toHaveBeenCalled()
+ expect(refillOwnerCount(batcher)).toBe(0)
+ expect(vi.getTimerCount()).toBe(0)
+ })
+})
@@ -0,0 +1,51 @@
{
"decision": "Keep original PR held: complete live-overload protection requires a user-visible or resource tradeoff.",
"conservationConstraint": "With an indefinitely stalled consumer and continued arbitrary new input, undelivered information grows as produced minus consumed. Finite memory cannot retain every byte while leaving producer progress unchanged. Existing lossless bounded replay could change ownership, but no such complete replay owner exists in these three paths.",
"notZeroTradeoff": [
"Spooling introduces disk I/O, capacity, retention and privacy costs; finite disk eventually fills.",
"Raising/removing limits delays or restores unbounded memory growth.",
"Compression improves some inputs but consumes CPU and cannot bound arbitrary incompressible input.",
"Pull/ACK protocols move the wait to the producer; they do not make live input disappear."
],
"compatibilityReview": [
"docs/reference/ssh-execution-boundary.md",
"docs/reference/remote-wire-compatibility.md"
],
"validationLimits": "Exact-head repository source loader; locally installed packages. Unit/socket/worker tests ran with ORCA_BACKGROUND_LAUNCH=1. No visible application, SSH mixed-version integration, native speech recognition or cross-platform matrix was run.",
"number": 20947,
"head": "ca5aea1a056bcf38ff989907071e6beea003c5de",
"base": "07c7606feebc850d8b82c8c85a6a7fda71f29f14",
"risk": "Medium: producer progress may stall under a slow visible terminal subscriber.",
"originalProductionChangedLines": 568,
"mechanism": "Aggregates held data/control metadata and native socket writes; at 4 MiB aggregate high water pauses sessions contributing at least 64 KiB. Aggregate low water is 1 MiB and per-session low water 32 KiB. The separate stream-backpressure owner persists beyond the 5-second lost-resume failsafe.",
"tradeoff": "A paused PTY read can fill its OS pipe and block the child process. This may remain until stream pressure falls or the connection/session releases ownership. The execution host must own this decision; a remote disconnect does not establish process death.",
"existingRecoveryExamined": [
"session-output-plane.ts stores only 2,097,152 UTF-16 code units of pending delta before falling back to an emulator snapshot. It is not an unlimited byte journal.",
"terminal-history-session-writer.ts rotates its 5 MiB incremental log into checkpoints. Checkpoints are capped at 200,000,000 bytes and can trim old rows; emulator scrollback does not reconstruct every transient event.",
"dataGap and keep-tail dropping are existing policies for explicitly backgrounded sessions. Extending them to visible output changes which bytes/events clients receive, including old clients. Query salvage is not general event replay."
],
"rejectedAlternatives": [
"Resume automatically after the existing 5-second client pause failsafe: reopens the unbounded live stream growth this PR fixes.",
"Disconnect/resnapshot a visible subscriber: keeps the child running but drops intermediate output/transient events and changes recovery semantics.",
"Move the queue into history/spool: current history is bounded state, and a new lossless spool carries disk/retention/latency costs."
],
"safeScopeReduction": {
"status": "Implemented as a separate cleanup-only candidate, not a replacement for the original PR.",
"base": "99071175698dead2566d613bc52393b5e3c373a0",
"patch": "notes/tradeoff-removal/queues/20947/cleanup-only.patch",
"manifest": "notes/tradeoff-removal/queues/20947/candidate-manifest.json",
"productionChangedLines": 64,
"behavior": "Retires per-client refill owner tokens in clear(client)/clear() and makes late completions from retired sockets no-ops. Reuses the original PR's DaemonStreamHeldRefill implementation. No new quota, producer pause, frame shape or live output retention policy.",
"beforeControl": "3 expected failures and 1 pass on exact main: 200 retired IDs remain; old callback flushes successor; shutdown callbacks flush retired owners.",
"fixedControl": "31 tests in 3 files pass, including all 4 lifecycle controls and existing byte-order/droppability batcher controls. Ordinary lint and anti-slop lint pass.",
"limit": "Releases this metadata owner and prevents stale actions. Socket implementation may still retain its own pending callback until completion. Live payload overload remains unresolved by this narrow fix.",
"fullTypecheck": "Not run by this agent; parent central validation before publication."
},
"exactHeadTests": {
"passed": 35,
"files": 3,
"log": "20947/exact-head-tests.log"
},
"sourceProvenance": "notes/tradeoff-removal/queues/20947/sources.json",
"testGraph": "notes/tradeoff-removal/queues/20947/tested-source-graph.json"
}
@@ -0,0 +1,8 @@
{
"head": "d01363acb769306788de24b97154919e7531ef03",
"verifiedSources": 303,
"tests": 31,
"testSuites": 3,
"focusedTypecheck": "TypeScript7.0.2: candidate roots+247 exact-source imports; pass",
"fullProjectTypecheck": false
}
@@ -0,0 +1,45 @@
{
"decision": "Keep original PR held: complete live-overload protection requires a user-visible or resource tradeoff.",
"conservationConstraint": "With an indefinitely stalled consumer and continued arbitrary new input, undelivered information grows as produced minus consumed. Finite memory cannot retain every byte while leaving producer progress unchanged. Existing lossless bounded replay could change ownership, but no such complete replay owner exists in these three paths.",
"notZeroTradeoff": [
"Spooling introduces disk I/O, capacity, retention and privacy costs; finite disk eventually fills.",
"Raising/removing limits delays or restores unbounded memory growth.",
"Compression improves some inputs but consumes CPU and cannot bound arbitrary incompressible input.",
"Pull/ACK protocols move the wait to the producer; they do not make live input disappear."
],
"compatibilityReview": [
"docs/reference/ssh-execution-boundary.md",
"docs/reference/remote-wire-compatibility.md"
],
"validationLimits": "Exact-head repository source loader; locally installed packages. Unit/socket/worker tests ran with ORCA_BACKGROUND_LAUNCH=1. No visible application, SSH mixed-version integration, native speech recognition or cross-platform matrix was run.",
"number": 20949,
"head": "d12d1e0a06f3ced9425e98f3593e0864ef16830b",
"base": "e6a41081a3cc723ade11e719286ca6bd67c68884",
"risk": "Medium: overwhelmed CDP client loses its connection and queued replies/events.",
"originalProductionChangedLines": 39,
"mechanism": "CdpClientResponseWriter queues both replies and unsolicited debugger events through the shared outbound queue. Defaults: 8 MiB native soft cap, 64 MiB retained queue, 4096 frames, 128 sends per turn; overflow terminates the client.",
"tradeoff": "Termination drops pending command results and debugger events; CDP has no general event replay/ack cursor in this implementation. Reconnection cannot reconstruct arbitrary already-generated events or results.",
"existingRecoveryExamined": [
"cdp-debugger-channel.ts forwards unsolicited Electron debugger messages and asynchronous sendCommand replies; inbound request flow control alone does not stop those producers.",
"Page.printToPDF supports explicitly requested ReturnAsStream and IO.read/IO.close. This is one opt-in PDF result format backed by the complete PDF buffer, not a general durable CDP event owner. Changing default response shape breaks clients.",
"maxFrameBytes is deliberately Infinity so a draining connection still accepts one large screenshot/PDF reply; therefore the PR is not a strict cap on one-frame serialization/transient allocation."
],
"rejectedAlternatives": [
"Remove only client.terminate(): shared failOverflow already drops the backlog and permanently latches overflowed; this silently loses frames while leaving a dead-but-open connection.",
"Pause inbound requests: does not bound unsolicited Network/Runtime/Debugger events or already-issued command results.",
"Pause the page/debugger or suppress domains: changes application progress or event visibility.",
"Coalesce arbitrary events/responses: no equivalent state snapshot preserves arbitrary event sequence and command results.",
"Set queue limits to Infinity: restores unbounded retention."
],
"safeScopeReduction": {
"status": "No independent cleanup-only patch identified in the original writer change. Close/dispose cleanup is needed for the new queue itself; removing the queue/cap removes the live-backlog fix. Keep original held."
},
"exactHeadTests": {
"passed": 6,
"files": 1,
"log": "20949/exact-head-tests.log",
"coverage": "Includes a real localhost WebSocket stalled-reader overflow and complete 192-frame/12 MiB delivery to a draining client."
},
"sourceProvenance": "notes/tradeoff-removal/queues/20949/sources.json",
"testGraph": "notes/tradeoff-removal/queues/20949/tested-source-graph.json"
}
@@ -0,0 +1,47 @@
{
"decision": "Keep original PR held: complete live-overload protection requires a user-visible or resource tradeoff.",
"conservationConstraint": "With an indefinitely stalled consumer and continued arbitrary new input, undelivered information grows as produced minus consumed. Finite memory cannot retain every byte while leaving producer progress unchanged. Existing lossless bounded replay could change ownership, but no such complete replay owner exists in these three paths.",
"notZeroTradeoff": [
"Spooling introduces disk I/O, capacity, retention and privacy costs; finite disk eventually fills.",
"Raising/removing limits delays or restores unbounded memory growth.",
"Compression improves some inputs but consumes CPU and cannot bound arbitrary incompressible input.",
"Pull/ACK protocols move the wait to the producer; they do not make live input disappear."
],
"compatibilityReview": [
"docs/reference/ssh-execution-boundary.md",
"docs/reference/remote-wire-compatibility.md"
],
"validationLimits": "Exact-head repository source loader; locally installed packages. Unit/socket/worker tests ran with ORCA_BACKGROUND_LAUNCH=1. No visible application, SSH mixed-version integration, native speech recognition or cross-platform matrix was run.",
"number": 21129,
"head": "1f231d6147852a729fcbe4d2b5ad7262391fee27",
"base": "291b4ddd6f1c1af480169885e0fda7f9c78ff053",
"risk": "Medium: overload stops dictation and can discard accepted but not yet finalized transcript.",
"originalProductionChangedLines": 169,
"mechanism": "Counts actual transferred backing-buffer bytes and frames across active and predecessor workers until consumption acknowledgement or real worker exit. At 8 MiB or 1024 pending frames it stops the session and emits an error.",
"tradeoff": "The human microphone producer cannot be slowed losslessly. The rejected frame and subsequent speech are lost. Desktop error handling clears activeSessionId, so later final events are ignored; mobile finish rejects recorded errors even if final text arrives later. Already-inserted text remains.",
"existingRecoveryExamined": [
"The worker acknowledges after processing feedAudio; raw samples are transferred to its queue. There is no file-backed audio journal in this path.",
"Desktop capture sends 4096 Float32 samples per frame (16 KiB): 8 MiB holds 512 such frames, approximately 43.7 seconds at 48 kHz or 47.6 seconds at 44.1 kHz.",
"stop is ordered after admitted audio, but existing stop teardown has a 60-second deadline and can terminate an unresponsive worker. Drain completion cannot be guaranteed for a permanently stuck decoder.",
"Desktop DictationController error path invalidates final ownership; runtime-mobile-dictation-controller records the error and rejects completion."
],
"rejectedAlternatives": [
"Wait for ACK before capture sends: moves samples into another queue or pauses microphone capture and loses speech unless a separate recorder stores it.",
"Delay only the error until the worker drains: current feedAudio ignores audio once stopping, while the UI would still appear to listen, creating silent loss.",
"Spool audio: introduces storage/privacy/I/O/capacity costs and cannot provide finite-resource protection against permanent decoder failure.",
"Compress/resample: carries CPU or quality costs and does not remove the sustained producer/consumer imbalance.",
"Keep only ACK accounting without cap: observes but does not fix retained audio backlog."
],
"safeScopeReduction": {
"status": "No zero-tradeoff localized replacement. Keep original held.",
"possibleReducedTradeoffFollowup": "Stop capture explicitly while preserving the accepted session owner long enough to drain and deliver already-admitted final transcript, then report recoverable overload. This can reduce avoidable accepted-transcript loss, but future capture still stops and the 60-second stuck-worker bound still applies.",
"requiredScope": "Requires distinct capture-stop/final-delivery semantics across desktop and mobile readers, mixed-version compatibility review, owner fencing and stale-final isolation tests. It is a feature behavior change, not a zero-tradeoff queue cleanup."
},
"exactHeadTests": {
"passed": 15,
"files": 2,
"log": "21129/exact-head-tests.log"
},
"sourceProvenance": "notes/tradeoff-removal/queues/21129/sources.json",
"testGraph": "notes/tradeoff-removal/queues/21129/tested-source-graph.json"
}
@@ -0,0 +1,27 @@
[
{
"number": 20947,
"head": "ca5aea1a056bcf38ff989907071e6beea003c5de",
"verifiedSourceCount": 125
},
{
"number": 20949,
"head": "d12d1e0a06f3ced9425e98f3593e0864ef16830b",
"verifiedSourceCount": 8
},
{
"number": 21129,
"head": "1f231d6147852a729fcbe4d2b5ad7262391fee27",
"verifiedSourceCount": 17
},
{
"candidateGraph": "before-graph.json",
"head": "99071175698dead2566d613bc52393b5e3c373a0",
"verifiedSourceCount": 13
},
{
"candidateGraph": "expanded-candidate-graph.json",
"head": "99071175698dead2566d613bc52393b5e3c373a0",
"verifiedSourceCount": 300
}
]
@@ -0,0 +1,31 @@
# Queue tradeoff removal review
All three original PRs remain held. Under sustained overload, their live, undelivered input cannot disappear while preserving every byte, uninterrupted producer progress, and bounded resources. The existing replay mechanisms do not preserve the complete affected streams. Moving retention to disk or another process, increasing caps, and compression all retain costs or the eventual overflow problem.
| Original PR | Can all tradeoffs be removed locally? | Concrete outcome |
| --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| #20947 daemon stream backpressure | No: stalled output subscribers can still block PTY producer progress. Existing snapshot/history recovery is bounded and loses intermediate events. | Extracted a separate **64 production LoC cleanup-only candidate** that retires refill tokens and ignores stale socket callbacks. It does not solve live payload overload. |
| #20949 CDP outbound backlog | No: general CDP events and command results have no replay owner. Pausing page activity, disconnecting, or dropping events changes behavior. | Keep held. Removing only termination would silently discard the queue while leaving the connection open and permanently unable to enqueue. |
| #21129 speech audio backlog | No: a live microphone cannot be paused without losing future speech. Current overload error can also suppress accepted final transcript. | Keep held. A larger graceful-stop contract could preserve more already-admitted transcript, but still stops capture and cannot drain a permanently hung decoder. |
## Separate cleanup candidate
- Base: `99071175698dead2566d613bc52393b5e3c373a0`.
- Patch: [20947/cleanup-only.patch](20947/cleanup-only.patch).
- Files and hashes: [20947/candidate-manifest.json](20947/candidate-manifest.json).
- Reuses the already-reviewed `DaemonStreamHeldRefill` implementation from #20947; no new backpressure, byte limit, protocol frame, timeout or loss policy.
- Exact baseline: **3 expected failures / 1 pass**. Clearing 200 clients retains 200 refill IDs; a retired callback flushes its successor; shutdown callbacks flush retired owners.
- Fixed candidate: **31 tests / 3 files pass**; ordinary lint and anti-slop lint pass. Tests include live output preservation, byte order, and droppability behavior. Full project typecheck is left to central publication validation.
- The owner map releases its references immediately; pending socket callbacks themselves remain governed by socket completion. This is a lifecycle fix, not a claim that all pending socket allocations vanish.
## Evidence
Exact published-head controls: **#20947: 35 tests**, **#20949: 6 tests**, **#21129: 15 tests**, all pass. CDP controls include real localhost sockets. The final candidate adds 31 focused checks. All test/app commands used `ORCA_BACKGROUND_LAUNCH=1`; no visible app was launched.
Per-PR reports contain exact heads, caller/replay review, discarded alternatives and limitations:
- [20947/report.json](20947/report.json)
- [20949/report.json](20949/report.json)
- [21129/report.json](21129/report.json)
[provenance-check.json](provenance-check.json) verifies every dynamically loaded repository source against its named Git head; the candidate overlay hashes are in its test log and manifest. Installed package versions are local. No SSH mixed-version integration, native speech recognition, or cross-platform matrix was run.
@@ -0,0 +1,51 @@
{
"reviewer": "/root/merge_ci_dependencies",
"base": "fa06e08229e677e69592e6f68ea4f9e5a96ffc2b",
"head": "e1141803f475a7de8d790d593668238bd4285d04",
"scope": "Independent read-only review of four changed files and async reader call sites; no mutations and no new test reruns.",
"decision": "No blocking correctness or API regression found in this follow-up delta.",
"productionChangedLines": 21,
"reasoning": [
"The new optional options argument preserves the previous default. Existing callers without followGrowth:false take the exact prior growth-probe path; sync reader is unchanged.",
"For positive-size regular files only, followGrowth:false returns after filling the same-descriptor stat size. It performs no growth probe or second large allocation. Native Buffer readFile controls show matching prefix behavior in both Node 26.6.0 and Electron 43.7.0 / Node 24.21.0.",
"Shrink/early EOF returns only initialized bytes. Zero-size sources still probe/read to EOF under the existing bound. Nonregular files retain the previous path. Initially oversized sizes are still rejected before allocation.",
"Crashpad is the only new opt-in caller. It parses the exact opened prefix and records buffer.byteLength; the reservation remains in a finally block and the claimed-path behavior is preserved.",
"New tests preserve the actual racing dump rather than incorrectly accepting a skipped alternate dump. Separate growth-after-directory-stat remains covered and returns actual opened bytes."
],
"verificationReviewed": {
"nativeReadFileControls": [
"notes/tradeoff-removal/readers/readfile-growth-node.json",
"notes/tradeoff-removal/readers/readfile-growth-electron.json"
],
"recordedByParent": "56 tests / 5 suites pass, 2 expected baseline failures, ordinary and anti-slop lint pass for 4 files, focused TypeScript check pass.",
"sourceHashes": [
{
"path": "src/main/crash-reporting/crashpad-capture-read-limit.test.ts",
"sha256": "d8809cd561e71a84ec9d122c6493f4630d2684c63e26980b1ef0037430548d02",
"exportMatches": true
},
{
"path": "src/main/crash-reporting/crashpad-capture.ts",
"sha256": "b4dffa3f210d5904e79e485df2403739cdf8b3ec661c8fb825ff53dfdf52de33",
"exportMatches": true
},
{
"path": "src/shared/node-bounded-file-reader.test.ts",
"sha256": "7d60e8e86f3d8bb533c17641bbc31d6acb8b5d8b64a737e5d56900adb9c7f222",
"exportMatches": true
},
{
"path": "src/shared/node-bounded-file-reader.ts",
"sha256": "668c59151fa640a307411dc230c68de9ddfedf1c2a4267beb30cc565ee381ddd",
"exportMatches": true
}
],
"nativeControlLimit": "Test-only internal fs binding interception deliberately appends between descriptor fstat and first read. This is concrete evidence for tested runtimes, not a promise about every future Node implementation."
},
"nonBlockingNote": "Existing growth-loop comment says ordinary readFile includes concurrent growth. The new controls show that is not generally true for Buffer reads; consider narrowing the comment to callers that intentionally follow growth. No runtime defect follows from this comment.",
"remainingScopeLimits": [
"This is a partial improvement to #21128, not proof that every original refusal/tradeoff disappeared. Files already oversized at opened-descriptor stat remain rejected under the existing 64 MiB policy.",
"The prefix is not an atomic file snapshot against in-place rewrites; neither was native readFile. This patch does not add such a claim.",
"Independent review did not rerun the parent's successful tests or typecheck."
]
}
@@ -0,0 +1,77 @@
const fs = require('node:fs/promises')
const path = require('node:path')
const assert = require('node:assert/strict')
const binding = process.binding('fs')
async function measure(root, initialBytes, appendedBytes, encoding) {
const file = path.join(root, `case-${initialBytes}-${encoding || 'buffer'}`)
await fs.writeFile(file, Buffer.alloc(initialBytes, 0x61))
const handle = await fs.open(file, 'r')
const original = binding.fstat
let observedSize
let hookCalls = 0
binding.fstat = function (...args) {
const result = original.apply(this, args)
if (args[0] !== handle.fd || !result?.then || hookCalls > 0) return result
hookCalls++
return result.then(async (stats) => {
observedSize = stats[8]
await fs.appendFile(file, Buffer.alloc(appendedBytes, 0x62))
return stats
})
}
let value
try {
value = await handle.readFile(encoding)
} finally {
binding.fstat = original
await handle.close()
}
assert.equal(hookCalls, 1)
assert.equal(observedSize, initialBytes)
return {
initialBytes,
appendedBytes,
encoding: encoding || 'buffer',
observedSize,
returnedBytes: Buffer.byteLength(value),
hookCalls
}
}
async function main() {
const root = await fs.mkdtemp(path.join(__dirname, 'growth-control-'))
try {
const cases = []
for (const [size, encoding] of [
[131, undefined],
[1024 * 1024 + 131, undefined],
[131, 'utf8'],
[1024 * 1024 + 131, 'utf8'],
[0, undefined]
]) {
cases.push(await measure(root, size, 1024 * 1024, encoding))
}
assert.equal(cases[0].returnedBytes, 131)
assert.equal(cases[1].returnedBytes, 1024 * 1024 + 131)
assert.equal(cases[2].returnedBytes, 131)
assert.equal(cases[3].returnedBytes, 2 * 1024 * 1024 + 131)
assert.equal(cases[4].returnedBytes, 1024 * 1024)
process.stdout.write(
JSON.stringify(
{
versions: process.versions,
cases,
meaning:
'Native readFile fstat intercepted once to append before the first read; Buffer and large encoded reads differ. Test-only internal binding interception.'
},
null,
2
) + '\n'
)
} finally {
await fs.rm(root, { recursive: true, force: true })
}
}
main().catch((error) => {
process.stderr.write(error.stack + '\n')
process.exitCode = 1
})
@@ -0,0 +1,78 @@
{
"versions": {
"node": "24.21.0",
"acorn": "8.18.0",
"ada": "4.0.0",
"amaro": "1.1.11",
"ares": "1.34.8",
"brotli": "1.2.0",
"cldr": "48.0",
"icu": "78.2",
"llhttp": "9.4.3",
"merve": "1.2.2",
"modules": "148",
"napi": "10",
"nbytes": "0.1.4",
"ncrypto": "0.0.1",
"nghttp2": "1.70.0",
"nghttp3": "",
"ngtcp2": "",
"openssl": "0.0.0",
"simdjson": "4.6.7",
"simdutf": "7.7.0",
"sqlite": "3.53.4",
"tz": "2025c",
"undici": "7.29.1",
"unicode": "17.0",
"uv": "1.52.1",
"uvwasi": "0.0.23",
"v8": "15.0.245.31-electron.0",
"zlib": "1.3.2.1-motley",
"zstd": "1.6.0",
"electron": "43.7.0",
"chrome": "150.0.7871.250"
},
"cases": [
{
"initialBytes": 131,
"appendedBytes": 1048576,
"encoding": "buffer",
"observedSize": 131,
"returnedBytes": 131,
"hookCalls": 1
},
{
"initialBytes": 1048707,
"appendedBytes": 1048576,
"encoding": "buffer",
"observedSize": 1048707,
"returnedBytes": 1048707,
"hookCalls": 1
},
{
"initialBytes": 131,
"appendedBytes": 1048576,
"encoding": "utf8",
"observedSize": 131,
"returnedBytes": 131,
"hookCalls": 1
},
{
"initialBytes": 1048707,
"appendedBytes": 1048576,
"encoding": "utf8",
"observedSize": 1048707,
"returnedBytes": 2097283,
"hookCalls": 1
},
{
"initialBytes": 0,
"appendedBytes": 1048576,
"encoding": "buffer",
"observedSize": 0,
"returnedBytes": 1048576,
"hookCalls": 1
}
],
"meaning": "Native readFile fstat intercepted once to append before the first read; Buffer and large encoded reads differ. Test-only internal binding interception."
}
@@ -0,0 +1,77 @@
{
"versions": {
"node": "26.6.0",
"acorn": "8.17.0",
"ada": "4.0.0",
"amaro": "1.1.11",
"ares": "1.34.8",
"brotli": "1.2.0",
"cldr": "48.0",
"icu": "78.3",
"libffi": "3.7.1",
"llhttp": "9.4.3",
"merve": "1.2.2",
"modules": "147",
"napi": "10",
"nbytes": "0.1.4",
"ncrypto": "0.0.1",
"nghttp2": "1.70.0",
"nghttp3": "",
"ngtcp2": "",
"openssl": "3.6.3",
"simdjson": "4.6.6",
"simdutf": "7.7.0",
"sqlite": "3.53.4",
"tz": "2026a",
"undici": "8.9.0",
"unicode": "17.0",
"uv": "1.52.1",
"uvwasi": "0.0.23",
"v8": "14.6.202.34-node.26",
"zlib": "1.2.12",
"zstd": "1.5.7"
},
"cases": [
{
"initialBytes": 131,
"appendedBytes": 1048576,
"encoding": "buffer",
"observedSize": 131,
"returnedBytes": 131,
"hookCalls": 1
},
{
"initialBytes": 1048707,
"appendedBytes": 1048576,
"encoding": "buffer",
"observedSize": 1048707,
"returnedBytes": 1048707,
"hookCalls": 1
},
{
"initialBytes": 131,
"appendedBytes": 1048576,
"encoding": "utf8",
"observedSize": 131,
"returnedBytes": 131,
"hookCalls": 1
},
{
"initialBytes": 1048707,
"appendedBytes": 1048576,
"encoding": "utf8",
"observedSize": 1048707,
"returnedBytes": 2097283,
"hookCalls": 1
},
{
"initialBytes": 0,
"appendedBytes": 1048576,
"encoding": "buffer",
"observedSize": 0,
"returnedBytes": 1048576,
"hookCalls": 1
}
],
"meaning": "Native readFile fstat intercepted once to append before the first read; Buffer and large encoded reads differ. Test-only internal binding interception."
}
@@ -0,0 +1,76 @@
{
"scope": "Five file-reader PRs; source audit plus focused controls, not affected-host attribution.",
"rows": [
{
"number": 20963,
"verdict": "No verified zero-tradeoff replacement",
"residual": "Complete JSONL records over 10 MiB remain rejected; the containing session may be incomplete.",
"investigated": [
"Reuse of session-document-stream.ts and existing @streamparser/json projection",
"Existing Codex timeline-only prefix classifier",
"Disk spill and prefix-only success"
],
"finding": "The current callback contracts require a complete record/string or Buffer. Existing JSON projection retains even ignored scalar tokens: two 12 MiB controls retained all 12 MiB with and without partial tokens. Codex prefix classification only covers a subset and runs after record assembly. A parser/consumer redesign may preserve more records, but deleting the guard or moving the same full assembly to another layer reintroduces the allocation. No new parser was published without provider/consumer parity proof.",
"paths": [
"src/main/ai-vault/session-scanner-jsonl-reader.ts",
"src/main/ai-vault/session-document-stream.ts",
"src/main/ai-vault/session-scanner-codex-record-fast-path.ts",
"src/main/ai-vault/session-transcript-consumers.ts",
"src/main/ai-vault/session-transcript-message-content.ts"
]
},
{
"number": 20976,
"verdict": "No verified zero-tradeoff replacement",
"residual": "An initially admissible legacy import that grows beyond 16 MiB is rejected.",
"investigated": [
"Read only the original prefix",
"Retry until stable",
"Streaming decoder plus atomic journal replacement"
],
"finding": "The decoder retains full NativeChatMessage and identity arrays, then constructs the complete replacement epoch. Prefix success can silently publish an incomplete import; retrying a growing writer adds delay and may never settle. A transactional streaming decoder/journal redesign could change the memory model but is not a safe local substitute proven in this pass.",
"paths": [
"src/main/native-chat/agent-session-journal/journal-legacy-import.ts",
"src/main/native-chat/transcript-stream-lines.ts"
]
},
{
"number": 21021,
"verdict": "No verified zero-tradeoff replacement",
"residual": "History growing beyond the existing 16 MiB quota can fail reconciliation.",
"investigated": [
"Stream ancestry and fingerprint generation",
"Accept a bounded prefix",
"Discard parsed text after indexing"
],
"finding": "The history window indexes records and reconstructs exact raw prompt text and fingerprints. Incomplete evidence cannot establish absence of a pending message. A streaming graph/fingerprint redesign needs identity, duplicate, reordered-record and EOF parity; truncation or unconditional success weakens reconciliation.",
"paths": ["src/main/claude/claude-structured-history-window.ts"]
},
{
"number": 21024,
"verdict": "No verified zero-tradeoff replacement",
"residual": "Markers appended beyond the initial read extent can require retry.",
"investigated": [
"Native readFile extent on installed Node and Electron",
"Stream until EOF rather than initial size",
"Treat incomplete prefix as complete proof"
],
"finding": "Real runtime controls show nonempty Buffer reads stop at the initial size, but large UTF-8 reads can include later appends. Thus the prior UTF-8 ancestry reader could include a marker that the fixed-prefix stream misses. Following a continuously growing file adds work/latency and can grow the proof graph. The safe retry is retained.",
"paths": ["src/main/claude/claude-transcript-branch-proof.ts"]
},
{
"number": 21128,
"verdict": "Partial improvement implemented",
"residual": "A dump already over 64 MiB at opened-descriptor stat is still rejected, including growth/replacement before that stat.",
"investigated": [
"Native Buffer readFile extent",
"Explicit followGrowth:false in existing bounded reader",
"Shrink, zero-size, oversize, descriptor/reservation and next-candidate controls"
],
"finding": "Preserve the original opened prefix for positive-size regular files. Growth after descriptor stat no longer unnecessarily rejects that dump or allocates growth copies. Other callers retain default behavior; zero-size sources retain bounded EOF reads.",
"candidateCommit": "09dbe227547fadaec8d9163f35fd127b0dc1c3ed",
"testedCommit": "e1141803f475a7de8d790d593668238bd4285d04",
"validation": "56 tests / 5 suites pass; test-only old-production control has 2 expected failures; 4-file ordinary/anti-slop lint and focused TS7 pass; independent review found no blocker. Final delta is one explanatory comment."
}
]
}
@@ -0,0 +1,35 @@
const assert = require('node:assert/strict')
const { JSONParser } = require('@streamparser/json')
const scalarBytes = 12 * 1024 * 1024
const rows = []
for (const emitPartialTokens of [false, true]) {
const parser = new JSONParser({
paths: ['$.keep'],
keepStack: false,
stringBufferSize: 64 * 1024,
emitPartialTokens
})
const values = []
parser.onValue = ({ value }) => values.push(value)
parser.write('{"ignored":"')
const chunk = 'x'.repeat(64 * 1024)
for (let i = 0; i < scalarBytes / chunk.length; i++) parser.write(chunk)
const retainedScalarBytes = parser.tokenizer.bufferedString.byteLength
assert.equal(retainedScalarBytes, scalarBytes)
assert.equal(parser.tokenizer.bufferedString.toString().length, scalarBytes)
parser.write('","keep":7}')
assert.deepEqual(values, [7])
rows.push({ emitPartialTokens, scalarBytes, retainedScalarBytes, selectedValues: values })
}
console.log(
JSON.stringify(
{
node: process.version,
purpose:
'Path projection and partial-token emission do not discard an ignored giant scalar; this does not rule out a deeper parser redesign.',
rows
},
null,
2
)
)
@@ -0,0 +1,18 @@
{
"node": "v26.6.0",
"purpose": "Path projection and partial-token emission do not discard an ignored giant scalar; this does not rule out a deeper parser redesign.",
"rows": [
{
"emitPartialTokens": false,
"scalarBytes": 12582912,
"retainedScalarBytes": 12582912,
"selectedValues": [7]
},
{
"emitPartialTokens": true,
"scalarBytes": 12582912,
"retainedScalarBytes": 12582912,
"selectedValues": [7]
}
]
}
@@ -0,0 +1,40 @@
{
"reviewer": "/root/merge_ci_dependencies",
"base": "5e984fd09326c41a596863a3dee6607d3a1024ad",
"path": "src/shared/terminal-osc-link-retirement.ts",
"candidatePath": "notes/tradeoff-removal/xterm/terminal-osc-link-retirement.ts",
"candidateSha256": "9be36d6c51fb830cbe01aff6bcdf961c596d788af20ec5fe75ca956f9e21ba3a",
"status": "Rejected experiment; do not publish or replace the original #20955. Root reported repeatable timing regressions from author controls.",
"evidence": [
"Everything outside collectBufferLinks is byte-identical to the published head, including normal and alternate buffers, parser attributes, both saved cursor holders, sweep scheduling and marker-only retirement.",
"Pinned BufferLine stores every cell with HAS_EXTENDED in its numeric _extendedAttrs dictionary. Any live urlId therefore has a corresponding candidate column.",
"Sparse dictionary entries are not treated as live evidence by themselves: the candidate rereads each valid column through public getCell, which checks actual cell flags. Stale metadata on an erased cell cannot preserve a dead URL.",
"Wide/combined characters carry attributes through BufferLine set/copy operations; the sparse scan does not interpret codepoint width or text, so live columns continue to be collected after reflow.",
"The dense heuristic and midpoint probe select a full scan; false positives only affect performance, not the collected live set.",
"The final scratch guard accepts only the known plain Object.prototype dictionary shape. Missing/private Map/array/class/cross-realm/null-prototype shapes fall back to the unchanged public-cell scan. This addresses the earlier generic-isRecord concern."
],
"requestedGuard": "Addressed in final scratch variant; no further change requested.",
"installedVersions": {
"@xterm/xterm": "6.1.0-beta.303",
"@xterm/headless": "6.1.0-beta.302"
},
"validation": "Reviewed source and author test fixtures; no independent test execution or timing run. Author owns final timing and candidate validation.",
"limitations": [
"The optimization reduces common-case scanning; it is not zero CPU and still traverses buffer rows and uses dense fallback.",
"Private xterm field compatibility remains a pinned-version contract; public API fallback must be conservative."
],
"publicationDecision": {
"decision": "Do not publish this optimization. Keep original #20955 held.",
"reportedTimingEvidence": "Parent reported repeated author measurements showing 1\u20131.3% dense-midpoint-hole regression and one 5.9% prefix-density regression. Timing validation was delegated to the author; this reviewer did not rerun it.",
"correctnessConclusion": "No loss of live OSC8 links found for the pinned implementation. Private-holder shape fallback concern was addressed in the final scratch variant. The optimization is still rejected for measured workload regressions; timings apply to the saved benchmarked bytes, not a separately measured final guard."
},
"benchmarkedCandidate": {
"path": "notes/tradeoff-removal/xterm/terminal-osc-link-retirement-benchmarked.ts",
"sha256": "6609eb53c0bf79d9330f1051e870924da8f8e8663f5a90bff3a9f437311744a4"
},
"privateShapeFollowup": {
"status": "Correctness caveat addressed in final rejected scratch variant.",
"change": "Fast path now requires Object.getPrototypeOf(_extendedAttrs) === Object.prototype; Map, array, custom/null prototypes and absent private fields use public-cell fallback.",
"testsReviewed": "Author added missing/Map/array private-holder cases that preserve functional public getCell, require all 80\u00d724 normal cells scanned and retain the live URL. Author was running final validation; this reviewer did not run tests."
}
}
@@ -0,0 +1,352 @@
{
"number": 20955,
"title": "Retire overwritten OSC 8 metadata",
"observedAt": "2026-09-18T07:13:26.073370+00:00",
"head": "5e984fd09326c41a596863a3dee6607d3a1024ad",
"decision": "reject optimization experiment; hold existing PR for sweep-cost review",
"pureWin": false,
"candidate": null,
"candidateCommit": null,
"externalWrites": false,
"sourceOrPrimaryIndexEdits": false,
"finding": "Sparse attribute-map enumeration reduces plain/sparse buffer sweep work, but enumeration and density selection add work for some dense layouts. No robust improvement across the tested representative layouts.",
"proposedAlgorithm": "Check known plain-object private extended-attribute dictionary; enumerate sparse columns and reread public cells to filter stale metadata. Fall back to all public cells for absent/unsupported metadata or estimated dense rows.",
"rejectionEvidence": "A 158-linked-column row with an unlinked midpoint regressed about 1.0%, 1.3%, 1.2% in three independent paired runs. A 40-linked-column row regressed 5.9% in one of three runs. The initial sparse-only attempt regressed fully linked rows much more.",
"benchmarks": {
"script": "notes/tradeoff-removal/xterm/osc-sweep-benchmark.mjs",
"rawResultFiles": [
"notes/tradeoff-removal/xterm/osc-sweep-repeat-1.json",
"notes/tradeoff-removal/xterm/osc-sweep-repeat-2.json",
"notes/tradeoff-removal/xterm/osc-sweep-repeat-3.json"
],
"initialPrefixRun": "notes/tradeoff-removal/xterm/osc-sweep-prefix-initial.json",
"preliminaryObservations": "notes/tradeoff-removal/xterm/osc-exploratory-observations.json",
"benchmarkedSource": "notes/tradeoff-removal/xterm/terminal-osc-link-retirement-benchmarked.ts",
"benchmarkedSourceSha256": "6609eb53c0bf79d9330f1051e870924da8f8e8663f5a90bff3a9f437311744a4",
"finalGuardedSource": "notes/tradeoff-removal/xterm/terminal-osc-link-retirement.ts",
"finalGuardedSourceSha256": "9be36d6c51fb830cbe01aff6bcdf961c596d788af20ec5fe75ca956f9e21ba3a",
"guardedSourceTimingStatus": "Not benchmarked. The subsequent plain-object prototype guard fixes unsupported-private-metadata fallback only; it cannot be credited with improving the adverse timings.",
"method": "Actual installed headless xterm; 16 paired alternating-order sweeps per layout, discard 4 warmups, three separate process runs, 11 layouts per run. Measures sweep after writes, not end-to-end app latency.",
"comparison": [
{
"rows": 5000,
"linkedColumns": 0,
"layout": "prefix",
"pairedRunMediansMs": [
{
"published": 4.736354000000006,
"sparse": 2.433562500000022
},
{
"published": 4.0603334999999845,
"sparse": 1.573875000000001
},
{
"published": 5.216833500000007,
"sparse": 1.5433129999999977
}
],
"relativeChangesPercent": [-48.61949719129907, -61.237789950012555, -70.41667133904129]
},
{
"rows": 50000,
"linkedColumns": 0,
"layout": "prefix",
"pairedRunMediansMs": [
{
"published": 30.144125500000087,
"sparse": 3.5825625000000514
},
{
"published": 28.928229499999986,
"sparse": 2.899000000000001
},
{
"published": 28.70852100000002,
"sparse": 2.6603545000000395
}
],
"relativeChangesPercent": [-88.11522165404983, -89.97864698218049, -90.73322342171497]
},
{
"rows": 5000,
"linkedColumns": 1,
"layout": "prefix",
"pairedRunMediansMs": [
{
"published": 19.453979000000004,
"sparse": 8.515416999999957
},
{
"published": 11.225812500000075,
"sparse": 8.761353999999983
},
{
"published": 10.93489599999998,
"sparse": 8.732457999999951
}
],
"relativeChangesPercent": [-56.22789044853007, -21.953497798044243, -20.141371257669327]
},
{
"rows": 5000,
"linkedColumns": 16,
"layout": "prefix",
"pairedRunMediansMs": [
{
"published": 20.295395999999982,
"sparse": 9.475916999999754
},
{
"published": 10.814646000000039,
"sparse": 9.921041500000001
},
{
"published": 11.155416999999943,
"sparse": 9.777437499999905
}
],
"relativeChangesPercent": [-53.310016715122174, -8.262910316251082, -12.35255929921799]
},
{
"rows": 5000,
"linkedColumns": 40,
"layout": "prefix",
"pairedRunMediansMs": [
{
"published": 19.64545850000013,
"sparse": 12.14291699999967
},
{
"published": 11.597999999999502,
"sparse": 12.278062500000033
},
{
"published": 19.266625500000373,
"sparse": 12.47072900000012
}
],
"relativeChangesPercent": [-38.18969916126117, 5.863618727371622, -35.27289457097778]
},
{
"rows": 5000,
"linkedColumns": 80,
"layout": "prefix",
"pairedRunMediansMs": [
{
"published": 20.849957999999788,
"sparse": 13.64612550000038
},
{
"published": 21.400020999999924,
"sparse": 14.10897900000009
},
{
"published": 21.357104499999878,
"sparse": 13.866167000000132
}
],
"relativeChangesPercent": [-34.550824994465124, -34.07025628619644, -35.07468673948656]
},
{
"rows": 5000,
"linkedColumns": 159,
"layout": "prefix",
"pairedRunMediansMs": [
{
"published": 17.135478999999577,
"sparse": 13.60162500000024
},
{
"published": 25.404708500001107,
"sparse": 14.146999999999935
},
{
"published": 25.08789650000017,
"sparse": 14.383083499998975
}
],
"relativeChangesPercent": [-20.62302431113495, -44.31347244153847, -42.669232950642645]
},
{
"rows": 5000,
"linkedColumns": 1,
"layout": "middle",
"pairedRunMediansMs": [
{
"published": 15.92725000000064,
"sparse": 11.677666999999929
},
{
"published": 19.391916499999752,
"sparse": 11.813041999999768
},
{
"published": 19.29156250000142,
"sparse": 11.916186999999809
}
],
"relativeChangesPercent": [-26.68120987615904, -39.08264817456325, -38.23109455235193]
},
{
"rows": 5000,
"linkedColumns": 159,
"layout": "mixed",
"pairedRunMediansMs": [
{
"published": 13.101020999999491,
"sparse": 7.854833500000495
},
{
"published": 17.883396000000175,
"sparse": 8.158916999999747
},
{
"published": 13.326583500000197,
"sparse": 8.17102100000011
}
],
"relativeChangesPercent": [-40.04411182914064, -54.3771384361244, -38.686303207420046]
},
{
"rows": 5000,
"linkedColumns": 80,
"layout": "scattered",
"pairedRunMediansMs": [
{
"published": 16.994416500001535,
"sparse": 13.142520499999591
},
{
"published": 16.953457999999955,
"sparse": 13.00110400000085
},
{
"published": 16.76606250000077,
"sparse": 13.085667000001195
}
],
"relativeChangesPercent": [-22.665656099470056, -23.31296659359474, -21.951459980537514]
},
{
"rows": 5000,
"linkedColumns": 158,
"layout": "middle-hole",
"pairedRunMediansMs": [
{
"published": 17.908125000001746,
"sparse": 18.089208999997936
},
{
"published": 16.994103999999425,
"sparse": 17.217062499999884
},
{
"published": 17.187791999998808,
"sparse": 17.39979200000016
}
],
"relativeChangesPercent": [1.0111834711683754, 1.3119756122503823, 1.233433590547106]
}
]
},
"validation": {
"log": "notes/tradeoff-removal/xterm/osc-validation-final.log",
"tests": {
"passed": 21,
"suites": 2
},
"coverage": [
"Existing headless and renderer link retirement controls",
"Stale extended metadata behind erased cells",
"Wide and combined linked cells",
"Normal and alternate saved-attribute holders",
"Plain scrollback sparse-cell visit count",
"Missing, Map and array private-view fallbacks",
"Freshly built Chrome74-target mobile engine retirement"
],
"savedCursorLimitation": "The saved-holder tests populate the real holder directly. They do not assert that upstream DEC save/restore clones URL attributes.",
"focusedStrictTypecheck": "passed",
"oxlint": "passed after test-only style fixes",
"antiSlopLint": "passed after naming fix",
"independentReview": "notes/tradeoff-removal/xterm/20955-independent-review-queues.json",
"fullProjectOrAllPlatformTests": "Not run for rejected experiment.",
"backgroundPolicy": "Every test and generator launched with ORCA_BACKGROUND_LAUNCH=1; no windows or focus calls."
},
"remainingTradeoff": "Existing PR's sweep still visits every retained row/cell periodically, causing CPU work and possible pauses on large terminal buffers. No content/history/link limit was introduced.",
"alternatives": [
{
"alternative": "Use only original link marker rows",
"result": "Unsafe: wrapping/reflow can move live linked cells beyond the original marker row."
},
{
"alternative": "Trust sparse extended-attribute values directly",
"result": "Unsafe: stale entries may outlive erased cell flags. Public-cell reread is required."
},
{
"alternative": "Scan sparse keys with a density fallback",
"result": "Implemented and semantically tested, but rejected after adverse repeated timings."
},
{
"alternative": "Per-mutation hyperlink reference ownership in xterm",
"result": "Possible larger design, not implemented/proven here; adds mutation bookkeeping and must cover every reflow/copy/resize path."
}
],
"generatedPatchCoherence": {
"description": "This is an application addon change, not a dependency-engine patch. No maintained dependency patch, generated runtime patch or lockfile changed.",
"mobileGenerator": "notes/tradeoff-removal/xterm/build-mobile-candidate.mjs",
"mobileGeneratorAdaptation": "Exact PR generator settings preserved; redirects source to ignored experiment and output to ignored notes, using mobile dependency resolution.",
"mobileGeneratedOutput": "notes/tradeoff-removal/xterm/terminal-webview-engine.generated.ts",
"mobileGeneratedOutputSha256": "30ff3e80c5f75f870324d2e3c0627cc0882ff00152e598b33a70f320a551a90c",
"trackedGeneratedAsset": false
},
"originalPrLineAccounting": {
"head": "5e984fd09326c41a596863a3dee6607d3a1024ad",
"base": "9c921360090667e02363fe6e4dee98410665427a",
"mergeBase": "357c9780f8bffa10a21d004449d8d6d9846a9310",
"production": {
"files": 6,
"additions": 129,
"deletions": 7,
"changed": 136,
"binaryFiles": []
},
"total": {
"files": 14,
"additions": 979,
"deletions": 9,
"changed": 988,
"binaryFiles": []
},
"categories": {
"documentation": {
"files": 3,
"additions": 613,
"deletions": 0,
"changed": 613,
"binaryFiles": []
},
"production-tooling": {
"files": 1,
"additions": 2,
"deletions": 0,
"changed": 2,
"binaryFiles": []
},
"test": {
"files": 5,
"additions": 237,
"deletions": 2,
"changed": 239,
"binaryFiles": []
},
"production": {
"files": 5,
"additions": 127,
"deletions": 7,
"changed": 134,
"binaryFiles": []
}
}
}
}
@@ -0,0 +1,108 @@
{
"observedAt": "2026-09-18T07:07:01.601938+00:00",
"candidate": null,
"externalWrites": false,
"sourceOrPrimaryIndexEdits": false,
"scope": "Independent review of exact named PR heads; all experiments and reports remain in ignored notes.",
"decision": "hold: remaining performance tradeoff requires explicit review",
"pureWin": false,
"number": 20965,
"title": "WebGL empty-glyph cache",
"head": "2a48cae631b81b4b58c8dfd7f8379cfad7b6365f",
"finding": "Both numeric and combined-string empty-glyph maps share 4,096 entries. Ordinary visible glyph atlas entries are unaffected. A fixed empty-result rasterizer isolates the actual cache methods; it does not measure GPU/rasterization latency.",
"freshEvidence": {
"file": "notes/tradeoff-removal/xterm/cache-revisit-results.json",
"script": "notes/tradeoff-removal/xterm/cache-revisit-proof.cjs",
"exactSourceBlob": "ccf57dbcfff85eeb4c383fa987bcc07aa28e5d14",
"sourceHashes": {
"baseline": "4af6e55b14dc91e3eecf9f22a3ba9803b1fe6776d132ddf64e79d496d5566e5c",
"published": "7132d0a7aedcc0922bcb7b1a47b9c10454f8f668168bc6d0864e9caab4836237"
},
"at4097DistinctKeys": [
{
"variant": "baseline",
"keyCount": 4097,
"firstPassMisses": 4097,
"revisitMisses": 0
},
{
"variant": "published",
"keyCount": 4097,
"firstPassMisses": 4097,
"revisitMisses": 4097
}
],
"limitation": "Exact published cache methods bundled from maintained source; a fixed empty-glyph rasterizer and null contrast result isolate hit/miss policy. This proves repeated-work possibility, not measured rasterization/contrast latency or GPU behavior. No app/browser is launched."
},
"alternatives": [
{
"alternative": "Tie empty entries to texture-page eviction",
"result": "Empty glyphs occupy no atlas pixels, so normal page pressure cannot retire these entries."
},
{
"alternative": "Canonicalize all invisible results to a space or omit colors",
"result": "Ink depends on character/combined text, foreground/background, style and decorations. Equal-color invisibility can differ at another color. No safe general canonical key identified."
},
{
"alternative": "Bypass rasterization for explicit invisible attributes",
"result": "May improve one subset, but does not solve the demonstrated colored-space and combined-space key growth."
},
{
"alternative": "Use LRU or generations",
"result": "Can improve some locality but capacity+1 cycling still recomputes. Hit bookkeeping adds work; not a no-tradeoff solution."
}
],
"proven": "At 4,097 distinct keys, exact published methods produce 4,097 cache misses on the second pass; unbounded baseline produces zero. Returned results match.",
"notProven": "No claim that these misses cause a perceptible app-wide slowdown on ordinary usage, or that a larger architectural redesign cannot improve ownership.",
"remainingTradeoff": "Bounded derived-cache memory versus possible repeated computation after eviction.",
"generatedPatchCoherence": "No maintained patch, generated bundle, source map, generator or lockfile changed.",
"originalPrLineAccounting": {
"head": "2a48cae631b81b4b58c8dfd7f8379cfad7b6365f",
"base": "9c921360090667e02363fe6e4dee98410665427a",
"mergeBase": "feb04ec254585ba69587699d41f80a72dda2cb27",
"production": {
"files": 3,
"additions": 192,
"deletions": 24,
"changed": 216,
"binaryFiles": []
},
"total": {
"files": 6,
"additions": 1021,
"deletions": 24,
"changed": 1045,
"binaryFiles": []
},
"categories": {
"production-generated-patch": {
"files": 1,
"additions": 102,
"deletions": 17,
"changed": 119,
"binaryFiles": []
},
"production-source-patch": {
"files": 1,
"additions": 87,
"deletions": 4,
"changed": 91,
"binaryFiles": []
},
"documentation": {
"files": 3,
"additions": 829,
"deletions": 0,
"changed": 829,
"binaryFiles": []
},
"production-lockfile": {
"files": 1,
"additions": 3,
"deletions": 3,
"changed": 6,
"binaryFiles": []
}
}
}
}
@@ -0,0 +1,129 @@
{
"observedAt": "2026-09-18T07:07:01.601938+00:00",
"candidate": null,
"externalWrites": false,
"sourceOrPrimaryIndexEdits": false,
"scope": "Independent review of exact named PR heads; all experiments and reports remain in ignored notes.",
"decision": "hold: remaining performance tradeoff requires explicit review",
"pureWin": false,
"number": 20981,
"title": "Terminal contrast-color cache",
"head": "47bb299d4d5e0a3d5e1e53a88fe5c5a68012519e",
"finding": "The color and CSS maps share 4,096 entries per cache; normal and dim caches are separate. Results are unchanged but eviction permits repeat contrast calculation.",
"freshEvidence": {
"file": "notes/tradeoff-removal/xterm/cache-revisit-results.json",
"script": "notes/tradeoff-removal/xterm/cache-revisit-proof.cjs",
"exactSourceBlob": "0558a8873f680e8fb2a27cc833c49c5ba658e1dd",
"sourceHashes": {
"baseline": "c0956daf17b82fa4557149608eae3aac343e69a81521998544a4b1cf39e19fb8",
"published": "b0a5e7e2044d2b6980aca266ea2c23d9749e6aacd5524fb90a6e780f42fe44f7"
},
"at4097DistinctKeys": [
{
"variant": "baseline",
"keyCount": 4097,
"firstPassMisses": 4097,
"revisitMisses": 0
},
{
"variant": "published",
"keyCount": 4097,
"firstPassMisses": 4097,
"revisitMisses": 4097
}
],
"limitation": "Exact published cache methods bundled from maintained source; a fixed empty-glyph rasterizer and null contrast result isolate hit/miss policy. This proves repeated-work possibility, not measured rasterization/contrast latency or GPU behavior. No app/browser is launched."
},
"alternatives": [
{
"alternative": "Use LRU or two generations",
"result": "Can retain hot subsets longer but does not retain every arbitrary future color pair within fixed memory. Adds hit bookkeeping and still misses on capacity+1 cycles."
},
{
"alternative": "Tie contrast lifetime to atlas pages",
"result": "Contrast is also used outside the WebGL atlas and may be requested again for visible colors after page eviction; no shared ownership invariant removes recomputation."
},
{
"alternative": "Use weak retention",
"result": "Color keys are primitives, and weakly retaining values does not guarantee a future hit. Key metadata still requires ownership."
},
{
"alternative": "Disable contrast correction",
"result": "Changes intended rendering/readability. Orca normally enables correction (dark 3, light 4.5), so the xterm upstream default ratio of 1 does not avoid the tradeoff."
}
],
"proven": "At 4,097 distinct keys, exact published methods produce 4,097 cache misses on the second pass; unbounded baseline produces zero. Returned results match.",
"notProven": "No claim that these misses cause a perceptible app-wide slowdown on ordinary usage, or that a larger architectural redesign cannot improve ownership.",
"remainingTradeoff": "Bounded derived-cache memory versus possible repeated computation after eviction.",
"generatedPatchCoherence": "No maintained patch, generated bundle, source map, generator or lockfile changed.",
"originalPrLineAccounting": {
"head": "47bb299d4d5e0a3d5e1e53a88fe5c5a68012519e",
"base": "9c921360090667e02363fe6e4dee98410665427a",
"mergeBase": "96eb97aad641f3d8324bd5488d51c06a3eba59ad",
"production": {
"files": 11,
"additions": 398,
"deletions": 56,
"changed": 454,
"binaryFiles": []
},
"total": {
"files": 23,
"additions": 3711,
"deletions": 62,
"changed": 3773,
"binaryFiles": []
},
"categories": {
"production-tooling": {
"files": 4,
"additions": 111,
"deletions": 3,
"changed": 114,
"binaryFiles": []
},
"production-generated-patch": {
"files": 2,
"additions": 156,
"deletions": 12,
"changed": 168,
"binaryFiles": []
},
"production-source-patch": {
"files": 2,
"additions": 94,
"deletions": 0,
"changed": 94,
"binaryFiles": []
},
"test": {
"files": 5,
"additions": 294,
"deletions": 2,
"changed": 296,
"binaryFiles": []
},
"documentation": {
"files": 7,
"additions": 3019,
"deletions": 4,
"changed": 3023,
"binaryFiles": []
},
"production-lockfile": {
"files": 2,
"additions": 36,
"deletions": 41,
"changed": 77,
"binaryFiles": []
},
"production": {
"files": 1,
"additions": 1,
"deletions": 0,
"changed": 1,
"binaryFiles": []
}
}
}
}
@@ -0,0 +1,173 @@
{
"observedAt": "2026-09-18T07:07:01.601938+00:00",
"candidate": null,
"externalWrites": false,
"sourceOrPrimaryIndexEdits": false,
"scope": "Independent review of exact named PR heads; all experiments and reports remain in ignored notes.",
"decision": "hold: remaining performance tradeoff requires explicit review",
"pureWin": false,
"number": 20992,
"title": "Release erased BufferLine backing strings",
"head": "565cbd6c6d1991410268d9d036dcd6876490bca0",
"finding": "Cleanup preserves terminal content but adds work in hot BufferLine mutation paths. No tested representation reliably recovered baseline speed.",
"alternatives": [
{
"alternative": "Use undefined, false or null as invalid cache sentinel instead of a separate valid flag",
"result": "All preserved tested semantics; timing was workload/JIT sensitive and none reliably beat baseline."
},
{
"alternative": "Only clear the string cache when marked valid",
"result": "Preserved semantics but was slower than baseline; a branch does not eliminate hot-path bookkeeping cost."
},
{
"alternative": "Group metadata ownership checks",
"result": "Unimplemented hypothesis only; no performance or correctness claim."
}
],
"freshEvidence": {
"file": "notes/tradeoff-removal/xterm/bufferline-source-results.json",
"script": "notes/tradeoff-removal/xterm/bufferline-source-experiment.cjs",
"sourceHashes": {
"baseline": "26551bd2db8ddd5cdb4f77b0f62f3b5f1ae4d14fd76ac4d5b5eae70eab10ea12",
"published": "435b6bccb646071deda696d8e5ffccb5396524570a0d6f345093a1e0aebead1a",
"optionalCache": "1bc91c6e7eda4e8e8c028a2a427320f80642be53c5b24ef63816a6c0e18aab93",
"falseCache": "800627a54a7827d3ccf0320a9e1c2a502d0a89a51d9c910a6e6493acfd6f06bc",
"nullCache": "c5997045cd4ccdf8ecd7307f313906c5ed3b6c1eac3da1f21461fbb957a9a05a",
"validGuard": "53621b2c90a45c77372812735d462a1a40578431518bb008c2f1fb554ab9fa4c"
},
"baselineMapHash": "593c3d75f22146a34afad73aa8b8295084116796e82b46721ea5ce4f14a1307a",
"semantic": {
"published": {
"matchedMutations": 25000,
"translationModesPerMutation": 4,
"erasedCacheChars": 0,
"erasedCombinedChars": 0,
"scratchCharsAfterInsertAndDelete": 0,
"liveCombinedChars": 100001
},
"optionalCache": {
"matchedMutations": 25000,
"translationModesPerMutation": 4,
"erasedCacheChars": 0,
"erasedCombinedChars": 0,
"scratchCharsAfterInsertAndDelete": 0,
"liveCombinedChars": 100001
},
"falseCache": {
"matchedMutations": 25000,
"translationModesPerMutation": 4,
"erasedCacheChars": 0,
"erasedCombinedChars": 0,
"scratchCharsAfterInsertAndDelete": 0,
"liveCombinedChars": 100001
},
"nullCache": {
"matchedMutations": 25000,
"translationModesPerMutation": 4,
"erasedCacheChars": 0,
"erasedCombinedChars": 0,
"scratchCharsAfterInsertAndDelete": 0,
"liveCombinedChars": 100001
},
"validGuard": {
"matchedMutations": 25000,
"translationModesPerMutation": 4,
"erasedCacheChars": 0,
"erasedCombinedChars": 0,
"scratchCharsAfterInsertAndDelete": 0,
"liveCombinedChars": 100001
}
},
"mediansMs": {
"baseline": 9.974072937499955,
"published": 11.017651062499908,
"optionalCache": 10.672986999999978,
"falseCache": 10.970770812500007,
"nullCache": 10.690830687499954,
"validGuard": 10.82650000000001
},
"bytesPerWrite": 1200000,
"writesPerRound": 8,
"discardedWarmupRounds": 6,
"limitation": "Source experiment using actual pinned headless sourcemap and identical esbuild settings. Not release webpack bundles; installed source used only for missing enum modules. No app/native all-platform timing or zero-cost claim."
},
"proven": "Each fixed variant matched 25,000 seeded mutations with four translation modes, released erased cached/combined strings and shift scratch storage, and retained a live 100,001-character combining cell.",
"notProven": "The alternative sentinels are not a reliable speed win; no production patch proposed from noisy microbenchmarks.",
"remainingTradeoff": "Original emitted-parser benchmark records approximately 5% slowdown; fresh source-compiled test also leaves all cleanup variants slower than leaking baseline. This is not an app-wide latency estimate.",
"generatedPatchCoherence": "No changes. A real change would require synchronized headless, desktop and mobile maintained patches, generated bundles/source maps and lock hashes.",
"dependencies": {
"parent": 20981,
"child": 21112,
"action": "Leave existing dependency chain unchanged; #21112's reflow correctness fix does not remove these cache/parser tradeoffs."
},
"originalPrLineAccounting": {
"head": "565cbd6c6d1991410268d9d036dcd6876490bca0",
"base": "47bb299d4d5e0a3d5e1e53a88fe5c5a68012519e",
"mergeBase": "47bb299d4d5e0a3d5e1e53a88fe5c5a68012519e",
"production": {
"files": 13,
"additions": 989,
"deletions": 77,
"changed": 1066,
"binaryFiles": []
},
"total": {
"files": 29,
"additions": 2780,
"deletions": 95,
"changed": 2875,
"binaryFiles": []
},
"categories": {
"production-generated-patch": {
"files": 3,
"additions": 388,
"deletions": 28,
"changed": 416,
"binaryFiles": []
},
"production-source-patch": {
"files": 3,
"additions": 459,
"deletions": 0,
"changed": 459,
"binaryFiles": []
},
"production": {
"files": 2,
"additions": 19,
"deletions": 0,
"changed": 19,
"binaryFiles": []
},
"production-tooling": {
"files": 3,
"additions": 87,
"deletions": 14,
"changed": 101,
"binaryFiles": []
},
"test": {
"files": 6,
"additions": 421,
"deletions": 8,
"changed": 429,
"binaryFiles": []
},
"documentation": {
"files": 10,
"additions": 1370,
"deletions": 10,
"changed": 1380,
"binaryFiles": []
},
"production-lockfile": {
"files": 2,
"additions": 36,
"deletions": 35,
"changed": 71,
"binaryFiles": []
}
}
}
}
@@ -0,0 +1,119 @@
{
"head": "565cbd6c6d1991410268d9d036dcd6876490bca0",
"node": "v26.6.0",
"platform": "darwin",
"architecture": "arm64",
"sourceHashes": {
"baseline": "26551bd2db8ddd5cdb4f77b0f62f3b5f1ae4d14fd76ac4d5b5eae70eab10ea12",
"published": "435b6bccb646071deda696d8e5ffccb5396524570a0d6f345093a1e0aebead1a",
"optionalCache": "1bc91c6e7eda4e8e8c028a2a427320f80642be53c5b24ef63816a6c0e18aab93",
"falseCache": "800627a54a7827d3ccf0320a9e1c2a502d0a89a51d9c910a6e6493acfd6f06bc",
"nullCache": "c5997045cd4ccdf8ecd7307f313906c5ed3b6c1eac3da1f21461fbb957a9a05a",
"validGuard": "53621b2c90a45c77372812735d462a1a40578431518bb008c2f1fb554ab9fa4c"
},
"baselineMapHash": "593c3d75f22146a34afad73aa8b8295084116796e82b46721ea5ce4f14a1307a",
"semantic": {
"published": {
"matchedMutations": 25000,
"translationModesPerMutation": 4,
"erasedCacheChars": 0,
"erasedCombinedChars": 0,
"scratchCharsAfterInsertAndDelete": 0,
"liveCombinedChars": 100001
},
"optionalCache": {
"matchedMutations": 25000,
"translationModesPerMutation": 4,
"erasedCacheChars": 0,
"erasedCombinedChars": 0,
"scratchCharsAfterInsertAndDelete": 0,
"liveCombinedChars": 100001
},
"falseCache": {
"matchedMutations": 25000,
"translationModesPerMutation": 4,
"erasedCacheChars": 0,
"erasedCombinedChars": 0,
"scratchCharsAfterInsertAndDelete": 0,
"liveCombinedChars": 100001
},
"nullCache": {
"matchedMutations": 25000,
"translationModesPerMutation": 4,
"erasedCacheChars": 0,
"erasedCombinedChars": 0,
"scratchCharsAfterInsertAndDelete": 0,
"liveCombinedChars": 100001
},
"validGuard": {
"matchedMutations": 25000,
"translationModesPerMutation": 4,
"erasedCacheChars": 0,
"erasedCombinedChars": 0,
"scratchCharsAfterInsertAndDelete": 0,
"liveCombinedChars": 100001
}
},
"bytesPerWrite": 1200000,
"writesPerRound": 8,
"discardedWarmupRounds": 6,
"timings": {
"baseline": [
12.748380124999997, 9.753552124999999, 9.733015624999979, 9.83517712500003, 9.97717187500001,
9.974093750000009, 9.988421875000029, 9.956156249999935, 9.959703125000033,
10.111046875000056, 9.954380249999986, 10.020484375000024, 9.96019274999992,
10.175265624999952, 9.945390625000073, 9.969640625000011, 9.952489499999956,
9.978505249999898, 9.963661375000129, 10.242645875000107, 10.153307375000168,
10.015968749999956, 9.981171874999973, 9.935281249999889
],
"published": [
13.931359375, 10.758400999999992, 10.778249999999957, 10.791198000000009, 10.964052124999967,
10.992859374999966, 12.816307250000023, 11.02026049999995, 11.04384374999995,
11.149802125000065, 10.998802124999997, 11.12441662499998, 10.986213625000005,
10.974255250000056, 11.015041624999867, 10.997520749999921, 11.021380249999993,
11.003968750000013, 10.98577612500003, 11.123473999999987, 11.220223999999916,
11.057343749999973, 11.005192750000106, 10.991895875000182
],
"optionalCache": [
12.612937500000001, 10.409859374999996, 10.422953124999992, 10.452802125000005,
10.669093750000002, 10.629880249999985, 12.655302124999992, 10.675963625000009,
10.649723999999992, 10.85188012499998, 10.61571349999997, 10.691802000000052,
10.634578125000075, 10.696000000000026, 10.676671875000011, 10.658718749999935,
10.670010374999947, 10.655937499999936, 10.619531249999909, 10.843536374999985,
11.040442750000011, 10.71903637499986, 10.64434899999992, 10.656598999999915
],
"falseCache": [
12.302750000000003, 10.71968237499999, 10.782177125000004, 10.944296874999964,
10.981046875000004, 10.965583374999994, 11.113099000000034, 10.928067750000082,
10.772650999999996, 10.969692624999993, 10.967848874999959, 10.651588624999931,
13.560614625000085, 10.97811450000006, 10.987812500000018, 10.97184900000002,
10.814536500000031, 10.736249999999927, 10.964801999999963, 10.952208375000055,
11.298551999999972, 10.976317624999865, 10.98178125000004, 10.990671874999862
],
"nullCache": [
12.20673437500001, 10.572817750000013, 10.467781250000002, 10.702125000000024,
10.666525999999976, 10.670270749999986, 10.939932250000027, 10.671760374999963,
10.675328125000078, 10.638864624999997, 10.705859374999932, 10.661015625000005,
11.817322875000059, 10.698515624999914, 10.657171875000017, 10.683145749999994,
10.646192750000182, 10.653583375000153, 11.88388537500009, 10.94292712499987,
11.114692750000131, 10.798885375000054, 10.724234375000151, 10.662854124999967
],
"validGuard": [
12.27800000000002, 10.658203125, 10.57986975, 10.775223874999995, 10.763281250000034,
10.797510375000002, 11.087968750000073, 10.819187499999998, 10.783437499999991,
10.824427125000057, 10.732385375000035, 10.862895874999936, 11.021052124999983,
10.917442749999964, 10.751880124999957, 10.784015625000166, 10.778182375000142,
10.828572874999963, 11.997421874999873, 11.111744749999843, 11.119875000000093,
10.862098874999901, 10.79976049999982, 10.794541624999965
]
},
"mediansMs": {
"baseline": 9.974072937499955,
"published": 11.017651062499908,
"optionalCache": 10.672986999999978,
"falseCache": 10.970770812500007,
"nullCache": 10.690830687499954,
"validGuard": 10.82650000000001
},
"limitations": "Source experiment using actual pinned headless sourcemap and identical esbuild settings. Not release webpack bundles; installed source used only for missing enum modules. No app/native all-platform timing or zero-cost claim."
}
@@ -0,0 +1,126 @@
{
"node": "v26.6.0",
"results": [
{
"number": 20965,
"head": "2a48cae631b81b4b58c8dfd7f8379cfad7b6365f",
"maintainedPatch": "config/patches/xterm-src/@xterm__addon-webgl@0.20.0-beta.299.src.patch",
"verifiedPublishedBlob": "ccf57dbcfff85eeb4c383fa987bcc07aa28e5d14",
"sourceHashes": {
"baseline": "4af6e55b14dc91e3eecf9f22a3ba9803b1fe6776d132ddf64e79d496d5566e5c",
"published": "7132d0a7aedcc0922bcb7b1a47b9c10454f8f668168bc6d0864e9caab4836237"
},
"samples": [
{
"variant": "baseline",
"keyCount": 64,
"firstPassMisses": 64,
"revisitMisses": 0
},
{
"variant": "published",
"keyCount": 64,
"firstPassMisses": 64,
"revisitMisses": 0
},
{
"variant": "baseline",
"keyCount": 4096,
"firstPassMisses": 4096,
"revisitMisses": 0
},
{
"variant": "published",
"keyCount": 4096,
"firstPassMisses": 4096,
"revisitMisses": 0
},
{
"variant": "baseline",
"keyCount": 4097,
"firstPassMisses": 4097,
"revisitMisses": 0
},
{
"variant": "published",
"keyCount": 4097,
"firstPassMisses": 4097,
"revisitMisses": 4097
},
{
"variant": "baseline",
"keyCount": 10000,
"firstPassMisses": 10000,
"revisitMisses": 0
},
{
"variant": "published",
"keyCount": 10000,
"firstPassMisses": 10000,
"revisitMisses": 10000
}
]
},
{
"number": 20981,
"head": "47bb299d4d5e0a3d5e1e53a88fe5c5a68012519e",
"maintainedPatch": "config/patches/xterm-src/@xterm__xterm@6.1.0-beta.303.src.patch",
"verifiedPublishedBlob": "0558a8873f680e8fb2a27cc833c49c5ba658e1dd",
"sourceHashes": {
"baseline": "c0956daf17b82fa4557149608eae3aac343e69a81521998544a4b1cf39e19fb8",
"published": "b0a5e7e2044d2b6980aca266ea2c23d9749e6aacd5524fb90a6e780f42fe44f7"
},
"samples": [
{
"variant": "baseline",
"keyCount": 64,
"firstPassMisses": 64,
"revisitMisses": 0
},
{
"variant": "published",
"keyCount": 64,
"firstPassMisses": 64,
"revisitMisses": 0
},
{
"variant": "baseline",
"keyCount": 4096,
"firstPassMisses": 4096,
"revisitMisses": 0
},
{
"variant": "published",
"keyCount": 4096,
"firstPassMisses": 4096,
"revisitMisses": 0
},
{
"variant": "baseline",
"keyCount": 4097,
"firstPassMisses": 4097,
"revisitMisses": 0
},
{
"variant": "published",
"keyCount": 4097,
"firstPassMisses": 4097,
"revisitMisses": 4097
},
{
"variant": "baseline",
"keyCount": 10000,
"firstPassMisses": 10000,
"revisitMisses": 0
},
{
"variant": "published",
"keyCount": 10000,
"firstPassMisses": 10000,
"revisitMisses": 10000
}
]
}
],
"limitation": "Exact published cache methods bundled from maintained source; a fixed empty-glyph rasterizer and null contrast result isolate hit/miss policy. This proves repeated-work possibility, not measured rasterization/contrast latency or GPU behavior. No app/browser is launched."
}
@@ -0,0 +1,46 @@
{
"status": "Observed exploratory medians retained from session tool outputs; raw samples were overwritten during exploratory iteration. Do not treat these as independently rerunnable archived benchmark files.",
"sparseOnlySource": "source-formatted.ts",
"sparseOnlySourceSha256": "f4b92bb99580beec0a35ba6dba04e56dc035a9998cd8efde814b34ffeb785d54",
"sparseOnlyObservedMediansMs": [
{
"rows": 5000,
"linkedColumns": 0,
"published": 3.864,
"sparse": 1.457
},
{
"rows": 50000,
"linkedColumns": 0,
"published": 29.393,
"sparse": 2.836
},
{
"rows": 5000,
"linkedColumns": 159,
"published": 14.309,
"sparse": 20.151
}
],
"densityFallbackObservedMediansMs": [
{
"rows": 5000,
"linkedColumns": 0,
"published": 5.13,
"sparse": 2.784
},
{
"rows": 50000,
"linkedColumns": 0,
"published": 31.1,
"sparse": 4.161
},
{
"rows": 5000,
"linkedColumns": 159,
"published": 26.83,
"sparse": 17.945
}
],
"interpretation": "The initial sparse-only algorithm materially regressed dense links; the density fallback and midpoint heuristic improved common cases but repeated expanded tests still found adverse cases."
}
@@ -0,0 +1,175 @@
{
"observedAt": "2026-09-18T07:13:26.073370+00:00",
"completedPrs": [20955, 20965, 20981, 20992],
"publicationCandidates": [],
"decision": "No tested change removes its existing tradeoff reliably.",
"artifactRoot": "notes/tradeoff-removal/xterm",
"artifacts": [
{
"path": "notes/tradeoff-removal/xterm/20955-verdict.json",
"sha256": "ea0c5fbf99c7c860abeec9d6fadc42668b4a22976511f2246453dfda8b5beb81",
"bytes": 13086
},
{
"path": "notes/tradeoff-removal/xterm/20965-verdict.json",
"sha256": "e3d2304cab90f51173ba7f7a222bd562440ca6241b7d8a3ee3d9ff1e6d8b8663",
"bytes": 4379
},
{
"path": "notes/tradeoff-removal/xterm/20981-verdict.json",
"sha256": "35e338f0abb3363fac9a07e6b1ba6d3fbe477e6dc1f1a4963b38927eddd8a783",
"bytes": 4819
},
{
"path": "notes/tradeoff-removal/xterm/20992-verdict.json",
"sha256": "07473c72b01fa148f1b2d12ec8c0ed2ba4c431eb5de40a23977298e8de71315d",
"bytes": 6562
},
{
"path": "notes/tradeoff-removal/xterm/summary.md",
"sha256": "b7e3a608964581d983d1811219d56b0ca7eaa59044dc3102bdcb148ea34069d5",
"bytes": 1809
},
{
"path": "notes/tradeoff-removal/xterm/20955-independent-review-queues.json",
"sha256": "5601ba9b008290fb1dc70be56be1abaa6df8903084a9b21cb6fc6c4417718928",
"bytes": 3792
},
{
"path": "notes/tradeoff-removal/xterm/osc-sweep-benchmark.mjs",
"sha256": "aadda4262daa44f0b578e44cdf2ec3d73e1beb15aaf377086609fed3ee8d100e",
"bytes": 4430
},
{
"path": "notes/tradeoff-removal/xterm/osc-sweep-repeat-1.json",
"sha256": "a8997945dca137076f660b13a95838829440d2e3364358d7e9c1bacd7c1b11c6",
"bytes": 14627
},
{
"path": "notes/tradeoff-removal/xterm/osc-sweep-repeat-2.json",
"sha256": "1989eb65cf04a04f0a00b3f2c869da1f2b599133c929827c4fa8d6d652e825c8",
"bytes": 14661
},
{
"path": "notes/tradeoff-removal/xterm/osc-sweep-repeat-3.json",
"sha256": "791031302c0fcb2f0683c2734e6e6eaadcfe12430214b097f5d6c96082dc9dff",
"bytes": 14599
},
{
"path": "notes/tradeoff-removal/xterm/osc-sweep-prefix-initial.json",
"sha256": "02d5ae5016e0db13794e0375e2190c760e289a11cf26d5d2c2cca37cd3586b8c",
"bytes": 9341
},
{
"path": "notes/tradeoff-removal/xterm/osc-exploratory-observations.json",
"sha256": "4579414714f47ae9aa54bd8b7aa665a15a76a4f1003de71e2a75d14767771f85",
"bytes": 1301
},
{
"path": "notes/tradeoff-removal/xterm/terminal-osc-link-retirement-benchmarked.ts",
"sha256": "6609eb53c0bf79d9330f1051e870924da8f8e8663f5a90bff3a9f437311744a4",
"bytes": 4403
},
{
"path": "notes/tradeoff-removal/xterm/terminal-osc-link-retirement.ts",
"sha256": "9be36d6c51fb830cbe01aff6bcdf961c596d788af20ec5fe75ca956f9e21ba3a",
"bytes": 4484
},
{
"path": "notes/tradeoff-removal/xterm/terminal-osc-link-retirement.test.ts",
"sha256": "e62728645721142b2d3cc9d0ead45b3f772e91678a5edf6a6066f561155842c6",
"bytes": 10967
},
{
"path": "notes/tradeoff-removal/xterm/osc-validation-final.log",
"sha256": "f58f7474e96872a78312e54f6b17731370e0eb32770d9a0aa2f4e99599d2e050",
"bytes": 7114
},
{
"path": "notes/tradeoff-removal/xterm/osc.config.mjs",
"sha256": "28af3ad86bf30fc5534f2f24cf0d4f83edb60b7572f90e4d86b899286a6df9a5",
"bytes": 378
},
{
"path": "notes/tradeoff-removal/xterm/terminal-webview-osc-link-retirement.test.ts",
"sha256": "b40cc43f3c608248da9016c5445fce04db4b1c2d367cde48cee9dac6b6da9947",
"bytes": 1716
},
{
"path": "notes/tradeoff-removal/xterm/build-mobile-candidate.mjs",
"sha256": "57dd346e2ca3ab0348ff550c10e4a87e15e9d05cfd71cb573701910cc44fe9cf",
"bytes": 4688
},
{
"path": "notes/tradeoff-removal/xterm/terminal-webview-engine.generated.ts",
"sha256": "30ff3e80c5f75f870324d2e3c0627cc0882ff00152e598b33a70f320a551a90c",
"bytes": 627186
},
{
"path": "notes/tradeoff-removal/xterm/source-formatted.ts",
"sha256": "f4b92bb99580beec0a35ba6dba04e56dc035a9998cd8efde814b34ffeb785d54",
"bytes": 4185
},
{
"path": "notes/tradeoff-removal/xterm/cache-revisit-proof.cjs",
"sha256": "52b676ed2058a2ae603bc254ab8e047752aee2e9bb697f2138f53607a4db100b",
"bytes": 4962
},
{
"path": "notes/tradeoff-removal/xterm/cache-revisit-results.json",
"sha256": "98f96f928e624dcd3f964738298d14ed23431f6658b286d891678214b7ad0d59",
"bytes": 3682
},
{
"path": "notes/tradeoff-removal/xterm/cache-revisit.log",
"sha256": "93197943b3a47b52c1674edb8965b7677ed8ef7c6a2894cd02f3cba857f06f7e",
"bytes": 2265
},
{
"path": "notes/tradeoff-removal/xterm/bufferline-source-experiment.cjs",
"sha256": "d6aa881c4d7562ab42951df648712de275de78f55efd8974e5284481c508aed9",
"bytes": 8999
},
{
"path": "notes/tradeoff-removal/xterm/bufferline-source-results.json",
"sha256": "27acaa73c54d66fb1fec3873e01e65994f51f982d9a8667fd2b97dd2840bd8bf",
"bytes": 6412
},
{
"path": "notes/tradeoff-removal/xterm/bufferline-source.log",
"sha256": "33ceecbf1a60f37e71e45bc13daa66a9b79abc6d7636c105baadffe44b726345",
"bytes": 1470
},
{
"path": "notes/tradeoff-removal/xterm/baseline-BufferLine.ts",
"sha256": "26551bd2db8ddd5cdb4f77b0f62f3b5f1ae4d14fd76ac4d5b5eae70eab10ea12",
"bytes": 22760
},
{
"path": "notes/tradeoff-removal/xterm/published-BufferLine.ts",
"sha256": "435b6bccb646071deda696d8e5ffccb5396524570a0d6f345093a1e0aebead1a",
"bytes": 24042
},
{
"path": "notes/tradeoff-removal/xterm/optionalCache-BufferLine.ts",
"sha256": "1bc91c6e7eda4e8e8c028a2a427320f80642be53c5b24ef63816a6c0e18aab93",
"bytes": 23741
},
{
"path": "notes/tradeoff-removal/xterm/falseCache-BufferLine.ts",
"sha256": "800627a54a7827d3ccf0320a9e1c2a502d0a89a51d9c910a6e6493acfd6f06bc",
"bytes": 23697
},
{
"path": "notes/tradeoff-removal/xterm/nullCache-BufferLine.ts",
"sha256": "c5997045cd4ccdf8ecd7307f313906c5ed3b6c1eac3da1f21461fbb957a9a05a",
"bytes": 23683
},
{
"path": "notes/tradeoff-removal/xterm/validGuard-BufferLine.ts",
"sha256": "53621b2c90a45c77372812735d462a1a40578431518bb008c2f1fb554ab9fa4c",
"bytes": 24284
}
],
"primaryWorktreeGitStatus": ""
}
@@ -0,0 +1,14 @@
# Xterm tradeoff-removal review
All four assigned PRs were reviewed. No new candidate is recommended for publication.
| PR | Result | Evidence and remaining tradeoff |
| ------ | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| #20955 | Reject sparse-sweep experiment; keep original PR held | Plain/sparse sweeps improved, but dense rows with an unlinked midpoint regressed 1.01.3% in all three repeated runs. Another density regressed 5.9% once. Final guarded experiment passes 21 tests, strict focused TS and lint; it was not benchmarked after the final compatibility guard. Periodic row/cell scanning still costs CPU. |
| #20965 | Keep held | Exact-source 4,097-key revisit yields 4,097 misses, versus zero for unbounded baseline. Cache eviction can repeat rasterization; alternatives do not eliminate the general tradeoff. |
| #20981 | Keep held | Same 4,097-key repeated-miss proof for contrast calculation. Rendering values stay unchanged, but recomputation remains possible. Orca enables contrast correction by default. |
| #20992 | Reject cache-representation experiments; keep held | Four alternatives preserve 25,000 mutation checks but do not reliably recover baseline speed. Existing emitted-parser evidence records roughly 5% overhead; fresh source builds also remain slower. |
The cache proof counts recomputations with a fixed result producer; it is not a GPU or app-latency measurement. Parser benchmarks are identically source-compiled variants, not release bundles. No result is tied to a specific affected host without incident data.
Full per-PR findings, original production/generated-patch/lockfile accounting, raw timings and limitations are in the four verdict JSON files. The proof manifest records artifact hashes. Source files, Git index, refs and remote PRs were not changed. #21112 remains dependent on #20992/#20981.