Files
callstack__agent-device/scripts/layering/session-authority-overlay.test.ts
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

138 lines
5.8 KiB
TypeScript

import assert from 'node:assert/strict';
import { test } from 'node:test';
import { resolveImportEdges } from './model.ts';
import {
checkSessionAuthorityOverlay,
handlerOwnedOverlay,
measureSessionAuthorityOverlay,
SESSION_AUTHORITY_OVERLAY_RULE,
type SessionAuthorityOverlay,
} from './session-authority-overlay.ts';
const STATE_STUB =
'export type SessionState = {\n name: string;\n};\n' +
'export type DaemonRequest = { x: number; };\n';
const STORE_STUB =
'export class SessionStore { get(name: string) { return name; } }\n' +
'export function resolveDaemonStateDir() { return "."; };\n';
function overlayOf(sources: Record<string, string>): SessionAuthorityOverlay {
const tree = new Map(Object.entries(sources));
return measureSessionAuthorityOverlay(tree, resolveImportEdges(tree));
}
test('the overlay counts symbol-level production importers, not file-level importers', () => {
const sources = {
'src/daemon/session-state.ts': STATE_STUB,
'src/daemon/session-store.ts': STORE_STUB,
'src/daemon/handlers/fixture.ts':
"import type { SessionState } from '../session-state.ts';\n" +
"import { SessionStore } from '../session-store.ts';\n",
'src/daemon/handlers/request-only.ts':
"import type { DaemonRequest } from '../session-state.ts';\n" +
"import { resolveDaemonStateDir } from '../session-store.ts';\n",
'src/daemon/non-handler.ts': "import type { SessionState } from './session-state.ts';\n",
'src/daemon/handlers/fixture.test.ts':
"import type { SessionState } from '../session-state.ts';\n",
};
assert.deepEqual(overlayOf(sources), {
shapeFiles: ['src/daemon/handlers/fixture.ts', 'src/daemon/non-handler.ts'],
authorityFiles: ['src/daemon/handlers/fixture.ts'],
});
});
test('the overlay follows the SessionState declaration to a moved path, not a recorded one', () => {
// Planted-red against a hardcoded src/daemon/types.ts target: #2346 moved the declaration to
// session-state.ts, so importers point there, and the overlay must still count them.
const sources = {
'src/daemon/types.ts': 'export type DaemonRequest = { x: number; };\n',
'src/daemon/session-state.ts': STATE_STUB,
'src/daemon/session-store.ts': STORE_STUB,
'src/daemon/handlers/fixture.ts': "import type { SessionState } from '../session-state.ts';\n",
'src/daemon/non-handler.ts': "import type { SessionState } from './session-state.ts';\n",
};
assert.deepEqual(overlayOf(sources), {
shapeFiles: ['src/daemon/handlers/fixture.ts', 'src/daemon/non-handler.ts'],
authorityFiles: [],
});
});
test('the handler-owned subset is the flat handlers surface only', () => {
const overlay: SessionAuthorityOverlay = {
shapeFiles: [
'src/daemon/handlers/fixture.ts',
'src/daemon/non-handler.ts',
'src/daemon/interaction/internal/interaction.ts',
],
authorityFiles: ['src/daemon/handlers/fixture.ts', 'src/daemon/request-router.ts'],
};
assert.deepEqual(handlerOwnedOverlay(overlay), {
shapeFiles: ['src/daemon/handlers/fixture.ts'],
authorityFiles: ['src/daemon/handlers/fixture.ts'],
});
});
test('R75 fails a handler file that gains a shape or authority edge beyond the merge-base', () => {
const reference: SessionAuthorityOverlay = {
shapeFiles: ['src/daemon/handlers/kept.ts'],
authorityFiles: ['src/daemon/handlers/kept.ts'],
};
const measured: SessionAuthorityOverlay = {
shapeFiles: ['src/daemon/handlers/kept.ts', 'src/daemon/handlers/new-shape.ts'],
authorityFiles: ['src/daemon/handlers/new-authority.ts'],
};
const violations = checkSessionAuthorityOverlay(measured, reference);
assert.equal(violations.length, 2);
const shape = violations.find(
(violation) => violation.file === 'src/daemon/handlers/new-shape.ts',
)!;
const authority = violations.find(
(violation) => violation.file === 'src/daemon/handlers/new-authority.ts',
)!;
assert.equal(shape.rule, SESSION_AUTHORITY_OVERLAY_RULE);
assert.equal(authority.rule, SESSION_AUTHORITY_OVERLAY_RULE);
assert.match(shape.message, /new handler-owned SessionState shape edge/);
assert.match(authority.message, /new handler-owned SessionStore authority edge/);
});
test('R75 passes when the handler-owned sets hold or shrink', () => {
const reference: SessionAuthorityOverlay = {
shapeFiles: ['src/daemon/handlers/a.ts', 'src/daemon/handlers/b.ts'],
authorityFiles: ['src/daemon/handlers/a.ts'],
};
const measured: SessionAuthorityOverlay = {
shapeFiles: ['src/daemon/handlers/a.ts'],
authorityFiles: [],
};
assert.deepEqual(checkSessionAuthorityOverlay(measured, reference), []);
});
test('R75 leaves new non-handler importers to the module declarations, not this ratchet', () => {
const measured: SessionAuthorityOverlay = {
shapeFiles: ['src/daemon/new-module.ts'],
authorityFiles: ['src/daemon/server/new-module.ts'],
};
assert.deepEqual(
checkSessionAuthorityOverlay(measured, { shapeFiles: [], authorityFiles: [] }),
[],
);
});
test('the end-to-end measurement feeds the ratchet: a new handler importer is red, an existing one is not', () => {
const base = {
'src/daemon/session-state.ts': STATE_STUB,
'src/daemon/session-store.ts': STORE_STUB,
'src/daemon/handlers/kept.ts': "import type { SessionState } from '../session-state.ts';\n",
};
const reference = handlerOwnedOverlay(overlayOf(base));
const grown = {
...base,
'src/daemon/handlers/new.ts': "import type { SessionState } from '../session-state.ts';\n",
};
const measured = handlerOwnedOverlay(overlayOf(grown));
assert.deepEqual(checkSessionAuthorityOverlay(reference, reference), []);
const violations = checkSessionAuthorityOverlay(measured, reference);
assert.equal(violations.length, 1);
assert.equal(violations[0]!.file, 'src/daemon/handlers/new.ts');
});