import { cpSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' import { rm } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' import { fileURLToPath } from 'node:url' import { afterAll, describe, expect, it } from 'vitest' import { defineAcpSnapshotSuite, stabilizeFixtureMessageIds, tokenizeSessionFixtureCwd, type HarvestedLog, type Scenario, } from '../src/index.ts' import { assertChildSystemPromptSnapshot, assertUniqueSnapshotContents, claimSharedSnapshot, fixtureContext, formatSystemPromptSnapshot, headerChangeCount, formatToolSchemasSnapshot, normalizedHeaders, normalizedSystemPrompts, normalizedToolSchemas, parseToolSchemasSnapshot, refreshFixtureReplacements, scenarioSkipped, sessionFixtureNames, restorePinnedToolSchemas, type SharedSnapshotClaim, stabilizeRefreshLog, stdoutExpectedVariants, unknownToolCallIds, } from '../src/suite.ts' /** * Unit tests for the suite factory, by running it: two synthetic suites over the scripted fake * ACP bin (./fixtures/fake-acp-agent.ts) register real describe/it trees at collection time, * so every factory path — expected-output and log comparisons, the per-suite header pin and its uniformity * guard, record-mode fixture write-back, skip semantics, and the fixture guard block — * executes as an ordinary green test. * * Record tests use a temp copy. To intentionally rebuild their committed fixtures, run this * spec once with `ACP_SNAPSHOT_SPEC_BOOTSTRAP=1`, then review and commit the resulting tree. */ const fakeAgent = fileURLToPath(new URL('./fixtures/fake-acp-agent.ts', import.meta.url)) const AGENT = { binScript: fakeAgent, libBinScript: fakeAgent, configPath: fakeAgent, tsconfigPath: fileURLToPath(new URL('../../../../tsconfig.json', import.meta.url)), } const REPLAY_DIR = fileURLToPath(new URL('./fixtures/suite', import.meta.url)) function stabilize( fresh: string, existing: string, replacements: Parameters[2] = [], freshContext: Parameters[3] = fixtureContext(fresh), ): string { return stabilizeRefreshLog(fresh, existing, replacements, freshContext) } const RECORD_SRC = fileURLToPath(new URL('./fixtures/record-suite', import.meta.url)) // Replay pins explicit header classes; recording covers the default fallback. const REPLAY_SCENARIOS: Scenario[] = [ { name: 'pin-turn', hasModelTurn: true, recorded: true, pinsHeader: true, expectedHeaderChanges: 1, headerClass: 'main' }, { name: 'shared-pin', hasModelTurn: true, recorded: true, pinsHeader: true, expectedHeaderChanges: 1, headerClass: 'shared', systemPromptSource: 'pin-turn', toolSchemasSource: 'pin-turn', }, { name: 'plain-turn', hasModelTurn: true, recorded: true, headerClass: 'main', env: { DSH_PERMISSION_MODE: 'never' }, configPath: AGENT.configPath, workspaceParent: tmpdir(), pinsChildToolSchemas: [1], pinsChildSystemPrompts: [1], prepareWorkspace: (cwd) => { writeFileSync(join(cwd, 'seed.txt'), 'prepared at runtime') }, }, { name: 'no-model', hasModelTurn: false, recorded: false, headerClass: 'main' }, { name: 'blocked-log', hasModelTurn: false, comparesLog: true, recorded: false, headerClass: 'main' }, { name: 'authored-error', hasModelTurn: true, recorded: false, overridden: true, headerClass: 'main' }, ] const RECORD_SCENARIOS: Scenario[] = [ { name: 'rec-pin', hasModelTurn: true, recorded: true, pinsHeader: true }, { name: 'rec-child', hasModelTurn: true, recorded: true, pinsChildToolSchemas: [1] }, // recorded:false in record mode → registered but skipped (never re-recorded). { name: 'rec-skip', hasModelTurn: true, recorded: false, overridden: true }, ] // Record/refresh modes mutate their snapshots dir, so run them on throwaway // copies — except record's documented bootstrap knob, which regenerates the // committed record fixtures and expected outputs in place. const BOOTSTRAP = process.env.ACP_SNAPSHOT_SPEC_BOOTSTRAP === '1' const recordDir = BOOTSTRAP ? RECORD_SRC : mkdtempSync(join(tmpdir(), 'acp-snap-record-suite-')) if (!BOOTSTRAP) { cpSync(RECORD_SRC, recordDir, { recursive: true }) // Record mode owns its output inventory: a new scenario has no primary yet, // while a changed child count can leave old numbered fixtures behind. rmSync(join(recordDir, 'rec-pin', 'session.jsonl')) writeFileSync(join(recordDir, 'rec-child', 'session.2.jsonl'), 'stale child\n') } const refreshDir = mkdtempSync(join(tmpdir(), 'acp-snap-refresh-suite-')) cpSync(REPLAY_DIR, refreshDir, { recursive: true }) staleRefreshFixtures(refreshDir) afterAll(async () => { if (!BOOTSTRAP) await rm(recordDir, { recursive: true, force: true }) await rm(refreshDir, { recursive: true, force: true }) }) function staleRefreshFixtures(dir: string): void { writeFileSync(join(dir, 'plain-turn', 'stdout.expected.jsonl'), 'stale stdout\n') writeFileSync(join(dir, 'pin-turn', 'system-prompt.expected.md'), 'STALE PROMPT\n') writeFileSync(join(dir, 'pin-turn', 'tool-schemas.expected.json'), '{"initial":[{"name":"stale"}],"changes":[]}\n') writeFileSync(join(dir, 'plain-turn', 'tool-schemas.1.expected.json'), '{"initial":[{"name":"stale-child"}],"changes":[]}\n') writeFileSync(join(dir, 'plain-turn', 'system-prompt.1.expected.md'), 'STALE CHILD PROMPT\n') const plainBehaviorFile = join(dir, 'plain-turn', 'behavior.json') const plainBehavior = JSON.parse(readFileSync(plainBehaviorFile, 'utf8')) as Record plainBehavior.echoEnv = true writeFileSync(plainBehaviorFile, `${JSON.stringify(plainBehavior, null, 2)}\n`) writeFileSync(join(dir, 'blocked-log', 'session.jsonl'), [ '{"type":"session","id":"99999999-8888-4777-8666-555555555555","createdAt":13,"cwd":"/rec/blocked-cwd","delegationDepth":0}', '{"type":"hook/result","seq":1,"time":13,"data":{"decision":"stale","durationMs":99}}', '', ].join('\n')) writeFileSync(join(dir, 'authored-error', 'session.jsonl'), [ '{"type":"session","id":"77777777-8888-4777-8666-555555555555","createdAt":13,"cwd":"/rec/error-cwd","delegationDepth":0}', '{"type":"turn/end","seq":1,"time":9,"data":{"error":"stale"}}', '', ].join('\n')) } describe('defineAcpSnapshotSuite: replay mode', () => { defineAcpSnapshotSuite({ agent: AGENT, snapshotsDir: REPLAY_DIR, scenarios: REPLAY_SCENARIOS, mode: 'replay' }) }) // The record suite's tests run in registration order: rec-pin re-records the // pinned fixture FIRST, so rec-child's uniformity guard reads the fresh pin. describe('defineAcpSnapshotSuite: record mode', () => { defineAcpSnapshotSuite({ agent: AGENT, snapshotsDir: recordDir, scenarios: RECORD_SCENARIOS, mode: 'record' }) }) describe('defineAcpSnapshotSuite: refresh mode', () => { defineAcpSnapshotSuite({ agent: AGENT, snapshotsDir: refreshDir, scenarios: REPLAY_SCENARIOS, mode: 'refresh' }) }) describe('defineAcpSnapshotSuite: refresh write-back', () => { it('rewrites stdout and comparable logs from a replay-mode child run', () => { const stdout = readFileSync(join(refreshDir, 'plain-turn', 'stdout.expected.jsonl'), 'utf8') expect(stdout).not.toContain('stale stdout') expect(stdout).toContain('env:{\\"mode\\":\\"replay\\"') expect(stdout).not.toContain('\\"mode\\":\\"refresh\\"') // The scenario's own env layer reached the subprocess. expect(stdout).toContain('\\"permissionMode\\":\\"never\\"') const blocked = readFileSync(join(refreshDir, 'blocked-log', 'session.jsonl'), 'utf8') expect(blocked).toContain('"decision":"block"') expect(blocked).not.toContain('"decision":"stale"') const authored = readFileSync(join(refreshDir, 'authored-error', 'session.jsonl'), 'utf8') expect(authored).toContain('"error":"model exploded"') expect(authored).not.toContain('"error":"stale"') expect(readFileSync(join(refreshDir, 'pin-turn', 'system-prompt.expected.md'), 'utf8')).toBe([ 'SYS PROMPT', '', '', '', 'SYS PROMPT', '', 'NEW PROMPT LINE', '', ].join('\n')) const schemas = readFileSync(join(refreshDir, 'pin-turn', 'tool-schemas.expected.json'), 'utf8') expect(schemas).toContain('"description": "D1"') expect(schemas).not.toContain('"name":"stale"') const childSchemas = readFileSync(join(refreshDir, 'plain-turn', 'tool-schemas.1.expected.json'), 'utf8') expect(childSchemas).toContain('"name": "child-only"') expect(childSchemas).not.toContain('stale-child') const childPrompt = readFileSync(join(refreshDir, 'plain-turn', 'system-prompt.1.expected.md'), 'utf8') expect(childPrompt).toBe('SYS PROMPT\n\nCHILD GUIDANCE\n') const pinSession = readFileSync(join(refreshDir, 'pin-turn', 'session.jsonl'), 'utf8') expect(pinSession).toContain('"cwd":"{{cwd}}"') }) }) describe('defineAcpSnapshotSuite: record inventory write-back', () => { it('creates a missing primary fixture and prunes stale child fixtures', () => { const fixture = readFileSync(join(recordDir, 'rec-pin', 'session.jsonl'), 'utf8') expect(fixture).toContain('"type":"session"') expect(fixture).toContain('"cwd":"{{cwd}}"') expect(() => readFileSync(join(recordDir, 'rec-child', 'session.2.jsonl'), 'utf8')).toThrow() expect(readFileSync(join(recordDir, 'rec-child', 'tool-schemas.1.expected.json'), 'utf8')) .toContain('"name": "t1"') }) it('retains an unchanged message id across the recorded parent and child fixtures', () => { const existingMessageId = '22222222-2222-4222-8222-222222222222' const freshMessageId = '11111111-1111-4111-8111-111111111111' const fixtures = ['session.jsonl', 'session.1.jsonl'] .map(file => readFileSync(join(recordDir, 'rec-child', file), 'utf8')) for (const fixture of fixtures) { expect(fixture).toContain(`"id":"${existingMessageId}"`) expect(fixture).not.toContain(freshMessageId) } }) }) describe('defineAcpSnapshotSuite: registration contract', () => { it("throws when a scenario's header class has no pinning scenario", () => { expect(() => { defineAcpSnapshotSuite({ agent: AGENT, snapshotsDir: REPLAY_DIR, scenarios: [{ name: 'pinless', hasModelTurn: true, recorded: true }], mode: 'replay', }) }).toThrow(/no scenario pins the request-header content of class "default"/) // A pinned class does not cover a DIFFERENT class's members. expect(() => { defineAcpSnapshotSuite({ agent: AGENT, snapshotsDir: REPLAY_DIR, scenarios: [ { name: 'pinned', hasModelTurn: true, recorded: true, pinsHeader: true }, { name: 'classless-orphan', hasModelTurn: true, recorded: true, headerClass: 'other' }, ], mode: 'replay', }) }).toThrow(/class "other" \(needed by classless-orphan\)/) }) it('throws when two scenarios pin the same header class', () => { expect(() => { defineAcpSnapshotSuite({ agent: AGENT, snapshotsDir: REPLAY_DIR, scenarios: [ { name: 'first-pin', hasModelTurn: true, recorded: true, pinsHeader: true }, { name: 'second-pin', hasModelTurn: true, recorded: true, pinsHeader: true }, ], mode: 'replay', }) }).toThrow(/header class "default" pinned by both first-pin and second-pin/) }) it('throws when scenario names are duplicated', () => { expect(() => { defineAcpSnapshotSuite({ agent: AGENT, snapshotsDir: REPLAY_DIR, scenarios: [ { name: 'duplicate', hasModelTurn: true, recorded: true, pinsHeader: true }, { name: 'duplicate', hasModelTurn: true, recorded: true }, ], mode: 'replay', }) }).toThrow(/duplicate scenario name "duplicate"/) }) it.each(['systemPromptSource', 'toolSchemasSource'] as const)( 'rejects %s away from a header pin', (field) => { expect(() => { defineAcpSnapshotSuite({ agent: AGENT, snapshotsDir: REPLAY_DIR, scenarios: [{ name: 'plain', hasModelTurn: true, recorded: true, [field]: 'owner', }], mode: 'replay', }) }).toThrow(new RegExp(`plain\\.${field} is only valid on a header-pinning scenario`)) }, ) it('rejects an unknown or non-pinning sidecar source', () => { expect(() => { defineAcpSnapshotSuite({ agent: AGENT, snapshotsDir: REPLAY_DIR, scenarios: [{ name: 'pin', hasModelTurn: true, recorded: true, pinsHeader: true, systemPromptSource: 'missing', }], mode: 'replay', }) }).toThrow(/pin names unknown system-prompt snapshot source "missing"/) expect(() => { defineAcpSnapshotSuite({ agent: AGENT, snapshotsDir: REPLAY_DIR, scenarios: [ { name: 'pin', hasModelTurn: true, recorded: true, pinsHeader: true, toolSchemasSource: 'plain', }, { name: 'plain', hasModelTurn: true, recorded: true }, ], mode: 'replay', }) }).toThrow(/pin names non-pinning tool-schema snapshot source "plain"/) }) it('rejects a sidecar source that redirects the same artifact', () => { expect(() => { defineAcpSnapshotSuite({ agent: AGENT, snapshotsDir: REPLAY_DIR, scenarios: [ { name: 'owner', hasModelTurn: true, recorded: true, pinsHeader: true }, { name: 'redirect', hasModelTurn: true, recorded: true, pinsHeader: true, headerClass: 'redirect', systemPromptSource: 'owner', }, { name: 'consumer', hasModelTurn: true, recorded: true, pinsHeader: true, headerClass: 'consumer', systemPromptSource: 'redirect', }, ], mode: 'replay', }) }).toThrow(/consumer names system-prompt snapshot source "redirect", which does not own its sidecar/) }) it('rejects shared sidecars with different header-change counts', () => { expect(() => { defineAcpSnapshotSuite({ agent: AGENT, snapshotsDir: REPLAY_DIR, scenarios: [ { name: 'owner', hasModelTurn: true, recorded: true, pinsHeader: true, expectedHeaderChanges: 1, }, { name: 'consumer', hasModelTurn: true, recorded: true, pinsHeader: true, headerClass: 'consumer', toolSchemasSource: 'owner', }, ], mode: 'replay', }) }).toThrow(/consumer and owner declare different header-change counts for shared tool-schema snapshot/) }) }) describe('shared snapshot content', () => { it('accepts identical claims and rejects order-dependent shared output', () => { const claims = new Map() claimSharedSnapshot(claims, 'shared/system-prompt.expected.md', 'first', 'prompt\n') claimSharedSnapshot(claims, 'shared/system-prompt.expected.md', 'second', 'prompt\n') expect(claims.get('shared/system-prompt.expected.md')).toEqual({ scenario: 'first', content: 'prompt\n', }) expect(() => { claimSharedSnapshot(claims, 'shared/system-prompt.expected.md', 'third', 'different\n') }).toThrow(/diverged between first and third/) }) it('rejects identical committed content under different paths', () => { assertUniqueSnapshotContents('prompt', [ { path: 'one/system-prompt.expected.md', content: 'one\n' }, { path: 'two/system-prompt.expected.md', content: 'two\n' }, ]) expect(() => { assertUniqueSnapshotContents('prompt', [ { path: 'one/system-prompt.expected.md', content: 'same\n' }, { path: 'two/system-prompt.expected.md', content: 'same\n' }, ]) }).toThrow(/identical prompt snapshots appear in one\/system-prompt\.expected\.md and two\/system-prompt\.expected\.md/) }) }) describe('sessionFixtureNames', () => { it('orders the primary and contiguous child fixtures while ignoring other files', () => { expect(sessionFixtureNames([ 'stdout.expected.jsonl', 'session.2.jsonl', 'session.jsonl', 'session.1.jsonl', 'input.json', ])).toEqual(['session.jsonl', 'session.1.jsonl', 'session.2.jsonl']) }) it('accepts a primary-only scenario', () => { expect(sessionFixtureNames(['session.jsonl'])).toEqual(['session.jsonl']) }) it('rejects a directory without the primary fixture', () => { expect(() => sessionFixtureNames(['session.1.jsonl'])).toThrow('missing session.jsonl') }) it('rejects gapped child fixtures', () => { expect(() => sessionFixtureNames(['session.jsonl', 'session.2.jsonl'])) .toThrow('expected session.1.jsonl, found session.2.jsonl') }) it.each(['session.0.jsonl', 'session.child.jsonl', 'session.01.jsonl'])( 'rejects invalid child fixture name %s', (name) => { expect(() => sessionFixtureNames(['session.jsonl', name])) .toThrow(`invalid child session fixture name: ${name}`) }, ) it('rejects duplicate child indexes', () => { expect(() => sessionFixtureNames(['session.jsonl', 'session.1.jsonl', 'session.1.jsonl'])) .toThrow('expected session.2.jsonl, found session.1.jsonl') }) }) describe('stdoutExpectedVariants', () => { const scenario: Scenario = { name: 'windows-native', hasModelTurn: true, recorded: true, pinsNativeWindowsStdout: true, } it('adds the native sidecar after the shared golden on Windows', () => { expect(stdoutExpectedVariants(scenario, 'win32')).toEqual([ { file: 'stdout.expected.jsonl', cwdPathMode: 'canonical' }, { file: 'stdout.expected.windows.jsonl', cwdPathMode: 'native' }, ]) }) it('keeps only the shared golden on other platforms or without the declaration', () => { expect(stdoutExpectedVariants(scenario, 'linux')).toEqual([ { file: 'stdout.expected.jsonl', cwdPathMode: 'canonical' }, ]) expect(stdoutExpectedVariants({ ...scenario, pinsNativeWindowsStdout: false }, 'win32')).toEqual([ { file: 'stdout.expected.jsonl', cwdPathMode: 'canonical' }, ]) }) }) describe('scenarioSkipped', () => { const authored: Scenario = { name: 'authored', hasModelTurn: true, recorded: false } const posix: Scenario = { name: 'posix-cancel', hasModelTurn: true, recorded: false, posixOnly: true } const pwsh: Scenario = { name: 'pwsh-tool', hasModelTurn: true, recorded: false, pwshOnly: true } it('skips authored scenarios only while recording', () => { expect(scenarioSkipped(authored, true, 'linux')).toBe(true) expect(scenarioSkipped(authored, false, 'linux')).toBe(false) }) it('skips posixOnly scenarios on Windows and nowhere else', () => { expect(scenarioSkipped(posix, false, 'win32')).toBe(true) expect(scenarioSkipped(posix, false, 'linux')).toBe(false) expect(scenarioSkipped(posix, false, 'darwin')).toBe(false) expect(scenarioSkipped(authored, false, 'win32')).toBe(false) }) it('skips pwshOnly scenarios when the host lacks pwsh, and runs them otherwise', () => { expect(scenarioSkipped(pwsh, false, 'linux', false)).toBe(true) expect(scenarioSkipped(pwsh, false, 'win32', true)).toBe(false) expect(scenarioSkipped(pwsh, false, 'linux', true)).toBe(false) expect(scenarioSkipped(authored, false, 'linux', false)).toBe(false) }) }) describe('fixtureContext', () => { it('reads the fixture header id and cwd', () => { const ctx = fixtureContext('{"type":"session","id":"abc","cwd":"/rec"}\n{"type":"turn/start"}\n') expect(ctx).toEqual({ sessionIds: ['abc'], cwd: '/rec' }) }) it('yields no session ids for a header without a string id', () => { expect(fixtureContext('{"type":"session","cwd":"/rec"}\n').sessionIds).toEqual([]) }) it('falls back to an impossible sentinel cwd (never the empty string)', () => { const ctx = fixtureContext('{"type":"session","id":"abc"}\n') expect(ctx.cwd).toBe('\0no-cwd\0') expect(ctx.cwd).not.toBe('') }) it('treats an empty fixture as an empty header', () => { expect(fixtureContext('')).toEqual({ sessionIds: [], cwd: '\0no-cwd\0' }) }) }) describe('normalizedHeaders', () => { const header = (system: string): string => JSON.stringify({ type: 'request/header', seq: 0, time: 9, data: { header: { config: { model: 'm' }, system }, reason: 'initial' }, }) it('extracts every request/header payload in log order, normalized', () => { const id = '11111111-2222-4333-8444-555555555555' const log = `${JSON.stringify({ type: 'session', id, createdAt: 5, cwd: '/w' })}\n${header('one')}\n` + `${JSON.stringify({ type: 'turn/start', seq: 1, time: 9, data: { turn: 1 } })}\n${header('two')}\n` const headers = normalizedHeaders(log, { sessionIds: [id], cwd: '/w' }) expect(headers).toEqual([ { config: { model: 'm' }, system: 'one' }, { config: { model: 'm' }, system: 'two' }, ]) }) it('yields nothing for a log without header events', () => { const log = `${JSON.stringify({ type: 'session', id: 'a', createdAt: 5 })}\n` expect(normalizedHeaders(log, { sessionIds: [], cwd: '/w' })).toEqual([]) }) }) describe('normalizedSystemPrompts', () => { it('extracts normalized string prompts and omits absent or non-string fields', () => { const log = [ '{"type":"session","id":"a","createdAt":5,"cwd":"/w"}', '{"type":"request/header","seq":0,"time":9,"data":{"header":{"system":"work in /w"}}}', '{"type":"request/header","seq":1,"time":9,"data":{"header":{}}}', '{"type":"request/header","seq":2,"time":9,"data":{"header":{"system":null}}}', '{"type":"request/header","seq":3,"time":9,"data":{"header":null}}', '{"type":"request/header","seq":4,"time":9,"data":{"header":"invalid"}}', '', ].join('\n') expect(normalizedSystemPrompts(log, { sessionIds: [], cwd: '/w' })).toEqual(['work in {{cwd}}']) }) }) describe('normalizedToolSchemas', () => { it('extracts normalized schema arrays and omits absent or non-array fields', () => { const log = [ '{"type":"session","id":"a","createdAt":5,"cwd":"/w"}', '{"type":"request/header","seq":0,"time":9,"data":{"header":{"tools":[{"name":"read","description":"work in /w"}]}}}', '{"type":"request/header","seq":1,"time":9,"data":{"header":{}}}', '{"type":"request/header","seq":2,"time":9,"data":{"header":{"tools":null}}}', '{"type":"request/header","seq":3,"time":9,"data":{"header":null}}', '{"type":"request/header","seq":4,"time":9,"data":{"header":"invalid"}}', '', ].join('\n') expect(normalizedToolSchemas(log, { sessionIds: [], cwd: '/w' })).toEqual([ [{ name: 'read', description: 'work in {{cwd}}' }], ]) }) }) describe('formatSystemPromptSnapshot', () => { it('adds a missing terminal newline without changing an existing one', () => { expect(formatSystemPromptSnapshot('prompt')).toBe('prompt\n') expect(formatSystemPromptSnapshot('prompt\n')).toBe('prompt\n') }) it('renders readable changed-prompt sections', () => { expect(formatSystemPromptSnapshot('prompt', ['new\nlines'])) .toBe('prompt\n\n\n\nnew\nlines\n') }) it('does not double the newline of a changed prompt', () => { expect(formatSystemPromptSnapshot('prompt\n', ['changed\n'])) .toBe('prompt\n\n\n\nchanged\n') }) }) describe('assertChildSystemPromptSnapshot', () => { const label = 'plain-turn/system-prompt.1.expected.md' it('accepts a distinct non-empty canonical child prompt', () => { expect(() => { assertChildSystemPromptSnapshot('SYS PROMPT\n\nCHILD GUIDANCE\n', 'SYS PROMPT\n', label) }).not.toThrow() }) it('rejects an empty or non-canonical child prompt', () => { expect(() => { assertChildSystemPromptSnapshot('\n', 'SYS PROMPT\n', label) }).toThrow(/non-empty prompt/) expect(() => { assertChildSystemPromptSnapshot('CHILD GUIDANCE', 'SYS PROMPT\n', label) }).toThrow(/end in a newline/) }) it('rejects a child prompt that duplicates its class pin', () => { const classSnapshot = readFileSync(join(REPLAY_DIR, 'pin-turn', 'system-prompt.expected.md'), 'utf8') const marker = classSnapshot.indexOf('\n