agentic-workflow-manager 9.11.11 → 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 (80) 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 -12
  7. package/dist/src/commands/preflight/checks.js +18 -0
  8. package/dist/src/commands/watch/apply.js +71 -5
  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 +125 -16
  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 +117 -3
  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 +12 -5
  44. package/dist/tests/commands/job/routing.test.js +2 -2
  45. package/dist/tests/commands/model-policy/claude-hook-flow.test.js +104 -0
  46. package/dist/tests/commands/model-policy/index.test.js +179 -0
  47. package/dist/tests/commands/plan/index.test.js +2 -2
  48. package/dist/tests/commands/preflight/preflight.test.js +65 -0
  49. package/dist/tests/commands/watch/apply.test.js +116 -10
  50. package/dist/tests/commands/watch/dispatch-routing-identity.test.js +23 -0
  51. package/dist/tests/core/admission/index.test.js +21 -0
  52. package/dist/tests/core/model-policy/capabilities-v2.test.js +42 -0
  53. package/dist/tests/core/model-policy/claude-hook-events.test.js +40 -0
  54. package/dist/tests/core/model-policy/event-store-claude.test.js +64 -0
  55. package/dist/tests/core/model-policy/event-store.test.js +151 -0
  56. package/dist/tests/core/model-policy/hook-diagnostics.test.js +34 -0
  57. package/dist/tests/core/model-policy/journal.test.js +165 -12
  58. package/dist/tests/core/model-policy/local-claude-scope.test.js +31 -0
  59. package/dist/tests/core/model-policy/machine-key.test.js +38 -0
  60. package/dist/tests/core/model-policy/native-claude-agent-definition.test.js +31 -0
  61. package/dist/tests/core/model-policy/native-claude-config.test.js +53 -0
  62. package/dist/tests/core/model-policy/native-claude-machine.test.js +18 -0
  63. package/dist/tests/core/model-policy/native-claude-transcript.test.js +45 -0
  64. package/dist/tests/core/model-policy/native-claude.test.js +21 -0
  65. package/dist/tests/core/model-policy/native-codex-machine.test.js +34 -0
  66. package/dist/tests/core/model-policy/native-codex-rollout.test.js +44 -0
  67. package/dist/tests/core/model-policy/native-codex.test.js +133 -0
  68. package/dist/tests/core/model-policy/native-routing-observe.test.js +60 -0
  69. package/dist/tests/core/model-policy/native-routing-proof.test.js +30 -0
  70. package/dist/tests/core/model-policy/native-runtime.test.js +14 -0
  71. package/dist/tests/core/model-policy/resolve-event.test.js +65 -0
  72. package/dist/tests/core/model-policy/resolve.test.js +17 -0
  73. package/dist/tests/core/model-policy/setup-readiness.test.js +83 -0
  74. package/dist/tests/helpers/routing-approval.js +14 -0
  75. package/dist/tests/providers/index.test.js +1 -1
  76. package/package.json +2 -2
  77. package/prebuilds/darwin-arm64/secure_fs.node +0 -0
  78. package/prebuilds/darwin-x64/secure_fs.node +0 -0
  79. package/prebuilds/win32-arm64/secure_fs.node +0 -0
  80. package/prebuilds/win32-x64/secure_fs.node +0 -0
@@ -23,6 +23,8 @@ const store_2 = require("../../core/model-policy/store");
23
23
  const capabilities_1 = require("../../core/model-policy/capabilities");
24
24
  const resolve_1 = require("../../core/model-policy/resolve");
25
25
  const journal_1 = require("../../core/model-policy/journal");
26
+ const event_store_1 = require("../../core/model-policy/event-store");
27
+ const local_event_scope_1 = require("../../core/model-policy/local-event-scope");
26
28
  const SUPPORTED_SCHEMA = 'compact-slices/v1, compact-slices/v2';
27
29
  const MAX_PATH_LENGTH = 4096;
28
30
  const MAX_DIAGNOSTICS = 20;
