diff --git a/src/main/persistence/loading-store/__fixtures__/terminal-binding-writer-allowlist.txt b/src/main/persistence/loading-store/__fixtures__/terminal-binding-writer-allowlist.txt deleted file mode 100644 index aee25880000..00000000000 --- a/src/main/persistence/loading-store/__fixtures__/terminal-binding-writer-allowlist.txt +++ /dev/null @@ -1,16 +0,0 @@ -# Files that assign a terminal binding value (ptyIdsByLeafId, .ptyId, layout .root, -# terminalPtyIncarnationsByPaneKey, terminalSurfaceTombstonesByPaneKey) under src/main. -# Syntactic allowlist only: aliases, deletes and replacement objects are not counted. -# Live writers must invalidate durability via scheduleSave, flushOrThrow or session replacement. -# Behavioral coverage: persistence-flush-and-save-scheduling.test.ts. Only shrinks. -src/main/orca-profiles/profile-project-session-state.ts -src/main/orca-profiles/profile-project-session-transfer.ts -src/main/persistence/leasing-ssh-ptys/ssh-pty-binding-cleanup.ts -src/main/persistence/leasing-ssh-ptys/ssh-pty-lease-operations.ts -src/main/persistence/loading-store/pty-binding-persistence.ts -src/main/persistence/loading-store/workspace-session-terminal-binding-replay.ts -src/main/persistence/restoring-sessions/session-owner-removal.ts -src/main/persistence/tracking-repos/worktree-identity-migration.ts -src/main/runtime/mobile-session-layout-projection.ts -src/main/runtime/runtime-terminal-orphan-session-adoption.ts -src/main/ssh/ssh-target-id-migration.ts diff --git a/src/main/persistence/loading-store/pty-binding-fast-lane.test.ts b/src/main/persistence/loading-store/pty-binding-fast-lane.test.ts index 8a1ca3788d7..8ac6de70a0d 100644 --- a/src/main/persistence/loading-store/pty-binding-fast-lane.test.ts +++ b/src/main/persistence/loading-store/pty-binding-fast-lane.test.ts @@ -74,12 +74,6 @@ describe('evaluatePtyBindingFastLane', () => { expect(miss({}, session({ terminalPtyIncarnationsByPaneKey: { [paneKey]: 'a' } }))).toEqual([ 'incarnation' ]) - expect( - miss( - { incarnationId: 'b', expectedBinding: { ptyId: 'pty-1', incarnationId: 'a' } }, - session({ terminalPtyIncarnationsByPaneKey: { [paneKey]: 'b' } }) - ) - ).toEqual(['reconciled']) expect( miss( { incarnationId: 'a' }, @@ -127,15 +121,10 @@ describe('evaluatePtyBindingFastLane', () => { ).toEqual({ eligible: true, misses: [] }) }) - it('accepts a matching incarnation and a reconciled-to-same expected binding', () => { + it('accepts a matching incarnation', () => { const state = session({ terminalPtyIncarnationsByPaneKey: { [paneKey]: 'a' } }) expect( - evaluatePtyBindingFastLane( - { ...request, incarnationId: 'a', expectedBinding: { ptyId: 'pty-1', incarnationId: 'a' } }, - state, - WORKTREE, - true - ).eligible + evaluatePtyBindingFastLane({ ...request, incarnationId: 'a' }, state, WORKTREE, true).eligible ).toBe(true) }) }) diff --git a/src/main/persistence/loading-store/pty-binding-fast-lane.ts b/src/main/persistence/loading-store/pty-binding-fast-lane.ts index 287a9412885..9ae6304ed0f 100644 --- a/src/main/persistence/loading-store/pty-binding-fast-lane.ts +++ b/src/main/persistence/loading-store/pty-binding-fast-lane.ts @@ -17,7 +17,6 @@ export type PtyBindingFastLaneMiss = | 'leaf_absent' | 'leaf_pty' | 'incarnation' - | 'reconciled' | 'tombstone' | 'not_durable' @@ -26,7 +25,6 @@ export type PtyBindingFastLaneRequest = { leafId: string ptyId: string incarnationId?: string - expectedBinding?: { ptyId: string; incarnationId?: string } expectedSourceBinding?: unknown } @@ -79,12 +77,6 @@ export function evaluatePtyBindingFastLane( if (session.terminalPtyIncarnationsByPaneKey?.[paneKey] !== args.incarnationId) { misses.push('incarnation') } - if ( - args.expectedBinding !== undefined && - args.expectedBinding.incarnationId !== args.incarnationId - ) { - misses.push('reconciled') - } if (session.terminalSurfaceTombstonesByPaneKey?.[paneKey]) { misses.push('tombstone') } diff --git a/src/main/persistence/loading-store/terminal-binding-writer-boundary.test.ts b/src/main/persistence/loading-store/terminal-binding-writer-boundary.test.ts deleted file mode 100644 index 063c0194475..00000000000 --- a/src/main/persistence/loading-store/terminal-binding-writer-boundary.test.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { readFileSync, readdirSync, statSync } from 'node:fs' -import { join, relative, resolve } from 'node:path' -import { describe, expect, it } from 'vitest' - -/** - * Pins direct binding assignments so new writers cannot bypass durability review silently. - * This is only a syntax tripwire: aliases, deletes and replacement objects can evade it. - * Behavioral durability coverage lives in persistence-flush-and-save-scheduling.test.ts. - */ -const TERMINAL_BINDING_WRITER_ALLOWLIST: readonly string[] = readFileSync( - join(__dirname, '__fixtures__', 'terminal-binding-writer-allowlist.txt'), - 'utf8' -) - .split('\n') - .map((line) => line.trim()) - .filter((line) => line.length > 0 && !line.startsWith('#')) - -/** May only ever be DECREASED, by removing a binding writer. Raising it is never the fix. */ -const BINDING_WRITER_PIN = 11 - -// Assignment to a binding field: a property access or index expression on one of the five -// names, then `=` (or a compound `??=` / `||=` / `&&=`) not followed by `=`. -const ASSIGNMENT_PATTERN = - /(?:\.(?:ptyIdsByLeafId|ptyId|root|terminalPtyIncarnationsByPaneKey|terminalSurfaceTombstonesByPaneKey)|(?:ptyIdsByLeafId|terminalPtyIncarnationsByPaneKey|terminalSurfaceTombstonesByPaneKey)\s*(?:\?\.)?\[[^\]\n]*\])\s*(?:\?\?|\|\||&&)?=(?!=)/ - -const SCANNED_ROOT = 'src/main' -const SCANNED_EXTENSIONS = ['.ts'] -const IGNORED_DIRECTORIES = new Set([ - 'node_modules', - 'dist', - 'out', - 'build', - '.git', - '__fixtures__' -]) - -function isTestFile(path: string): boolean { - return ( - /\.(?:test|spec)\.tsx?$/.test(path) || - /(?:test-harness|test-utils|test-setup|test-fixture|repro)/.test(path) || - path.includes('/__tests__/') - ) -} - -function collectSourceFiles(root: string): string[] { - let found: string[] = [] - let entries: string[] - try { - entries = readdirSync(root) - } catch { - return found - } - for (const entry of entries) { - if (IGNORED_DIRECTORIES.has(entry)) { - continue - } - const full = join(root, entry) - if (statSync(full).isDirectory()) { - found = found.concat(collectSourceFiles(full)) - continue - } - if (SCANNED_EXTENSIONS.some((extension) => full.endsWith(extension))) { - found.push(full) - } - } - return found -} - -/** Drop comment-only lines so prose naming a field is not an offender. */ -function codeText(contents: string): string { - return contents - .split('\n') - .filter((line) => !/^\s*(?:\/\/|\/\*|\*)/.test(line)) - .join('\n') -} - -describe('terminal binding writer boundary', () => { - const repoRoot = resolve(__dirname, '..', '..', '..', '..') - const files = collectSourceFiles(join(repoRoot, SCANNED_ROOT)) - const offenders = files - .map((file) => relative(repoRoot, file).split('\\').join('/')) - .filter((path) => !isTestFile(path)) - .filter((path) => ASSIGNMENT_PATTERN.test(codeText(readFileSync(join(repoRoot, path), 'utf8')))) - - it('scans a plausible number of files', () => { - expect(files.length).toBeGreaterThan(500) - }) - - it('has no binding writer outside the allowlist', () => { - const unlisted = offenders.filter((path) => !TERMINAL_BINDING_WRITER_ALLOWLIST.includes(path)) - expect( - unlisted, - 'New writer of a terminal binding value. It must bump the persistence write generation ' + - '(scheduleSave, flushOrThrow, or setWorkspaceSession) in the same operation, or ' + - "persistPtyBinding's fast path can skip a flush it needed. " + - 'Verify durability in persistence-flush-and-save-scheduling.test.ts; ' + - 'this scanner does not prove the writer advances the generation.' - ).toEqual([]) - }) - - it('has no stale allowlist entry', () => { - const stale = TERMINAL_BINDING_WRITER_ALLOWLIST.filter((path) => !offenders.includes(path)) - expect(stale, 'Allowlist entry no longer writes a binding value — delete the line.').toEqual([]) - }) - - it('holds the writer count at the pin', () => { - // The pin is a literal so a swap (one writer removed, one added with its entry) cannot pass. - expect( - offenders.length, - `${offenders.length} files write terminal binding values; the pin is ${BINDING_WRITER_PIN}. ` + - 'Never raise the pin -- route the write through a path that bumps the write generation.' - ).toBeLessThanOrEqual(BINDING_WRITER_PIN) - expect( - offenders.length, - `Only ${offenders.length} files write terminal binding values. Lower BINDING_WRITER_PIN to ` + - `${offenders.length} to keep the ground you just took.` - ).toBeGreaterThanOrEqual(BINDING_WRITER_PIN) - }) -})