Files
callstack__agent-device/scripts/layering/record-runtime-registry-policy.ts
Michał Pierzchała 03c3984066 perf(contracts): granularize entry surfaces so hub importers stop evaluating the facade clump (#1969)
* perf(contracts): granularize entry surfaces so hub importers stop evaluating the facade clump

`@agent-device/contracts/platform` unions 32 vocabulary modules and
`/interaction` another 18. A file that value-imports either evaluates the whole
union to reach one function, and because permanent hubs sat behind them —
`command-descriptor/registry.ts`, `core/capabilities.ts`,
`interactors/register-builtins.ts`, `command-descriptor/platform-execution-entry.ts` —
that union rode into roughly half the unit suite's test graphs.

Give every vocabulary module its own entry subpath and move all value-importers
onto the module that owns the symbol. Type-only importers are left alone: `import
type` is erased, so it already evaluated nothing.

Measured with the #1950 eager-import-closure walker over all 974 unit-core test
files, against base e5bfde3d1:

  aggregate eager module evaluations  143,248 -> 129,738  (-9.4%)
  facades/platform.ts   carried by    466 -> 1 test graphs
  facades/interaction.ts carried by   451 -> 0 test graphs

  registry.ts                 105 -> 66
  capabilities.ts             113 -> 76
  register-builtins.ts        111 -> 73
  platform-execution-entry.ts  43 -> 3
  dispatch.ts                 134 -> 100

Three gate adjustments the split forces:

- R11's pinned contracts subpath list grows to the new entries, and the resolver
  test's "must not resolve" example moves to `./clipboard`, since `./gesture-plan`
  is now a real entry.
- R16 anchored the record-runtime join on the literal `contracts/platform`
  specifier. It now accepts any contracts entry — the assertion's provenance is
  what the rule pins, not which subpath carried it.
- `gesture-plan.ts` became an entry target, and the no-bare-star rule rejects the
  `export * from './gesture-plan-types.ts'` it carried. Its one internal consumer
  now imports the owning module directly.

Both facades keep their type re-exports for the ~490 type-only importers, so
every symbol on them now reads as value-unused; one fallow entry records that
and names retiring them as the follow-up.

Closes #1959

* test(contracts): text-filter the facade scan before parsing

The repo-wide scan parsed all ~3000 sources, which the coverage lane's
instrumentation pushed past both the 5s test timeout and the 2.5s slow-test
budget. A file that never names the specifier cannot import it, so filter on the
text first and parse only the ~490 candidates.

Non-vacuity moves with it: instead of counting narrow imports across every file,
require that the surviving type-only importers were seen and classified as
erased — which an empty scan cannot satisfy.
2026-08-22 15:35:38 +02:00

107 lines
3.8 KiB
TypeScript

import { parseSync } from 'oxc-parser';
import { memberName, type ProductionSource, visitAst } from './cutover-policy-ast.ts';
export function recordRuntimeRegistryJoinViolations(
sources: readonly ProductionSource[],
): string[] {
const file = sources.find(({ path }) => path === 'src/core/command-descriptor/registry.ts');
if (!file) return [missingRecordRuntimeRegistryJoin()];
const parsed = parseSync(file.path, file.source);
const assertionName = importedRecordRuntimeAssertionName(parsed.program);
if (!assertionName) return [missingRecordRuntimeRegistryJoin()];
let joined = false;
visitAst(parsed.program, (node) => {
if (
node.type === 'IfStatement' &&
isRecordDescriptorGuard(node.test) &&
containsRecordRuntimeAssertion(node.consequent, assertionName)
) {
joined = true;
}
});
return joined ? [] : [missingRecordRuntimeRegistryJoin()];
}
function missingRecordRuntimeRegistryJoin(): string {
return 'src/core/command-descriptor/registry.ts: missing record runtime descriptor join assertion';
}
function importedRecordRuntimeAssertionName(node: unknown): string | undefined {
let localName: string | undefined;
visitAst(node, (candidate) => {
if (candidate.type !== 'ImportDeclaration') return;
const source = candidate.source as Record<string, unknown> | undefined;
// Any contracts entry, not one named subpath: the assertion's provenance is what
// this rule pins, and #1959 splits that vocabulary across per-module entries.
if (
source?.type !== 'Literal' ||
!String(source.value).startsWith('@agent-device/contracts/')
) {
return;
}
const specifiers = candidate.specifiers as readonly Record<string, unknown>[] | undefined;
const assertion = specifiers?.find((specifier) => {
const imported = specifier.imported as Record<string, unknown> | undefined;
return imported?.type === 'Identifier' && imported.name === 'assertRecordRuntimeExecution';
});
const local = assertion?.local as Record<string, unknown> | undefined;
if (local?.type === 'Identifier') localName = String(local.name);
});
return localName;
}
function isRecordDescriptorGuard(node: unknown): boolean {
if (node === null || typeof node !== 'object') return false;
const expression = node as Record<string, unknown>;
if (
expression.type !== 'BinaryExpression' ||
!['===', '=='].includes(String(expression.operator))
) {
return false;
}
return (
(isDescriptorNameAccess(expression.left) && isRecordLiteral(expression.right)) ||
(isDescriptorNameAccess(expression.right) && isRecordLiteral(expression.left))
);
}
function isDescriptorNameAccess(node: unknown): boolean {
if (node === null || typeof node !== 'object') return false;
const member = node as Record<string, unknown>;
const object = member.object as Record<string, unknown> | undefined;
return (
member.type === 'MemberExpression' &&
memberName(member) === 'name' &&
object?.type === 'Identifier' &&
object.name === 'descriptor'
);
}
function isRecordLiteral(node: unknown): boolean {
return (
node !== null &&
typeof node === 'object' &&
(node as Record<string, unknown>).type === 'Literal' &&
(node as Record<string, unknown>).value === 'record'
);
}
function containsRecordRuntimeAssertion(node: unknown, assertionName: string): boolean {
let found = false;
visitAst(node, (candidate) => {
if (candidate.type !== 'CallExpression') return;
const callee = candidate.callee as Record<string, unknown> | undefined;
const args = candidate.arguments as readonly Record<string, unknown>[] | undefined;
if (
callee?.type === 'Identifier' &&
callee.name === assertionName &&
args?.length === 1 &&
args[0]?.type === 'Identifier' &&
args[0].name === 'platformExecution'
) {
found = true;
}
});
return found;
}