@@ -145,7 +147,7 @@ function registerPlanCommand(program, deps = { validatePlanFile: validate_1.vali
145
147
  throw new Error('program must be a Commander command');
146
148
  assertDependencies(deps);
147
149
  const plan = program.command('plan').description('inspect plan contracts');
148
- plan.command('resolve <plan-path>').requiredOption('--provider <target>').requiredOption('--runtime-kind <kind>').requiredOption('--runtime-version <version>').requiredOption('--account-scope-digest <sha>').requiredOption('--role <role>').option('--opt-in-v1').option('--slice <id>').option('--lineage <id>').option('--cwd <path>').option('--json').action((planPath, options) => {
150
+ plan.command('resolve <plan-path>').requiredOption('--provider <target>').requiredOption('--runtime-kind <kind>').requiredOption('--runtime-version <version>').requiredOption('--account-scope-digest <sha>').requiredOption('--role <role>').option('--opt-in-v1').option('--slice <id>').option('--lineage <id>').option('--cwd <path>').option('--json').action(async (planPath, options) => {
149
151
  assertText(planPath, 'plan path');
150
152
  for (const [value, label] of [[options.provider, '--provider'], [options.runtimeKind, '--runtime-kind'], [options.runtimeVersion, '--runtime-version'], [options.accountScopeDigest, '--account-scope-digest'], [options.role, '--role']])
151
153
  assertText(value, label);
@@ -184,11 +186,31 @@ function registerPlanCommand(program, deps = { validatePlanFile: validate_1.vali
184
186
  if (!roles.includes(options.role))
185
187
  throw new Error('--role is invalid');
186
188
  const runtime = (0, capabilities_1.validateRuntimeKey)({ target: options.provider, kind: options.runtimeKind, version: options.runtimeVersion, accountScopeDigest: options.accountScopeDigest });
189
+ let eventFacts;
190
+ if (report.schema === 'compact-slices/v2' && (runtime.target === 'codex' || runtime.target === 'claude-code')) {
191
+ const stored = (deps.readStoredEventReceipt ?? event_store_1.readStoredEventReceipt)(runtime);
192
+ if (stored.state === 'invalid') {
193
+ process.stdout.write(`${JSON.stringify({ state: 'blocked', diagnostics: [{ code: 'ROUTING_CAPABILITY_INVALID', message: 'Native event receipt is invalid.' }] })}\n`);
194
+ process.exitCode = 2;
195
+ return;
196
+ }
197
+ if (stored.state === 'present') {
198
+ const local = await (runtime.target === 'codex' && deps.queryLocalCodexScope ? deps.queryLocalCodexScope(path_1.default.resolve(cwd), runtime.kind) : (0, local_event_scope_1.queryLocalEventScope)(path_1.default.resolve(cwd), runtime.target, runtime.kind));
199
+ if (local.state !== 'current' || JSON.stringify(local.scope.runtime) !== JSON.stringify(runtime)) {
200
+ const reason = local.state === 'unverified' ? local.reason : 'RUNTIME_IDENTITY_MISMATCH';
201
+ process.stdout.write(`${JSON.stringify({ state: 'blocked', diagnostics: [{ code: `ROUTING_${reason}`, message: `Current local ${runtime.target} scope cannot be verified (${reason}); run awm model-policy setup --provider ${runtime.target} --json.` }] })}\n`);
202
+ process.exitCode = 2;
203
+ return;
204
+ }
205
+ eventFacts = { eventReceipt: stored.receipt, eventScope: local.scope };
206
+ }
207
+ }
208
+ const circuitIncidents = report.schema === 'compact-slices/v2' ? journalObservation(cwd).journalState?.routingIncidents : undefined;
187
209
  const result = report.schema === 'compact-slices/v1' && !options.optInV1 ? (0, resolve_1.resolveDispatch)({ plan: report, role: options.role, policy: undefined, capabilities: undefined, runtime, now: new Date(), optInV1: false }) : (() => {
188
210
  const policy = (deps.readEffectivePolicy ?? store_2.readEffectivePolicy)(cwd);
189
- const capabilities = (deps.readCapabilities ?? capabilities_1.readCapabilities)(runtime, new Date());
211
+ const capabilities = eventFacts ? { state: 'absent' } : (deps.readCapabilities ?? capabilities_1.readCapabilities)(runtime, new Date());
190
212
  if (!options.lineage) {
191
- const first = (0, resolve_1.resolveDispatch)({ plan: report, role: options.role, sliceId: options.slice, policy: policy.state === 'approved' ? policy.policy : undefined, capabilities: capabilities.state === 'current' ? capabilities.receipt : undefined, runtime, now: new Date(), optInV1: options.optInV1 === true });
213
+ const first = (0, resolve_1.resolveDispatch)({ plan: report, role: options.role, sliceId: options.slice, policy: policy.state === 'approved' ? policy.policy : undefined, capabilities: capabilities.state === 'current' ? capabilities.receipt : undefined, ...eventFacts, circuitIncidents, runtime, now: new Date(), optInV1: options.optInV1 === true });
192
214
  // The consumer forwards THIS envelope to `job routing-reserve`, which
193
215
  // is what creates the lineage the --lineage escalation path below
194
216
  // then reads. Emitting it only there made the first attempt of any
@@ -204,18 +226,15 @@ function registerPlanCommand(program, deps = { validatePlanFile: validate_1.vali
204
226
  const requestedProfile = options.role === 'implementer' ? slice?.implementerProfile : 'full';
205
227
  if (requestedProfile === undefined)
206
228
  return first;
207
- return { ...first, envelope: { schema: 'routing-envelope/v1', runtime, role: options.role, planDigest: report.planDigest, executionDigest: report.executionDigest, ...(options.slice === undefined ? {} : { sliceId: options.slice }), requestedProfile, effectiveProfile: first.effectiveProfile, resolved: first.selection, policyDigest: first.policyDigest, capabilityDigest: first.capabilityDigest, outcome: first.outcome, unavailableEvidence: first.unavailableEvidence } };
229
+ return { ...first, envelope: { schema: 'routing-envelope/v1', runtime, role: options.role, planDigest: report.planDigest, executionDigest: report.executionDigest, ...(options.slice === undefined ? {} : { sliceId: options.slice }), requestedProfile, effectiveProfile: first.effectiveProfile, resolved: first.selection, policyDigest: first.policyDigest, capabilityDigest: first.capabilityDigest, outcome: first.outcome, unavailableEvidence: first.unavailableEvidence, ...(first.nativeAgentType ? { nativeAgentType: first.nativeAgentType } : {}) } };
208
230
  }
209
231
  const state = journalObservation(cwd).journalState;
210
232
  const lineage = state.implementationLineages.find(candidate => candidate.id === options.lineage);
211
233
  const next = (0, journal_1.resolveLineageEscalation)(state, options.lineage, lineage.initialProfile);
212
- const resolved = (0, resolve_1.resolveSelection)({ role: 'implementer', requestedProfile: next.profile, policy: policy.state === 'approved' ? policy.policy : undefined, capabilities: capabilities.state === 'current' ? capabilities.receipt : undefined, runtime, now: new Date() });
234
+ const resolved = (0, resolve_1.resolveEscalatedSelection)({ role: 'implementer', requestedProfile: next.profile, expectedEffort: next.effort, policy: policy.state === 'approved' ? policy.policy : undefined, capabilities: capabilities.state === 'current' ? capabilities.receipt : undefined, ...eventFacts, circuitIncidents, runtime, now: new Date() });
213
235
  if (resolved.state === 'blocked')
214
236
  return resolved;
215
- const highRequiresFull = next.effort !== 'high' || (policy.state === 'approved' && (() => { const full = policy.policy.content.mappings.find(row => row.target === runtime.target && row.runtimeKind === runtime.kind)?.fullCapability; return full?.selector.kind === resolved.selection.selector.kind && full.selector.id === resolved.selection.selector.id && full.effort.kind === 'explicit' && full.effort.value === 'high'; })());
216
- if (resolved.selection.effort.kind !== 'explicit' || resolved.selection.effort.value !== next.effort || !highRequiresFull)
217
- return { state: 'blocked', diagnostics: [{ code: 'ROUTING_ESCALATION_EFFORT_UNAVAILABLE', message: 'The approved selected effort does not match the next lineage escalation.' }] };
218
- return { ...resolved, envelope: { schema: 'routing-envelope/v1', runtime, role: 'implementer', planDigest: report.planDigest, executionDigest: report.executionDigest, sliceId: lineage.sliceId, requestedProfile: lineage.initialProfile, effectiveProfile: next.profile, resolved: resolved.selection, policyDigest: resolved.policyDigest, capabilityDigest: resolved.capabilityDigest, outcome: resolved.outcome, unavailableEvidence: resolved.unavailableEvidence }, custodyHandoff: { kind: 'routing-reserve', obligationId: lineage.obligationId, lineageId: lineage.id } };
237
+ return { ...resolved, envelope: { schema: 'routing-envelope/v1', runtime, role: 'implementer', planDigest: report.planDigest, executionDigest: report.executionDigest, sliceId: lineage.sliceId, requestedProfile: lineage.initialProfile, effectiveProfile: resolved.effectiveProfile, resolved: resolved.selection, policyDigest: resolved.policyDigest, capabilityDigest: resolved.capabilityDigest, outcome: resolved.outcome, unavailableEvidence: resolved.unavailableEvidence, ...(resolved.nativeAgentType ? { nativeAgentType: resolved.nativeAgentType } : {}) }, custodyHandoff: { kind: 'routing-reserve', obligationId: lineage.obligationId, lineageId: lineage.id } };
219
238
  })();
220
239
  process.stdout.write(options.json ? `${JSON.stringify(result)}\n` : `Plan routing: ${result.state}\n`);
221
240
  if (result.state === 'blocked')
@@ -293,9 +312,31 @@ function registerPlanCommand(program, deps = { validatePlanFile: validate_1.vali
293
312
  process.exitCode = 2;
294
313
  return;
295
314
  }
296
- const readRouting = () => { if (!options.runtimeKind || !options.runtimeVersion || !options.accountScopeDigest)
297
- return undefined; const runtime = (0, capabilities_1.validateRuntimeKey)({ target: options.provider, kind: options.runtimeKind, version: options.runtimeVersion, accountScopeDigest: options.accountScopeDigest }); const policy = (deps.readEffectivePolicy ?? store_2.readEffectivePolicy)(options.cwd); const at = deps.routingNow?.() ?? new Date(); if (!(at instanceof Date) || !Number.isFinite(at.getTime()))
298
- throw new Error('routingNow must return a finite Date'); const capabilities = (deps.readCapabilities ?? capabilities_1.readCapabilities)(runtime, at); return { runtime, policy: policy.state === 'approved' ? policy.policy : undefined, capabilities: capabilities.state === 'current' ? capabilities.receipt : undefined, now: at }; };
315
+ const readRouting = async () => {
316
+ if (!options.runtimeKind || !options.runtimeVersion || !options.accountScopeDigest)
317
+ return undefined;
318
+ const runtime = (0, capabilities_1.validateRuntimeKey)({ target: options.provider, kind: options.runtimeKind, version: options.runtimeVersion, accountScopeDigest: options.accountScopeDigest });
319
+ const policy = (deps.readEffectivePolicy ?? store_2.readEffectivePolicy)(options.cwd);
320
+ const at = deps.routingNow?.() ?? new Date();
321
+ if (!(at instanceof Date) || !Number.isFinite(at.getTime()))
322
+ throw new Error('routingNow must return a finite Date');
323
+ const base = { runtime, policy: policy.state === 'approved' ? policy.policy : undefined, now: at };
324
+ if (runtime.target === 'codex' || runtime.target === 'claude-code') {
325
+ const stored = (deps.readStoredEventReceipt ?? event_store_1.readStoredEventReceipt)(runtime);
326
+ if (stored.state === 'invalid')
327
+ return { ...base, eventIssue: { code: 'ROUTING_CAPABILITY_INVALID', message: 'Sealed native event receipt is invalid.' } };
328
+ if (stored.state === 'present') {
329
+ const local = await (runtime.target === 'codex' && deps.queryLocalCodexScope ? deps.queryLocalCodexScope(path_1.default.resolve(options.cwd), runtime.kind) : (0, local_event_scope_1.queryLocalEventScope)(path_1.default.resolve(options.cwd), runtime.target, runtime.kind));
330
+ if (local.state !== 'current' || JSON.stringify(local.scope.runtime) !== JSON.stringify(runtime)) {
331
+ const reason = local.state === 'unverified' ? local.reason : 'RUNTIME_IDENTITY_MISMATCH';
332
+ return { ...base, eventIssue: { code: `ROUTING_${reason}`, message: `Local ${runtime.target} scope cannot be verified (${reason}); run awm model-policy setup --provider ${runtime.target} --json.` } };
333
+ }
334
+ return { ...base, eventReceipt: stored.receipt, eventScope: local.scope };
335
+ }
336
+ }
337
+ const capabilities = (deps.readCapabilities ?? capabilities_1.readCapabilities)(runtime, at);
338
+ return { ...base, capabilities: capabilities.state === 'current' ? capabilities.receipt : undefined };
339
+ };
299
340
  if (options.controllerAutonomy !== undefined && !(0, adapter_1.isControllerAutonomy)(options.controllerAutonomy))
300
341
  throw new Error(`--controller-autonomy is invalid: ${options.controllerAutonomy} (valid: ${adapter_1.CONTROLLER_AUTONOMIES.join(', ')})`);
301
342
  const report = await (0, registry_contracts_1.admitRegistryPlan)({ plan: planReport, provider: options.provider, cwd: options.cwd, enabledAgents, executionMode, planPath: normalizedPlanPath, ...journal, requireCurrent: options.requireCurrent === true, verifySensors: options.verifySensors === true, ...(options.controllerAutonomy === undefined ? {} : { controllerAutonomy: options.controllerAutonomy }) }, { admitPlan: admission, listRegistries: registryInventory, checkCurrentness: currentnessCheck, runSensors: sensorRun, readRouting });
@@ -17,7 +17,24 @@ const registries_1 = require("../../core/registries");
17
17
  const inspect_1 = require("../../core/context-kernel/inspect");
18
18
  const registries_2 = require("../../core/registries");
19
19
  const check_1 = require("../../core/currentness/check");
20
+ const store_1 = require("../../core/model-policy/store");
21
+ const setup_readiness_1 = require("../../core/model-policy/setup-readiness");
20
22
  const MANIFEST = path_1.default.join('.awm', 'sensors.json');
23
+ function checkRoutingSetup(cwd) {
24
+ const guidance = (0, setup_readiness_1.routingSetupGuidance)((0, store_1.readEffectivePolicy)(cwd));
25
+ if (guidance.length === 0)
26
+ return [];
27
+ const invalid = guidance.find(item => item.state === 'policy-invalid');
28
+ if (invalid?.state === 'policy-invalid')
29
+ return [{ id: 'routing-setup', ok: false, advisory: true, detail: 'approved routing policy is invalid', remedy: 'repair the model policy before using routed subagents' }];
30
+ const targets = guidance.filter((item) => item.state === 'needs-evidence');
31
+ if (targets.length === 0)
32
+ return [{ id: 'routing-setup', ok: true, advisory: true,
33
+ detail: 'sealed routing selections are covered locally; doctor/preflight do not verify current runtime/account/config scope (checked at routed dispatch)' }];
34
+ return [{ id: 'routing-setup', ok: false, advisory: true,
35
+ detail: `routing machine evidence needs a native check for ${targets.map(item => `${item.target}/${item.runtimeKind}`).join(', ')}`,
36
+ remedy: targets[0].command }];
37
+ }
21
38
  /**
22
39
  * The agent needs project context delivered every session. A repo with neither file
23
40
  * hands every agent — and every teammate's agent — a blank slate.
@@ -472,6 +489,7 @@ async function preflight(cwd = process.cwd(), opts = {}) {
472
489
  ...(opts.verifySensors === true ? [await checkSensorExecution(cwd)] : []),
473
490
  // Strict mode is the only path that contacts authoritative npm/Git sources.
474
491
  ...(opts.requireCurrent === true ? [checkCompatibility()] : []),
492
+ ...checkRoutingSetup(cwd),
475
493
  // Runs unconditionally — orthogonal to sensor configuration entirely, this is
476
494
  // about PR/MR tooling, not sensors.
477
495
  checkHost(cwd),
@@ -20,7 +20,30 @@ const redact_1 = require("../../core/journal/redact");
20
20
  const git_1 = require("../../core/tracks/git");
21
21
  const types_1 = require("../../core/journal/types");
22
22
  const journal_1 = require("../../core/model-policy/journal");
23
+ const store_2 = require("../../core/model-policy/store");
24
+ const capabilities_1 = require("../../core/model-policy/capabilities");
25
+ const event_store_1 = require("../../core/model-policy/event-store");
26
+ const capabilities_v2_1 = require("../../core/model-policy/capabilities-v2");
27
+ const machine_key_1 = require("../../core/model-policy/machine-key");
28
+ const paths_2 = require("../../core/paths");
29
+ const native_routing_proof_1 = require("../../core/model-policy/native-routing-proof");
30
+ const selection_policy_digest_1 = require("../../core/model-policy/selection-policy-digest");
23
31
  function now() { return new Date().toISOString(); }
32
+ function currentNativeAttempt(repoRoot, envelope, eventScope, at) {
33
+ if (!eventScope || JSON.stringify(eventScope.runtime) !== JSON.stringify(envelope.runtime))
34
+ return false;
35
+ try {
36
+ const stored = (0, event_store_1.readStoredEventReceipt)((0, capabilities_1.validateRuntimeKey)(envelope.runtime));
37
+ const approved = (0, store_2.readEffectivePolicy)(repoRoot);
38
+ if (stored.state !== 'present' || approved.state !== 'approved' || approved.policy.contentDigest !== envelope.policyDigest)
39
+ return false;
40
+ const mapping = approved.policy.content.mappings.find(row => row.target === envelope.runtime.target && row.runtimeKind === envelope.runtime.kind);
41
+ return !!mapping && (0, capabilities_v2_1.evaluateEventReceipt)(stored.receipt, eventScope, envelope.resolved, (0, selection_policy_digest_1.selectionPolicyDigest)(mapping, envelope.resolved), at).state === 'current';
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ }
24
47
  const VERIFICATION_KINDS = ['test', 'lint', 'sensors', 'review', 'qa', 'interlock', 'track-integration'];
25
48
  function verificationItems(value, field) {
26
49
  if (!Array.isArray(value) || !value.every((item) => typeof item === 'object' && item !== null
@@ -105,7 +128,7 @@ function registerTrackIntegrationItems(state) {
105
128
  function trackWorktreePath(repoRoot, trackId) {
106
129
  return path_1.default.join(path_1.default.dirname(repoRoot), `${path_1.default.basename(repoRoot)}.track-${trackId}`);
107
130
  }
108
- function applyRequestToState(s, env, digest, repoRoot) {
131
+ function applyRequestToState(s, env, digest, repoRoot, eventScope) {
109
132
  const base = { requestId: env.requestId, idempotencyKey: env.idempotencyKey, payloadDigest: digest };
110
133
  if (env.kind === 'controller-heartbeat') {
111
134
  s.controllerHeartbeatAt = now();
@@ -116,7 +139,21 @@ function applyRequestToState(s, env, digest, repoRoot) {
116
139
  const p = env.payload;
117
140
  if (typeof p.obligationId !== 'string' || typeof p.lineageId !== 'string' || !(0, types_1.isRoutingEnvelope)(p.envelope) || typeof p.fingerprint !== 'string' || (p.at !== undefined && typeof p.at !== 'string'))
118
141
  throw new Error('routing-reserve requiere payload estricto');
119
- const reserved = (0, journal_1.reserveRoutingAttempt)(s, { obligationId: p.obligationId, lineageId: p.lineageId, envelope: p.envelope, fingerprint: p.fingerprint }, p.at ?? now());
142
+ const envelope = p.envelope;
143
+ const reserved = (0, journal_1.reserveRoutingAttempt)(s, { obligationId: p.obligationId, lineageId: p.lineageId, envelope, fingerprint: p.fingerprint, approval: () => {
144
+ const checkedAt = new Date();
145
+ const policy = (0, store_2.readEffectivePolicy)(repoRoot);
146
+ const event = (0, event_store_1.readStoredEventReceipt)((0, capabilities_1.validateRuntimeKey)(envelope.runtime));
147
+ if (event.state === 'invalid')
148
+ throw new Error('routing native event receipt is invalid');
149
+ if (event.state === 'present') {
150
+ if (!eventScope)
151
+ throw new Error('routing native event scope is unverified');
152
+ return { checkedAt, policy: policy.state === 'approved' ? policy.policy : undefined, eventReceipt: event.receipt, eventScope };
153
+ }
154
+ const capabilities = (0, capabilities_1.readCapabilities)((0, capabilities_1.validateRuntimeKey)(envelope.runtime), checkedAt);
155
+ return { checkedAt, policy: policy.state === 'approved' ? policy.policy : undefined, capabilities: capabilities.state === 'current' ? capabilities.receipt : undefined };
156
+ } }, p.at ?? now());
120
157
  Object.assign(s, reserved.state);
121
158
  (0, requests_1.applyOutcome)(s, { ...base, outcome: 'applied', resultRef: reserved.attemptId });
122
159
  return;
@@ -125,7 +162,36 @@ function applyRequestToState(s, env, digest, repoRoot) {
125
162
  const p = env.payload;
126
163
  if (typeof p.attemptId !== 'string' || typeof p.nativeAgentId !== 'string' || (p.observed !== undefined && !(0, types_1.isRoutingSelection)(p.observed)) || (p.unavailableReason !== undefined && typeof p.unavailableReason !== 'string') || (p.at !== undefined && typeof p.at !== 'string'))
127
164
  throw new Error('routing-observe requiere payload estricto');
128
- const observed = (0, journal_1.observeRoutingAttempt)(s, { attemptId: p.attemptId, nativeAgentId: p.nativeAgentId, ...(p.observed === undefined ? {} : { observed: p.observed }), ...(p.unavailableReason === undefined ? {} : { unavailableReason: p.unavailableReason }) }, p.at ?? now());
165
+ const attempt = s.routingAttempts?.find(item => item.id === p.attemptId);
166
+ if (!attempt)
167
+ throw new Error('routing-observe attempt is unknown');
168
+ let key = null;
169
+ if (attempt.nativeEvidenceRequired) {
170
+ try {
171
+ key = (0, machine_key_1.readMachineKey)((0, paths_2.awmHome)());
172
+ }
173
+ catch { /* missing/unsafe machine key is recorded as PROVENANCE_MISSING */ }
174
+ }
175
+ const proof = p.nativeProof;
176
+ const nativeProof = proof;
177
+ const checkedAt = new Date();
178
+ const validProof = attempt.nativeEvidenceRequired && key && attempt.reservedAt
179
+ ? (0, native_routing_proof_1.verifyNativeRoutingProof)(proof, { attemptId: p.attemptId, nativeAgentId: p.nativeAgentId,
180
+ reservedAt: attempt.reservedAt, selection: attempt.envelope.resolved }, key, checkedAt)
181
+ && checkedAt.getTime() - Date.parse(nativeProof.observedAt) <= 15 * 60_000
182
+ && currentNativeAttempt(repoRoot, attempt.envelope, eventScope, checkedAt)
183
+ && (attempt.envelope.runtime.target === 'codex' ? nativeProof?.source === 'codex-turn-context' : nativeProof?.source === 'claude-assistant-transcript')
184
+ && p.observed !== undefined && JSON.stringify(p.observed) === JSON.stringify(nativeProof?.selection)
185
+ && !s.routingAttempts?.some(item => item.id !== attempt.id && item.nativeEvidenceRequired
186
+ && (item.nativeAgentId === p.nativeAgentId || item.nativeEventDigest === nativeProof?.eventDigest))
187
+ : false;
188
+ const observed = (0, journal_1.observeRoutingAttempt)(s, { attemptId: p.attemptId, nativeAgentId: p.nativeAgentId,
189
+ ...(validProof ? { observed: nativeProof.selection, nativeEventDigest: nativeProof.eventDigest,
190
+ ...(nativeProof.actualModel === undefined ? {} : { observedBackendModel: nativeProof.actualModel }) }
191
+ : attempt.nativeEvidenceRequired ? {} : p.observed === undefined ? {} : { observed: p.observed }),
192
+ ...(attempt.nativeEvidenceRequired
193
+ ? validProof ? {} : { unavailableReason: p.unavailableReason === 'PROVIDER_REJECTED' ? 'PROVIDER_REJECTED' : 'PROVENANCE_MISSING' }
194
+ : p.unavailableReason === undefined ? {} : { unavailableReason: p.unavailableReason }) }, p.at ?? now());
129
195
  Object.assign(s, observed);
130
196
  (0, requests_1.applyOutcome)(s, { ...base, outcome: 'applied', resultRef: p.attemptId });
131
197
  return;
@@ -533,7 +599,7 @@ function applyRequestToState(s, env, digest, repoRoot) {
533
599
  /** Consume TODAS las requests pendientes en orden. ORDEN CRITICO (R1.3,
534
600
  * bloqueador 4): (1) mutar estado, (2) writeJournal, (3) borrar archivos,
535
601
  * (4) fsync del directorio. Solo el supervisor llama esto (single-writer). */
536
- function consumePendingRequests(repoRoot, branch, activeToken) {
602
+ function consumePendingRequests(repoRoot, branch, activeToken, eventScope) {
537
603
  const r = (0, store_1.readJournal)(repoRoot, branch);
538
604
  if (r.corrupt || r.state === null)
539
605
  throw new Error('journal corrupto: el supervisor no opera sobre corrupcion (R1.6)');
@@ -591,7 +657,7 @@ function consumePendingRequests(repoRoot, branch, activeToken) {
591
657
  // nunca deja un estado parcialmente contaminado que luego no se
592
658
  // pueda serializar o reintentar.
593
659
  const candidate = structuredClone(s);
594
- applyRequestToState(candidate, env, digest, repoRoot);
660
+ applyRequestToState(candidate, env, digest, repoRoot, eventScope);
595
661
  s = candidate;
596
662
  applied++;
597
663
  stateTouched = true;
@@ -15,6 +15,9 @@ const registry_contracts_1 = require("../../core/admission/registry-contracts");
15
15
  const config_1 = require("../../utils/config");
16
16
  const store_2 = require("../../core/model-policy/store");
17
17
  const capabilities_1 = require("../../core/model-policy/capabilities");
18
+ const event_store_1 = require("../../core/model-policy/event-store");
19
+ const local_event_scope_1 = require("../../core/model-policy/local-event-scope");
20
+ const journal_1 = require("../../core/model-policy/journal");
18
21
  const adapter_1 = require("../../core/journal/adapter");
19
22
  const process_1 = require("../../core/journal/process");
20
23
  const gate_1 = require("../job/gate");
@@ -56,10 +59,39 @@ function defaultDispatchAdmission(repoRoot, branch, provider, identity, deps = {
56
59
  }
57
60
  const plan = (0, validate_1.validatePlanFile)(binding.path, repoRoot);
58
61
  const preferences = (0, config_1.readPreferences)();
62
+ let routing;
63
+ if ((provider === 'codex' || provider === 'claude-code') && identity) {
64
+ const runtime = (0, capabilities_1.validateRuntimeKey)({ target: provider, kind: identity.kind, version: identity.version, accountScopeDigest: identity.accountScopeDigest });
65
+ const stored = (deps.readStoredEventReceipt ?? event_store_1.readStoredEventReceipt)(runtime);
66
+ if (stored.state === 'absent')
67
+ routing = routingFacts(provider, identity, repoRoot, deps);
68
+ else {
69
+ const at = deps.now?.() ?? new Date();
70
+ if (!(at instanceof Date) || !Number.isFinite(at.getTime()))
71
+ throw new Error('routing observation time must be a finite Date');
72
+ const policy = (deps.readEffectivePolicy ?? store_2.readEffectivePolicy)(repoRoot);
73
+ routing = { runtime, policy: policy.state === 'approved' ? policy.policy : undefined, now: at };
74
+ if (stored.state === 'invalid')
75
+ routing.eventIssue = { code: 'ROUTING_CAPABILITY_INVALID', message: `Sealed native event receipt is invalid; run awm model-policy setup --provider ${provider}.` };
76
+ else {
77
+ const local = await (provider === 'codex' && deps.queryLocalCodexScope ? deps.queryLocalCodexScope(repoRoot, identity.kind) : (0, local_event_scope_1.queryLocalEventScope)(repoRoot, provider, identity.kind));
78
+ if (local.state === 'current' && JSON.stringify(local.scope.runtime) === JSON.stringify(runtime)) {
79
+ routing.eventReceipt = stored.receipt;
80
+ routing.eventScope = local.scope;
81
+ }
82
+ else {
83
+ const reason = local.state === 'unverified' ? local.reason : 'RUNTIME_IDENTITY_MISMATCH';
84
+ routing.eventIssue = { code: `ROUTING_${reason}`, message: `${provider} runtime/account scope changed or cannot be verified (${reason}); run awm model-policy setup --provider ${provider} --json.` };
85
+ }
86
+ }
87
+ }
88
+ }
89
+ else
90
+ routing = routingFacts(provider, identity, repoRoot, deps);
59
91
  return (deps.admit ?? registry_contracts_1.admitRegistryPlan)({ plan, provider, cwd: repoRoot, enabledAgents: preferences.enabledAgents,
60
92
  executionMode: 'desatendido', requireCurrent: true, verifySensors: true,
61
93
  journalState: observed.state, journalCorrupt: observed.corrupt, planPath: binding.path,
62
- routing: routingFacts(provider, identity, repoRoot, deps),
94
+ routing,
63
95
  controllerAutonomy: autonomy });
64
96
  };
65
97
  }
@@ -414,7 +446,31 @@ class Supervisor {
414
446
  if (r0.corrupt || r0.state === null)
415
447
  throw new Error('journal corrupto: el supervisor no opera sobre corrupcion (R1.6)');
416
448
  const gen = (0, generations_1.activeGeneration)(r0.state);
417
- (0, apply_1.consumePendingRequests)(this.repoRoot, this.branch, gen?.token ?? null);
449
+ let eventScope;
450
+ if ((this.cfg.provider === 'codex' || this.cfg.provider === 'claude-code') && this.cfg.routingIdentity) {
451
+ const asserted = (0, capabilities_1.validateRuntimeKey)({ target: this.cfg.provider, ...this.cfg.routingIdentity });
452
+ const event = (0, event_store_1.readStoredEventReceipt)(asserted);
453
+ if (event.state === 'present') {
454
+ const local = await (0, local_event_scope_1.queryLocalEventScope)(this.repoRoot, asserted.target, asserted.kind);
455
+ if (local.state === 'current' && JSON.stringify(local.scope.runtime) === JSON.stringify(asserted))
456
+ eventScope = local.scope;
457
+ }
458
+ }
459
+ (0, apply_1.consumePendingRequests)(this.repoRoot, this.branch, gen?.token ?? null, eventScope);
460
+ const alertRead = (0, store_1.readJournal)(this.repoRoot, this.branch);
461
+ if (alertRead.corrupt || !alertRead.state)
462
+ throw new Error('routing alert cannot read durable journal');
463
+ const pendingAlerts = alertRead.state.routingIncidents?.filter(item => item.alertState === 'pending') ?? [];
464
+ if (pendingAlerts.length > 0) {
465
+ for (const incident of pendingAlerts) {
466
+ const alert = { id: incident.id, reasonCode: incident.reasonCode, selection: incident.selection,
467
+ fallbackCount: incident.fallbackCount, remedy: `awm model-policy setup --provider ${incident.target} --json` };
468
+ process.stderr.write(`AWM routing alert ${JSON.stringify(alert)}\n`);
469
+ (0, store_1.appendEvent)(this.repoRoot, this.branch, { kind: 'routing-incident', ...alert });
470
+ incident.alertState = 'reported';
471
+ }
472
+ (0, store_1.writeJournal)(this.repoRoot, this.branch, alertRead.state);
473
+ }
418
474
  // P1/P2 (R4.1-R4.10): a lo sumo un side effect de bootstrap de tracks
419
475
  // por tick, ANTES de tocar jobs — mientras la cohorte está PREPARING,
420
476
  // ningún job de track se despacha (eso lo maneja `runnerTick` con los
@@ -674,8 +730,12 @@ async function runSupervisorLoop(repoRoot, branch, cfg, spawner = (0, runner_1.d
674
730
  // 'frozen' (Task 10): mismo camino de salida que 'complete' —
675
731
  // drenar ownership y liberar el lock, el track ya cumplió su
676
732
  // freeze y no debe seguir despachando ni corriendo su loop.
677
- if (out === 'complete' || out === 'frozen')
733
+ if (out === 'complete' || out === 'frozen') {
734
+ const finalState = (0, store_1.readJournal)(repoRoot, branch);
735
+ if (!finalState.corrupt && finalState.state?.routingIncidents?.length)
736
+ process.stderr.write(`AWM final routing summary ${JSON.stringify((0, journal_1.routingReport)(finalState.state))}\n`);
678
737
  break;
738
+ }
679
739
  // 'custody': NO liberar lock, NO salir — seguir auditando (R4.5)
680
740
  await new Promise((resolve) => {
681
741
  let settled = false;
@@ -246,20 +246,24 @@ async function admitPlan(input) {
246
246
  : diagnostic('ADMISSION_CONTROLLER_AUTONOMY_REQUIRED', `Unattended dispatch on ${provider} requires an explicit controller autonomy posture; without it the controller blocks on its first tool call.`);
247
247
  return blocked(input, [reason], { planDigest: plan.planDigest, provider, executionMode: mode, journal, currentness: input.requireCurrent ? 'current' : 'not-checked', cliCurrentness, sensors: input.verifySensors ? 'pass' : 'not-required', capabilityResolution: resolution });
248
248
  }
249
- return completeAdmission(input, plan, provider, mode, journal, input.requireCurrent ? 'current' : 'not-checked', input.verifySensors ? 'pass' : 'not-required', resolution, cliCurrentness);
249
+ const routing = plan.schema === 'compact-slices/v2' ? input.routing ?? await input.routingReader?.() : input.routing;
250
+ return completeAdmission({ ...input, routing, routingReader: undefined }, plan, provider, mode, journal, input.requireCurrent ? 'current' : 'not-checked', input.verifySensors ? 'pass' : 'not-required', resolution, cliCurrentness);
250
251
  }
251
252
  const capabilities = exports.PROVIDER_EXECUTION_CAPABILITIES[provider];
252
253
  const resolution = { outcome: capabilities.interactiveExecution === 'supported' ? 'native' : 'blocked', provider, capabilities, evidenceVersion: 'r1-v1', diagnostics: [] };
253
254
  if (resolution.outcome === 'blocked')
254
255
  return blocked(input, [diagnostic('ADMISSION_CAPABILITY_UNVERIFIED', `Provider ${provider} has no verified interactive execution capability.`)], { planDigest: plan.planDigest, provider, executionMode: mode, capabilityResolution: resolution });
255
- return completeAdmission(input, plan, provider, mode, 'not-required', input.requireCurrent ? 'current' : 'not-checked', input.verifySensors ? 'pass' : 'not-required', resolution, cliCurrentness);
256
+ const routing = plan.schema === 'compact-slices/v2' ? input.routing ?? await input.routingReader?.() : input.routing;
257
+ return completeAdmission({ ...input, routing, routingReader: undefined }, plan, provider, mode, 'not-required', input.requireCurrent ? 'current' : 'not-checked', input.verifySensors ? 'pass' : 'not-required', resolution, cliCurrentness);
256
258
  }
257
259
  function completeAdmission(input, plan, provider, executionMode, journal, currentness, sensors, capabilityResolution, cliCurrentness = 'not-checked') {
258
260
  if (plan.schema === 'compact-slices/v1')
259
261
  return { state: 'admitted', planState: 'valid', planDigest: plan.planDigest, provider, executionMode, journal, currentness, cliCurrentness, sensors, capabilityResolution, forecast: forecast(plan.manifest.slices.length), diagnostics: [] };
260
- const routing = input.routing ?? input.routingReader?.();
261
- if (!routing?.runtime || !routing.policy || !routing.capabilities)
262
- return blocked(input, [diagnostic('ADMISSION_ROUTING_FACTS_REQUIRED', 'Compact v2 requires an approved policy, current capability receipt, and runtime identity.')], { planDigest: plan.planDigest, provider, executionMode, journal, currentness, cliCurrentness, sensors, capabilityResolution });
262
+ const routing = input.routing;
263
+ if (routing?.eventIssue)
264
+ return blocked(input, [diagnostic(routing.eventIssue.code, routing.eventIssue.message)], { planDigest: plan.planDigest, provider, executionMode, journal, currentness, cliCurrentness, sensors, capabilityResolution });
265
+ if (!routing?.runtime || !routing.policy || (!routing.capabilities && !(routing.eventReceipt && routing.eventScope)))
266
+ return blocked(input, [diagnostic('ADMISSION_ROUTING_FACTS_REQUIRED', 'Compact v2 requires an approved policy, current capability evidence, and runtime identity.')], { planDigest: plan.planDigest, provider, executionMode, journal, currentness, cliCurrentness, sensors, capabilityResolution });
263
267
  let runtime;
264
268
  try {
265
269
  runtime = (0, capabilities_1.validateRuntimeKey)(routing.runtime);
@@ -269,12 +273,22 @@ function completeAdmission(input, plan, provider, executionMode, journal, curren
269
273
  }
270
274
  if (runtime.target !== provider)
271
275
  return blocked(input, [diagnostic('ADMISSION_ROUTING_PROVIDER_MISMATCH', 'Compact v2 routing runtime target must exactly match the admitted provider.')], { planDigest: plan.planDigest, provider, executionMode, journal, currentness, cliCurrentness, sensors, capabilityResolution });
276
+ if (routing.eventReceipt && routing.eventScope && JSON.stringify(runtime) !== JSON.stringify(routing.eventScope.runtime))
277
+ return blocked(input, [diagnostic('ADMISSION_ROUTING_RUNTIME_MISMATCH', 'Event-scoped routing facts do not match the admitted runtime.')], { planDigest: plan.planDigest, provider, executionMode, journal, currentness, cliCurrentness, sensors, capabilityResolution });
272
278
  const now = routing.now ?? new Date();
273
279
  for (const slice of plan.manifest.slices) {
274
- const resolved = (0, resolve_1.resolveSelection)({ role: 'implementer', requestedProfile: slice.implementerProfile, policy: routing.policy, capabilities: routing.capabilities, runtime, now });
280
+ const profile = slice.implementerProfile;
281
+ const resolved = routing.eventReceipt && routing.eventScope
282
+ ? (0, resolve_1.resolveEventWithFallback)({ role: 'implementer', requestedProfile: profile, policy: routing.policy, receipt: routing.eventReceipt, scope: routing.eventScope, now })
283
+ : (0, resolve_1.resolveSelection)({ role: 'implementer', requestedProfile: profile, policy: routing.policy, capabilities: routing.capabilities, runtime, now });
275
284
  if (resolved.state === 'blocked')
276
285
  return blocked(input, resolved.diagnostics, { planDigest: plan.planDigest, provider, executionMode, journal, currentness, cliCurrentness, sensors, capabilityResolution });
277
286
  }
287
+ if (routing.eventReceipt && routing.eventScope) {
288
+ const full = (0, resolve_1.resolveEventSelection)({ role: 'code-quality-reviewer', requestedProfile: 'full', policy: routing.policy, receipt: routing.eventReceipt, scope: routing.eventScope, now });
289
+ if (full.state === 'blocked')
290
+ return blocked(input, full.diagnostics, { planDigest: plan.planDigest, provider, executionMode, journal, currentness, cliCurrentness, sensors, capabilityResolution });
291
+ }
278
292
  return { state: 'admitted', planState: 'valid', planDigest: plan.planDigest, provider, executionMode, journal, currentness, cliCurrentness, sensors, capabilityResolution, forecast: forecast(plan.manifest.slices.length), routingForecast: routingForecast(plan, routing), diagnostics: [] };
279
293
  }
280
294
  // Structural exhaustiveness guard: adding an AgentTarget requires an explicit entry above.
@@ -94,6 +94,8 @@ function isWellFormedState(x) {
94
94
  return false;
95
95
  if (x.routingAttempts !== undefined && (!Array.isArray(x.routingAttempts) || x.routingAttempts.length > 4096 || !x.routingAttempts.every(isWellFormedRoutingAttempt)))
96
96
  return false;
97
+ if (x.routingIncidents !== undefined && (!Array.isArray(x.routingIncidents) || x.routingIncidents.length > 4096 || !x.routingIncidents.every(isWellFormedRoutingIncident)))
98
+ return false;
97
99
  if (x.implementationLineages !== undefined && (!Array.isArray(x.implementationLineages) || x.implementationLineages.length > 4096 || !x.implementationLineages.every(isWellFormedImplementationLineage)))
98
100
  return false;
99
101
  if (!Array.isArray(x.requestProblems) || !x.requestProblems.every(isWellFormedRequestProblem))
@@ -211,17 +213,31 @@ function isWellFormedAppliedRequest(x) {
211
213
  && (x.resultRef === undefined || typeof x.resultRef === 'string');
212
214
  }
213
215
  function isWellFormedRoutingAttempt(x) {
214
- return isObj(x) && Object.keys(x).every(key => ['schema', 'id', 'obligationId', 'lineageId', 'attempt', 'envelope', 'envelopeDigest', 'fingerprint', 'state', 'nativeAgentId', 'observed', 'verdict', 'reasonCode', 'administrativeRepair'].includes(key))
216
+ return isObj(x) && Object.keys(x).every(key => ['schema', 'id', 'obligationId', 'lineageId', 'attempt', 'envelope', 'envelopeDigest', 'fingerprint', 'state', 'reservedAt', 'nativeEvidenceRequired', 'nativeEventDigest', 'nativeAgentId', 'observed', 'observedBackendModel', 'verdict', 'reasonCode', 'administrativeRepair'].includes(key))
215
217
  && x.schema === 'routing-attempt/v1'
216
218
  && typeof x.id === 'string' && typeof x.obligationId === 'string' && typeof x.lineageId === 'string' && Number.isSafeInteger(x.attempt) && x.attempt > 0
217
219
  && typeof x.envelopeDigest === 'string' && /^[a-f0-9]{64}$/.test(x.envelopeDigest) && typeof x.fingerprint === 'string' && /^[a-f0-9]{64}$/.test(x.fingerprint)
218
- && ['reserved', 'active', 'complete', 'blocked', 'unknown'].includes(String(x.state)) && (x.nativeAgentId === undefined || typeof x.nativeAgentId === 'string') && (x.observed === undefined || isRoutingSelection(x.observed)) && (x.verdict === undefined || ['pass', 'fail', 'inconclusive'].includes(String(x.verdict))) && (x.reasonCode === undefined || typeof x.reasonCode === 'string') && (x.administrativeRepair === undefined || x.administrativeRepair === true) && isRoutingEnvelope(x.envelope);
220
+ && ['reserved', 'active', 'complete', 'blocked', 'unknown'].includes(String(x.state)) && (x.reservedAt === undefined || (typeof x.reservedAt === 'string' && Number.isFinite(Date.parse(x.reservedAt)))) && (x.nativeEvidenceRequired === undefined || x.nativeEvidenceRequired === true) && (x.nativeEventDigest === undefined || isDigest(x.nativeEventDigest)) && (x.nativeAgentId === undefined || typeof x.nativeAgentId === 'string') && (x.observed === undefined || isRoutingSelection(x.observed)) && (x.observedBackendModel === undefined || (typeof x.observedBackendModel === 'string' && x.observedBackendModel.length > 0 && x.observedBackendModel.length <= 128)) && (x.verdict === undefined || ['pass', 'fail', 'inconclusive'].includes(String(x.verdict))) && (x.reasonCode === undefined || typeof x.reasonCode === 'string') && (x.administrativeRepair === undefined || x.administrativeRepair === true) && isRoutingEnvelope(x.envelope);
221
+ }
222
+ function isWellFormedRoutingIncident(x) {
223
+ if (!isObj(x) || Object.keys(x).length !== 12 || !Object.keys(x).every(key => ['schema', 'id', 'runStartedAt', 'target', 'selection', 'reasonCode', 'firstAt', 'lastAt', 'affectedObligations', 'fallbackCount', 'blockedCount', 'alertState'].includes(key)))
224
+ return false;
225
+ return x.schema === 'routing-incident/v1' && typeof x.id === 'string' && /^[a-f0-9]{24}$/.test(x.id)
226
+ && typeof x.runStartedAt === 'string' && Number.isFinite(Date.parse(x.runStartedAt))
227
+ && typeof x.target === 'string' && x.target.length > 0 && x.target.length <= 128
228
+ && isRoutingSelection(x.selection) && typeof x.reasonCode === 'string' && /^[A-Z0-9_]{3,64}$/.test(x.reasonCode)
229
+ && typeof x.firstAt === 'string' && Number.isFinite(Date.parse(x.firstAt))
230
+ && typeof x.lastAt === 'string' && Number.isFinite(Date.parse(x.lastAt))
231
+ && Number.isSafeInteger(x.affectedObligations) && x.affectedObligations > 0
232
+ && Number.isSafeInteger(x.fallbackCount) && x.fallbackCount >= 0
233
+ && Number.isSafeInteger(x.blockedCount) && x.blockedCount >= 0
234
+ && ['pending', 'reported'].includes(String(x.alertState));
219
235
  }
220
236
  function isDigest(value) { return typeof value === 'string' && /^[a-f0-9]{64}$/.test(value); }
221
237
  function isRoutingSelection(x) { return isObj(x) && Object.keys(x).every(key => key === 'selector' || key === 'effort') && isObj(x.selector) && Object.keys(x.selector).every(key => key === 'kind' || key === 'id') && ['model', 'tier'].includes(String(x.selector.kind)) && typeof x.selector.id === 'string' && x.selector.id.length > 0 && x.selector.id.length <= 128 && isObj(x.effort) && ((x.effort.kind === 'runtime-default' && Object.keys(x.effort).length === 1) || (x.effort.kind === 'explicit' && Object.keys(x.effort).length === 2 && typeof x.effort.value === 'string' && x.effort.value.length > 0 && x.effort.value.length <= 128)); }
222
- function isRoutingEnvelope(x) { if (!isObj(x) || !Object.keys(x).every(key => ['schema', 'runtime', 'role', 'planDigest', 'executionDigest', 'sliceId', 'requestedProfile', 'effectiveProfile', 'resolved', 'policyDigest', 'capabilityDigest', 'outcome', 'unavailableEvidence'].includes(key)))
223
- return false; const runtime = x.runtime; return x.schema === 'routing-envelope/v1' && isObj(runtime) && Object.keys(runtime).every(key => ['target', 'kind', 'version', 'accountScopeDigest'].includes(key)) && ['codex', 'claude-code', 'cursor', 'copilot', 'opencode', 'antigravity'].includes(String(runtime.target)) && typeof runtime.kind === 'string' && runtime.kind.length > 0 && runtime.kind.length <= 128 && typeof runtime.version === 'string' && runtime.version.length > 0 && runtime.version.length <= 128 && isDigest(runtime.accountScopeDigest) && typeof x.role === 'string' && ROUTING_ROLES.includes(x.role) && isDigest(x.planDigest) && isDigest(x.executionDigest) && (x.sliceId === undefined || (typeof x.sliceId === 'string' && x.sliceId.length > 0 && x.sliceId.length <= 128)) && ['mechanical', 'integration', 'judgment', 'full'].includes(String(x.requestedProfile)) && ['mechanical', 'integration', 'judgment', 'full'].includes(String(x.effectiveProfile)) && isRoutingSelection(x.resolved) && isDigest(x.policyDigest) && isDigest(x.capabilityDigest) && ['native', 'degraded'].includes(String(x.outcome)) && Array.isArray(x.unavailableEvidence) && x.unavailableEvidence.length <= UNAVAILABLE_EVIDENCE.length && x.unavailableEvidence.every(value => typeof value === 'string' && UNAVAILABLE_EVIDENCE.includes(value)); }
224
- function isWellFormedImplementationLineage(x) { return isObj(x) && Object.keys(x).every(key => ['id', 'obligationId', 'sliceId', 'planDigest', 'executionDigest', 'initialProfile', 'initialEffort', 'attempts'].includes(key)) && typeof x.id === 'string' && x.id.length > 0 && typeof x.obligationId === 'string' && x.obligationId.length > 0 && typeof x.sliceId === 'string' && x.sliceId.length > 0 && isDigest(x.planDigest) && isDigest(x.executionDigest) && ['mechanical', 'integration', 'judgment'].includes(String(x.initialProfile)) && ['medium', 'high'].includes(String(x.initialEffort)) && Number.isSafeInteger(x.attempts) && x.attempts >= 0 && x.attempts <= 3; }
238
+ function isRoutingEnvelope(x) { if (!isObj(x) || !Object.keys(x).every(key => ['schema', 'runtime', 'role', 'planDigest', 'executionDigest', 'sliceId', 'requestedProfile', 'effectiveProfile', 'resolved', 'policyDigest', 'capabilityDigest', 'outcome', 'unavailableEvidence', 'nativeAgentType'].includes(key)))
239
+ return false; const runtime = x.runtime; return x.schema === 'routing-envelope/v1' && isObj(runtime) && Object.keys(runtime).every(key => ['target', 'kind', 'version', 'accountScopeDigest'].includes(key)) && ['codex', 'claude-code', 'cursor', 'copilot', 'opencode', 'antigravity'].includes(String(runtime.target)) && typeof runtime.kind === 'string' && runtime.kind.length > 0 && runtime.kind.length <= 128 && typeof runtime.version === 'string' && runtime.version.length > 0 && runtime.version.length <= 128 && isDigest(runtime.accountScopeDigest) && typeof x.role === 'string' && ROUTING_ROLES.includes(x.role) && isDigest(x.planDigest) && isDigest(x.executionDigest) && (x.sliceId === undefined || (typeof x.sliceId === 'string' && x.sliceId.length > 0 && x.sliceId.length <= 128)) && ['mechanical', 'integration', 'judgment', 'full'].includes(String(x.requestedProfile)) && ['mechanical', 'integration', 'judgment', 'full'].includes(String(x.effectiveProfile)) && isRoutingSelection(x.resolved) && isDigest(x.policyDigest) && isDigest(x.capabilityDigest) && ['native', 'degraded'].includes(String(x.outcome)) && Array.isArray(x.unavailableEvidence) && x.unavailableEvidence.length <= UNAVAILABLE_EVIDENCE.length && x.unavailableEvidence.every(value => typeof value === 'string' && UNAVAILABLE_EVIDENCE.includes(value)) && (x.nativeAgentType === undefined || (runtime.target === 'claude-code' && typeof x.nativeAgentType === 'string' && /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/.test(x.nativeAgentType))); }
240
+ function isWellFormedImplementationLineage(x) { return isObj(x) && Object.keys(x).every(key => ['id', 'obligationId', 'sliceId', 'planDigest', 'executionDigest', 'initialProfile', 'initialEffort', 'attempts'].includes(key)) && typeof x.id === 'string' && x.id.length > 0 && typeof x.obligationId === 'string' && x.obligationId.length > 0 && typeof x.sliceId === 'string' && x.sliceId.length > 0 && isDigest(x.planDigest) && isDigest(x.executionDigest) && ['mechanical', 'integration', 'judgment'].includes(String(x.initialProfile)) && ['medium', 'high', 'runtime-default'].includes(String(x.initialEffort)) && Number.isSafeInteger(x.attempts) && x.attempts >= 0 && x.attempts <= 3; }
225
241
  function isWellFormedRequestProblem(x) {
226
242
  return isObj(x) && typeof x.file === 'string' && (x.kind === 'corrupt' || x.kind === 'rejected')
227
243
  && typeof x.detail === 'string' && typeof x.at === 'string';