agentic-workflow-manager 9.8.0 → 9.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/src/commands/job/gate.js +18 -0
  2. package/dist/src/commands/job/index.js +61 -0
  3. package/dist/src/commands/model-policy/index.js +73 -0
  4. package/dist/src/commands/plan/index.js +59 -2
  5. package/dist/src/commands/watch/apply.js +32 -0
  6. package/dist/src/core/admission/index.js +52 -2
  7. package/dist/src/core/admission/registry-contracts.js +1 -1
  8. package/dist/src/core/journal/requests.js +1 -1
  9. package/dist/src/core/journal/types.js +22 -1
  10. package/dist/src/core/model-policy/canonical.js +18 -0
  11. package/dist/src/core/model-policy/capabilities.js +197 -0
  12. package/dist/src/core/model-policy/capability-types.js +2 -0
  13. package/dist/src/core/model-policy/journal.js +124 -0
  14. package/dist/src/core/model-policy/paths.js +12 -0
  15. package/dist/src/core/model-policy/resolve.js +116 -0
  16. package/dist/src/core/model-policy/store.js +182 -0
  17. package/dist/src/core/model-policy/types.js +2 -0
  18. package/dist/src/core/model-policy/validate.js +112 -0
  19. package/dist/src/core/plan/identity.js +4 -2
  20. package/dist/src/core/plan/validate.js +15 -16
  21. package/dist/src/index.js +2 -0
  22. package/dist/tests/commands/job/gate-reconcile.test.js +16 -0
  23. package/dist/tests/commands/job/gate.test.js +9 -0
  24. package/dist/tests/commands/job/routing-report-cli.test.js +46 -0
  25. package/dist/tests/commands/job/routing.test.js +11 -0
  26. package/dist/tests/commands/model-policy/index.test.js +57 -0
  27. package/dist/tests/commands/plan/index.test.js +52 -0
  28. package/dist/tests/commands/watch/apply.test.js +12 -0
  29. package/dist/tests/core/admission/index.test.js +53 -0
  30. package/dist/tests/core/model-policy/capabilities.test.js +365 -0
  31. package/dist/tests/core/model-policy/journal.test.js +46 -0
  32. package/dist/tests/core/model-policy/policy.test.js +47 -0
  33. package/dist/tests/core/model-policy/resolve.test.js +111 -0
  34. package/dist/tests/core/model-policy/store.test.js +177 -0
  35. package/dist/tests/core/plan/validate.test.js +40 -2
  36. package/dist/tests/core/secure-fs/native-bridge.test.js +81 -4
  37. package/dist/tests/structural/directory-fsync-is-single-source.test.js +97 -0
  38. package/dist/tests/structural/native-release-artifacts.test.js +14 -0
  39. package/package.json +3 -2
  40. package/prebuilds/darwin-arm64/secure_fs.node +0 -0
  41. package/prebuilds/darwin-x64/secure_fs.node +0 -0
  42. package/prebuilds/linux-arm64/secure_fs.node +0 -0
  43. package/prebuilds/linux-x64/secure_fs.node +0 -0
  44. package/prebuilds/win32-arm64/secure_fs.node +0 -0
  45. package/prebuilds/win32-x64/secure_fs.node +0 -0
