agentic-workflow-manager 9.11.12 → 9.12.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 (76) hide show
  1. package/dist/src/commands/doctor.js +23 -1
  2. package/dist/src/commands/hooks/claude.js +61 -8
  3. package/dist/src/commands/hooks/resync.js +1 -1
  4. package/dist/src/commands/job/index.js +39 -4
  5. package/dist/src/commands/model-policy/index.js +253 -0
  6. package/dist/src/commands/plan/index.js +53 -9
  7. package/dist/src/commands/preflight/checks.js +18 -0
  8. package/dist/src/commands/watch/apply.js +62 -4
  9. package/dist/src/commands/watch/supervisor.js +63 -3
  10. package/dist/src/core/admission/index.js +20 -6
  11. package/dist/src/core/journal/types.js +21 -5
  12. package/dist/src/core/model-policy/capabilities-v2.js +152 -0
  13. package/dist/src/core/model-policy/capabilities.js +7 -1
  14. package/dist/src/core/model-policy/claude-hook-events.js +120 -0
  15. package/dist/src/core/model-policy/event-store.js +221 -0
  16. package/dist/src/core/model-policy/hook-diagnostics.js +94 -0
  17. package/dist/src/core/model-policy/journal.js +113 -18
  18. package/dist/src/core/model-policy/local-claude-scope.js +41 -0
  19. package/dist/src/core/model-policy/local-codex-scope.js +33 -0
  20. package/dist/src/core/model-policy/local-event-scope.js +13 -0
  21. package/dist/src/core/model-policy/machine-key.js +56 -0
  22. package/dist/src/core/model-policy/native-claude-agent-definition.js +82 -0
  23. package/dist/src/core/model-policy/native-claude-config.js +107 -0
  24. package/dist/src/core/model-policy/native-claude-machine.js +58 -0
  25. package/dist/src/core/model-policy/native-claude-transcript.js +80 -0
  26. package/dist/src/core/model-policy/native-claude.js +41 -0
  27. package/dist/src/core/model-policy/native-codex-machine.js +116 -0
  28. package/dist/src/core/model-policy/native-codex-rollout.js +111 -0
  29. package/dist/src/core/model-policy/native-codex.js +302 -0
  30. package/dist/src/core/model-policy/native-routing-observe.js +106 -0
  31. package/dist/src/core/model-policy/native-routing-proof.js +52 -0
  32. package/dist/src/core/model-policy/native-runtime.js +86 -0
  33. package/dist/src/core/model-policy/resolve.js +96 -6
  34. package/dist/src/core/model-policy/selection-policy-digest.js +22 -0
  35. package/dist/src/core/model-policy/setup-readiness.js +77 -0
  36. package/dist/src/providers/index.js +3 -1
  37. package/dist/tests/commands/doctor-routing.test.js +22 -0
  38. package/dist/tests/commands/doctor.test.js +5 -0
  39. package/dist/tests/commands/hooks/install.test.js +6 -0
  40. package/dist/tests/commands/hooks/resync.test.js +3 -0
  41. package/dist/tests/commands/hooks/status.test.js +12 -1
  42. package/dist/tests/commands/job/routing-file.test.js +32 -0
  43. package/dist/tests/commands/job/routing-report-cli.test.js +4 -3
  44. package/dist/tests/commands/model-policy/claude-hook-flow.test.js +104 -0
  45. package/dist/tests/commands/model-policy/index.test.js +179 -0
  46. package/dist/tests/commands/preflight/preflight.test.js +65 -0
  47. package/dist/tests/commands/watch/apply.test.js +84 -0
  48. package/dist/tests/commands/watch/dispatch-routing-identity.test.js +23 -0
  49. package/dist/tests/core/admission/index.test.js +21 -0
  50. package/dist/tests/core/model-policy/capabilities-v2.test.js +42 -0
  51. package/dist/tests/core/model-policy/claude-hook-events.test.js +40 -0
  52. package/dist/tests/core/model-policy/event-store-claude.test.js +64 -0
  53. package/dist/tests/core/model-policy/event-store.test.js +151 -0
  54. package/dist/tests/core/model-policy/hook-diagnostics.test.js +34 -0
  55. package/dist/tests/core/model-policy/journal.test.js +112 -1
  56. package/dist/tests/core/model-policy/local-claude-scope.test.js +31 -0
  57. package/dist/tests/core/model-policy/machine-key.test.js +38 -0
  58. package/dist/tests/core/model-policy/native-claude-agent-definition.test.js +31 -0
  59. package/dist/tests/core/model-policy/native-claude-config.test.js +53 -0
  60. package/dist/tests/core/model-policy/native-claude-machine.test.js +18 -0
  61. package/dist/tests/core/model-policy/native-claude-transcript.test.js +45 -0
  62. package/dist/tests/core/model-policy/native-claude.test.js +21 -0
  63. package/dist/tests/core/model-policy/native-codex-machine.test.js +34 -0
  64. package/dist/tests/core/model-policy/native-codex-rollout.test.js +44 -0
  65. package/dist/tests/core/model-policy/native-codex.test.js +133 -0
  66. package/dist/tests/core/model-policy/native-routing-observe.test.js +60 -0
  67. package/dist/tests/core/model-policy/native-routing-proof.test.js +30 -0
  68. package/dist/tests/core/model-policy/native-runtime.test.js +14 -0
  69. package/dist/tests/core/model-policy/resolve-event.test.js +65 -0
  70. package/dist/tests/core/model-policy/setup-readiness.test.js +83 -0
  71. package/dist/tests/providers/index.test.js +1 -1
  72. package/package.json +2 -2
  73. package/prebuilds/darwin-arm64/secure_fs.node +0 -0
  74. package/prebuilds/darwin-x64/secure_fs.node +0 -0
  75. package/prebuilds/win32-arm64/secure_fs.node +0 -0
  76. package/prebuilds/win32-x64/secure_fs.node +0 -0
