// M1/#648: deterministic synthetic reuse ONLY after actual owned-process exit. import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import { syncBuiltinESMExports } from 'node:module'; import { reviewFixture } from './model-review-fixtures.mjs'; function syntheticReuse(t, entries) { const originalRead = fs.readFileSync, originalKill = process.kill; const stats = new Map(entries.map(({ pid, startTime }) => { const fields = ['S', ...Array(18).fill('0'), String(BigInt(startTime) + 1n)]; return [`/proc/${pid}/stat`, `${pid} (synthetic-scratch-reuse) ${fields.join(' ')}\n`]; })); const protectedPids = new Set(entries.map(e => e.pid)); let signals = 0; t.after(() => { fs.readFileSync = originalRead; process.kill = originalKill; syncBuiltinESMExports(); }); fs.readFileSync = function (file, ...args) { if (typeof file === 'string' && stats.has(file)) return args[0] === 'utf8' ? stats.get(file) : Buffer.from(stats.get(file)); return originalRead.call(this, file, ...args); }; process.kill = function (pid, ...args) { if (protectedPids.has(pid)) { signals++; throw Error('synthetic identity must never be signalled'); } return originalKill.call(this, pid, ...args); }; syncBuiltinESMExports(); return () => assert.equal(signals, 0, 'no signal to synthetic reused identity'); } test('M1 confirmed outer and runner exits stay terminal through stale registry and synthetic reuse for a later generation', async t => { const f = await reviewFixture(t, { overdue: true }); await f.boot(); await f.observeSweep(); f.retained(); await f.exitOuter(); await f.observeSweep(); f.retained(); await f.exitRunner(); await f.observeSweep(); f.absent(); // Both actual owned children have exited/reaped and distinct completions observed. // This synthetic proc view is NOT a claim of actual OS PID wraparound/reuse. const noSignals = syntheticReuse(t, [{ pid: f.entry.pid, startTime: f.entry.startTime }, { pid: f.entry.runnerPid, startTime: f.entry.runnerStartTime }]); f.writeSessions([f.entry]); // same stale immutable identity must not erase terminal proof const removed = f.nextGeneration(); await f.observeSweep(); removed.removed(); noSignals(); }); test('M1 separately confirmed outer exit does not mark a live runner terminal', async t => { const f = await reviewFixture(t, { overdue: true }); await f.boot(); await f.observeSweep(); await f.exitOuter(); await f.observeSweep(); f.retained(); }); for (const field of ['startTime', 'runnerStartTime', 'modelKeyId']) test(`M1 initial corrupt ${field} does not acquire terminal proof`, async t => { const f = await reviewFixture(t, { overdue: true }); f.writeSessions([{ ...f.entry, [field]: field === 'modelKeyId' ? 'fedcba987654' : '0' }]); await f.boot(); await f.observeSweep(); f.retained(); }); test('M1 terminal proof never authorizes a changed persisted key identity', async t => { const f = await reviewFixture(t, { overdue: true }); await f.boot(); await f.observeSweep(); await f.exitOuter(); await f.observeSweep(); await f.exitRunner(); await f.observeSweep(); f.absent(); const removed = f.nextGeneration(); f.writeSessions([{ ...f.entry, modelKeyId: 'fedcba987654' }]); await f.observeSweep(); removed.retained(); }); test('M1 an initially corrupt key on an exited pair cannot acquire terminal permission', async t => { const f = await reviewFixture(t, { overdue: true, exited: true }); f.writeSessions([{ ...f.entry, modelKeyId: 'fedcba987654' }]); await f.boot(); await f.observeSweep(); f.retained(); });