Skip to content

Commit 2f97049

Browse files
committed
chore(gates): derive the contracts export inventory from package.json
R11's package-boundaries test pinned every packages/contracts export subpath by hand (~115 entries, compared with deepEqual), so every merge that touched packages/contracts/package.json also had to hand-edit the pin. Replace it with a structural check derived from the manifest itself: every exports target must resolve to an existing, tracked source file, and the number of resolved targets must equal Object.keys(manifest.exports).length. The must-not-resolve negative list (Node resolution enforces the exports map at runtime) is untouched.
1 parent 09c1cae commit 2f97049

1 file changed

Lines changed: 27 additions & 120 deletions

File tree

scripts/layering/package-boundaries.test.ts

Lines changed: 27 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
specifierSites,
2222
type WorkspacePackage,
2323
} from './package-boundaries.ts';
24+
import { listTrackedTypeScriptFiles } from './tracked-sources.ts';
2425

2526
const repoRoot = path.resolve(import.meta.dirname, '../..');
2627

@@ -46,130 +47,36 @@ const contracts: WorkspacePackage = {
4647
};
4748

4849
const ALL = [kernel, contracts];
49-
const CONTRACT_EXPORTS = [
50-
'@agent-device/contracts/alert-contract',
51-
'@agent-device/contracts/alert-runtime',
52-
'@agent-device/contracts/android-clipboard-support',
53-
'@agent-device/contracts/android-helper-artifacts',
54-
'@agent-device/contracts/android-input-ownership',
55-
'@agent-device/contracts/android-observation',
56-
'@agent-device/contracts/android-snapshot-quality',
57-
'@agent-device/contracts/android-system-chrome',
58-
'@agent-device/contracts/android-touch-plan',
59-
'@agent-device/contracts/app-deployment-runtime',
60-
'@agent-device/contracts/app-deployment-runtime-plan',
61-
'@agent-device/contracts/app-event-runtime',
62-
'@agent-device/contracts/app-inventory-runtime',
63-
'@agent-device/contracts/app-log-runtime',
64-
'@agent-device/contracts/app-state-runtime',
65-
'@agent-device/contracts/app-switcher-runtime',
66-
'@agent-device/contracts/apple-multitouch-support',
67-
'@agent-device/contracts/apple-runner-request',
68-
'@agent-device/contracts/application-lifecycle-interaction',
69-
'@agent-device/contracts/application-lifecycle-runtime',
70-
'@agent-device/contracts/application-lifecycle-runtime-plan',
71-
'@agent-device/contracts/async-lifecycle',
72-
'@agent-device/contracts/audio-probe-result',
73-
'@agent-device/contracts/audio-probe-runtime',
74-
'@agent-device/contracts/audio-probe-runtime-host',
75-
'@agent-device/contracts/audio-probe-support',
76-
'@agent-device/contracts/audio-runtime-plan',
77-
'@agent-device/contracts/back-mode',
78-
'@agent-device/contracts/backend-diagnostics',
79-
'@agent-device/contracts/back-runtime',
80-
'@agent-device/contracts/boot-failure',
81-
'@agent-device/contracts/capture',
82-
'@agent-device/contracts/click-button',
83-
'@agent-device/contracts/client',
84-
'@agent-device/contracts/clipboard',
85-
'@agent-device/contracts/clipboard-runtime',
86-
'@agent-device/contracts/command',
87-
'@agent-device/contracts/command-platform-execution',
88-
'@agent-device/contracts/device',
89-
'@agent-device/contracts/device-readiness-runtime',
90-
'@agent-device/contracts/device-shutdown-runtime',
91-
'@agent-device/contracts/divergence',
92-
'@agent-device/contracts/durable-resource',
93-
'@agent-device/contracts/durable-resource-envelope',
94-
'@agent-device/contracts/element-text-runtime',
95-
'@agent-device/contracts/focus-runtime',
96-
'@agent-device/contracts/gesture-admission',
97-
'@agent-device/contracts/gesture-input',
98-
'@agent-device/contracts/gesture-normalization',
99-
'@agent-device/contracts/gesture-plan',
100-
'@agent-device/contracts/gesture-plan-types',
101-
'@agent-device/contracts/gesture-runtime',
102-
'@agent-device/contracts/home-runtime',
103-
'@agent-device/contracts/host-diagnostics',
104-
'@agent-device/contracts/daemon-owner-cleanup',
105-
'@agent-device/contracts/interaction',
106-
'@agent-device/contracts/interaction-error',
107-
'@agent-device/contracts/interaction-guarantees',
108-
'@agent-device/contracts/interactor-operation-catalog',
109-
'@agent-device/contracts/interactor-types',
110-
'@agent-device/contracts/ios-snapshot',
111-
'@agent-device/contracts/is-predicate',
112-
'@agent-device/contracts/keyboard',
113-
'@agent-device/contracts/keyboard-runtime',
114-
'@agent-device/contracts/local-interactor-operation-set',
115-
'@agent-device/contracts/logs-runtime-plan',
116-
'@agent-device/contracts/managed-device-allocation',
117-
'@agent-device/contracts/managed-web-backend',
118-
'@agent-device/contracts/navigation',
119-
'@agent-device/contracts/network-runtime',
120-
'@agent-device/contracts/network-runtime-plan',
121-
'@agent-device/contracts/network-traffic',
122-
'@agent-device/contracts/observability',
123-
'@agent-device/contracts/orientation-runtime',
124-
'@agent-device/contracts/perf-runtime',
125-
'@agent-device/contracts/perf-runtime-host',
126-
'@agent-device/contracts/perf-runtime-operation-builder',
127-
'@agent-device/contracts/perf-runtime-plan',
128-
'@agent-device/contracts/platform-module',
129-
'@agent-device/contracts/platform-plugin',
130-
'@agent-device/contracts/platform-providers',
131-
'@agent-device/contracts/platform-resource-cleanup',
132-
'@agent-device/contracts/platform-runtime',
133-
'@agent-device/contracts/platform-runtime-host',
134-
'@agent-device/contracts/platform-runtime-operations',
135-
'@agent-device/contracts/platform-runtime-unavailable',
136-
'@agent-device/contracts/progress',
137-
'@agent-device/contracts/record-runtime-execution',
138-
'@agent-device/contracts/recording',
139-
'@agent-device/contracts/remote',
140-
'@agent-device/contracts/replay',
141-
'@agent-device/contracts/react-native-overlay',
142-
'@agent-device/contracts/runner-lease-context',
143-
'@agent-device/contracts/screen-recording-runtime',
144-
'@agent-device/contracts/screen-recording-runtime-host',
145-
'@agent-device/contracts/screen-recording-runtime-plan',
146-
'@agent-device/contracts/screenshot-runtime',
147-
'@agent-device/contracts/scroll-command',
148-
'@agent-device/contracts/scroll-gesture',
149-
'@agent-device/contracts/scroll-runtime',
150-
'@agent-device/contracts/selector-observation-runtime',
151-
'@agent-device/contracts/session',
152-
'@agent-device/contracts/settings',
153-
'@agent-device/contracts/settings-runtime',
154-
'@agent-device/contracts/snapshot',
155-
'@agent-device/contracts/snapshot-presentation',
156-
'@agent-device/contracts/snapshot-runtime',
157-
'@agent-device/contracts/snapshot-scope',
158-
'@agent-device/contracts/snapshot-timeout-evidence',
159-
'@agent-device/contracts/startup-recovery-fence',
160-
'@agent-device/contracts/touch-runtime',
161-
'@agent-device/contracts/tv-remote',
162-
'@agent-device/contracts/tv-remote-runtime',
163-
'@agent-device/contracts/type-text-runtime',
164-
'@agent-device/contracts/viewport-runtime',
165-
'@agent-device/contracts/wait',
166-
'@agent-device/contracts/wait-runtime-plan',
167-
] as const;
16850