@@ -0,0 +1,32 @@
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 job_1 = require("../../../src/commands/job");
10
+ describe('bounded routing input', () => {
11
+ it('rejects a file that grows between metadata check and read', () => {
12
+ const dir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-routing-input-'));
13
+ const file = path_1.default.join(dir, 'observation.json');
14
+ try {
15
+ fs_1.default.writeFileSync(file, JSON.stringify({ parentThreadId: 'a'.repeat(300 * 1024) }));
16
+ const original = fs_1.default.lstatSync;
17
+ const stat = jest.spyOn(fs_1.default, 'lstatSync').mockImplementation(((target, ...args) => {
18
+ const actual = original(target, ...args);
19
+ return String(target) === file ? Object.assign(Object.create(Object.getPrototypeOf(actual)), actual, { size: 1 }) : actual;
20
+ }));
21
+ try {
22
+ expect(() => (0, job_1.readBoundedJson)(file)).toThrow(/bound|256|size|regular|large/i);
23
+ }
24
+ finally {
25
+ stat.mockRestore();
26
+ }
27
+ }
28
+ finally {
29
+ fs_1.default.rmSync(dir, { recursive: true, force: true });
30
+ }
31
+ });
32
+ });
@@ -19,7 +19,7 @@ function gitInit(repo) {
19
19
  (0, child_process_1.execFileSync)('git', ['add', '.'], { cwd: repo });
20
20
  (0, child_process_1.execFileSync)('git', ['-c', 'user.email=t@t.t', '-c', 'user.name=t', 'commit', '-qm', 'fixture'], { cwd: repo });
21
21
  }