@@ -0,0 +1,365 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fs_1 = __importDefault(require("fs"));
7
+ const os_1 = __importDefault(require("os"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const child_process_1 = require("child_process");
10
+ const capabilities_1 = require("../../../src/core/model-policy/capabilities");
11
+ const digest = 'a'.repeat(64);
12
+ const receipt = () => ({
13
+ schema: 'routing-capabilities/v1',
14
+ runtime: { target: 'codex', kind: 'native', version: '1.0.0', accountScopeDigest: digest },
15
+ recordedAt: '2026-09-17T00:00:00.000Z', expiresAt: '2026-09-18T00:00:00.000Z',
16
+ capabilities: { artifactDelivery: 'unverified', interactiveExecution: 'supported', unattendedController: 'supported', nativeSubagents: 'unverified', modelOverride: 'supported', effortOverride: 'supported', observedModelEvidence: 'supported', durableResume: 'unverified' },
17
+ availableSelections: [{ selector: { kind: 'model', id: 'full' }, effort: { kind: 'explicit', value: 'high' } }],
18
+ runtimeDefaultSelection: { selector: { kind: 'model', id: 'full' }, effort: { kind: 'explicit', value: 'high' } },
19
+ evidence: ['interactiveExecution', 'unattendedController', 'modelOverride', 'effortOverride', 'observedModelEvidence'].map(capability => ({ capability, kind: 'native-control', receiptDigest: digest })),
20
+ approval: { approvalId: 'approval-1', snapshotDigest: digest },
21
+ });
22
+ /** A child can retain its fixture script briefly after it reports an outcome on
23
+ * Windows. Retry only that documented transient after every child has exited. */
24
+ async function removeC2Fixture(target, attempts = 10, delayMs = 50, remove = (pathToRemove) => fs_1.default.rmSync(pathToRemove, { recursive: true, force: true }), isWindows = process.platform === 'win32') {
25
+ for (let attempt = 0; attempt < attempts; attempt++) {
26
+ try {
27
+ remove(target);
28
+ return;
29
+ }
30
+ catch (error) {
31
+ if (!isWindows || error.code !== 'EBUSY' || attempt === attempts - 1)
32
+ throw error;
33
+ await new Promise(resolve => setTimeout(resolve, delayMs));
34
+ }
35
+ }
36
+ }
37
+ function startC2Competitor(root, candidate, expectedDigest, predecessor, awmHome) {
38
+ const module = path_1.default.resolve(__dirname, '../../../dist/src/core/model-policy/capabilities.js');
39
+ const worker = path_1.default.join(root, `c2-competitor-${path_1.default.basename(candidate)}.js`);
40
+ fs_1.default.writeFileSync(worker, `
41
+ const { approveCapabilities, capabilityReceiptDigest } = require(process.env.C2_CAPABILITIES_MODULE);
42
+ function report(message) {
43
+ if (typeof process.send !== 'function' || !process.connected) process.exit(1);
44
+ process.send(message, () => {
45
+ if (process.connected) process.disconnect();
46
+ });
47
+ }
48
+ process.once('message', message => {
49
+ if (message !== 'go') process.exit(1);
50
+ try {
51
+ const receipt = approveCapabilities({ file: process.env.C2_CANDIDATE, cwd: process.env.C2_CWD, expectedDigest: process.env.C2_EXPECTED_DIGEST, replaceDigest: process.env.C2_PREDECESSOR, now: new Date(process.env.C2_NOW) });
52
+ report({ outcome: 'accepted', digest: capabilityReceiptDigest(receipt) });
53
+ } catch (error) {
54
+ report({ outcome: 'rejected', reason: error instanceof Error ? error.message : String(error) });
55
+ }
56
+ });
57
+ process.once('disconnect', () => process.exit(0));
58
+ process.send({ type: 'ready' });
59
+ `);
60
+ let readyResolve;
61
+ let readyReject;
62
+ let outcomeResolve;
63
+ let outcomeReject;
64
+ let readySettled = false;
65
+ let outcomeSettled = false;
66
+ let exitResolve;
67
+ const ready = new Promise((resolve, reject) => { readyResolve = resolve; readyReject = reject; });
68
+ const outcome = new Promise((resolve, reject) => { outcomeResolve = resolve; outcomeReject = reject; });
69
+ const exited = new Promise(resolve => { exitResolve = resolve; });
70
+ const child = (0, child_process_1.fork)(worker, [], { cwd: root, env: { ...process.env, AWM_HOME: awmHome, C2_CAPABILITIES_MODULE: module, C2_CANDIDATE: candidate, C2_CWD: root, C2_EXPECTED_DIGEST: expectedDigest, C2_PREDECESSOR: predecessor, C2_NOW: '2026-09-17T12:00:00.000Z' }, stdio: ['ignore', 'ignore', 'ignore', 'ipc'] });
71
+ const rejectPending = (error) => {
72
+ if (!readySettled) {
73
+ readySettled = true;
74
+ readyReject(error);
75
+ }
76
+ if (!outcomeSettled) {
77
+ outcomeSettled = true;
78
+ outcomeReject(error);
79
+ }
80
+ };
81
+ child.once('error', rejectPending);
82
+ child.on('message', (message) => {
83
+ if (message && typeof message === 'object' && message.type === 'ready') {
84
+ if (!readySettled) {
85
+ readySettled = true;
86
+ readyResolve();
87
+ }
88
+ return;
89
+ }
90
+ const result = message;
91
+ if (!outcomeSettled && (result.outcome === 'accepted' || result.outcome === 'rejected')) {
92
+ outcomeSettled = true;
93
+ outcomeResolve(result);
94
+ }
95
+ });
96
+ child.once('exit', code => { exitResolve(); rejectPending(new Error(`C2 competitor exited before reporting an outcome (${code})`)); });
97
+ // A failure before both outcomes are awaited must not leave a rejected
98
+ // promise unobserved while the test's finally block is closing the child.
99
+ void ready.catch(() => undefined);
100
+ void outcome.catch(() => undefined);
101
+ return {
102
+ ready,
103
+ release: () => {
104
+ if (!child.connected)
105
+ throw new Error('C2 competitor IPC closed before release');
106
+ child.send('go');
107
+ },
108
+ outcome,
109
+ close: async () => {
110
+ if (child.exitCode !== null || child.signalCode !== null)
111
+ return exited;
112
+ if (child.connected) {
113
+ try {
114
+ child.disconnect();
115
+ }
116
+ catch (error) {
117
+ if (error.code !== 'ERR_IPC_DISCONNECTED')
118
+ throw error;
119
+ }
120
+ }
121
+ const timeout = setTimeout(() => {
122
+ if (child.exitCode === null && child.signalCode === null)
123
+ child.kill();
124
+ }, 5000);
125
+ try {
126
+ await exited;
127
+ }
128
+ finally {
129
+ clearTimeout(timeout);
130
+ }
131
+ },
132
+ };
133
+ }
134
+ describe('capability receipt validation', () => {
135
+ it('accepts an exhaustive explicit native attestation', () => {
136
+ expect((0, capabilities_1.validateCapabilityReceipt)(receipt())).toMatchObject({ runtime: { target: 'codex', kind: 'native' } });
137
+ });
138
+ it.each([
139
+ ['renderer-only supported evidence', () => { const value = receipt(); value.evidence[0].kind = 'unsupported'; return value; }],
140
+ ['expiry greater than 24 hours', () => { const value = receipt(); value.expiresAt = '2026-09-18T00:00:00.001Z'; return value; }],
141
+ ['missing capability field', () => { const value = receipt(); delete value.capabilities.effortOverride; return value; }],
142
+ ])('rejects %s', (_name, make) => expect(() => (0, capabilities_1.validateCapabilityReceipt)(make())).toThrow());
143
+ it.each(['September 17, 2026 00:00:00 UTC', '2026-09-17', '2026-09-17T00:00:00.000+00:00', '2026-09-17T00:00:00.000Zx', '2026-02-30T00:00:00.000Z', '2026-09-17T00:00:00Z'])('rejects a noncanonical receipt timestamp: %s', timestamp => {
144
+ const recorded = receipt();
145
+ recorded.recordedAt = timestamp;
146
+ const expires = receipt();
147
+ expires.expiresAt = timestamp;
148
+ expect(() => (0, capabilities_1.validateCapabilityReceipt)(recorded)).toThrow();
149
+ expect(() => (0, capabilities_1.validateCapabilityReceipt)(expires)).toThrow();
150
+ });
151
+ it.each(['renderer', 'documentation'])('does not certify supported execution from %s evidence', kind => {
152
+ const value = receipt();
153
+ value.evidence = value.evidence.map(entry => ({ ...entry, kind: kind }));
154
+ expect(() => (0, capabilities_1.validateCapabilityReceipt)(value)).toThrow(/evidence|native/i);
155
+ });
156
+ it('reads absent capability state without creating operator storage', () => {
157
+ const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-receipt-'));
158
+ const prior = process.env.AWM_HOME;
159
+ process.env.AWM_HOME = path_1.default.join(root, 'operator');
160
+ try {
161
+ expect((0, capabilities_1.readCapabilities)(receipt().runtime, new Date('2026-09-17T12:00:00.000Z'))).toEqual({ state: 'absent' });
162
+ expect(fs_1.default.existsSync(process.env.AWM_HOME)).toBe(false);
163
+ }
164
+ finally {
165
+ if (prior === undefined)
166
+ delete process.env.AWM_HOME;
167
+ else
168
+ process.env.AWM_HOME = prior;
169
+ fs_1.default.rmSync(root, { recursive: true, force: true });
170
+ }
171
+ });
172
+ it('uses only a validated target and runtime kind in its persistence path', () => {
173
+ expect((0, capabilities_1.capabilityReceiptPath)(receipt().runtime)).toMatch(/routing-capabilities[\\/]codex[\\/]native\.json$/);
174
+ expect(() => (0, capabilities_1.capabilityReceiptPath)({ ...receipt().runtime, kind: '../native' })).toThrow();
175
+ });
176
+ it.each(['2026-09-15T23:59:59.999Z', '2026-09-18T00:00:00.001Z'])('rejects stale or future approval at the injected clock', recordedAt => {
177
+ const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-receipt-'));
178
+ const candidate = path_1.default.join(root, 'receipt.json');
179
+ const value = receipt();
180
+ value.recordedAt = recordedAt;
181
+ value.expiresAt = recordedAt === '2026-09-15T23:59:59.999Z' ? '2026-09-16T23:59:59.999Z' : '2026-09-19T00:00:00.001Z';
182
+ fs_1.default.writeFileSync(candidate, JSON.stringify(value));
183
+ try {
184
+ expect(() => (0, capabilities_1.approveCapabilities)({ file: candidate, cwd: root, expectedDigest: (0, capabilities_1.capabilityReceiptDigest)(value), now: new Date('2026-09-17T00:00:00.000Z') })).toThrow(/future|stale/);
185
+ }
186
+ finally {
187
+ fs_1.default.rmSync(root, { recursive: true, force: true });
188
+ }
189
+ });
190
+ it('rejects an empty replace digest before reading or writing capability state', () => {
191
+ expect(() => (0, capabilities_1.approveCapabilities)({ file: 'missing.json', cwd: process.cwd(), expectedDigest: digest, replaceDigest: '' })).toThrow(/replaceDigest/);
192
+ });
193
+ it('rejects a symlinked candidate and a symlinked receipt destination', () => {
194
+ const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-receipt-'));
195
+ const linked = path_1.default.join(root, 'linked.json');
196
+ const outside = path_1.default.join(root, 'outside.json');
197
+ fs_1.default.writeFileSync(outside, JSON.stringify(receipt()));
198
+ const before = fs_1.default.readFileSync(outside);
199
+ fs_1.default.symlinkSync(outside, linked);
200
+ try {
201
+ expect(() => (0, capabilities_1.approveCapabilities)({ file: linked, cwd: root, expectedDigest: digest, now: new Date('2026-09-17T00:00:00.000Z') })).toThrow(/symlink|unsafe/);
202
+ expect(fs_1.default.readFileSync(outside).equals(before)).toBe(true);
203
+ }
204
+ finally {
205
+ fs_1.default.rmSync(root, { recursive: true, force: true });
206
+ }
207
+ });
208
+ it.each(['destination', 'ancestor'])('rejects a symlinked %s without changing external bytes', kind => {
209
+ const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-receipt-'));
210
+ const prior = process.env.AWM_HOME;
211
+ process.env.AWM_HOME = path_1.default.join(root, 'operator');
212
+ const external = path_1.default.join(root, 'external.json');
213
+ fs_1.default.writeFileSync(external, 'outside');
214
+ const runtime = receipt().runtime;
215
+ try {
216
+ const target = (0, capabilities_1.capabilityReceiptPath)(runtime);
217
+ const ancestor = path_1.default.dirname(path_1.default.dirname(target));
218
+ if (kind === 'destination') {
219
+ fs_1.default.mkdirSync(path_1.default.dirname(target), { recursive: true });
220
+ fs_1.default.symlinkSync(external, target);
221
+ }
222
+ else {
223
+ const externalTree = path_1.default.join(root, 'external-tree');
224
+ const sentinel = path_1.default.join(externalTree, 'codex', 'native.json');
225
+ fs_1.default.mkdirSync(path_1.default.dirname(sentinel), { recursive: true });
226
+ fs_1.default.writeFileSync(sentinel, 'sentinel');
227
+ fs_1.default.mkdirSync(path_1.default.dirname(ancestor), { recursive: true });
228
+ fs_1.default.symlinkSync(externalTree, ancestor);
229
+ }
230
+ expect((0, capabilities_1.readCapabilities)(runtime, new Date('2026-09-17T12:00:00.000Z')).state).toBe('invalid');
231
+ expect(fs_1.default.readFileSync(external, 'utf8')).toBe('outside');
232
+ }
233
+ finally {
234
+ if (prior === undefined)
235
+ delete process.env.AWM_HOME;
236
+ else
237
+ process.env.AWM_HOME = prior;
238
+ fs_1.default.rmSync(root, { recursive: true, force: true });
239
+ }
240
+ });
241
+ it('publishes with exact predecessor CAS and leaves the accepted C2 receipt intact', () => {
242
+ const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-receipt-'));
243
+ const previous = process.env.AWM_HOME;
244
+ process.env.AWM_HOME = path_1.default.join(root, 'operator');
245
+ const file = path_1.default.join(root, 'receipt.json');
246
+ const now = new Date('2026-09-17T12:00:00.000Z');
247
+ const first = receipt();
248
+ fs_1.default.writeFileSync(file, JSON.stringify(first));
249
+ try {
250
+ const firstDigest = (0, capabilities_1.capabilityReceiptDigest)(first);
251
+ expect((0, capabilities_1.approveCapabilities)({ file, cwd: root, expectedDigest: firstDigest, now })).toEqual(first);
252
+ expect(() => (0, capabilities_1.approveCapabilities)({ file, cwd: root, expectedDigest: firstDigest, now })).toThrow(/predecessor|exists/i);
253
+ const second = receipt();
254
+ second.approval.approvalId = 'approval-2';
255
+ fs_1.default.writeFileSync(file, JSON.stringify(second));
256
+ const secondDigest = (0, capabilities_1.capabilityReceiptDigest)(second);
257
+ expect(() => (0, capabilities_1.approveCapabilities)({ file, cwd: root, expectedDigest: secondDigest, replaceDigest: 'f'.repeat(64), now })).toThrow(/predecessor/);
258
+ expect((0, capabilities_1.approveCapabilities)({ file, cwd: root, expectedDigest: secondDigest, replaceDigest: firstDigest, now })).toEqual(second);
259
+ expect((0, capabilities_1.readCapabilities)(second.runtime, now)).toMatchObject({ state: 'current', digest: secondDigest });
260
+ }
261
+ finally {
262
+ if (previous === undefined)
263
+ delete process.env.AWM_HOME;
264
+ else
265
+ process.env.AWM_HOME = previous;
266
+ fs_1.default.rmSync(root, { recursive: true, force: true });
267
+ }
268
+ });
269
+ it('retries only bounded Windows EBUSY cleanup after a C2 child exits', async () => {
270
+ const calls = [];
271
+ await removeC2Fixture('fixture', 3, 0, () => {
272
+ calls.push('remove');
273
+ if (calls.length < 3)
274
+ throw Object.assign(new Error('busy'), { code: 'EBUSY' });
275
+ }, true);
276
+ expect(calls).toHaveLength(3);
277
+ await expect(removeC2Fixture('fixture', 3, 0, () => {
278
+ calls.push('non-busy');
279
+ throw Object.assign(new Error('denied'), { code: 'EPERM' });
280
+ }, true)).rejects.toThrow('denied');
281
+ expect(calls.filter(call => call === 'non-busy')).toHaveLength(1);
282
+ });
283
+ it('accepts exactly one process-raced C2 replacement from the same observed predecessor', async () => {
284
+ const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-receipt-'));
285
+ const prior = process.env.AWM_HOME;
286
+ const now = new Date('2026-09-17T12:00:00.000Z');
287
+ const file = path_1.default.join(root, 'receipt.json');
288
+ const base = receipt();
289
+ let leftProcess;
290
+ let rightProcess;
291
+ process.env.AWM_HOME = path_1.default.join(root, 'operator');
292
+ fs_1.default.writeFileSync(file, JSON.stringify(base));
293
+ try {
294
+ const predecessor = (0, capabilities_1.capabilityReceiptDigest)(base);
295
+ (0, capabilities_1.approveCapabilities)({ file, cwd: root, expectedDigest: predecessor, now });
296
+ const candidate = (id) => {
297
+ const value = receipt();
298
+ value.approval.approvalId = id;
299
+ const candidateFile = path_1.default.join(root, `${id}.json`);
300
+ fs_1.default.writeFileSync(candidateFile, JSON.stringify(value), { mode: 0o400 });
301
+ return { file: candidateFile, digest: (0, capabilities_1.capabilityReceiptDigest)(value) };
302
+ };
303
+ const left = candidate('left');
304
+ const right = candidate('right');
305
+ leftProcess = startC2Competitor(root, left.file, left.digest, predecessor, process.env.AWM_HOME);
306
+ rightProcess = startC2Competitor(root, right.file, right.digest, predecessor, process.env.AWM_HOME);
307
+ await Promise.all([leftProcess.ready, rightProcess.ready]);
308
+ leftProcess.release();
309
+ rightProcess.release();
310
+ const outcomes = await Promise.all([leftProcess.outcome, rightProcess.outcome]);
311
+ const accepted = outcomes.filter((outcome) => outcome.outcome === 'accepted');
312
+ const rejected = outcomes.filter((outcome) => outcome.outcome === 'rejected');
313
+ expect(accepted).toHaveLength(1);
314
+ expect(rejected).toHaveLength(1);
315
+ expect(rejected[0].reason).toMatch(/predecessor|lease|exist/i);
316
+ const persisted = (0, capabilities_1.readCapabilities)(base.runtime, now);
317
+ expect(persisted).toMatchObject({ state: 'current', digest: accepted[0].digest });
318
+ expect([left.digest, right.digest]).toContain(accepted[0].digest);
319
+ }
320
+ finally {
321
+ await Promise.all([leftProcess?.close(), rightProcess?.close()].filter((value) => value !== undefined));
322
+ if (prior === undefined)
323
+ delete process.env.AWM_HOME;
324
+ else
325
+ process.env.AWM_HOME = prior;
326
+ await removeC2Fixture(root);
327
+ }
328
+ });
329
+ it.each(['destination', 'ancestor'])('writer rejects symlinked %s and preserves external bytes', kind => {
330
+ const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-receipt-'));
331
+ const prior = process.env.AWM_HOME;
332
+ process.env.AWM_HOME = path_1.default.join(root, 'operator');
333
+ const now = new Date('2026-09-17T12:00:00.000Z');
334
+ const value = receipt();
335
+ const file = path_1.default.join(root, 'candidate.json');
336
+ fs_1.default.writeFileSync(file, JSON.stringify(value));
337
+ const outside = path_1.default.join(root, 'outside');
338
+ fs_1.default.writeFileSync(outside, 'outside');
339
+ const target = (0, capabilities_1.capabilityReceiptPath)(value.runtime);
340
+ const ancestor = path_1.default.dirname(path_1.default.dirname(target));
341
+ try {
342
+ if (kind === 'destination') {
343
+ fs_1.default.mkdirSync(path_1.default.dirname(target), { recursive: true });
344
+ fs_1.default.symlinkSync(outside, target);
345
+ }
346
+ else {
347
+ const externalTree = path_1.default.join(root, 'external-tree');
348
+ const sentinel = path_1.default.join(externalTree, 'codex', 'native.json');
349
+ fs_1.default.mkdirSync(path_1.default.dirname(sentinel), { recursive: true });
350
+ fs_1.default.writeFileSync(sentinel, 'sentinel');
351
+ fs_1.default.mkdirSync(path_1.default.dirname(ancestor), { recursive: true });
352
+ fs_1.default.symlinkSync(externalTree, ancestor);
353
+ }
354
+ expect(() => (0, capabilities_1.approveCapabilities)({ file, cwd: root, expectedDigest: (0, capabilities_1.capabilityReceiptDigest)(value), now })).toThrow(/unsafe|symlink|lease/);
355
+ expect(fs_1.default.readFileSync(outside, 'utf8')).toBe('outside');
356
+ }
357
+ finally {
358
+ if (prior === undefined)
359
+ delete process.env.AWM_HOME;
360
+ else
361
+ process.env.AWM_HOME = prior;
362
+ fs_1.default.rmSync(root, { recursive: true, force: true });
363
+ }
364
+ });
365
+ });
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const types_1 = require("../../../src/core/journal/types");
4
+ const journal_1 = require("../../../src/core/model-policy/journal");
5
+ const envelope = { schema: 'routing-envelope/v1', runtime: { target: 'codex', kind: 'native', version: '1', accountScopeDigest: '0'.repeat(64) }, role: 'implementer', sliceId: 'S1', requestedProfile: 'mechanical', effectiveProfile: 'mechanical', resolved: { selector: { kind: 'model', id: 'm' }, effort: { kind: 'explicit', value: 'medium' } }, outcome: 'native', unavailableEvidence: [], policyDigest: 'a'.repeat(64), capabilityDigest: 'b'.repeat(64), planDigest: 'c'.repeat(64), executionDigest: 'd'.repeat(64) };
6
+ describe('routing journal helpers', () => {
7
+ it('reserves one idempotent attempt and records native observation', () => {
8
+ const state = (0, types_1.emptyState)('main');
9
+ const reserved = (0, journal_1.reserveRoutingAttempt)(state, { obligationId: 'impl:S1', lineageId: 'lineage:S1', envelope, fingerprint: 'e'.repeat(64) }, '2026-09-17T00:00:00.000Z');
10
+ const replay = (0, journal_1.reserveRoutingAttempt)(reserved.state, { obligationId: 'impl:S1', lineageId: 'lineage:S1', envelope, fingerprint: 'e'.repeat(64) }, '2026-09-17T00:01:00.000Z');
11
+ expect(replay.attemptId).toBe(reserved.attemptId);
12
+ const observed = (0, journal_1.observeRoutingAttempt)(replay.state, { attemptId: reserved.attemptId, nativeAgentId: 'native-1' }, '2026-09-17T00:02:00.000Z');
13
+ expect(observed.routingAttempts?.[0]).toMatchObject({ state: 'active', nativeAgentId: 'native-1' });
14
+ });
15
+ it('rejects a fourth implementer attempt in one lineage', () => {
16
+ let state = (0, types_1.emptyState)('main');
17
+ for (const [index, profile] of ['mechanical', 'integration', 'judgment'].entries()) {
18
+ state = (0, journal_1.reserveRoutingAttempt)(state, { obligationId: 'impl:S1', lineageId: 'lineage:S1', envelope: { ...envelope, effectiveProfile: profile }, fingerprint: `${'a'.repeat(63)}${index}` }, '2026-09-17T00:00:00.000Z').state;
19
+ state.routingAttempts[state.routingAttempts.length - 1].state = 'blocked';
20
+ state.routingAttempts[state.routingAttempts.length - 1].verdict = 'fail';
21
+ }
22
+ expect(() => (0, journal_1.reserveRoutingAttempt)(state, { obligationId: 'impl:S1', lineageId: 'lineage:S1', envelope, fingerprint: 'f'.repeat(64) }, '2026-09-17T00:00:00.000Z')).toThrow(/budget/i);
23
+ });
24
+ it('reports routing attempts without envelope bodies or native identities', () => {
25
+ const state = (0, journal_1.reserveRoutingAttempt)((0, types_1.emptyState)('main'), { obligationId: 'impl:S1', lineageId: 'lineage:S1', envelope, fingerprint: 'e'.repeat(64) }, '2026-09-17T00:00:00.000Z').state;
26
+ expect((0, journal_1.routingReport)(state)).toEqual({ schema: 'routing-report/v1', attempts: 1, plannedByRole: { implementer: 1 }, actualByRole: {}, byState: { reserved: 1 }, retries: 0, fallbacks: 0, unavailable: {}, verdicts: {}, administrativeRepairs: 0 });
27
+ });
28
+ it('uses the exact deterministic implementation escalation sequence', () => {
29
+ let state = (0, types_1.emptyState)('main');
30
+ expect((0, journal_1.resolveLineageEscalation)(state, 'l1', 'mechanical')).toEqual({ profile: 'mechanical', effort: 'medium' });
31
+ state = (0, journal_1.reserveRoutingAttempt)(state, { obligationId: 'impl:S1', lineageId: 'l1', envelope, fingerprint: '1'.repeat(64) }, '2026-09-17T00:00:00.000Z').state;
32
+ state.routingAttempts[0].state = 'blocked';
33
+ state.routingAttempts[0].verdict = 'fail';
34
+ expect((0, journal_1.resolveLineageEscalation)(state, 'l1', 'mechanical')).toEqual({ profile: 'integration', effort: 'medium' });
35
+ state.routingAttempts.push({ ...state.routingAttempts[0], id: 'route-2', attempt: 2, envelope: { ...envelope, effectiveProfile: 'integration' }, state: 'blocked', verdict: 'fail' });
36
+ expect((0, journal_1.resolveLineageEscalation)(state, 'l1', 'mechanical')).toEqual({ profile: 'judgment', effort: 'medium' });
37
+ state.routingAttempts.push({ ...state.routingAttempts[0], id: 'route-3', attempt: 3, envelope: { ...envelope, effectiveProfile: 'judgment', resolved: { selector: { kind: 'model', id: 'm' }, effort: { kind: 'explicit', value: 'medium' } } }, state: 'blocked', verdict: 'fail' });
38
+ expect((0, journal_1.resolveLineageEscalation)(state, 'l1', 'mechanical')).toEqual({ profile: 'judgment', effort: 'high' });
39
+ state.routingAttempts[2].envelope = { ...state.routingAttempts[2].envelope, resolved: { selector: { kind: 'model', id: 'm' }, effort: { kind: 'explicit', value: 'high' } } };
40
+ expect(() => (0, journal_1.resolveLineageEscalation)(state, 'l1', 'mechanical')).toThrow(/exhausted/i);
41
+ });
42
+ it('rejects hostile roles and unavailable provenance before it can reach a report', () => {
43
+ expect((0, types_1.isRoutingEnvelope)({ ...envelope, role: 'attacker-key' })).toBe(false);
44
+ expect((0, types_1.isRoutingEnvelope)({ ...envelope, unavailableEvidence: ['secret=leak'] })).toBe(false);
45
+ });
46
+ });
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const canonical_1 = require("../../../src/core/model-policy/canonical");
4
+ const validate_1 = require("../../../src/core/model-policy/validate");
5
+ const selection = (id, effort = 'medium') => ({ selector: { kind: 'model', id }, effort: { kind: 'explicit', value: effort } });
6
+ const policy = () => ({
7
+ schema: 'model-policy/v1',
8
+ mappings: [{ target: 'codex', runtimeKind: 'native', profiles: {
9
+ mechanical: selection('gpt-5.6-luna'), integration: selection('gpt-5.6-terra'), judgment: selection('gpt-5.6-sol'),
10
+ }, fullCapability: selection('gpt-5.6-sol', 'high'), degradation: {
11
+ allowMissingModelOverride: false, allowMissingEffortOverride: false, allowMissingObservedIdentity: false,
12
+ } }],
13
+ implementationBudget: { maxAttempts: 3, escalation: ['mechanical', 'integration', 'judgment'], judgmentEfforts: ['medium', 'high'] },
14
+ });
15
+ const approvedPolicy = () => ({ schema: 'approved-model-policy/v1', content: policy(), contentDigest: 'a'.repeat(64), approval: { approvedAt: '2026-09-17T00:00:00.000Z', approvalId: 'approval-1' }, lineage: { previousDigest: null } });
16
+ describe('model policy validation and canonical digest', () => {
17
+ it.each(['September 17, 2026 00:00:00 UTC', '2026-09-17', '2026-09-17T00:00:00.000+00:00', '2026-09-17T00:00:00.000Zx', '2026-02-30T00:00:00.000Z', '2026-09-17T00:00:00Z'])('rejects a noncanonical approval timestamp: %s', approvedAt => {
18
+ const candidate = approvedPolicy();
19
+ candidate.approval.approvedAt = approvedAt;
20
+ expect(() => (0, validate_1.validateApprovedPolicy)(candidate)).toThrow(/approval\.approvedAt/);
21
+ });
22
+ it('validates the complete policy contract and gives reordered object keys the same digest', () => {
23
+ const candidate = policy();
24
+ const reordered = JSON.parse('{"implementationBudget":{"judgmentEfforts":["medium","high"],"escalation":["mechanical","integration","judgment"],"maxAttempts":3},"mappings":[{"fullCapability":{"effort":{"value":"high","kind":"explicit"},"selector":{"id":"gpt-5.6-sol","kind":"model"}},"degradation":{"allowMissingObservedIdentity":false,"allowMissingEffortOverride":false,"allowMissingModelOverride":false},"profiles":{"judgment":{"selector":{"kind":"model","id":"gpt-5.6-sol"},"effort":{"kind":"explicit","value":"medium"}},"integration":{"selector":{"kind":"model","id":"gpt-5.6-terra"},"effort":{"kind":"explicit","value":"medium"}},"mechanical":{"selector":{"kind":"model","id":"gpt-5.6-luna"},"effort":{"kind":"explicit","value":"medium"}}},"runtimeKind":"native","target":"codex"}],"schema":"model-policy/v1"}');
25
+ expect((0, validate_1.validatePolicyContent)(candidate)).toEqual(candidate);
26
+ expect((0, canonical_1.canonicalPolicyDigest)(candidate)).toBe((0, canonical_1.canonicalPolicyDigest)(reordered));
27
+ });
28
+ it('preserves array order in the digest', () => {
29
+ const candidate = policy();
30
+ const swapped = structuredClone(policy());
31
+ const second = structuredClone(swapped.mappings[0]);
32
+ second.target = 'claude-code';
33
+ swapped.mappings.push(second);
34
+ candidate.mappings.push(structuredClone(second));
35
+ swapped.mappings.reverse();
36
+ expect((0, canonical_1.canonicalPolicyDigest)(candidate)).not.toBe((0, canonical_1.canonicalPolicyDigest)(swapped));
37
+ });
38
+ it.each([
39
+ ['unknown field', () => ({ ...policy(), unexpected: true })],
40
+ ['partial profile map', () => { const value = policy(); delete value.mappings[0].profiles.judgment; return value; }],
41
+ ['duplicate target/runtime map', () => { const value = policy(); value.mappings.push(structuredClone(value.mappings[0])); return value; }],
42
+ ['unsafe runtime kind', () => { const value = policy(); value.mappings[0].runtimeKind = '../native'; return value; }],
43
+ ['unsafe model id control character', () => { const value = policy(); value.mappings[0].profiles.mechanical.selector.id = 'bad\nmodel'; return value; }],
44
+ ])('rejects %s', (_name, make) => {
45
+ expect(() => (0, validate_1.validatePolicyContent)(make())).toThrow();
46
+ });
47
+ });
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const path_1 = __importDefault(require("path"));
7
+ const resolve_1 = require("../../../src/core/model-policy/resolve");
8
+ const resolve_2 = require("../../../src/core/model-policy/resolve");
9
+ const validate_1 = require("../../../src/core/plan/validate");
10
+ const sha = 'a'.repeat(64);
11
+ const selection = (id, value) => ({ selector: { kind: 'model', id }, effort: { kind: 'explicit', value } });
12
+ const runtimeDefaultSelection = (id) => ({ selector: { kind: 'model', id }, effort: { kind: 'runtime-default' } });
13
+ const verifiedV1Plan = (0, validate_1.validatePlanFile)('docs/plans/2026-09-14-compact-only-bootstrap-plan.md', path_1.default.resolve(__dirname, '../../../..'));
14
+ if (verifiedV1Plan.state !== 'valid')
15
+ throw new Error(`tracked bootstrap plan must validate before resolver tests: ${verifiedV1Plan.state}`);
16
+ const policy = () => ({ schema: 'approved-model-policy/v1', content: { schema: 'model-policy/v1', mappings: [{ target: 'codex', runtimeKind: 'native', profiles: { mechanical: selection('mechanical', 'low'), integration: selection('integration', 'medium'), judgment: selection('judgment', 'medium') }, fullCapability: selection('full', 'high'), degradation: { allowMissingModelOverride: false, allowMissingEffortOverride: false, allowMissingObservedIdentity: false } }], implementationBudget: { maxAttempts: 3, escalation: ['mechanical', 'integration', 'judgment'], judgmentEfforts: ['medium', 'high'] } }, contentDigest: sha, approval: { approvedAt: '2026-09-17T00:00:00.000Z', approvalId: 'approval-1' }, lineage: { previousDigest: null } });
17
+ const capabilities = () => ({ schema: 'routing-capabilities/v1', runtime: { target: 'codex', kind: 'native', version: '1.0.0', accountScopeDigest: sha }, recordedAt: '2026-09-17T00:00:00.000Z', expiresAt: '2026-09-18T00:00:00.000Z', capabilities: { artifactDelivery: 'unverified', interactiveExecution: 'supported', unattendedController: 'supported', nativeSubagents: 'unverified', modelOverride: 'supported', effortOverride: 'supported', observedModelEvidence: 'supported', durableResume: 'unverified' }, availableSelections: [selection('mechanical', 'low'), selection('integration', 'medium'), selection('judgment', 'medium'), selection('full', 'high')], evidence: ['interactiveExecution', 'unattendedController', 'modelOverride', 'effortOverride', 'observedModelEvidence'].map(capability => ({ capability, kind: 'native-control', receiptDigest: sha })), approval: { approvalId: 'approval-1', snapshotDigest: sha } });
18
+ const input = () => ({ role: 'implementer', requestedProfile: 'mechanical', policy: policy(), capabilities: capabilities(), runtime: capabilities().runtime, now: new Date('2026-09-17T12:00:00.000Z') });
19
+ describe('resolveSelection', () => {
20
+ it('rejects a structurally fabricated v1 report before resolution', () => {
21
+ expect(() => (0, resolve_2.resolveV1Dispatch)({ ...input(), plan: { state: 'valid', schema: 'compact-slices/v1', planDigest: sha, manifest: {} }, optInV1: false })).toThrow(/invalid valid report/);
22
+ });
23
+ it('fails loudly for an unknown runtime role or requested profile', () => {
24
+ expect(() => (0, resolve_1.resolveSelection)({ ...input(), role: 'renderer' })).toThrow(/role is invalid/);
25
+ expect(() => (0, resolve_1.resolveSelection)({ ...input(), requestedProfile: 'cheap' })).toThrow(/requestedProfile is invalid/);
26
+ });
27
+ it.each(['antigravity', 'opencode', 'claude-code', 'cursor', 'copilot'])('does not infer routed support for %s from any renderer fact', target => {
28
+ const value = input();
29
+ value.runtime = { ...value.runtime, target };
30
+ value.capabilities.runtime = { ...value.capabilities.runtime, target };
31
+ expect((0, resolve_1.resolveSelection)(value)).toMatchObject({ state: 'blocked' });
32
+ });
33
+ it('accepts codex only through its explicit native receipt fixture', () => expect((0, resolve_1.resolveSelection)(input())).toMatchObject({ state: 'resolved' }));
34
+ it.each(['antigravity', 'opencode', 'claude-code', 'codex', 'cursor', 'copilot'])('resolves an explicit matching policy and native receipt for %s', target => {
35
+ const value = input();
36
+ value.policy.content.mappings = ['antigravity', 'opencode', 'claude-code', 'codex', 'cursor', 'copilot'].map(rowTarget => ({ ...structuredClone(value.policy.content.mappings[0]), target: rowTarget }));
37
+ value.runtime = { ...value.runtime, target };
38
+ value.capabilities.runtime = { ...value.capabilities.runtime, target };
39
+ expect((0, resolve_1.resolveSelection)(value)).toMatchObject({ state: 'resolved' });
40
+ });
41
+ it('blocks an explicit unverified override despite a complete target mapping', () => {
42
+ const value = input();
43
+ value.capabilities.capabilities.modelOverride = 'unverified';
44
+ expect((0, resolve_1.resolveSelection)(value)).toMatchObject({ state: 'blocked', diagnostics: [{ code: 'ROUTING_MODEL_OVERRIDE_UNAVAILABLE' }] });
45
+ });
46
+ it.each(['specification-reviewer', 'code-quality-reviewer', 'final-reviewer', 'architecture', 'track-a-qa', 'track-b-qa', 'controller', 'documentation', 'retro', 'finishing'])('routes %s to full capability independently of requested profile', role => {
47
+ const result = (0, resolve_1.resolveSelection)({ ...input(), role, requestedProfile: 'mechanical' });
48
+ expect(result.state).toBe('resolved');
49
+ if (result.state === 'resolved')
50
+ expect(result.selection).toEqual(selection('full', 'high'));
51
+ });
52
+ it('blocks a receipt whose runtime account differs even when selections match', () => {
53
+ const value = input();
54
+ value.runtime = { ...value.runtime, accountScopeDigest: 'b'.repeat(64) };
55
+ expect((0, resolve_1.resolveSelection)(value)).toMatchObject({ state: 'blocked', diagnostics: [{ code: 'ROUTING_CAPABILITY_RUNTIME_MISMATCH' }] });
56
+ });
57
+ it('blocks an unavailable approved selection instead of silently substituting', () => {
58
+ const value = input();
59
+ value.capabilities.availableSelections = [selection('full', 'high')];
60
+ expect((0, resolve_1.resolveSelection)(value)).toMatchObject({ state: 'blocked', diagnostics: [{ code: 'ROUTING_SELECTION_UNAVAILABLE' }] });
61
+ });
62
+ it('blocks a corrupt receipt before trusting its availability list', () => {
63
+ const value = input();
64
+ value.capabilities.availableSelections = [];
65
+ expect((0, resolve_1.resolveSelection)(value)).toMatchObject({ state: 'blocked', diagnostics: [{ code: 'ROUTING_CAPABILITY_INVALID' }] });
66
+ });
67
+ it('degrades only to an attested matching full default when a missing override is approved', () => {
68
+ const value = input();
69
+ value.policy.content.mappings[0].degradation.allowMissingModelOverride = true;
70
+ value.capabilities.capabilities.modelOverride = 'unsupported';
71
+ value.capabilities.runtimeDefaultSelection = selection('full', 'high');
72
+ expect((0, resolve_1.resolveSelection)(value)).toMatchObject({ state: 'resolved', outcome: 'degraded', selection: selection('full', 'high') });
73
+ });
74
+ it('blocks missing override where its full default is not actually attested', () => {
75
+ const value = input();
76
+ value.policy.content.mappings[0].degradation.allowMissingModelOverride = true;
77
+ value.capabilities.capabilities.modelOverride = 'unsupported';
78
+ expect((0, resolve_1.resolveSelection)(value)).toMatchObject({ state: 'blocked', diagnostics: [{ code: 'ROUTING_MODEL_OVERRIDE_UNAVAILABLE' }] });
79
+ });
80
+ it('requires effort override for an explicit native full selection', () => {
81
+ const value = input();
82
+ value.capabilities.capabilities.effortOverride = 'unsupported';
83
+ expect((0, resolve_1.resolveSelection)({ ...value, role: 'code-quality-reviewer' })).toMatchObject({ state: 'blocked', diagnostics: [{ code: 'ROUTING_EFFORT_OVERRIDE_UNAVAILABLE' }] });
84
+ });
85
+ it('does not require effort override for an attested runtime-default native full selection', () => {
86
+ const value = input();
87
+ value.policy.content.mappings[0].fullCapability = runtimeDefaultSelection('full');
88
+ value.capabilities.availableSelections = [selection('mechanical', 'low'), selection('integration', 'medium'), selection('judgment', 'medium'), runtimeDefaultSelection('full')];
89
+ value.capabilities.runtimeDefaultSelection = runtimeDefaultSelection('full');
90
+ value.capabilities.capabilities.effortOverride = 'unsupported';
91
+ expect((0, resolve_1.resolveSelection)({ ...value, role: 'code-quality-reviewer' })).toMatchObject({ state: 'resolved', outcome: 'native', selection: runtimeDefaultSelection('full') });
92
+ });
93
+ it('does not require effort override for an attested runtime-default v1 full selection', () => {
94
+ const value = input();
95
+ value.policy.content.mappings[0].fullCapability = runtimeDefaultSelection('full');
96
+ value.capabilities.availableSelections = [selection('mechanical', 'low'), selection('integration', 'medium'), selection('judgment', 'medium'), runtimeDefaultSelection('full')];
97
+ value.capabilities.runtimeDefaultSelection = runtimeDefaultSelection('full');
98
+ value.capabilities.capabilities.effortOverride = 'unsupported';
99
+ expect((0, resolve_2.resolveV1Dispatch)({ ...value, plan: verifiedV1Plan, optInV1: true })).toMatchObject({ state: 'resolved', outcome: 'native', selection: runtimeDefaultSelection('full') });
100
+ });
101
+ it('does not require effort override after model fallback selects an attested runtime-default full selection', () => {
102
+ const value = input();
103
+ value.policy.content.mappings[0].fullCapability = runtimeDefaultSelection('full');
104
+ value.capabilities.availableSelections = [selection('mechanical', 'low'), selection('integration', 'medium'), selection('judgment', 'medium'), runtimeDefaultSelection('full')];
105
+ value.capabilities.runtimeDefaultSelection = runtimeDefaultSelection('full');
106
+ value.policy.content.mappings[0].degradation.allowMissingModelOverride = true;
107
+ value.capabilities.capabilities.modelOverride = 'unsupported';
108
+ value.capabilities.capabilities.effortOverride = 'unsupported';
109
+ expect((0, resolve_1.resolveSelection)(value)).toMatchObject({ state: 'resolved', outcome: 'degraded', selection: runtimeDefaultSelection('full'), unavailableEvidence: ['modelOverride'] });
110
+ });
111
+ });