16951
function rules(violations: { rule: string }[]): string[] {
17052
return violations.map((violation) => violation.rule);
17153
}
17254

55+
/**
56+
* The manifest is its own inventory: every `exports` target must resolve to an existing,
57+
* TRACKED source file, and every manifest entry must have produced exactly one `exportTargets`
58+
* entry (nothing dropped, nothing collapsed by a duplicate key). This replaces a ~120-line pinned
59+
* subpath list that every `packages/contracts/package.json` change also had to hand-edit; the
60+
* manifest is now the only place the export surface is declared.
61+
*/
62+
function assertExportTargetsMatchManifest(pkg: WorkspacePackage, manifestFile: string): void {
63+
const manifest = JSON.parse(fs.readFileSync(path.join(repoRoot, manifestFile), 'utf8')) as {
64+
exports?: Record<string, unknown>;
65+
};
66+
const trackedSources = new Set(listTrackedTypeScriptFiles(repoRoot));
67+
for (const [specifier, target] of pkg.exportTargets) {
68+
assert.ok(
69+
trackedSources.has(target) && fs.existsSync(path.join(repoRoot, target)),
70+
`${specifier} -> ${target} must resolve to an existing, tracked file`,
71+
);
72+
}
73+
assert.equal(
74+
pkg.exportTargets.size,
75+
Object.keys(manifest.exports ?? {}).length,
76+
`${pkg.name} exports map entries must each produce one resolved export target`,
77+
);
78+
}
79+
17380
test('specifier sites carry 1-based lines for static and dynamic imports', () => {
17481
const sites = specifierSites(
17582
'src/a.ts',
@@ -451,7 +358,7 @@ test('the real tree parses, declares, and passes R11', () => {
451358
assert.ok(kernelPackage.exportTargets.size >= 8, 'kernel exports its vocabulary subpaths');
452359
const contractsPackage = packages.find((pkg) => pkg.name === '@agent-device/contracts');
453360
assert.ok(contractsPackage, 'contracts package must exist');
454-
assert.deepEqual([...contractsPackage.exportTargets.keys()].sort(), [...CONTRACT_EXPORTS].sort());
361+
assertExportTargetsMatchManifest(contractsPackage, 'packages/contracts/package.json');
455362
assert.deepEqual([...contractsPackage.workspaceDependencies], ['@agent-device/kernel']);
456363
const captureKitPackage = packages.find((pkg) => pkg.name === '@agent-device/capture-kit');
457364
assert.ok(captureKitPackage, 'capture-kit package must exist');

0 commit comments

Comments
 (0)