Files
Michał Pierzchała d4cf02a889 chore(gates): classify #2278 daemon-platform-runtime edges and ratchet handler session authority (#2354)
* chore(gates): classify #2278 daemon-platform-runtime edges (R74) and ratchet handler session authority (R75)

* chore(gates): discover the R75 shape target from the SessionState declaration

* chore(gates): capture dynamic-import bindings in R74 so symbol drift cannot hide

* chore(gates): reject dynamic-import destructure residue in R74

* chore(gates): R74 rejects open-ended dynamic imports beside named bindings

* chore(gates): renumber daemon-platform-runtime-inventory to R76 (R74 taken on main)
2026-09-08 13:21:29 +02:00

110 lines
4.3 KiB
TypeScript

import assert from 'node:assert/strict';
import { execFileSync } from 'node:child_process';
import { test } from 'node:test';
import { memoizedImportParser, resolveImportEdges } from './model.ts';
import { measureRatchets, mergeBaseRatchets } from './ratchet-reference.ts';
import { sessionStateWritePressure } from './session-state.ts';
import { listTrackedProductionSources } from './tracked-sources.ts';
import { readCommittedSources } from '../__tests__/committed-source-tree.ts';
const SESSION_TYPES = [
'export type SessionState = {',
' snapshot?: string;',
' trace?: string;',
' name: string;',
'};',
].join('\n');
function tree(extra: Record<string, string> = {}) {
return new Map<string, string>([
['src/daemon/session-state.ts', SESSION_TYPES],
['src/daemon/session-snapshot.ts', 'session.snapshot = "a"; nextSession.snapshot = "b";'],
['src/daemon/ref-frame.ts', 'session.snapshot = undefined;'],
['src/daemon/handlers/trace-runtime.ts', 'session.trace ??= "t";'],
['src/client/client.ts', "import type { Loop } from '../commands/loop.ts';"],
['src/commands/loop.ts', "import type { Client } from '../client/client.ts';"],
...Object.entries(extra),
]);
}
const repoRoot = execFileSync('git', ['rev-parse', '--show-toplevel'], {
encoding: 'utf8',
}).trim();
test('sessionStateWritePressure counts written fields and (field, writer) claims, not writes', () => {
assert.deepEqual(sessionStateWritePressure(tree()), {
writerOwnedFields: 2,
ownerFileClaims: 3,
});
assert.deepEqual(
sessionStateWritePressure(tree({ 'src/daemon/other.ts': 'session[key] = 1;' })),
{
writerOwnedFields: 2,
ownerFileClaims: 3,
},
);
assert.deepEqual(sessionStateWritePressure(new Map()), {
writerOwnedFields: 0,
ownerFileClaims: 0,
});
});
test('measureRatchets reports all ratchets from one tree', () => {
const sources = tree();
assert.deepEqual(measureRatchets(sources, resolveImportEdges(sources)), {
typeInversions: { 'commands -> client': 1 },
largestTypeCycle: ['src/client/client.ts', 'src/commands/loop.ts'],
sessionState: { writerOwnedFields: 2, ownerFileClaims: 3 },
sessionAuthority: { shapeFiles: [], authorityFiles: [] },
});
const withAuthority = tree({
'src/daemon/handlers/fixture.ts':
"import type { SessionState } from '../session-state.ts';\n" +
"import { SessionStore } from '../session-store.ts';",
'src/daemon/session-store.ts': 'export class SessionStore {}',
});
assert.deepEqual(
measureRatchets(withAuthority, resolveImportEdges(withAuthority)).sessionAuthority,
{
shapeFiles: ['src/daemon/handlers/fixture.ts'],
authorityFiles: ['src/daemon/handlers/fixture.ts'],
},
);
});
test('memoizedImportParser parses each distinct source text once', () => {
let parses = 0;
const a = "import type { Client } from '../client/client.ts';";
const sources = new Map([
['src/commands/a.ts', a],
['src/commands/b.ts', `${a.slice(0, 5)}${a.slice(5)}`],
['src/client/client.ts', 'export type Client = {};'],
]);
const parse = memoizedImportParser();
assert.deepEqual(resolveImportEdges(sources, undefined, parse), resolveImportEdges(sources));
resolveImportEdges(sources, undefined, (source) => {
parses++;
return parse(source);
});
assert.equal(parses, 3);
assert.equal(parse(a), parse(a));
});
// The reference is a committed tree read through the shared committed-tree reader, so its file
// set must be the one the working-tree scan uses. A divergence here means the git-side
// enumeration or blob read no longer matches the layering scan input.
test('the committed enumeration at HEAD is the working-tree scan input', () => {
const { sources, manifests } = readCommittedSources(repoRoot, 'HEAD');
assert.deepEqual([...sources.keys()], listTrackedProductionSources(repoRoot));
assert.ok(manifests.has('packages/kernel/package.json'));
});
test('the merge-base reference names its ref and measures the real tree', () => {
const reference = mergeBaseRatchets(repoRoot);
assert.match(reference.ref, /^[0-9a-f]{40}$/);
assert.ok(reference.largestTypeCycle.length >= 1);
assert.ok(reference.sessionState.writerOwnedFields > 0);
assert.ok(reference.sessionState.ownerFileClaims >= reference.sessionState.writerOwnedFields);
assert.ok(Object.keys(reference.typeInversions).length > 0);
});