22
- test('`job routing-report --json` emits only aggregate routing evidence', async () => {
22
+ test('`job routing-report --json` exposes selections but not native child identities or envelopes', async () => {
23
23
  const repo = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-routing-report-'));
24
24
  try {
25
25
  gitInit(repo);
@@ -40,9 +40,10 @@ test('`job routing-report --json` emits only aggregate routing evidence', async
40
40
  await program.parseAsync(['node', 'awm', 'job', 'routing-report', '--json']);
41
41
  const rendered = String(out.mock.calls[0][0]);
42
42
  const report = JSON.parse(rendered);
43
- expect(report).toMatchObject({ schema: 'routing-report/v1', attempts: 1, plannedByRole: { implementer: 1 }, actualByRole: { implementer: 1 }, byState: { active: 1 } });
43
+ expect(report).toMatchObject({ schema: 'routing-report/v1', attempts: 1, plannedByRole: { implementer: 1 }, actualByRole: { implementer: 1 }, byState: { active: 1 },
44
+ selections: [{ configured: privateSelection, accepted: 'unknown', backendModel: 'unknown' }] });
44
45
  expect(rendered).not.toContain('native-private');
45
- expect(rendered).not.toContain('model-private');
46
+ expect(rendered).not.toContain('obligation');
46
47
  cwd.mockRestore();
47
48
  out.mockRestore();
48
49
  }
@@ -0,0 +1,104 @@
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 store_1 = require("../../../src/core/model-policy/store");
11
+ const canonical_1 = require("../../../src/core/model-policy/canonical");
12
+ const machine_key_1 = require("../../../src/core/model-policy/machine-key");
13
+ const event_store_1 = require("../../../src/core/model-policy/event-store");
14
+ describe('Claude hook to event receipt integration', () => {
15
+ it('captures a real-format hook pair and assistant trace without paid inference', () => {
16
+ const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-claude-hook-flow-'));
17
+ const previous = { home: process.env.HOME, awm: process.env.AWM_HOME, config: process.env.CLAUDE_CONFIG_DIR };
18
+ const awmHome = path_1.default.join(root, 'awm');
19
+ const project = path_1.default.join(root, 'project');
20
+ const configDir = path_1.default.join(root, 'claude');
21
+ const bin = path_1.default.join(root, 'bin');
22
+ fs_1.default.mkdirSync(awmHome);
23
+ fs_1.default.mkdirSync(project);
24
+ fs_1.default.mkdirSync(configDir);
25
+ fs_1.default.mkdirSync(bin);
26
+ process.env.HOME = root;
27
+ process.env.AWM_HOME = awmHome;
28
+ process.env.CLAUDE_CONFIG_DIR = configDir;
29
+ try {
30
+ (0, machine_key_1.ensureMachineKey)(awmHome);
31
+ const selected = { selector: { kind: 'model', id: 'claude-sonnet-4-6' }, effort: { kind: 'runtime-default' } };
32
+ const content = { schema: 'model-policy/v1', mappings: [{ target: 'claude-code', runtimeKind: 'native',
33
+ profiles: { mechanical: selected, integration: selected, judgment: selected }, fullCapability: selected,
34
+ degradation: { allowMissingModelOverride: false, allowMissingEffortOverride: false, allowMissingObservedIdentity: false } }],
35
+ implementationBudget: { maxAttempts: 3, escalation: ['mechanical', 'integration', 'judgment'], judgmentEfforts: ['medium', 'high'] } };
36
+ fs_1.default.writeFileSync(path_1.default.join(project, 'candidate.json'), JSON.stringify(content));
37
+ (0, store_1.approvePolicy)({ file: 'candidate.json', scope: 'project', cwd: project, expectedDigest: (0, canonical_1.canonicalPolicyDigest)(content) });
38
+ const executable = path_1.default.join(bin, process.platform === 'win32' ? 'claude.exe' : 'claude');
39
+ const authResponse = { loggedIn: true, authMethod: 'claude.ai', apiProvider: 'anthropic', email: 'test@example.invalid', orgId: 'org-test' };
40
+ let preload;
41
+ if (process.platform === 'win32') {
42
+ // A Unix shebang cannot be launched by CreateProcess. Use a real
43
+ // .exe and intercept only its auth-status invocation in Node.
44
+ fs_1.default.copyFileSync(process.execPath, executable);
45
+ preload = path_1.default.join(root, 'claude-preload.cjs');
46
+ fs_1.default.writeFileSync(preload, `if (require('path').basename(process.execPath).toLowerCase() === 'claude.exe' && require('path').basename(process.argv[1] || '') === 'auth') { process.stdout.write(${JSON.stringify(JSON.stringify(authResponse))}); process.exit(0); }\n`);
47
+ }
48
+ else {
49
+ fs_1.default.writeFileSync(executable, `#!${process.execPath}\nif (process.argv[2] === '--version') process.stdout.write('2.1.263\\n');\nelse if (process.argv[2] === 'auth') process.stdout.write(${JSON.stringify(JSON.stringify(authResponse))});\n`, { mode: 0o755 });
50
+ }
51
+ const timestamp = new Date().toISOString();
52
+ const transcript = path_1.default.join(configDir, 'projects', 'p', 's', 'subagents', 'agent-agent-1.jsonl');
53
+ fs_1.default.mkdirSync(path_1.default.dirname(transcript), { recursive: true });
54
+ fs_1.default.writeFileSync(transcript, `${JSON.stringify({ type: 'assistant', timestamp, message: { model: 'claude-sonnet-4-6', content: [] } })}\n`);
55
+ fs_1.default.mkdirSync(path_1.default.join(configDir, 'agents'));
56
+ fs_1.default.writeFileSync(path_1.default.join(configDir, 'agents', 'awm-integration.md'), '---\nname: awm-integration\ndescription: AWM integration agent\nmodel: claude-sonnet-4-6\n---\nPerform integration work.\n');
57
+ const start = { hook_event_name: 'SubagentStart', session_id: 'session-1', agent_id: 'agent-1', agent_type: 'awm-integration' };
58
+ const stop = { ...start, hook_event_name: 'SubagentStop', agent_transcript_path: transcript, stop_hook_active: false };
59
+ const cli = path_1.default.resolve(__dirname, '../../../dist/src/index.js');
60
+ const env = { ...process.env, PATH: `${bin}${path_1.default.delimiter}${process.env.PATH ?? ''}` };
61
+ if (preload)
62
+ env.NODE_OPTIONS = `${process.env.NODE_OPTIONS ?? ''} --require=${JSON.stringify(preload)}`;
63
+ const authProbe = (0, child_process_1.spawnSync)(executable, ['auth', 'status'], { env, encoding: 'utf8' });
64
+ expect(authProbe.status).toBe(0);
65
+ expect(JSON.parse(authProbe.stdout)).toMatchObject(authResponse);
66
+ const versionProbe = (0, child_process_1.spawnSync)(executable, ['--version'], { env, encoding: 'utf8' });
67
+ expect(versionProbe.status).toBe(0);
68
+ expect(versionProbe.stdout).toMatch(/\d+\.\d+\.\d+/);
69
+ const first = (0, child_process_1.spawnSync)(process.execPath, [cli, 'model-policy', 'hook-event', '--event', 'start', '--cwd', project], { cwd: project, env, input: JSON.stringify(start), encoding: 'utf8' });
70
+ expect(first.status).toBe(0);
71
+ expect(first.stdout).toBe('');
72
+ const second = (0, child_process_1.spawnSync)(process.execPath, [cli, 'model-policy', 'hook-event', '--event', 'stop', '--cwd', project], { cwd: project, env, input: JSON.stringify(stop), encoding: 'utf8' });
73
+ expect(second.status).toBe(0);
74
+ expect(second.stdout).toBe('');
75
+ expect(second.stderr).toBe('');
76
+ const files = fs_1.default.readdirSync(path_1.default.join(awmHome, 'routing-capabilities-v2', 'claude-code'));
77
+ expect(files).toEqual(['native.json']);
78
+ const raw = fs_1.default.readFileSync(path_1.default.join(awmHome, 'routing-capabilities-v2', 'claude-code', 'native.json'), 'utf8');
79
+ expect(raw).not.toContain('test@example.invalid');
80
+ const persisted = JSON.parse(raw);
81
+ expect((0, event_store_1.readStoredEventReceipt)(persisted.receipt.runtime)).toMatchObject({ state: 'present', receipt: { claims: [expect.objectContaining({ selection: selected, nativeAgentType: 'awm-integration', actualModel: expect.objectContaining({ id: 'claude-sonnet-4-6' }), tokenUsage: 'unknown' })] } });
82
+ const generic = { ...start, agent_id: 'other-agent', agent_type: 'general-purpose' };
83
+ const ignored = (0, child_process_1.spawnSync)(process.execPath, [cli, 'model-policy', 'hook-event', '--event', 'start', '--cwd', project, '--json'], { cwd: project, env, input: JSON.stringify(generic), encoding: 'utf8' });
84
+ expect(ignored.status).toBe(0);
85
+ expect(JSON.parse(ignored.stdout)).toMatchObject({ state: 'ignored' });
86
+ expect(fs_1.default.readFileSync(path_1.default.join(awmHome, 'routing-capabilities-v2', 'claude-code', 'native.json'), 'utf8')).toBe(raw);
87
+ }
88
+ finally {
89
+ if (previous.home === undefined)
90
+ delete process.env.HOME;
91
+ else
92
+ process.env.HOME = previous.home;
93
+ if (previous.awm === undefined)
94
+ delete process.env.AWM_HOME;
95
+ else
96
+ process.env.AWM_HOME = previous.awm;
97
+ if (previous.config === undefined)
98
+ delete process.env.CLAUDE_CONFIG_DIR;
99
+ else
100
+ process.env.CLAUDE_CONFIG_DIR = previous.config;
101
+ fs_1.default.rmSync(root, { recursive: true, force: true });
102
+ }
103
+ });
104
+ });
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  const commander_1 = require("commander");
4
37
  const model_policy_1 = require("../../../src/commands/model-policy");
@@ -114,4 +147,150 @@ describe('model-policy command', () => {
114
147
  await expect(program.parseAsync(['node', 'awm', 'model-policy', 'capabilities', 'approve', '--file', 'receipt.json', '--expected-digest', 'a'.repeat(64), '--replace-digest', ''])).rejects.toThrow(/requires a non-empty value/);
115
148
  expect(approveCapabilities).not.toHaveBeenCalled();
116
149
  });
150
+ it('discovers the Codex catalog explicitly without approving capabilities', async () => {
151
+ const queryCodexModelCatalog = jest.fn(async () => ({ provenance: 'native-catalog', selections: [], nativeDispatchVerified: false, actualModelVerified: false }));
152
+ const approveCapabilities = jest.fn();
153
+ const program = new commander_1.Command();
154
+ program.exitOverride();
155
+ program.configureOutput({ writeErr: () => undefined });
156
+ (0, model_policy_1.registerModelPolicyCommand)(program, { queryCodexModelCatalog, approveCapabilities: approveCapabilities });
157
+ await program.parseAsync(['node', 'awm', 'model-policy', 'discover', '--provider', 'codex', '--json']);
158
+ expect(queryCodexModelCatalog).toHaveBeenCalledTimes(1);
159
+ expect(JSON.parse(String(out.mock.calls[0][0]))).toMatchObject({ state: 'catalog-only', nativeDispatchVerified: false, actualModelVerified: false });
160
+ expect(approveCapabilities).not.toHaveBeenCalled();
161
+ });
162
+ it('reports missing machine selections from the approved Codex policy without certifying dispatch', async () => {
163
+ const available = { selector: { kind: 'model', id: 'gpt-6-sol' }, effort: { kind: 'explicit', value: 'high' } };
164
+ const missing = { selector: { kind: 'model', id: 'gpt-6-luna' }, effort: { kind: 'explicit', value: 'low' } };
165
+ const queryCodexModelCatalog = jest.fn(async () => ({ provenance: 'native-catalog', selections: [available], nativeDispatchVerified: false, actualModelVerified: false }));
166
+ const readEffectivePolicy = jest.fn(() => ({ state: 'approved', policy: { content: { mappings: [{ target: 'codex', runtimeKind: 'native', profiles: { mechanical: missing, integration: available, judgment: available }, fullCapability: available }] } } }));
167
+ const program = new commander_1.Command();
168
+ program.exitOverride();
169
+ program.configureOutput({ writeErr: () => undefined });
170
+ (0, model_policy_1.registerModelPolicyCommand)(program, { queryCodexModelCatalog, readEffectivePolicy: readEffectivePolicy });
171
+ await program.parseAsync(['node', 'awm', 'model-policy', 'discover', '--provider', 'codex', '--cwd', 'fixture-root', '--json']);
172
+ expect(readEffectivePolicy).toHaveBeenCalledWith('fixture-root');
173
+ expect(JSON.parse(String(out.mock.calls[0][0]))).toMatchObject({ state: 'catalog-only', policyCoverage: { state: 'missing', missing: [missing] }, nativeDispatchVerified: false, actualModelVerified: false });
174
+ expect(process.exitCode).toBe(2);
175
+ });
176
+ it('reports catalog coverage but still refuses to claim native dispatch or backend identity', async () => {
177
+ const selection = { selector: { kind: 'model', id: 'gpt-6-sol' }, effort: { kind: 'explicit', value: 'high' } };
178
+ const queryCodexModelCatalog = jest.fn(async () => ({ provenance: 'native-catalog', selections: [selection], nativeDispatchVerified: false, actualModelVerified: false }));
179
+ const readEffectivePolicy = jest.fn(() => ({ state: 'approved', policy: { content: { mappings: [{ target: 'codex', runtimeKind: 'native', profiles: { mechanical: selection, integration: selection, judgment: selection }, fullCapability: selection }] } } }));
180
+ const program = new commander_1.Command();
181
+ program.exitOverride();
182
+ program.configureOutput({ writeErr: () => undefined });
183
+ (0, model_policy_1.registerModelPolicyCommand)(program, { queryCodexModelCatalog, readEffectivePolicy: readEffectivePolicy });
184
+ await program.parseAsync(['node', 'awm', 'model-policy', 'discover', '--provider', 'codex', '--json']);
185
+ expect(JSON.parse(String(out.mock.calls[0][0]))).toMatchObject({ state: 'catalog-only', policyCoverage: { state: 'complete', missing: [] }, nativeDispatchVerified: false, actualModelVerified: false });
186
+ });
187
+ it('does not silently treat Claude as Codex during native discovery', async () => {
188
+ const queryCodexModelCatalog = jest.fn();
189
+ const program = new commander_1.Command();
190
+ program.exitOverride();
191
+ program.configureOutput({ writeErr: () => undefined });
192
+ (0, model_policy_1.registerModelPolicyCommand)(program, { queryCodexModelCatalog });
193
+ await program.parseAsync(['node', 'awm', 'model-policy', 'discover', '--provider', 'claude-code', '--json']);
194
+ expect(JSON.parse(String(out.mock.calls[0][0]))).toMatchObject({ state: 'unverified', provider: 'claude-code' });
195
+ expect(queryCodexModelCatalog).not.toHaveBeenCalled();
196
+ expect(process.exitCode).toBe(2);
197
+ });
198
+ it('reports every Codex selection and the full fallback as unverified without dispatch', async () => {
199
+ const cheap = { selector: { kind: 'model', id: 'gpt-6-sol' }, effort: { kind: 'explicit', value: 'low' } };
200
+ const full = { selector: { kind: 'model', id: 'gpt-6-astra' }, effort: { kind: 'explicit', value: 'high' } };
201
+ const queryCodexModelCatalog = jest.fn(async () => ({ provenance: 'native-catalog', selections: [cheap, full], nativeDispatchVerified: false, actualModelVerified: false }));
202
+ const queryCodexMachineFacts = jest.fn(async () => ({ provenance: 'codex-app-server-config-account', configDigest: 'c'.repeat(64), accountState: 'identified', accountScopeDigest: 'a'.repeat(64), inferenceDispatched: false }));
203
+ const queryRuntimeExecutable = jest.fn(async () => ({ version: '0.156.0', binaryDigest: 'b'.repeat(64), inferenceDispatched: false }));
204
+ const ensureMachineKey = jest.fn(() => Buffer.alloc(32, 7));
205
+ const readEffectivePolicy = jest.fn(() => ({ state: 'approved', policy: { content: { mappings: [{ target: 'codex', runtimeKind: 'native', profiles: { mechanical: cheap, integration: cheap, judgment: full }, fullCapability: full, degradation: { allowMissingObservedIdentity: false } }] } } }));
206
+ const program = new commander_1.Command();
207
+ program.exitOverride();
208
+ program.configureOutput({ writeErr: () => undefined });
209
+ (0, model_policy_1.registerModelPolicyCommand)(program, { queryCodexModelCatalog, queryCodexMachineFacts, queryRuntimeExecutable, ensureMachineKey, readEffectivePolicy: readEffectivePolicy });
210
+ await program.parseAsync(['node', 'awm', 'model-policy', 'setup', '--provider', 'codex', '--json']);
211
+ const report = JSON.parse(String(out.mock.calls[0][0]));
212
+ expect(report).toMatchObject({ state: 'setup-pending', provider: 'codex', inferenceDispatched: false, tokenUsage: 'unknown', nativeDispatchVerified: false, actualModelVerified: false,
213
+ machine: { runtimeVersion: '0.156.0', binaryDigest: 'b'.repeat(64), configDigest: 'c'.repeat(64), accountState: 'identified', accountScopeDigest: 'a'.repeat(64) } });
214
+ expect(report.selections).toEqual(expect.arrayContaining([
215
+ expect.objectContaining({ role: 'mechanical', catalogAvailable: true, dispatch: 'untested' }),
216
+ expect.objectContaining({ role: 'fullCapability', catalogAvailable: true, dispatch: 'untested' }),
217
+ ]));
218
+ expect(report.policyAction).toMatch(/allowMissingObservedIdentity/);
219
+ expect(queryCodexModelCatalog).toHaveBeenCalledTimes(1);
220
+ expect(queryCodexMachineFacts).toHaveBeenCalledTimes(1);
221
+ expect(queryRuntimeExecutable).toHaveBeenCalledTimes(1);
222
+ expect(ensureMachineKey).toHaveBeenCalledTimes(1);
223
+ expect(process.exitCode).toBe(2);
224
+ });
225
+ it('never runs inference merely because setup was requested', async () => {
226
+ const queryCodexModelCatalog = jest.fn();
227
+ const program = new commander_1.Command();
228
+ program.exitOverride();
229
+ program.configureOutput({ writeErr: () => undefined });
230
+ (0, model_policy_1.registerModelPolicyCommand)(program, { queryCodexModelCatalog });
231
+ await expect(program.parseAsync(['node', 'awm', 'model-policy', 'setup', '--provider', 'codex', '--allow-inference'])).rejects.toThrow(/unknown option/i);
232
+ expect(queryCodexModelCatalog).not.toHaveBeenCalled();
233
+ });
234
+ it('captures only an approved Codex selection from an existing native child, with local scope', async () => {
235
+ const selected = { selector: { kind: 'model', id: 'gpt-6-luna' }, effort: { kind: 'explicit', value: 'high' } };
236
+ const mapping = { target: 'codex', runtimeKind: 'native', profiles: { mechanical: selected, integration: selected, judgment: selected }, fullCapability: selected,
237
+ degradation: { allowMissingModelOverride: false, allowMissingEffortOverride: false, allowMissingObservedIdentity: true } };
238
+ const queryCodexChildThreadObservation = jest.fn(async () => ({ configuredSelection: selected, childRuntimeVersion: '0.156.1', observedAt: '2026-09-23T01:00:00.000Z' }));
239
+ const publishCodexObservation = jest.fn(() => ({ schema: 'routing-capabilities/v2', claims: [{ selection: selected }] }));
240
+ const program = new commander_1.Command();
241
+ program.exitOverride();
242
+ program.configureOutput({ writeErr: () => undefined });
243
+ (0, model_policy_1.registerModelPolicyCommand)(program, { readEffectivePolicy: (() => ({ state: 'approved', policy: { content: { mappings: [mapping] } } })),
244
+ queryCodexChildThreadObservation: queryCodexChildThreadObservation, publishCodexObservation: publishCodexObservation,
245
+ queryCodexMachineFacts: (async () => ({ configDigest: 'c'.repeat(64), accountScopeDigest: 'a'.repeat(64), accountState: 'identified' })),
246
+ queryRuntimeExecutable: (async () => ({ version: '0.156.1', binaryDigest: 'b'.repeat(64) })),
247
+ ensureMachineKey: (() => Buffer.alloc(32, 7)) });
248
+ await program.parseAsync(['node', 'awm', 'model-policy', 'capture', '--provider', 'codex', '--runtime-kind', 'native', '--parent-thread-id', 'parent-1', '--child-thread-id', 'child-1', '--json']);
249
+ expect(queryCodexChildThreadObservation).toHaveBeenCalledWith(expect.objectContaining({ parentThreadId: 'parent-1', childThreadId: 'child-1' }));
250
+ expect(publishCodexObservation).toHaveBeenCalledWith(expect.objectContaining({ expectedSelection: selected,
251
+ scope: { runtime: { target: 'codex', kind: 'native', version: '0.156.1', accountScopeDigest: 'a'.repeat(64) }, binaryDigest: 'b'.repeat(64), configDigest: 'c'.repeat(64) } }));
252
+ expect(JSON.parse(String(out.mock.calls[0][0]))).toMatchObject({ state: 'captured', actualModelVerified: false, tokenUsage: 'unknown' });
253
+ });
254
+ it('reports a matching event-scoped enrollment as ready after 25 hours without refreshing it', async () => {
255
+ const selected = { selector: { kind: 'model', id: 'gpt-6-luna' }, effort: { kind: 'explicit', value: 'high' } };
256
+ const mapping = { target: 'codex', runtimeKind: 'native', profiles: { mechanical: selected, integration: selected, judgment: selected }, fullCapability: selected,
257
+ degradation: { allowMissingModelOverride: false, allowMissingEffortOverride: false, allowMissingObservedIdentity: true } };
258
+ const { createHash } = await Promise.resolve().then(() => __importStar(require('crypto')));
259
+ const mappingDigest = createHash('sha256').update(JSON.stringify({ target: mapping.target, runtimeKind: mapping.runtimeKind, selection: selected })).digest('hex');
260
+ const receipt = { schema: 'routing-capabilities/v2', runtime: { target: 'codex', kind: 'native', version: '0.156.1', accountScopeDigest: 'a'.repeat(64) },
261
+ binaryDigest: 'b'.repeat(64), configDigest: 'c'.repeat(64), recordedAt: '2026-09-22T01:00:00.000Z', claims: [{ selection: selected, mappingDigest,
262
+ eventDigest: 'e'.repeat(64), source: 'codex-turn-context', observedAt: '2026-09-22T00:59:00.000Z', actualModel: 'unverified', tokenUsage: 'unknown' }] };
263
+ const readStoredEventReceipt = jest.fn(() => ({ state: 'present', receipt }));
264
+ const program = new commander_1.Command();
265
+ program.exitOverride();
266
+ program.configureOutput({ writeErr: () => undefined });
267
+ (0, model_policy_1.registerModelPolicyCommand)(program, { readEffectivePolicy: (() => ({ state: 'approved', policy: { content: { mappings: [mapping] } } })),
268
+ readStoredEventReceipt: readStoredEventReceipt,
269
+ queryCodexModelCatalog: (async () => ({ selections: [selected] })),
270
+ queryCodexMachineFacts: (async () => ({ configDigest: 'c'.repeat(64), accountScopeDigest: 'a'.repeat(64), accountState: 'identified' })),
271
+ queryRuntimeExecutable: (async () => ({ version: '0.156.1', binaryDigest: 'b'.repeat(64) })),
272
+ ensureMachineKey: (() => Buffer.alloc(32, 7)) });
273
+ await program.parseAsync(['node', 'awm', 'model-policy', 'setup', '--provider', 'codex', '--json']);
274
+ expect(JSON.parse(String(out.mock.calls[0][0]))).toMatchObject({ state: 'ready-operational', selections: expect.arrayContaining([expect.objectContaining({ dispatch: 'verified', acceptedSelection: 'verified', actualModel: 'untested' })]) });
275
+ expect(readStoredEventReceipt).toHaveBeenCalledTimes(1);
276
+ expect(process.exitCode).toBeUndefined();
277
+ });
278
+ it('discovers Claude version and account without claiming a model or dispatch', async () => {
279
+ const selected = { selector: { kind: 'model', id: 'claude-sonnet-4-6' }, effort: { kind: 'runtime-default' } };
280
+ const mapping = { target: 'claude-code', runtimeKind: 'native', profiles: { mechanical: selected, integration: selected, judgment: selected }, fullCapability: selected,
281
+ degradation: { allowMissingModelOverride: false, allowMissingEffortOverride: false, allowMissingObservedIdentity: false } };
282
+ const queryClaudeAuthStatus = jest.fn(async () => ({ accountState: 'identified', accountScopeDigest: 'a'.repeat(64), inferenceDispatched: false }));
283
+ const queryRuntimeExecutable = jest.fn(async () => ({ version: '2.1.263', binaryDigest: 'b'.repeat(64), inferenceDispatched: false }));
284
+ const program = new commander_1.Command();
285
+ program.exitOverride();
286
+ program.configureOutput({ writeErr: () => undefined });
287
+ (0, model_policy_1.registerModelPolicyCommand)(program, { readEffectivePolicy: (() => ({ state: 'approved', policy: { content: { mappings: [mapping] } } })),
288
+ queryClaudeAuthStatus: queryClaudeAuthStatus, queryRuntimeExecutable: queryRuntimeExecutable,
289
+ readClaudeModelConfigDigest: (() => 'c'.repeat(64)),
290
+ ensureMachineKey: (() => Buffer.alloc(32, 7)) });
291
+ await program.parseAsync(['node', 'awm', 'model-policy', 'setup', '--provider', 'claude-code', '--json']);
292
+ expect(JSON.parse(String(out.mock.calls[0][0]))).toMatchObject({ state: 'setup-pending', provider: 'claude-code', machine: { runtimeVersion: '2.1.263', accountState: 'identified', configState: 'local-fingerprint' },
293
+ nativeDispatchVerified: false, actualModelVerified: false, inferenceDispatched: false });
294
+ expect(queryClaudeAuthStatus).toHaveBeenCalledTimes(1);
295
+ });
117
296
  });
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
@@ -11,6 +44,8 @@ const checks_1 = require("../../../src/commands/preflight/checks");
11
44
  const preflight_1 = require("../../../src/commands/preflight");
12
45
  const run_1 = require("../../../src/commands/sensors/run");
13
46
  const check_1 = require("../../../src/core/currentness/check");
47
+ const store_1 = require("../../../src/core/model-policy/store");
48
+ const setupReadiness = __importStar(require("../../../src/core/model-policy/setup-readiness"));
14
49
  // Only `execSync` (used by `resolveOnPath` to check for `gh`/`glab`) is mocked — `git
15
50
  // remote get-url origin` runs for real via `execFileSync` against real tmpdir git repos,
16
51
  // same as every other check in this file exercises the real filesystem.
@@ -25,8 +60,13 @@ jest.mock('../../../src/commands/sensors/run', () => ({
25
60
  jest.mock('../../../src/core/currentness/check', () => ({
26
61
  checkCurrentness: jest.fn(),
27
62
  }));
63
+ jest.mock('../../../src/core/model-policy/store', () => ({
64
+ ...jest.requireActual('../../../src/core/model-policy/store'),
65
+ readEffectivePolicy: jest.fn(),
66
+ }));
28
67
  const mockRunSensors = run_1.runSensors;
29
68
  const mockCheckCurrentness = check_1.checkCurrentness;
69
+ const mockReadEffectivePolicy = store_1.readEffectivePolicy;
30
70
  /** Turn a tmpdir into a real git repo with (optionally) an `origin` remote. */
31
71
  function gitRepo(dir, remoteUrl) {
32
72
  (0, child_process_1.execFileSync)('git', ['init'], { cwd: dir, stdio: 'pipe' });
@@ -104,6 +144,7 @@ function writePartialKernel(dir) {
104
144
  const check = (r, id) => r.checks.find(c => c.id === id);
105
145
  describe('preflight', () => {
106
146
  beforeEach(() => {
147
+ mockReadEffectivePolicy.mockReturnValue({ state: 'absent' });
107
148
  mockCheckCurrentness.mockResolvedValue({
108
149
  checkedAt: '2026-08-26T00:00:00.000Z',
109
150
  compatibility: { status: 'not-checked' },
@@ -115,6 +156,30 @@ describe('preflight', () => {
115
156
  }],
116
157
  });
117
158
  });
159
+ it('advises machine model setup for an approved mapping without degrading ordinary harness readiness', async () => {
160
+ mockReadEffectivePolicy.mockReturnValue({
161
+ state: 'approved', provenance: 'user',
162
+ policy: { content: { mappings: [{ target: 'codex', runtimeKind: 'native' }] } },
163
+ });
164
+ const report = await (0, checks_1.preflight)(make({ manifest: { pack: 'generic', sensors: { security: { enabled: false } } } }));
165
+ expect(check(report, 'routing-setup')).toMatchObject({ advisory: true, ok: false, remedy: 'awm model-policy setup --provider codex --json' });
166
+ expect(report.status).toBe('ready');
167
+ });
168
+ it('labels sealed local coverage without claiming current machine verification or demanding setup', async () => {
169
+ const guidance = jest.spyOn(setupReadiness, 'routingSetupGuidance').mockReturnValueOnce([
170
+ { target: 'codex', runtimeKind: 'native', state: 'coverage-only' },
171
+ ]);
172
+ try {
173
+ const report = await (0, checks_1.preflight)(make({ manifest: { pack: 'generic', sensors: { security: { enabled: false } } } }));
174
+ expect(check(report, 'routing-setup')).toMatchObject({ advisory: true, ok: true,
175
+ detail: expect.stringContaining('do not verify current runtime/account/config scope') });
176
+ expect(check(report, 'routing-setup').remedy).toBeUndefined();
177
+ expect(report.status).toBe('ready');
178
+ }
179
+ finally {
180
+ guidance.mockRestore();
181
+ }
182
+ });
118
183
  afterEach(() => {
119
184
  mockRunSensors.mockReset();
120
185
  mockCheckCurrentness.mockReset();
@@ -50,6 +50,11 @@ const gate_1 = require("../../../src/commands/job/gate");
50
50
  const canonical_1 = require("../../../src/core/model-policy/canonical");
51
51
  const capabilities_1 = require("../../../src/core/model-policy/capabilities");
52
52
  const routing_approval_1 = require("../../helpers/routing-approval");
53
+ const machine_key_1 = require("../../../src/core/model-policy/machine-key");
54
+ const native_routing_proof_1 = require("../../../src/core/model-policy/native-routing-proof");
55
+ const eventStore = __importStar(require("../../../src/core/model-policy/event-store"));
56
+ const policyStore = __importStar(require("../../../src/core/model-policy/store"));
57
+ const selection_policy_digest_1 = require("../../../src/core/model-policy/selection-policy-digest");
53
58
  function jobPayload(argv) {
54
59
  return { argv, paths: [], cwd: '.', fingerprint: 'fp-1', commandDigest: 'cd-1', expandedPaths: [] };
55
60
  }
@@ -228,6 +233,85 @@ describe('aplicacion transaccional de requests', () => {
228
233
  process.env.AWM_HOME = priorHome;
229
234
  }
230
235
  });
236
+ test('un recibo nativo v2 no acepta una observacion positiva redactada por el agente', () => {
237
+ const state = (0, store_1.readJournal)(repo, 'rama').state;
238
+ state.routingAttempts = [{ schema: 'routing-attempt/v1', id: 'route-native-1', obligationId: 'o1', lineageId: 'l1', attempt: 1,
239
+ envelope: routing_approval_1.routingEnvelope, envelopeDigest: 'a'.repeat(64), fingerprint: 'b'.repeat(64), state: 'reserved',
240
+ nativeEvidenceRequired: true, reservedAt: new Date(Date.now() - 1_000).toISOString() }];
241
+ (0, store_1.writeJournal)(repo, 'rama', state);
242
+ (0, requests_1.emitRequest)(repo, 'rama', { kind: 'routing-observe', generationToken: 'g1', idempotencyKey: 'forged-positive',
243
+ payload: { attemptId: 'route-native-1', nativeAgentId: 'fake-child', observed: routing_approval_1.routingEnvelope.resolved } });
244
+ const result = (0, apply_1.consumePendingRequests)(repo, 'rama', 'g1');
245
+ expect({ result, problems: (0, store_1.readJournal)(repo, 'rama').state?.requestProblems }).toMatchObject({ result: { applied: 1 } });
246
+ const after = (0, store_1.readJournal)(repo, 'rama').state;
247
+ expect(after.routingAttempts?.[0]).toMatchObject({ state: 'blocked', reasonCode: 'PROVENANCE_MISSING', verdict: 'inconclusive' });
248
+ expect(after.routingIncidents).toMatchObject([{ reasonCode: 'PROVENANCE_MISSING', alertState: 'pending' }]);
249
+ });
250
+ test('un evento nativo sellado posterior a la reserva activa solo su intento', () => {
251
+ const previousHome = process.env.AWM_HOME;
252
+ const operator = path_1.default.join(repo, 'operator');
253
+ fs_1.default.mkdirSync(operator);
254
+ process.env.AWM_HOME = operator;
255
+ const scope = { runtime: routing_approval_1.routingEnvelope.runtime, binaryDigest: 'b'.repeat(64), configDigest: 'c'.repeat(64) };
256
+ const approved = (0, routing_approval_1.routingApproval)().policy;
257
+ const enrolledAt = new Date(Date.now() - 1_000).toISOString();
258
+ const eventReader = jest.spyOn(eventStore, 'readStoredEventReceipt').mockReturnValue({ state: 'present', receipt: {
259
+ schema: 'routing-capabilities/v2', ...scope, recordedAt: enrolledAt, claims: [{
260
+ selection: routing_approval_1.routingEnvelope.resolved, mappingDigest: (0, selection_policy_digest_1.selectionPolicyDigest)(approved.content.mappings[0], routing_approval_1.routingEnvelope.resolved),
261
+ eventDigest: 'c'.repeat(64), source: 'codex-turn-context', observedAt: enrolledAt,
262
+ actualModel: 'unverified', tokenUsage: 'unknown'
263
+ }],
264
+ } });
265
+ const policyReader = jest.spyOn(policyStore, 'readEffectivePolicy').mockReturnValue({ state: 'approved', provenance: 'project', policy: approved });
266
+ try {
267
+ const reservedAt = new Date(Date.now() - 2_000).toISOString();
268
+ const state = (0, store_1.readJournal)(repo, 'rama').state;
269
+ state.routingAttempts = [{ schema: 'routing-attempt/v1', id: 'route-native-1', obligationId: 'o1', lineageId: 'l1', attempt: 1,
270
+ envelope: routing_approval_1.routingEnvelope, envelopeDigest: 'a'.repeat(64), fingerprint: 'b'.repeat(64), state: 'reserved',
271
+ nativeEvidenceRequired: true, reservedAt }];
272
+ (0, store_1.writeJournal)(repo, 'rama', state);
273
+ const proof = (0, native_routing_proof_1.signNativeRoutingProof)({ attemptId: 'route-native-1', nativeAgentId: 'child-1', source: 'codex-turn-context',
274
+ eventDigest: 'c'.repeat(64), observedAt: new Date(Date.now() - 1_000).toISOString(), selection: routing_approval_1.routingEnvelope.resolved }, (0, machine_key_1.ensureMachineKey)(operator));
275
+ (0, requests_1.emitRequest)(repo, 'rama', { kind: 'routing-observe', generationToken: 'g1', idempotencyKey: 'native-positive',
276
+ payload: { attemptId: 'route-native-1', nativeAgentId: 'child-1', observed: routing_approval_1.routingEnvelope.resolved, nativeProof: proof } });
277
+ expect((0, apply_1.consumePendingRequests)(repo, 'rama', 'g1', scope).applied).toBe(1);
278
+ expect((0, store_1.readJournal)(repo, 'rama').state.routingAttempts?.[0]).toMatchObject({ state: 'active', nativeEventDigest: 'c'.repeat(64) });
279
+ }
280
+ finally {
281
+ eventReader.mockRestore();
282
+ policyReader.mockRestore();
283
+ if (previousHome === undefined)
284
+ delete process.env.AWM_HOME;
285
+ else
286
+ process.env.AWM_HOME = previousHome;
287
+ }
288
+ });
289
+ test('un proof en cola no activa el intento sin scope local vigente', () => {
290
+ const previousHome = process.env.AWM_HOME;
291
+ const operator = path_1.default.join(repo, 'operator');
292
+ fs_1.default.mkdirSync(operator);
293
+ process.env.AWM_HOME = operator;
294
+ try {
295
+ const state = (0, store_1.readJournal)(repo, 'rama').state;
296
+ const reservedAt = new Date(Date.now() - 2_000).toISOString();
297
+ state.routingAttempts = [{ schema: 'routing-attempt/v1', id: 'route-native-1', obligationId: 'o1', lineageId: 'l1', attempt: 1,
298
+ envelope: routing_approval_1.routingEnvelope, envelopeDigest: 'a'.repeat(64), fingerprint: 'b'.repeat(64), state: 'reserved',
299
+ nativeEvidenceRequired: true, reservedAt }];
300
+ (0, store_1.writeJournal)(repo, 'rama', state);
301
+ const proof = (0, native_routing_proof_1.signNativeRoutingProof)({ attemptId: 'route-native-1', nativeAgentId: 'child-1', source: 'codex-turn-context',
302
+ eventDigest: 'c'.repeat(64), observedAt: new Date(Date.now() - 1_000).toISOString(), selection: routing_approval_1.routingEnvelope.resolved }, (0, machine_key_1.ensureMachineKey)(operator));
303
+ (0, requests_1.emitRequest)(repo, 'rama', { kind: 'routing-observe', generationToken: 'g1', idempotencyKey: 'native-stale-scope',
304
+ payload: { attemptId: 'route-native-1', nativeAgentId: 'child-1', observed: routing_approval_1.routingEnvelope.resolved, nativeProof: proof } });
305
+ (0, apply_1.consumePendingRequests)(repo, 'rama', 'g1');
306
+ expect((0, store_1.readJournal)(repo, 'rama').state.routingAttempts?.[0]).toMatchObject({ state: 'blocked', reasonCode: 'PROVENANCE_MISSING' });
307
+ }
308
+ finally {
309
+ if (previousHome === undefined)
310
+ delete process.env.AWM_HOME;
311
+ else
312
+ process.env.AWM_HOME = previousHome;
313
+ }
314
+ });
231
315
  test('request corrupta se aparta VISIBLE como .corrupt, jamas se descarta (R1.6)', () => {
232
316
  fs_1.default.writeFileSync(path_1.default.join((0, paths_1.requestsDir)(repo, 'rama'), 'req-roto.json'), '{no-json');
233
317
  const out = (0, apply_1.consumePendingRequests)(repo, 'rama', 'g1');
@@ -149,6 +149,29 @@ describe('the supervisor admission actually carries the identity (#166)', () =>
149
149
  fs_1.default.rmSync(repo, { recursive: true, force: true });
150
150
  }
151
151
  });
152
+ test('uses sealed event evidence and a freshly measured Codex scope instead of a 24h receipt', async () => {
153
+ const repo = boundRepo();
154
+ try {
155
+ const runtime = { target: 'codex', kind: 'native', version: '0.156.1', accountScopeDigest: DIGEST };
156
+ const eventScope = { runtime, binaryDigest: 'b'.repeat(64), configDigest: 'c'.repeat(64) };
157
+ const eventReceipt = { schema: 'routing-capabilities/v2', ...eventScope, recordedAt: '2026-09-22T00:00:00.000Z', claims: [] };
158
+ const seen = [];
159
+ const readCapabilities = jest.fn();
160
+ const admission = (0, supervisor_1.defaultDispatchAdmission)(repo, 'main', 'codex', { kind: 'native', version: '0.156.1', accountScopeDigest: DIGEST }, {
161
+ admit: (async (input) => { seen.push(input); return { state: 'admitted' }; }),
162
+ readEffectivePolicy: () => ({ state: 'absent' }),
163
+ readCapabilities,
164
+ readStoredEventReceipt: (() => ({ state: 'present', receipt: eventReceipt })),
165
+ queryLocalCodexScope: (async () => ({ state: 'current', scope: eventScope })),
166
+ });
167
+ await admission();
168
+ expect(readCapabilities).not.toHaveBeenCalled();
169
+ expect(seen[0].routing).toMatchObject({ runtime, eventScope, eventReceipt });
170
+ }
171
+ finally {
172
+ fs_1.default.rmSync(repo, { recursive: true, force: true });
173
+ }
174
+ });
152
175
  test('dispatches without routing facts when no identity was asserted', async () => {
153
176
  const repo = boundRepo();
154
177
  try {
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const admission_1 = require("../../../src/core/admission");
4
4
  const types_1 = require("../../../src/core/journal/types");
5
+ const selection_policy_digest_1 = require("../../../src/core/model-policy/selection-policy-digest");
5
6
  const valid = {
6
7
  state: 'valid', schema: 'compact-slices/v1', planDigest: 'a'.repeat(64),
7
8
  manifest: {
@@ -50,6 +51,26 @@ describe('admitPlan', () => {
50
51
  const report = await (0, admission_1.admitPlan)({ plan: v2(profile), provider: 'codex', cwd: process.cwd(), enabledAgents: ['codex'], routing: routing() });
51
52
  expect(report).toMatchObject({ state: 'admitted', routingForecast: { implementerProfiles: { [profile]: 1 }, trackB: { state: 'unavailable', lowerBound: 1 }, controller: { state: 'unavailable', lowerBound: 0 } } });
52
53
  });
54
+ it('awaits read-only routing evidence only after earlier admission gates pass', async () => {
55
+ const reader = jest.fn(async () => routing());
56
+ expect(await (0, admission_1.admitPlan)({ plan: v2(), provider: 'codex', cwd: process.cwd(), enabledAgents: ['codex'], routingReader: reader })).toMatchObject({ state: 'admitted' });
57
+ expect(reader).toHaveBeenCalledTimes(1);
58
+ });
59
+ it('admits a +25h event-scoped Codex enrollment only when the full fallback is independently proved', async () => {
60
+ const evidence = routing();
61
+ evidence.policy.content.mappings[0].degradation.allowMissingObservedIdentity = true;
62
+ const mapping = evidence.policy.content.mappings[0];
63
+ const eventScope = { runtime: evidence.runtime, binaryDigest: 'b'.repeat(64), configDigest: 'c'.repeat(64) };
64
+ const claimed = [mapping.profiles.mechanical, mapping.fullCapability];
65
+ const eventReceipt = { schema: 'routing-capabilities/v2', ...eventScope, recordedAt: '2026-09-17T00:00:00.000Z', claims: claimed.map(selection => ({ selection,
66
+ mappingDigest: (0, selection_policy_digest_1.selectionPolicyDigest)(mapping, selection), eventDigest: sha, source: 'codex-turn-context', observedAt: '2026-09-17T00:00:00.000Z', actualModel: 'unverified', tokenUsage: 'unknown' })) };
67
+ const routingFacts = { runtime: evidence.runtime, policy: evidence.policy, eventReceipt, eventScope, now: new Date('2026-09-18T01:00:00.000Z') };
68
+ expect(await (0, admission_1.admitPlan)({ plan: v2(), provider: 'codex', cwd: process.cwd(), enabledAgents: ['codex'], routing: routingFacts })).toMatchObject({ state: 'admitted' });
69
+ expect(await (0, admission_1.admitPlan)({ plan: v2(), provider: 'codex', cwd: process.cwd(), enabledAgents: ['codex'], routing: { ...routingFacts,
70
+ eventReceipt: { ...eventReceipt, claims: [eventReceipt.claims[1]] } } })).toMatchObject({ state: 'admitted' });
71
+ expect(await (0, admission_1.admitPlan)({ plan: v2(), provider: 'codex', cwd: process.cwd(), enabledAgents: ['codex'], routing: { ...routingFacts,
72
+ eventReceipt: { ...eventReceipt, claims: [eventReceipt.claims[0]] } } })).toMatchObject({ state: 'blocked', diagnostics: [{ code: 'ROUTING_SELECTION_UNENROLLED' }] });
73
+ });
53
74
  it('blocks a valid cross-provider policy and receipt instead of admitting codex under another runtime target', async () => {
54
75
  const evidence = routing();
55
76
  const foreign = structuredClone(evidence);