agentic-workflow-manager 9.8.0 → 9.10.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.
- package/dist/src/commands/job/gate.js +18 -0
- package/dist/src/commands/job/index.js +61 -0
- package/dist/src/commands/model-policy/index.js +94 -0
- package/dist/src/commands/plan/index.js +59 -2
- package/dist/src/commands/watch/apply.js +32 -0
- package/dist/src/core/admission/index.js +52 -2
- package/dist/src/core/admission/registry-contracts.js +1 -1
- package/dist/src/core/journal/requests.js +1 -1
- package/dist/src/core/journal/types.js +22 -1
- package/dist/src/core/model-policy/canonical.js +18 -0
- package/dist/src/core/model-policy/capabilities.js +197 -0
- package/dist/src/core/model-policy/capability-types.js +2 -0
- package/dist/src/core/model-policy/digest.js +35 -0
- package/dist/src/core/model-policy/journal.js +124 -0
- package/dist/src/core/model-policy/paths.js +12 -0
- package/dist/src/core/model-policy/resolve.js +155 -0
- package/dist/src/core/model-policy/store.js +189 -0
- package/dist/src/core/model-policy/types.js +2 -0
- package/dist/src/core/model-policy/validate.js +112 -0
- package/dist/src/core/plan/identity.js +4 -2
- package/dist/src/core/plan/validate.js +15 -16
- package/dist/src/index.js +2 -0
- package/dist/tests/commands/job/gate-reconcile.test.js +16 -0
- package/dist/tests/commands/job/gate.test.js +9 -0
- package/dist/tests/commands/job/routing-report-cli.test.js +46 -0
- package/dist/tests/commands/job/routing.test.js +11 -0
- package/dist/tests/commands/model-policy/index.test.js +117 -0
- package/dist/tests/commands/plan/index.test.js +52 -0
- package/dist/tests/commands/watch/apply.test.js +12 -0
- package/dist/tests/core/admission/index.test.js +53 -0
- package/dist/tests/core/model-policy/capabilities.test.js +365 -0
- package/dist/tests/core/model-policy/digest.test.js +117 -0
- package/dist/tests/core/model-policy/journal.test.js +46 -0
- package/dist/tests/core/model-policy/policy.test.js +47 -0
- package/dist/tests/core/model-policy/resolve.test.js +185 -0
- package/dist/tests/core/model-policy/store.test.js +177 -0
- package/dist/tests/core/plan/validate.test.js +40 -2
- package/dist/tests/core/secure-fs/native-bridge.test.js +81 -4
- package/dist/tests/structural/directory-fsync-is-single-source.test.js +97 -0
- package/dist/tests/structural/native-release-artifacts.test.js +14 -0
- package/package.json +3 -2
- package/prebuilds/darwin-arm64/secure_fs.node +0 -0
- package/prebuilds/darwin-x64/secure_fs.node +0 -0
- package/prebuilds/linux-arm64/secure_fs.node +0 -0
- package/prebuilds/linux-x64/secure_fs.node +0 -0
- package/prebuilds/win32-arm64/secure_fs.node +0 -0
- package/prebuilds/win32-x64/secure_fs.node +0 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const commander_1 = require("commander");
|
|
4
|
+
const model_policy_1 = require("../../../src/commands/model-policy");
|
|
5
|
+
const out = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
6
|
+
describe('model-policy command', () => {
|
|
7
|
+
beforeEach(() => { jest.clearAllMocks(); process.exitCode = undefined; });
|
|
8
|
+
afterAll(() => out.mockRestore());
|
|
9
|
+
it('emits a read-only protocol contract as JSON', async () => {
|
|
10
|
+
const program = new commander_1.Command();
|
|
11
|
+
program.exitOverride();
|
|
12
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
13
|
+
(0, model_policy_1.registerModelPolicyCommand)(program);
|
|
14
|
+
await program.parseAsync(['node', 'awm', 'model-policy', 'contract', '--json']);
|
|
15
|
+
expect(JSON.parse(String(out.mock.calls[0][0]))).toMatchObject({
|
|
16
|
+
schema: 'routing-protocol/v1',
|
|
17
|
+
supportedPlanSchemas: ['compact-slices/v1', 'compact-slices/v2'],
|
|
18
|
+
implementerProfiles: ['mechanical', 'integration', 'judgment'],
|
|
19
|
+
limits: { maxFileBytes: 262144 },
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
it('rejects missing values instead of silently accepting an incomplete approval', async () => {
|
|
23
|
+
const program = new commander_1.Command();
|
|
24
|
+
program.exitOverride();
|
|
25
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
26
|
+
(0, model_policy_1.registerModelPolicyCommand)(program);
|
|
27
|
+
await expect(program.parseAsync(['node', 'awm', 'model-policy', 'approve', '--file', '--scope', 'user', '--expected-digest', 'a'.repeat(64)])).rejects.toThrow();
|
|
28
|
+
});
|
|
29
|
+
it('accepts and validates --cwd on contract, and resolves status through it', async () => {
|
|
30
|
+
const readEffectivePolicy = jest.fn(() => ({ state: 'absent' }));
|
|
31
|
+
const program = new commander_1.Command();
|
|
32
|
+
program.exitOverride();
|
|
33
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
34
|
+
(0, model_policy_1.registerModelPolicyCommand)(program, { readEffectivePolicy });
|
|
35
|
+
await program.parseAsync(['node', 'awm', 'model-policy', 'contract', '--cwd', 'fixture-root', '--json']);
|
|
36
|
+
await program.parseAsync(['node', 'awm', 'model-policy', 'status', '--provider', 'codex', '--runtime-kind', 'native', '--runtime-version', '1.0.0', '--account-scope-digest', 'a'.repeat(64), '--cwd', 'fixture-root', '--json']);
|
|
37
|
+
expect(readEffectivePolicy).toHaveBeenCalledWith('fixture-root');
|
|
38
|
+
await expect(program.parseAsync(['node', 'awm', 'model-policy', 'contract', '--cwd', '--json'])).rejects.toThrow();
|
|
39
|
+
});
|
|
40
|
+
it('reports receipt provenance in status and rejects stale receipt state', async () => {
|
|
41
|
+
const readCapabilities = jest.fn(() => ({ state: 'stale', reason: 'expired' }));
|
|
42
|
+
const program = new commander_1.Command();
|
|
43
|
+
program.exitOverride();
|
|
44
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
45
|
+
(0, model_policy_1.registerModelPolicyCommand)(program, { readEffectivePolicy: () => ({ state: 'absent' }), readCapabilities });
|
|
46
|
+
await program.parseAsync(['node', 'awm', 'model-policy', 'status', '--provider', 'codex', '--runtime-kind', 'native', '--runtime-version', '1.0.0', '--account-scope-digest', 'a'.repeat(64), '--json']);
|
|
47
|
+
expect(JSON.parse(String(out.mock.calls[0][0]))).toMatchObject({ policy: { state: 'absent' }, capability: { state: 'stale' } });
|
|
48
|
+
expect(process.exitCode).toBe(2);
|
|
49
|
+
});
|
|
50
|
+
it('discloses the canonical digest through a read-only subcommand', async () => {
|
|
51
|
+
const candidateDigest = jest.fn(() => ({ schema: 'model-policy/v1', digest: 'b'.repeat(64) }));
|
|
52
|
+
const program = new commander_1.Command();
|
|
53
|
+
program.exitOverride();
|
|
54
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
55
|
+
(0, model_policy_1.registerModelPolicyCommand)(program, { candidateDigest });
|
|
56
|
+
await program.parseAsync(['node', 'awm', 'model-policy', 'digest', '--file', 'policy.json', '--cwd', 'fixture-root', '--json']);
|
|
57
|
+
expect(candidateDigest).toHaveBeenCalledWith({ file: 'policy.json', cwd: 'fixture-root' });
|
|
58
|
+
expect(JSON.parse(String(out.mock.calls[0][0]))).toEqual({ schema: 'model-policy/v1', digest: 'b'.repeat(64) });
|
|
59
|
+
});
|
|
60
|
+
it('takes no approval arguments on digest, so it cannot approve by accident', async () => {
|
|
61
|
+
const candidateDigest = jest.fn(() => ({ schema: 'model-policy/v1', digest: 'b'.repeat(64) }));
|
|
62
|
+
const approvePolicy = jest.fn();
|
|
63
|
+
const approveCapabilities = jest.fn();
|
|
64
|
+
const program = new commander_1.Command();
|
|
65
|
+
program.exitOverride();
|
|
66
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
67
|
+
(0, model_policy_1.registerModelPolicyCommand)(program, { candidateDigest, approvePolicy: approvePolicy, approveCapabilities: approveCapabilities });
|
|
68
|
+
await expect(program.parseAsync(['node', 'awm', 'model-policy', 'digest', '--file', 'policy.json', '--expected-digest', 'a'.repeat(64)])).rejects.toThrow();
|
|
69
|
+
expect(approvePolicy).not.toHaveBeenCalled();
|
|
70
|
+
expect(approveCapabilities).not.toHaveBeenCalled();
|
|
71
|
+
});
|
|
72
|
+
it('rejects a missing or malformed --file on digest instead of digesting the flag', async () => {
|
|
73
|
+
const candidateDigest = jest.fn(() => ({ schema: 'model-policy/v1', digest: 'b'.repeat(64) }));
|
|
74
|
+
const program = new commander_1.Command();
|
|
75
|
+
program.exitOverride();
|
|
76
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
77
|
+
(0, model_policy_1.registerModelPolicyCommand)(program, { candidateDigest });
|
|
78
|
+
await expect(program.parseAsync(['node', 'awm', 'model-policy', 'digest'])).rejects.toThrow();
|
|
79
|
+
await expect(program.parseAsync(['node', 'awm', 'model-policy', 'digest', '--file', '--cwd'])).rejects.toThrow(/requires a non-empty value/);
|
|
80
|
+
expect(candidateDigest).not.toHaveBeenCalled();
|
|
81
|
+
});
|
|
82
|
+
// This positive case is what the negative guard below could never establish.
|
|
83
|
+
// While `capabilities approve` was registered as one command with a
|
|
84
|
+
// positional `<approve>`, Commander handed the action (positional, options),
|
|
85
|
+
// so `--file` read as undefined and EVERY invocation — well-formed ones
|
|
86
|
+
// included — died on 'requires a non-empty value'. A suite that only
|
|
87
|
+
// asserted that rejection was green against a command that could not
|
|
88
|
+
// approve at all.
|
|
89
|
+
it('reaches the capability approval with parsed options, not a positional', async () => {
|
|
90
|
+
const approveCapabilities = jest.fn(() => ({ schema: 'routing-capabilities/v1' }));
|
|
91
|
+
const program = new commander_1.Command();
|
|
92
|
+
program.exitOverride();
|
|
93
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
94
|
+
(0, model_policy_1.registerModelPolicyCommand)(program, { approveCapabilities: approveCapabilities });
|
|
95
|
+
await program.parseAsync(['node', 'awm', 'model-policy', 'capabilities', 'approve', '--file', 'receipt.json', '--expected-digest', 'a'.repeat(64), '--cwd', 'fixture-root', '--json']);
|
|
96
|
+
expect(approveCapabilities).toHaveBeenCalledWith({ file: 'receipt.json', cwd: 'fixture-root', expectedDigest: 'a'.repeat(64), replaceDigest: undefined });
|
|
97
|
+
expect(JSON.parse(String(out.mock.calls[0][0]))).toMatchObject({ state: 'approved' });
|
|
98
|
+
});
|
|
99
|
+
it('rejects an unknown capabilities subcommand instead of treating it as an approval', async () => {
|
|
100
|
+
const approveCapabilities = jest.fn();
|
|
101
|
+
const program = new commander_1.Command();
|
|
102
|
+
program.exitOverride();
|
|
103
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
104
|
+
(0, model_policy_1.registerModelPolicyCommand)(program, { approveCapabilities: approveCapabilities });
|
|
105
|
+
await expect(program.parseAsync(['node', 'awm', 'model-policy', 'capabilities', 'revoke', '--file', 'receipt.json', '--expected-digest', 'a'.repeat(64)])).rejects.toThrow();
|
|
106
|
+
expect(approveCapabilities).not.toHaveBeenCalled();
|
|
107
|
+
});
|
|
108
|
+
it('rejects an empty replacement digest for capability approval at the command boundary', async () => {
|
|
109
|
+
const approveCapabilities = jest.fn();
|
|
110
|
+
const program = new commander_1.Command();
|
|
111
|
+
program.exitOverride();
|
|
112
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
113
|
+
(0, model_policy_1.registerModelPolicyCommand)(program, { approveCapabilities: approveCapabilities });
|
|
114
|
+
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
|
+
expect(approveCapabilities).not.toHaveBeenCalled();
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -48,6 +48,18 @@ describe('plan validate Commander wiring', () => {
|
|
|
48
48
|
stdoutWrite.mockRestore();
|
|
49
49
|
process.exitCode = previousExitCode;
|
|
50
50
|
});
|
|
51
|
+
it('returns v1 not-required before reading personal policy or capability state', async () => {
|
|
52
|
+
const policy = jest.fn();
|
|
53
|
+
const capabilities = jest.fn();
|
|
54
|
+
const program = new commander_1.Command();
|
|
55
|
+
program.exitOverride();
|
|
56
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
57
|
+
(0, plan_1.registerPlanCommand)(program, { validatePlanFile: () => valid, readEffectivePolicy: policy, readCapabilities: capabilities });
|
|
58
|
+
await program.parseAsync(['node', 'awm', 'plan', 'resolve', 'plans/r4.md', '--provider', 'codex', '--runtime-kind', 'native', '--runtime-version', '1.0.0', '--account-scope-digest', 'a'.repeat(64), '--role', 'controller', '--json']);
|
|
59
|
+
expect(JSON.parse(String(stdoutWrite.mock.calls[0][0]))).toEqual({ state: 'not-required', reason: 'v1-without-opt-in' });
|
|
60
|
+
expect(policy).not.toHaveBeenCalled();
|
|
61
|
+
expect(capabilities).not.toHaveBeenCalled();
|
|
62
|
+
});
|
|
51
63
|
it('emits deterministic human output for a valid compact plan', async () => {
|
|
52
64
|
await commandFor(valid).parseAsync(['node', 'awm', 'plan', 'validate', 'plans/r4.md']);
|
|
53
65
|
expect(String(stdoutWrite.mock.calls[0][0])).toBe('Plan validation: valid "plans/r4.md" (compact-slices/v1; 1 slices; 5 requirements; complete ownership)\n');
|
|
@@ -192,6 +204,46 @@ describe('plan validate Commander wiring', () => {
|
|
|
192
204
|
});
|
|
193
205
|
});
|
|
194
206
|
describe('plan admit Commander wiring', () => {
|
|
207
|
+
it('does not read v2 routing facts after currentness blocks', async () => {
|
|
208
|
+
const policy = jest.fn();
|
|
209
|
+
const capabilities = jest.fn();
|
|
210
|
+
const output = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
211
|
+
const program = new commander_1.Command();
|
|
212
|
+
program.exitOverride();
|
|
213
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
214
|
+
(0, plan_1.registerPlanCommand)(program, { validatePlanFile: () => ({ ...valid, schema: 'compact-slices/v2', manifest: { ...valid.manifest, schema: 'compact-slices/v2', slices: valid.manifest.slices.map(slice => ({ ...slice, implementerProfile: 'mechanical' })) } }), readPreferences: () => ({ defaultAgent: 'codex', enabledAgents: ['codex'], installMethod: 'symlink', defaultScope: 'local' }), readEffectivePolicy: policy, readCapabilities: capabilities, listRegistries: () => [], checkCurrentness: async () => ({ checkedAt: 'x', compatibility: { status: 'not-checked' }, components: [{ component: 'cli', installed: '1', latest: '2', channel: 'stable', source: 'x', checkedAt: 'x', status: 'stale', detail: 'x', remedy: 'x' }] }) });
|
|
215
|
+
try {
|
|
216
|
+
await program.parseAsync(['node', 'awm', 'plan', 'admit', 'plan.md', '--provider', 'codex', '--cwd', repositoryRoot, '--require-current', '--runtime-kind', 'native', '--runtime-version', '1.0.0', '--account-scope-digest', 'a'.repeat(64), '--json']);
|
|
217
|
+
expect(policy).not.toHaveBeenCalled();
|
|
218
|
+
expect(capabilities).not.toHaveBeenCalled();
|
|
219
|
+
}
|
|
220
|
+
finally {
|
|
221
|
+
output.mockRestore();
|
|
222
|
+
process.exitCode = undefined;
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
it.each([
|
|
226
|
+
['invalid plan', invalid, 'codex', ['codex']],
|
|
227
|
+
['invalid provider', valid, 'not-a-provider', ['codex']],
|
|
228
|
+
['disabled provider', valid, 'codex', ['cursor']],
|
|
229
|
+
])('does not read routing facts for %s even with complete runtime flags', async (_name, report, provider, enabledAgents) => {
|
|
230
|
+
const policy = jest.fn();
|
|
231
|
+
const capabilities = jest.fn();
|
|
232
|
+
const output = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
233
|
+
const program = new commander_1.Command();
|
|
234
|
+
program.exitOverride();
|
|
235
|
+
program.configureOutput({ writeErr: () => undefined });
|
|
236
|
+
(0, plan_1.registerPlanCommand)(program, { validatePlanFile: () => report, readPreferences: () => ({ defaultAgent: 'codex', enabledAgents: [...enabledAgents], installMethod: 'symlink', defaultScope: 'local' }), readEffectivePolicy: policy, readCapabilities: capabilities });
|
|
237
|
+
try {
|
|
238
|
+
await program.parseAsync(['node', 'awm', 'plan', 'admit', 'plan.md', '--provider', provider, '--cwd', repositoryRoot, '--runtime-kind', 'native', '--runtime-version', '1.0.0', '--account-scope-digest', 'a'.repeat(64), '--json']);
|
|
239
|
+
expect(policy).not.toHaveBeenCalled();
|
|
240
|
+
expect(capabilities).not.toHaveBeenCalled();
|
|
241
|
+
}
|
|
242
|
+
finally {
|
|
243
|
+
output.mockRestore();
|
|
244
|
+
process.exitCode = undefined;
|
|
245
|
+
}
|
|
246
|
+
});
|
|
195
247
|
it('derives desatendido from the canonical plan header and requires a journal without a flag', async () => {
|
|
196
248
|
const root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'awm-admit-header-'));
|
|
197
249
|
const output = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
@@ -194,6 +194,18 @@ describe('aplicacion transaccional de requests', () => {
|
|
|
194
194
|
expect(Object.values(s.appliedRequests).some((a) => a.outcome === 'rejected-stale-generation')).toBe(true);
|
|
195
195
|
expect(s.controllerHeartbeatAt).toBeUndefined();
|
|
196
196
|
});
|
|
197
|
+
test('routing reserve/observe es supervisado, idempotente y una generacion vieja no muta intentos', () => {
|
|
198
|
+
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) };
|
|
199
|
+
(0, requests_1.emitRequest)(repo, 'rama', { kind: 'routing-reserve', generationToken: 'g1', idempotencyKey: 'routing-1', payload: { obligationId: 'o1', lineageId: 'l1', envelope, fingerprint: 'e'.repeat(64) } });
|
|
200
|
+
(0, apply_1.consumePendingRequests)(repo, 'rama', 'g1');
|
|
201
|
+
const attempt = (0, store_1.readJournal)(repo, 'rama').state.routingAttempts[0];
|
|
202
|
+
(0, requests_1.emitRequest)(repo, 'rama', { kind: 'routing-observe', generationToken: 'g1', idempotencyKey: 'routing-2', payload: { attemptId: attempt.id, nativeAgentId: 'native-1' } });
|
|
203
|
+
(0, apply_1.consumePendingRequests)(repo, 'rama', 'g1');
|
|
204
|
+
expect((0, store_1.readJournal)(repo, 'rama').state.routingAttempts[0]).toMatchObject({ state: 'active', nativeAgentId: 'native-1' });
|
|
205
|
+
(0, requests_1.emitRequest)(repo, 'rama', { kind: 'routing-reserve', generationToken: 'old', idempotencyKey: 'routing-old', payload: { obligationId: 'o1', lineageId: 'l2', envelope, fingerprint: 'f'.repeat(64) } });
|
|
206
|
+
expect((0, apply_1.consumePendingRequests)(repo, 'rama', 'g1').rejectedStale).toBe(1);
|
|
207
|
+
expect((0, store_1.readJournal)(repo, 'rama').state.routingAttempts).toHaveLength(1);
|
|
208
|
+
});
|
|
197
209
|
test('request corrupta se aparta VISIBLE como .corrupt, jamas se descarta (R1.6)', () => {
|
|
198
210
|
fs_1.default.writeFileSync(path_1.default.join((0, paths_1.requestsDir)(repo, 'rama'), 'req-roto.json'), '{no-json');
|
|
199
211
|
const out = (0, apply_1.consumePendingRequests)(repo, 'rama', 'g1');
|
|
@@ -11,6 +11,54 @@ const valid = {
|
|
|
11
11
|
},
|
|
12
12
|
};
|
|
13
13
|
describe('admitPlan', () => {
|
|
14
|
+
const sha = 'a'.repeat(64);
|
|
15
|
+
const routing = () => ({
|
|
16
|
+
now: new Date('2026-09-17T12:00:00.000Z'),
|
|
17
|
+
runtime: { target: 'codex', kind: 'native', version: '1.0.0', accountScopeDigest: sha },
|
|
18
|
+
policy: { schema: 'approved-model-policy/v1', content: { schema: 'model-policy/v1', mappings: [{ target: 'codex', runtimeKind: 'native', profiles: { mechanical: { selector: { kind: 'model', id: 'm' }, effort: { kind: 'explicit', value: 'low' } }, integration: { selector: { kind: 'model', id: 'i' }, effort: { kind: 'explicit', value: 'medium' } }, judgment: { selector: { kind: 'model', id: 'j' }, effort: { kind: 'explicit', value: 'medium' } } }, fullCapability: { selector: { kind: 'model', id: 'f' }, effort: { kind: 'explicit', value: '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' }, lineage: { previousDigest: null } },
|
|
19
|
+
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: ['m', 'i', 'j', 'f'].map((id, n) => ({ selector: { kind: 'model', id }, effort: { kind: 'explicit', value: n === 0 ? 'low' : n === 3 ? 'high' : 'medium' } })), evidence: ['interactiveExecution', 'unattendedController', 'modelOverride', 'effortOverride', 'observedModelEvidence'].map(capability => ({ capability: capability, kind: 'native-control', receiptDigest: sha })), approval: { approvalId: 'approval', snapshotDigest: sha } },
|
|
20
|
+
});
|
|
21
|
+
const v2 = (profile = 'mechanical') => ({ ...valid, schema: 'compact-slices/v2', manifest: { ...valid.manifest, schema: 'compact-slices/v2', slices: valid.manifest.slices.map(slice => ({ ...slice, implementerProfile: profile })) } });
|
|
22
|
+
it('blocks v2 routing only after existing sensors pass when routing facts are absent', async () => {
|
|
23
|
+
const report = await (0, admission_1.admitPlan)({ plan: v2(), provider: 'codex', cwd: process.cwd(), enabledAgents: ['codex'], verifySensors: true, sensors: { overall: 'pass', sensors: [] } });
|
|
24
|
+
expect(report).toMatchObject({ state: 'blocked', sensors: 'pass' });
|
|
25
|
+
expect(report.diagnostics[0].code).toBe('ADMISSION_ROUTING_FACTS_REQUIRED');
|
|
26
|
+
});
|
|
27
|
+
it.each([
|
|
28
|
+
['journal', { provider: 'codex', executionMode: 'desatendido' }],
|
|
29
|
+
['provider capability', { provider: 'cursor', executionMode: 'interactivo' }],
|
|
30
|
+
])('does not invoke deferred v2 routing facts when %s gate blocks', async (_name, fields) => {
|
|
31
|
+
const reader = jest.fn(() => { throw new Error('routing reader must not run'); });
|
|
32
|
+
const report = await (0, admission_1.admitPlan)({ plan: v2(), cwd: process.cwd(), enabledAgents: [fields.provider], routingReader: reader, ...fields });
|
|
33
|
+
expect(report.state).toBe('blocked');
|
|
34
|
+
expect(reader).not.toHaveBeenCalled();
|
|
35
|
+
});
|
|
36
|
+
it.each(['fail', 'not_certified'])('does not invoke deferred v2 routing facts when sensors are %s', async (overall) => {
|
|
37
|
+
const reader = jest.fn(() => { throw new Error('routing reader must not run'); });
|
|
38
|
+
const report = await (0, admission_1.admitPlan)({ plan: v2(), provider: 'codex', cwd: process.cwd(), enabledAgents: ['codex'], verifySensors: true, sensors: { overall, sensors: [] }, routingReader: reader });
|
|
39
|
+
expect(report).toMatchObject({ state: 'blocked', sensors: overall === 'not_certified' ? 'not-certified' : 'fail' });
|
|
40
|
+
expect(reader).not.toHaveBeenCalled();
|
|
41
|
+
});
|
|
42
|
+
it('does not invoke deferred v2 routing facts when compatibility blocks', async () => {
|
|
43
|
+
const reader = jest.fn(() => { throw new Error('routing reader must not run'); });
|
|
44
|
+
const currentness = { checkedAt: 'x', compatibility: { status: 'not-checked' }, components: [{ component: 'cli', installed: '1', latest: '1', channel: 'stable', source: 'x', checkedAt: 'x', status: 'current', detail: 'x', remedy: 'none' }] };
|
|
45
|
+
const report = await (0, admission_1.admitPlan)({ plan: v2(), provider: 'codex', cwd: process.cwd(), enabledAgents: ['codex'], requireCurrent: true, provenance: 'proven', currentness, compatibilityDiagnostics: [{ code: 'COMPAT', message: 'blocked' }], routingReader: reader });
|
|
46
|
+
expect(report).toMatchObject({ state: 'blocked', diagnostics: [expect.objectContaining({ code: 'COMPAT' })] });
|
|
47
|
+
expect(reader).not.toHaveBeenCalled();
|
|
48
|
+
});
|
|
49
|
+
it.each(['mechanical', 'integration', 'judgment'])('admits v2 %s with policy and capability evidence and an honest unknown forecast', async (profile) => {
|
|
50
|
+
const report = await (0, admission_1.admitPlan)({ plan: v2(profile), provider: 'codex', cwd: process.cwd(), enabledAgents: ['codex'], routing: routing() });
|
|
51
|
+
expect(report).toMatchObject({ state: 'admitted', routingForecast: { implementerProfiles: { [profile]: 1 }, trackB: { state: 'unavailable', lowerBound: 1 }, controller: { state: 'unavailable', lowerBound: 0 } } });
|
|
52
|
+
});
|
|
53
|
+
it('blocks a valid cross-provider policy and receipt instead of admitting codex under another runtime target', async () => {
|
|
54
|
+
const evidence = routing();
|
|
55
|
+
const foreign = structuredClone(evidence);
|
|
56
|
+
foreign.runtime.target = 'cursor';
|
|
57
|
+
foreign.policy.content.mappings[0].target = 'cursor';
|
|
58
|
+
foreign.capabilities.runtime.target = 'cursor';
|
|
59
|
+
const report = await (0, admission_1.admitPlan)({ plan: v2(), provider: 'codex', cwd: process.cwd(), enabledAgents: ['codex'], routing: foreign });
|
|
60
|
+
expect(report).toMatchObject({ state: 'blocked', provider: 'codex', diagnostics: [expect.objectContaining({ code: 'ADMISSION_ROUTING_PROVIDER_MISMATCH' })] });
|
|
61
|
+
});
|
|
14
62
|
it('rejects a forecast whose total or role topology does not match its slices', () => {
|
|
15
63
|
const forecast = { kind: 'topology', slices: 2, roles: { implementer: 2, 'specification-reviewer': 2, 'code-quality-reviewer': 2, 'final-reviewer': 1, 'track-a-qa': 1, 'track-b-qa': 1, documentation: 1, retro: 1, finishing: 1 }, total: 99 };
|
|
16
64
|
expect(() => (0, admission_1.sanitizeAdmissionReport)({ state: 'admitted', planState: 'valid', journal: 'not-required', currentness: 'not-checked', sensors: 'not-required', diagnostics: [], forecast })).toThrow(/invalid report/);
|
|
@@ -18,6 +66,11 @@ describe('admitPlan', () => {
|
|
|
18
66
|
forecast.roles.implementer = 1;
|
|
19
67
|
expect(() => (0, admission_1.sanitizeAdmissionReport)({ state: 'admitted', planState: 'valid', journal: 'not-required', currentness: 'not-checked', sensors: 'not-required', diagnostics: [], forecast })).toThrow(/invalid report/);
|
|
20
68
|
});
|
|
69
|
+
it('rejects forged routing forecast role keys and profile totals at the public sanitizer', () => {
|
|
70
|
+
const base = { kind: 'routing-v1', slices: 1, implementerProfiles: { mechanical: 1, integration: 0, judgment: 0 }, roles: { 'specification-reviewer': 1, 'code-quality-reviewer': 1, 'final-reviewer': 1, 'track-a-qa': 1, documentation: 1, retro: 1, finishing: 1 }, trackB: { state: 'unavailable', lowerBound: 1 }, controller: { state: 'unavailable', lowerBound: 0 } };
|
|
71
|
+
expect(() => (0, admission_1.sanitizeAdmissionReport)({ state: 'admitted', planState: 'valid', journal: 'not-required', currentness: 'not-checked', sensors: 'not-required', diagnostics: [], routingForecast: { ...base, roles: { ...base.roles, architecture: 1 } } })).toThrow(/invalid report/);
|
|
72
|
+
expect(() => (0, admission_1.sanitizeAdmissionReport)({ state: 'admitted', planState: 'valid', journal: 'not-required', currentness: 'not-checked', sensors: 'not-required', diagnostics: [], routingForecast: { ...base, implementerProfiles: { ...base.implementerProfiles, mechanical: 0 } } })).toThrow(/invalid report/);
|
|
73
|
+
});
|
|
21
74
|
it('preserves the distinct unsupported plan state and bounded validator diagnostic', async () => {
|
|
22
75
|
const report = await (0, admission_1.admitPlan)({ plan: { state: 'unsupported', schema: 'compact-slices/v9', diagnostics: [{ code: 'PLAN_UNSUPPORTED_SCHEMA', message: `future\u001b${'x'.repeat(5000)}` }] }, provider: 'codex', cwd: process.cwd() });
|
|
23
76
|
expect(report).toMatchObject({ state: 'blocked', planState: 'unsupported', currentness: 'not-checked', sensors: 'not-required' });
|