@aiwg/cli 2026.10.4 → 2026.10.6

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 (220) hide show
  1. package/agentic/code/addons/composition-engine/lib/runtime.mjs +1401 -0
  2. package/agentic/code/addons/composition-engine/lib/validator.mjs +513 -0
  3. package/agentic/code/addons/composition-engine/schemas/flow-graph.schema.json +372 -0
  4. package/agentic/code/providers/model-capabilities.v1.json +74 -50
  5. package/bin/aiwg.mjs +3 -1
  6. package/dist/src/artifacts/browser-export.js +1 -0
  7. package/dist/src/artifacts/citation-parser.js +8 -1
  8. package/dist/src/artifacts/cli.js +72 -9
  9. package/dist/src/artifacts/fortemi-core-query-adapter.js +2 -0
  10. package/dist/src/artifacts/fortemi-core-sync.js +26 -8
  11. package/dist/src/artifacts/graph-query.js +18 -8
  12. package/dist/src/artifacts/index-adapters.js +339 -0
  13. package/dist/src/artifacts/index-builder.js +146 -16
  14. package/dist/src/artifacts/index-files.js +15 -4
  15. package/dist/src/artifacts/index-preparation.js +91 -26
  16. package/dist/src/artifacts/index-reader.js +44 -0
  17. package/dist/src/artifacts/index-refresh.js +130 -56
  18. package/dist/src/artifacts/index-status.js +20 -5
  19. package/dist/src/artifacts/index-worker.mjs +9 -7
  20. package/dist/src/artifacts/memory-maintenance.js +503 -0
  21. package/dist/src/artifacts/prebuilt-relations.js +3 -1
  22. package/dist/src/artifacts/query-engine.js +263 -108
  23. package/dist/src/artifacts/relations-builder.js +2 -2
  24. package/dist/src/artifacts/source-graph.js +2 -2
  25. package/dist/src/artifacts/types.js +9 -1
  26. package/dist/src/cli/handlers/decision.js +19 -1
  27. package/dist/src/cli/handlers/guided-setup.js +470 -0
  28. package/dist/src/cli/handlers/help.js +2 -2
  29. package/dist/src/cli/handlers/housekeeper.js +1110 -0
  30. package/dist/src/cli/handlers/index.js +4 -2
  31. package/dist/src/cli/handlers/init.js +41 -6
  32. package/dist/src/cli/handlers/local-executor.js +5 -3
  33. package/dist/src/cli/handlers/mc.js +509 -53
  34. package/dist/src/cli/handlers/models.js +32 -2
  35. package/dist/src/cli/handlers/ralph-launcher.js +76 -4
  36. package/dist/src/cli/handlers/rules.js +1 -1
  37. package/dist/src/cli/handlers/script-runner.js +73 -2
  38. package/dist/src/cli/handlers/serve.js +5 -3
  39. package/dist/src/cli/handlers/sessions.js +40 -6
  40. package/dist/src/cli/handlers/setup.js +428 -1
  41. package/dist/src/cli/handlers/skill-lint.js +1 -1
  42. package/dist/src/cli/handlers/subcommands.js +118 -8
  43. package/dist/src/cli/handlers/use.js +279 -93
  44. package/dist/src/cli/handlers/workspace.js +3 -1
  45. package/dist/src/cli/prompt-utils.js +8 -0
  46. package/dist/src/cli/router.js +16 -1
  47. package/dist/src/config/aiwg-config.js +42 -0
  48. package/dist/src/config/cli.js +7 -3
  49. package/dist/src/config/decision-config.js +14 -1
  50. package/dist/src/config/native-sandbox-warnings.js +25 -0
  51. package/dist/src/contributors/validation.js +6 -5
  52. package/dist/src/decision/admission.js +7 -3
  53. package/dist/src/decision/benchmark.js +469 -0
  54. package/dist/src/decision/ledger.js +22 -3
  55. package/dist/src/decision/pricing.js +147 -0
  56. package/dist/src/decision/qualification/gate-evidence.js +18 -15
  57. package/dist/src/decision/qualification/load-staged.js +539 -0
  58. package/dist/src/decision/qualification/load.js +109 -33
  59. package/dist/src/decision/qualification/runner.js +5 -2
  60. package/dist/src/decision/review/service.js +6 -4
  61. package/dist/src/decision/review/validate.js +23 -2
  62. package/dist/src/decision/savings.js +8 -3
  63. package/dist/src/discovery/index.js +492 -0
  64. package/dist/src/discovery/interview.js +233 -0
  65. package/dist/src/discovery/plan-apply.js +571 -0
  66. package/dist/src/discovery/plan-store.js +171 -0
  67. package/dist/src/discovery/plan-types.js +2 -0
  68. package/dist/src/discovery/plan-validation.js +139 -0
  69. package/dist/src/discovery/types.js +2 -0
  70. package/dist/src/extensions/commands/definitions.js +49 -9
  71. package/dist/src/extensions/manifest.js +71 -44
  72. package/dist/src/extensions/project-local-discovery.js +1 -1
  73. package/dist/src/extensions/project-quickref.js +18 -17
  74. package/dist/src/extensions/validation.js +32 -29
  75. package/dist/src/housekeeper/daemon-config.js +148 -0
  76. package/dist/src/housekeeper/ipc.js +84 -0
  77. package/dist/src/housekeeper/lifecycle.js +148 -0
  78. package/dist/src/housekeeper/platform.js +35 -0
  79. package/dist/src/housekeeper/status.js +70 -0
  80. package/dist/src/housekeeper/units.js +114 -0
  81. package/dist/src/jobs/flow.js +22 -21
  82. package/dist/src/lint/rule-activation.js +20 -5
  83. package/dist/src/lint/runner.js +1 -1
  84. package/dist/src/mcp/cli.mjs +5 -6
  85. package/dist/src/mcp/config-file.mjs +6 -2
  86. package/dist/src/mcp/config-layers.mjs +23 -7
  87. package/dist/src/mcp/profiles.js +18 -31
  88. package/dist/src/mcp/profiles.mjs +18 -32
  89. package/dist/src/mcp/registry.js +7 -27
  90. package/dist/src/mcp/registry.mjs +7 -28
  91. package/dist/src/mcp/server.mjs +34 -1
  92. package/dist/src/mcp/tools/agentic-sandbox.mjs +8 -7
  93. package/dist/src/mcp/tools/command-run.mjs +3 -2
  94. package/dist/src/mcp/tools/decision.mjs +49 -48
  95. package/dist/src/mcp/tools/discovery.mjs +46 -21
  96. package/dist/src/mcp/tools/orchestration.mjs +22 -22
  97. package/dist/src/mcp/tools/subsystems.mjs +9 -8
  98. package/dist/src/mcp/tools/worker-invoke.mjs +17 -4
  99. package/dist/src/mcp/tools/writer-profiles.mjs +1 -1
  100. package/dist/src/memory/audit.js +719 -0
  101. package/dist/src/memory/canonical-context.js +392 -13
  102. package/dist/src/memory/canonical-maintenance.js +95 -0
  103. package/dist/src/memory/cli-result.js +22 -0
  104. package/dist/src/memory/cli.js +176 -0
  105. package/dist/src/memory/context-pack.js +57 -6
  106. package/dist/src/memory/cost.js +512 -0
  107. package/dist/src/memory/firewall-classification.d.mts +7 -0
  108. package/dist/src/memory/firewall-classification.mjs +32 -0
  109. package/dist/src/memory/index.js +8 -0
  110. package/dist/src/memory/line-maintenance.js +68 -0
  111. package/dist/src/memory/maintenance-cli.js +286 -0
  112. package/dist/src/memory/maintenance-contract.js +136 -0
  113. package/dist/src/memory/maintenance-index.js +18 -0
  114. package/dist/src/memory/maintenance-owner.js +2 -0
  115. package/dist/src/memory/maintenance-record.js +138 -0
  116. package/dist/src/memory/maintenance.js +254 -0
  117. package/dist/src/memory/provider-memory-adapter.js +154 -0
  118. package/dist/src/memory/recommend-cli.js +83 -0
  119. package/dist/src/memory/recommend.js +269 -0
  120. package/dist/src/memory/scheduled.js +81 -0
  121. package/dist/src/memory/taxonomy.js +44 -0
  122. package/dist/src/mission-protocol/codecs.js +19 -9
  123. package/dist/src/models/config-loader.js +11 -1
  124. package/dist/src/models/model-capabilities.v1.json +74 -50
  125. package/dist/src/models/provider-policy.js +125 -62
  126. package/dist/src/models/resolver.js +45 -8
  127. package/dist/src/models/worker-installation.d.mts +7 -0
  128. package/dist/src/models/worker-installation.mjs +169 -37
  129. package/dist/src/models/wrapper-route.js +1 -1
  130. package/dist/src/output-modes/registry.js +8 -7
  131. package/dist/src/plugin/metadata-validator.js +1 -1
  132. package/dist/src/providers/deploy-version.d.mts +1 -0
  133. package/dist/src/providers/deploy-version.mjs +17 -0
  134. package/dist/src/providers/provider-definitions.js +19 -16
  135. package/dist/src/providers/skill-ownership.d.mts +11 -2
  136. package/dist/src/providers/skill-ownership.mjs +35 -17
  137. package/dist/src/rules/activation.d.mts +11 -2
  138. package/dist/src/rules/activation.mjs +82 -6
  139. package/dist/src/rules/inventory.js +1 -1
  140. package/dist/src/rules/rule-frontmatter.schema.json +2 -0
  141. package/dist/src/schema/zod-validation.d.mts +6 -0
  142. package/dist/src/schema/zod-validation.mjs +50 -0
  143. package/dist/src/serve/executor-registry.js +297 -20
  144. package/dist/src/serve/executor-token.d.mts +1 -0
  145. package/dist/src/serve/executor-token.mjs +8 -0
  146. package/dist/src/serve/shared-host-scheduler.js +1102 -31
  147. package/dist/src/serve/worker-invocation.js +114 -15
  148. package/dist/src/sessions/adapters/claude.js +19 -18
  149. package/dist/src/sessions/adapters/codex.js +33 -19
  150. package/dist/src/sessions/adapters/copilot.js +14 -13
  151. package/dist/src/sessions/adapters/cursor.js +19 -18
  152. package/dist/src/sessions/adapters/deepseek-harness.js +9 -8
  153. package/dist/src/sessions/adapters/factory.js +11 -10
  154. package/dist/src/sessions/adapters/generic.js +32 -23
  155. package/dist/src/sessions/adapters/grokbot.js +35 -35
  156. package/dist/src/sessions/adapters/hermes.js +20 -19
  157. package/dist/src/sessions/adapters/muse.js +50 -49
  158. package/dist/src/sessions/adapters/omp.js +5 -4
  159. package/dist/src/sessions/adapters/openclaw.js +30 -29
  160. package/dist/src/sessions/adapters/opencode.js +26 -26
  161. package/dist/src/sessions/adapters/openhuman.js +24 -23
  162. package/dist/src/sessions/adapters/pi.js +5 -4
  163. package/dist/src/sessions/adapters/windsurf.js +8 -8
  164. package/dist/src/sessions/analytics.js +10 -9
  165. package/dist/src/sessions/batch-contracts.js +1 -1
  166. package/dist/src/sessions/batch-import.js +202 -2
  167. package/dist/src/sessions/candidates.js +7 -6
  168. package/dist/src/sessions/contracts.js +73 -54
  169. package/dist/src/sessions/coverage-preflight.js +26 -1
  170. package/dist/src/sessions/output-registration.js +11 -10
  171. package/dist/src/sessions/policy.js +18 -7
  172. package/dist/src/sessions/refresh.js +2 -3
  173. package/dist/src/sessions/repository.js +4 -2
  174. package/dist/src/sessions/workspace-discovery.js +92 -26
  175. package/dist/src/smiths/context-pipeline/aiwg-md.js +18 -1
  176. package/dist/src/smiths/context-pipeline/claude-hook.js +42 -6
  177. package/dist/src/smiths/context-pipeline/parallelism-section.js +72 -5
  178. package/dist/src/smiths/context-pipeline/workspace-context.js +106 -10
  179. package/dist/src/update/checker.d.mts +4 -0
  180. package/dist/src/update/checker.mjs +14 -0
  181. package/dist/src/writing/exemplar-selection.js +6 -6
  182. package/dist/src/writing/voice-evaluation.js +24 -23
  183. package/dist/src/writing/writer-migration.js +14 -13
  184. package/dist/src/writing/writer-profile.js +19 -18
  185. package/dist/src/writing/writing-brief.js +18 -17
  186. package/dist/src/writing/writing-receipt.js +47 -46
  187. package/package.json +5 -2
  188. package/schemas/decision/DecisionReview.schema.json +78 -1
  189. package/schemas/mission-v1.schema.json +3 -0
  190. package/tools/agents/deploy-agents.mjs +67 -39
  191. package/tools/agents/providers/antigravity.mjs +6 -1
  192. package/tools/agents/providers/base.mjs +19 -13
  193. package/tools/agents/providers/claude.mjs +1 -1
  194. package/tools/agents/providers/codex.mjs +50 -56
  195. package/tools/agents/providers/copilot.mjs +8 -2
  196. package/tools/agents/providers/cursor.mjs +1 -1
  197. package/tools/agents/providers/deepseek-harness.mjs +1 -1
  198. package/tools/agents/providers/factory.mjs +7 -1
  199. package/tools/agents/providers/grok-build.mjs +18 -2
  200. package/tools/agents/providers/grokbot.mjs +1 -1
  201. package/tools/agents/providers/hermes.mjs +7 -13
  202. package/tools/agents/providers/muse-hooks.mjs +21 -14
  203. package/tools/agents/providers/muse.mjs +7 -2
  204. package/tools/agents/providers/omp.mjs +28 -4
  205. package/tools/agents/providers/opencode.mjs +14 -5
  206. package/tools/agents/providers/openhuman.mjs +1 -1
  207. package/tools/agents/providers/pi.mjs +1 -1
  208. package/tools/agents/providers/provider-prepare-coordinator.mjs +29 -9
  209. package/tools/agents/providers/rule-delivery.mjs +263 -71
  210. package/tools/agents/providers/windsurf.mjs +7 -0
  211. package/tools/cli/workspace-status.mjs +5 -0
  212. package/tools/commands/deploy-prompts-codex.mjs +11 -8
  213. package/tools/ralph-external/lib/codex-adapter.mjs +6 -2
  214. package/tools/ralph-external/lib/muse-adapter.mjs +12 -2
  215. package/tools/ralph-external/lib/worker-health.mjs +1 -1
  216. package/tools/ralph-external/lib/worker-isolation.mjs +65 -9
  217. package/tools/ralph-external/process-monitor.mjs +7 -4
  218. package/tools/ralph-external/session-launcher.mjs +280 -32
  219. package/tools/skills/deploy-skills-codex.mjs +11 -7
  220. package/vscode-extension/schemas/aiwg.config.v1.json +11 -1
@@ -0,0 +1,539 @@
1
+ import { cpus, hostname, totalmem } from 'node:os';
2
+ import { canonicalJson } from '../../security/artifact-trust.js';
3
+ import { JevDecisionAdapter, compileJevQuestion } from '../adapters/jev.js';
4
+ import { DecisionAdmissionRegistry } from '../admission.js';
5
+ import { CanonicalJsonByteEstimator } from '../context-plan.js';
6
+ import { assertContextLiveSource } from '../context-live-qualification.js';
7
+ import { admissionControllerLoadDriver, decisionLoadArrivals, compareDecisionLoadBounds, decisionLoadManifestDigest, decisionLoadPolicy, runDecisionLoadHarness, } from './load.js';
8
+ const finite = (value) => typeof value === 'number' && Number.isFinite(value) && value >= 0;
9
+ const positive = (value) => finite(value) && value > 0;
10
+ const exactCommit = (value) => /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(value);
11
+ /** Read historical manifests without rewriting them; v3 is the only staged runner input. */
12
+ export function readDecisionLoadManifest(bytes) {
13
+ const value = JSON.parse(bytes);
14
+ if (value?.schema === 'decision-load-manifest/v1' && value.profile && value.bounds && value.duration)
15
+ return value;
16
+ if (value?.schema === 'decision-load-manifest/v2' && value.workspace && value.providers && value.principals && value.arrivalModel && value.bounds)
17
+ return value;
18
+ validateDecisionLoadManifestV3(value);
19
+ return value;
20
+ }
21
+ export function validateDecisionLoadManifestV3(value) {
22
+ const m = value;
23
+ if (!m || m.schema !== 'decision-load-manifest/v3' || m.mode !== 'staged-provider' || !m.version || !m.profileVersion
24
+ || !/^jev-\d+\.\d+\.\d+$/.test(m.model) || !m.budget || !positive(m.budget.maxUsd) || m.budget.stopAtFraction !== 0.8
25
+ || ![m.budget.maxCalls, m.budget.maxTokens, m.budget.maxWallClockSeconds, m.sampleIntervalMs, m.requestTimeoutMs].every(v => Number.isSafeInteger(v) && v > 0)
26
+ || !m.stopConditions || m.stopConditions.maximumRetryAmplificationRatio !== 1.25 || m.stopConditions.maximumCrossPrincipalQuotaViolations !== 0
27
+ || ![m.stopConditions.maximumBreakerOpenMs, m.stopConditions.maximum429StormMs].every(positive)
28
+ || !m.rollout || !m.rollout.previousProfileVersion || m.rollout.previousProfileVersion === m.profileVersion
29
+ || ![m.rollout.shadowSeconds, m.rollout.rollbackSeconds].every(positive)
30
+ || !m.duration || ![m.duration.loadSeconds, m.duration.spikeSeconds, m.duration.soakSeconds, m.duration.evaluatorSampleSeconds].every(positive)
31
+ || !m.principals?.length || !m.principals.some(p => p.class === 'noisy') || !m.principals.some(p => p.class === 'quiet')
32
+ || new Set(m.principals.map(p => p.id)).size !== m.principals.length
33
+ || !m.providers || Object.keys(m.providers).join() !== 'jev' || !m.rollout.providers || Object.keys(m.rollout.providers).join() !== 'jev') {
34
+ throw new Error('Invalid staged v3 manifest: explicit maxUsd and complete budget, stop conditions and profiles required');
35
+ }
36
+ const scopes = [m.workspace, ...Object.values(m.providers), ...m.principals.map(p => p.limits), m.rollout.workspace, ...Object.values(m.rollout.providers)];
37
+ for (const scope of scopes) {
38
+ if (!scope || !Number.isSafeInteger(scope.concurrency) || scope.concurrency < 1 || scope.concurrency >= 8
39
+ || ![scope.requestsPerMinute, scope.tokensPerSecond, scope.maxCostUsd, scope.maxRetainedWork, scope.maxQueueLength, scope.maxQueueWaitMs].every(positive)) {
40
+ throw new Error('Every v3 scope requires rpm, tps, cost, retained-work and queue bounds; concurrency must be below 8');
41
+ }
42
+ }
43
+ const knownBounds = ['maximumActiveCalls', 'maximumQueuedCalls', 'maximumHeapUsedMiB', 'maximumResidentMemoryMiB', 'maximumCpuPercentOneCore',
44
+ 'maximumEligibleLaneWaitMs', 'maximumRetryAmplificationRatio', 'maximumCancellationLatencyMs', 'minimumQuietPrincipalAdmissionRatio', 'maximumSampleGapMs'];
45
+ if (!m.bounds || Object.keys(m.bounds).length !== knownBounds.length || !knownBounds.every(k => finite(m.bounds[k]))
46
+ || m.bounds.maximumRetryAmplificationRatio > 1.25 || m.bounds.minimumQuietPrincipalAdmissionRatio > 1
47
+ || m.bounds.maximumActiveCalls >= 8 || m.bounds.maximumSampleGapMs < m.sampleIntervalMs)
48
+ throw new Error('Invalid v3 measurement bounds');
49
+ const a = m.arrivalModel;
50
+ if (!a || a.kind !== 'seeded-bursty-poisson' || !Number.isSafeInteger(a.seed)
51
+ || ![a.averageRequestsPerSecond, a.spikeMultiplier, a.spikeDurationSeconds, a.smallTokens, a.hugeTokens,
52
+ a.serviceTimeMs?.minimum, a.serviceTimeMs?.maximum, a.retryBackoffMs, a.cancelAfterMs].every(positive)
53
+ || ![a.hugeTokenShare, a.retryableFailureRate, a.cancellationRate].every(v => finite(v) && v <= 1)
54
+ || !Number.isSafeInteger(a.maxRetries) || a.maxRetries < 0 || a.maxRetries > 3
55
+ || a.smallTokens < 2048 || a.hugeTokens > 32768 || a.hugeTokens < a.smallTokens || a.serviceTimeMs.maximum < a.serviceTimeMs.minimum
56
+ || m.sampleIntervalMs > 1000 || m.sampleIntervalMs > m.budget.maxWallClockSeconds * 1000
57
+ || !m.passFail?.allBoundsMustPass || !m.passFail.liveServiceRequired)
58
+ throw new Error('Invalid v3 arrival model or sampling interval');
59
+ }
60
+ export function validateDecisionLoadPricing(pricing, model) {
61
+ if (!pricing || !['typesafe-docs', 'typesafe-snapshot'].includes(pricing.source ?? '') || pricing.jev_model !== model
62
+ || !pricing.checked_at || !Number.isFinite(Date.parse(pricing.checked_at))
63
+ || !finite(pricing.jev_input_per_mtok) || !finite(pricing.jev_output_per_mtok))
64
+ throw new Error('Sourced split Jev cost config for the pinned model is required');
65
+ }
66
+ const price = (tokens, pricing) => tokens * Math.max(pricing.jev_input_per_mtok, pricing.jev_output_per_mtok) / 1e6;
67
+ /** Run-wide conservative reservations are never refunded on unknown provider outcomes. */
68
+ export class DecisionLoadBudgetGuard {
69
+ manifest;
70
+ now;
71
+ start;
72
+ stopped;
73
+ usage = { calls: 0, tokens: 0, usd: 0 };
74
+ stop = null;
75
+ invocations = new Set();
76
+ open = new Map();
77
+ storm = new Map();
78
+ constructor(manifest, now, start, stopped = () => { }) {
79
+ this.manifest = manifest;
80
+ this.now = now;
81
+ this.start = start;
82
+ this.stopped = stopped;
83
+ }
84
+ halt(reason) {
85
+ if (this.stop)
86
+ return;
87
+ this.stop = { reason, atMs: this.now() - this.start };
88
+ this.stopped();
89
+ }
90
+ reserve(id, tokens, usd) {
91
+ this.tick();
92
+ if (!Number.isSafeInteger(tokens) || tokens < 1 || !finite(usd))
93
+ this.halt('invalid-reservation');
94
+ if (this.stop)
95
+ return false;
96
+ const b = this.manifest.budget;
97
+ if (this.usage.usd + usd > b.maxUsd * b.stopAtFraction + 1e-12)
98
+ this.halt('budget-usd-80-percent');
99
+ else if (this.usage.calls + 1 > b.maxCalls)
100
+ this.halt('max-calls');
101
+ else if (this.usage.tokens + tokens > b.maxTokens)
102
+ this.halt('max-tokens');
103
+ if (this.stop)
104
+ return false;
105
+ const invocationCount = this.invocations.size + (this.invocations.has(id) ? 0 : 1);
106
+ if ((this.usage.calls + 1) / invocationCount > this.manifest.stopConditions.maximumRetryAmplificationRatio) {
107
+ this.halt('retry-amplification');
108
+ return false;
109
+ }
110
+ this.usage.calls++;
111
+ this.usage.tokens += tokens;
112
+ this.usage.usd += usd;
113
+ this.invocations.add(id);
114
+ return true;
115
+ }
116
+ observe(providerId, observation, tokens, usd) {
117
+ const u = observation.usage;
118
+ if (((u.inputTokens ?? 0) + (u.outputTokens ?? 0) > tokens)
119
+ || (u.costUsd !== null && u.costUsd > usd + 1e-12))
120
+ this.halt('usage-exceeds-reservation');
121
+ if (observation.httpStatus === 429) {
122
+ if (!this.storm.has(providerId))
123
+ this.storm.set(providerId, this.now());
124
+ }
125
+ else if (observation.status === 'success')
126
+ this.storm.delete(providerId);
127
+ if (this.usage.usd >= this.manifest.budget.maxUsd * 0.8)
128
+ this.halt('budget-usd-80-percent');
129
+ if (this.usage.calls >= this.manifest.budget.maxCalls)
130
+ this.halt('max-calls');
131
+ if (this.usage.tokens >= this.manifest.budget.maxTokens)
132
+ this.halt('max-tokens');
133
+ this.tick();
134
+ }
135
+ transition(transition) {
136
+ if (transition.to === 'open')
137
+ this.open.set(transition.providerId, transition.atEpochMs);
138
+ else
139
+ this.open.delete(transition.providerId);
140
+ this.tick();
141
+ }
142
+ tick() {
143
+ if (this.now() - this.start >= this.manifest.budget.maxWallClockSeconds * 1000)
144
+ this.halt('max-wall-clock');
145
+ if ([...this.open.values()].some(at => this.now() - at > this.manifest.stopConditions.maximumBreakerOpenMs))
146
+ this.halt('breaker-open');
147
+ if ([...this.storm.values()].some(at => this.now() - at > this.manifest.stopConditions.maximum429StormMs))
148
+ this.halt('429-storm');
149
+ }
150
+ quotaViolation() { this.halt('cross-principal-quota'); }
151
+ }
152
+ /** Fixed synthetic payload; never accepts user/customer state. D06 estimator checks the reservation before dispatch. */
153
+ function syntheticRequest(arrival) {
154
+ return {
155
+ definition: { apiVersion: 'decision.aiwg.io/v1alpha1', kind: 'DecisionDefinition', metadata: { id: 'd05-synthetic', version: '1.0.0', description: 'Synthetic D05 staging fixture' },
156
+ spec: { purpose: 'Synthetic staging load; no action.', inputSchema: { type: 'object' }, question: 'Select synthetic.',
157
+ answer: { kind: 'choice', options: [{ id: 'synthetic', description: 'Synthetic fixture.' }, { id: 'other', description: 'Other.' }] }, requiredCapabilities: ['choice'] } },
158
+ input: { message: 'fixture '.repeat(Math.floor((arrival.tokens - 1024) * 3 / 8)) },
159
+ };
160
+ }
161
+ export const realDecisionLoadClock = () => ({ now: Date.now, advance: ms => new Promise(resolve => setTimeout(resolve, ms)) });
162
+ export async function runDecisionStagedLoad(options) {
163
+ const manifest = readDecisionLoadManifest(options.manifestBytes);
164
+ validateDecisionLoadManifestV3(manifest);
165
+ const env = options.env ?? process.env;
166
+ // Validate before constructing an adapter, reading a credential value or starting timers.
167
+ if (options.live && !env[options.credentialEnv ?? 'AIWG_JEV_LOAD_API_KEY']?.trim())
168
+ throw new Error('--live requires the caller-supplied environment credential');
169
+ if (options.live && options.fakeBackend)
170
+ throw new Error('Live load cannot use a fake backend');
171
+ if (options.live && env.NODE_TLS_REJECT_UNAUTHORIZED !== undefined && env.NODE_TLS_REJECT_UNAUTHORIZED !== '1')
172
+ throw new Error('TLS verification must remain enabled');
173
+ validateDecisionLoadPricing(options.pricing, manifest.model);
174
+ if (!exactCommit(options.sourceCommit) || !options.networkPath.trim())
175
+ throw new Error('Exact source commit and recorded network path required');
176
+ const assertSource = options.assertSource ?? assertContextLiveSource;
177
+ await assertSource(options.sourceRoot, options.sourceCommit);
178
+ const clock = options.clock ?? realDecisionLoadClock();
179
+ const start = clock.now();
180
+ const abort = new AbortController();
181
+ const guard = new DecisionLoadBudgetGuard(manifest, clock.now, start, () => abort.abort());
182
+ const registry = new DecisionAdmissionRegistry();
183
+ const stages = [];
184
+ const receipts = [];
185
+ const samples = [];
186
+ const transitions = [];
187
+ registry.onBreakerTransition(t => { transitions.push(t); guard.transition(t); });
188
+ const resource = options.sampleResources ?? (() => ({ ...process.memoryUsage(), ...process.resourceUsage() }));
189
+ let previous = resource();
190
+ let previousAt = start;
191
+ const sample = () => {
192
+ const now = clock.now();
193
+ const current = resource();
194
+ const snapshot = registry.controller('load-harness')?.snapshot() ?? { active: 0, queued: 0 };
195
+ samples.push({ atMs: now - start, residentMemoryMiB: current.rss / 1_048_576, heapUsedMiB: current.heapUsed / 1_048_576,
196
+ cpuPercentOneCore: now === previousAt ? 0 : (current.userCPUTime + current.systemCPUTime - previous.userCPUTime - previous.systemCPUTime) / ((now - previousAt) * 10), ...snapshot });
197
+ previous = current;
198
+ previousAt = now;
199
+ guard.tick();
200
+ };
201
+ let sampler;
202
+ let deadline;
203
+ const adapter = options.live ? new JevDecisionAdapter({ now: clock.now }) : null;
204
+ const estimator = new CanonicalJsonByteEstimator();
205
+ const previousManifest = { ...manifest, profileVersion: manifest.rollout.previousProfileVersion,
206
+ workspace: manifest.rollout.workspace, providers: manifest.rollout.providers };
207
+ let phase = 'shadow';
208
+ const inFlight = new Map();
209
+ try {
210
+ for (const principal of manifest.principals)
211
+ registry.register(decisionLoadPolicy(previousManifest, 'load-harness', principal.id), clock.now);
212
+ sampler = setInterval(() => { try {
213
+ sample();
214
+ }
215
+ catch {
216
+ guard.halt('driver-error');
217
+ } }, manifest.sampleIntervalMs);
218
+ deadline = setTimeout(() => guard.halt('max-wall-clock'), manifest.budget.maxWallClockSeconds * 1000);
219
+ sample();
220
+ for (phase of ['shadow', 'canary', 'rollback']) {
221
+ const activeManifest = phase === 'rollback' ? previousManifest : manifest;
222
+ const windowSeconds = phase === 'shadow' ? manifest.rollout.shadowSeconds : phase === 'rollback' ? manifest.rollout.rollbackSeconds
223
+ : manifest.duration.loadSeconds + manifest.duration.spikeSeconds + manifest.duration.soakSeconds;
224
+ // Roll back even after a budget or outage stop; no additional provider work follows a stop.
225
+ const scopes = {};
226
+ const observeScopes = () => {
227
+ const controller = registry.controller('load-harness');
228
+ const counts = { workspace: controller.snapshot(),
229
+ ...Object.fromEntries(Object.keys(activeManifest.providers).map(id => [`provider.${id}`, controller.snapshot({ providerId: id })])),
230
+ ...Object.fromEntries(activeManifest.principals.map(p => [`principal.${p.id}`, controller.snapshot({ principalId: p.id })])) };
231
+ for (const [id, count] of Object.entries(counts))
232
+ scopes[id] = { active: Math.max(scopes[id]?.active ?? 0, count.active), queued: Math.max(scopes[id]?.queued ?? 0, count.queued) };
233
+ return counts.workspace;
234
+ };
235
+ const path = admissionControllerLoadDriver(activeManifest, clock, registry, {
236
+ onStateChange: () => { observeScopes(); },
237
+ onDriverError: () => guard.halt('driver-error'),
238
+ estimateCost: arrival => price(arrival.tokens, options.pricing),
239
+ beforeDispatch: (arrival, attempt) => {
240
+ const request = syntheticRequest(arrival);
241
+ const estimated = estimator.estimate({ state: { untrusted: request.input }, question: compileJevQuestion(request.definition) }).tokens + 256;
242
+ if (estimated > arrival.tokens)
243
+ guard.halt('invalid-reservation');
244
+ return !guard.stop && guard.reserve(`${phase}:${arrival.ordinal}`, arrival.tokens, price(arrival.tokens, options.pricing)) && attempt > 0;
245
+ },
246
+ onAdmission: (arrival, attempt, admission) => {
247
+ const receipt = { phase, arrivalOrdinal: arrival.ordinal, principalId: arrival.principalId,
248
+ providerId: arrival.providerId, attempt, admittedAtMs: clock.now(), settledAtMs: clock.now(), tokens: arrival.tokens,
249
+ costUsd: price(arrival.tokens, options.pricing), admission: structuredClone(admission), status: 'error', reason: 'executor-unavailable',
250
+ usage: { inputTokens: null, outputTokens: null, costUsd: null } };
251
+ receipts.push(receipt);
252
+ inFlight.set(`${arrival.ordinal}:${attempt}`, receipt);
253
+ const ownActive = [...inFlight.values()].filter(r => r.principalId === arrival.principalId).length;
254
+ const principal = manifest.principals.find(p => p.id === arrival.principalId);
255
+ const provider = activeManifest.providers[arrival.providerId];
256
+ const phaseReceipts = receipts.filter(r => r.phase === phase);
257
+ const scoped = [
258
+ [principal.limits, phaseReceipts.filter(r => r.principalId === arrival.principalId), ownActive],
259
+ [activeManifest.workspace, phaseReceipts, inFlight.size],
260
+ [provider, phaseReceipts.filter(r => r.providerId === arrival.providerId), [...inFlight.values()].filter(r => r.providerId === arrival.providerId).length],
261
+ ];
262
+ if (scoped.some(([limits, entries, active]) => active > limits.concurrency
263
+ || bucketDebit(entries, limits.requestsPerMinute, 60000, () => 1) > limits.requestsPerMinute + 1e-9
264
+ || bucketDebit(entries, limits.tokensPerSecond, 1000, r => r.tokens) > limits.tokensPerSecond + 1e-9
265
+ || entries.filter(r => r.arrivalOrdinal === arrival.ordinal).reduce((sum, r) => sum + r.costUsd, 0) > limits.maxCostUsd
266
+ || (limits.maxPrincipalShare !== undefined && ownActive > Math.max(1, Math.floor(limits.concurrency * limits.maxPrincipalShare)))))
267
+ guard.quotaViolation();
268
+ },
269
+ backend: async (arrival, signal, context, attempt) => {
270
+ if (signal.aborted)
271
+ return { status: 'cancelled', reason: 'cancelled', actualModel: null, uncertainty: null, requestId: null,
272
+ usage: { inputTokens: null, outputTokens: null, costUsd: null } };
273
+ if (adapter) {
274
+ const request = syntheticRequest(arrival);
275
+ return adapter.evaluate({ ...request, alias: 'synthetic', invocationId: `d05-${phase}-${arrival.ordinal}`,
276
+ signal, deadlineEpochMs: clock.now() + manifest.requestTimeoutMs,
277
+ target: { adapter: 'jev', adapterVersion: adapter.version, model: manifest.model, credentialRef: 'caller-env', requiredCapabilities: ['choice'],
278
+ acceptance: { mode: 'typed-value' }, timeoutMs: manifest.requestTimeoutMs, retry: { maxRetries: 0, initialDelayMs: 0, maxDelayMs: 0 } },
279
+ resolveCredential: async () => new TextEncoder().encode(env[options.credentialEnv ?? 'AIWG_JEV_LOAD_API_KEY']) });
280
+ }
281
+ if (options.fakeBackend)
282
+ return options.fakeBackend(arrival, signal);
283
+ const status = await context.dispatch(arrival.serviceMs, signal);
284
+ const failed = arrival.failsFirstAttempt && attempt === 1;
285
+ return { status: status === 'aborted' ? 'cancelled' : failed ? 'error' : 'success', reason: status === 'aborted' ? 'cancelled' : failed ? 'service-error' : 'none',
286
+ actualModel: manifest.model, uncertainty: null, requestId: null,
287
+ usage: { inputTokens: arrival.tokens - 256, outputTokens: 1, costUsd: null } };
288
+ },
289
+ onObservation: (arrival, attempt, admission, observation) => {
290
+ const receipt = inFlight.get(`${arrival.ordinal}:${attempt}`);
291
+ Object.assign(receipt, { settledAtMs: clock.now(), admission: structuredClone(admission), status: observation.status, reason: observation.reason,
292
+ usage: observation.usage, ...(observation.httpStatus === undefined ? {} : { httpStatus: observation.httpStatus }) });
293
+ inFlight.delete(`${arrival.ordinal}:${attempt}`);
294
+ guard.observe(arrival.providerId, observation, receipt.tokens, receipt.costUsd);
295
+ },
296
+ });
297
+ if (guard.stop)
298
+ continue;
299
+ const run = await runDecisionLoadHarness({ manifest: activeManifest, clock, ...path, sample: observeScopes, windowSeconds, signal: abort.signal, fullWindow: true });
300
+ const dispatched = receipts.filter(r => r.phase === phase);
301
+ run.observations.attempts = dispatched.length;
302
+ run.observations.retryAmplificationRatio = run.observations.arrivals ? Number((dispatched.length / run.observations.arrivals).toFixed(6)) : 1;
303
+ stages.push({ phase, profileVersion: activeManifest.profileVersion, windowSeconds, ...run, scopes });
304
+ }
305
+ try {
306
+ await assertSource(options.sourceRoot, options.sourceCommit);
307
+ }
308
+ catch {
309
+ guard.halt('source-drift');
310
+ }
311
+ }
312
+ catch {
313
+ guard.halt('driver-error');
314
+ }
315
+ finally {
316
+ // Idempotent boundary restoration preserves the registry's rollback audit and all receipts.
317
+ try {
318
+ for (const principal of manifest.principals)
319
+ registry.register(decisionLoadPolicy(previousManifest, 'load-harness', principal.id), clock.now);
320
+ }
321
+ catch {
322
+ guard.halt('driver-error');
323
+ }
324
+ clearInterval(sampler);
325
+ clearTimeout(deadline);
326
+ try {
327
+ sample();
328
+ }
329
+ catch {
330
+ guard.halt('driver-error');
331
+ }
332
+ }
333
+ return decisionStagedLoadResultRecord({ manifestBytes: options.manifestBytes, mode: 'staged-provider', execution: options.live ? 'live' : 'offline-fake-provider',
334
+ sourceCommit: options.sourceCommit, dirty: false,
335
+ host: { hostname: hostname(), cpuClass: `${cpus().length} cores; ${cpus()[0]?.model ?? 'unknown'}`, memoryGiB: totalmem() / 2 ** 30,
336
+ networkPath: options.networkPath, node: process.version, platform: process.platform, arch: process.arch },
337
+ pricing: options.pricing, stages, receipts, samples, profileHistory: registry.profileHistory('load-harness'), breakerTransitions: transitions,
338
+ usage: guard.usage, stop: guard.stop, startedAtMs: start, elapsedMs: samples.at(-1)?.atMs ?? clock.now() - start });
339
+ }
340
+ /** Token-bucket debit (burst plus refill), matching the admission controller's rate semantics. */
341
+ function bucketDebit(receipts, capacity, periodMs, amount) {
342
+ let debit = 0;
343
+ let maximum = 0;
344
+ let at = receipts[0]?.admittedAtMs ?? 0;
345
+ for (const receipt of receipts) {
346
+ debit = Math.max(0, debit - Math.max(0, receipt.admittedAtMs - at) * capacity / periodMs) + amount(receipt);
347
+ maximum = Math.max(maximum, debit);
348
+ at = receipt.admittedAtMs;
349
+ }
350
+ return maximum;
351
+ }
352
+ function concurrency(receipts) {
353
+ let maximum = 0;
354
+ for (const r of receipts)
355
+ maximum = Math.max(maximum, receipts.filter(other => other.admittedAtMs <= r.admittedAtMs && other.settledAtMs > r.admittedAtMs).length, 1);
356
+ return maximum;
357
+ }
358
+ const maximum = (values) => Math.max(0, ...values);
359
+ /** Every measurement/stop/budget bound is recomputed from retained evidence, never the record's passed field. */
360
+ export function compareDecisionStagedLoad(record) {
361
+ const m = record.manifest;
362
+ const out = [];
363
+ const atMost = (bound, limit, observed) => {
364
+ out.push({ bound, limit, observed,
365
+ pass: finite(observed) && observed <= limit + 1e-9 });
366
+ };
367
+ for (const stage of record.stages) {
368
+ const resources = { ...stage.resources, heapUsedMiB: maximum(record.samples.map(s => s.heapUsedMiB)),
369
+ cpuSource: 'thread', cpuPercentOneCore: maximum(record.samples.map(s => s.cpuPercentOneCore)) };
370
+ out.push(...compareDecisionLoadBounds(m, { ...stage.observations,
371
+ maximumActiveCalls: Math.max(stage.observations.maximumActiveCalls, stage.scopes?.workspace?.active ?? 0, maximum(record.samples.map(s => s.active))),
372
+ maximumQueuedCalls: Math.max(stage.observations.maximumQueuedCalls, stage.scopes?.workspace?.queued ?? 0, maximum(record.samples.map(s => s.queued))),
373
+ }, resources).map(c => ({ ...c, bound: `${stage.phase}.${c.bound}` })));
374
+ atMost(`${stage.phase}.maximumResidentMemoryMiB`, m.bounds.maximumResidentMemoryMiB, maximum(record.samples.map(s => s.residentMemoryMiB)));
375
+ const receipts = record.receipts.filter(r => r.phase === stage.phase).sort((a, b) => a.admittedAtMs - b.admittedAtMs);
376
+ atMost(`${stage.phase}.quietPrincipalLaneWaitMs`, m.bounds.maximumEligibleLaneWaitMs, maximum(receipts.filter(r => m.principals.find(p => p.id === r.principalId)?.class === 'quiet').map(r => r.admission.queueDelayMs)));
377
+ const workspace = stage.phase === 'rollback' ? m.rollout.workspace : m.workspace;
378
+ const providers = stage.phase === 'rollback' ? m.rollout.providers : m.providers;
379
+ const scopes = [
380
+ ['workspace', workspace, receipts],
381
+ ...Object.entries(providers).map(([id, limits]) => [`provider.${id}`, limits, receipts.filter(r => r.providerId === id)]),
382
+ ...m.principals.map(p => [`principal.${p.id}`, p.limits, receipts.filter(r => r.principalId === p.id)]),
383
+ ];
384
+ for (const [scope, limits, entries] of scopes) {
385
+ const prefix = `${stage.phase}.${scope}`;
386
+ atMost(`${prefix}.concurrency`, limits.concurrency, Math.max(concurrency(entries), stage.scopes[scope]?.active ?? 0));
387
+ atMost(`${prefix}.maxQueueLength`, limits.maxQueueLength, stage.scopes[scope]?.queued ?? Number.POSITIVE_INFINITY);
388
+ atMost(`${prefix}.requestsPerMinute`, limits.requestsPerMinute, bucketDebit(entries, limits.requestsPerMinute, 60000, () => 1));
389
+ atMost(`${prefix}.tokensPerSecond`, limits.tokensPerSecond, bucketDebit(entries, limits.tokensPerSecond, 1000, r => r.tokens));
390
+ // Admission cost/retained-work limits are invocation-scoped, as in DecisionAdmissionController.
391
+ const invocations = new Map();
392
+ for (const r of entries)
393
+ invocations.set(r.arrivalOrdinal, (invocations.get(r.arrivalOrdinal) ?? 0) + r.costUsd);
394
+ atMost(`${prefix}.maxCostUsd`, limits.maxCostUsd, maximum([...invocations.values()]));
395
+ atMost(`${prefix}.maxRetainedWork`, limits.maxRetainedWork, entries.length ? 1 : 0);
396
+ atMost(`${prefix}.maxQueueWaitMs`, limits.maxQueueWaitMs, maximum(entries.map(r => r.admission.queueDelayMs)));
397
+ if (limits.maxPrincipalShare !== undefined)
398
+ for (const principal of m.principals) {
399
+ atMost(`${prefix}.${principal.id}.shareConcurrency`, Math.max(1, Math.floor(limits.concurrency * limits.maxPrincipalShare)), concurrency(entries.filter(r => r.principalId === principal.id)));
400
+ }
401
+ }
402
+ }
403
+ atMost('budget.maxUsd.stopAtFraction', m.budget.maxUsd * m.budget.stopAtFraction, record.usage.usd);
404
+ atMost('budget.maxCalls', m.budget.maxCalls, record.usage.calls);
405
+ atMost('budget.maxTokens', m.budget.maxTokens, record.usage.tokens);
406
+ atMost('budget.maxWallClockSeconds', m.budget.maxWallClockSeconds, record.elapsedMs / 1000);
407
+ atMost('maximumSampleGapMs', m.bounds.maximumSampleGapMs, maximum(record.samples.slice(1).map((s, i) => s.atMs - record.samples[i].atMs)));
408
+ const endingAt = record.startedAtMs + record.elapsedMs;
409
+ const open = new Map();
410
+ let openMs = 0;
411
+ for (const t of record.breakerTransitions) {
412
+ const prior = open.get(t.providerId);
413
+ if (prior !== undefined)
414
+ openMs = Math.max(openMs, t.atEpochMs - prior);
415
+ if (t.to === 'open')
416
+ open.set(t.providerId, t.atEpochMs);
417
+ else
418
+ open.delete(t.providerId);
419
+ }
420
+ for (const at of open.values())
421
+ openMs = Math.max(openMs, endingAt - at);
422
+ let stormMs = 0;
423
+ const storms = new Map();
424
+ for (const receipt of [...record.receipts].sort((a, b) => a.settledAtMs - b.settledAtMs)) {
425
+ if (receipt.httpStatus === 429 && !storms.has(receipt.providerId))
426
+ storms.set(receipt.providerId, receipt.settledAtMs);
427
+ const prior = storms.get(receipt.providerId);
428
+ if (prior !== undefined)
429
+ stormMs = Math.max(stormMs, receipt.settledAtMs - prior);
430
+ if (receipt.status === 'success')
431
+ storms.delete(receipt.providerId);
432
+ }
433
+ for (const at of storms.values())
434
+ stormMs = Math.max(stormMs, endingAt - at);
435
+ atMost('stop.maximumBreakerOpenMs', m.stopConditions.maximumBreakerOpenMs, openMs);
436
+ atMost('stop.maximum429StormMs', m.stopConditions.maximum429StormMs, stormMs);
437
+ const ids = new Set(record.receipts.map(r => `${r.phase}:${r.arrivalOrdinal}`));
438
+ atMost('stop.maximumRetryAmplificationRatio', m.stopConditions.maximumRetryAmplificationRatio, ids.size ? record.receipts.length / ids.size : 0);
439
+ const violations = out.filter(c => /principal\..*\.concurrency|shareConcurrency/.test(c.bound) && !c.pass).length;
440
+ atMost('stop.maximumCrossPrincipalQuotaViolations', 0, violations);
441
+ return out;
442
+ }
443
+ export function decisionStagedLoadResultRecord(input) {
444
+ const manifest = readDecisionLoadManifest(input.manifestBytes);
445
+ validateDecisionLoadManifestV3(manifest);
446
+ const payload = { ...input, schemaVersion: 'decision-load-result/v1', kind: 'load-manifest-qualified',
447
+ manifest, manifestDigest: decisionLoadManifestDigest(input.manifestBytes) };
448
+ for (const key of ['digest', 'comparisons', 'passed', 'queueWaitDistribution', 'retries'])
449
+ delete payload[key];
450
+ const comparisons = compareDecisionStagedLoad(payload);
451
+ const complete = ['shadow', 'canary', 'rollback'].every(phase => input.stages.some(s => s.phase === phase))
452
+ && input.stages.every(s => s.observations.virtualDurationMs >= s.windowSeconds * 1000 && s.observations.arrivals > 0)
453
+ && input.samples.length > 1 && input.profileHistory.some(h => h.kind === 'rollback');
454
+ const waits = input.receipts.map(r => r.admission.queueDelayMs).sort((a, b) => a - b);
455
+ const percentile = (fraction) => waits[Math.max(0, Math.ceil(waits.length * fraction) - 1)] ?? 0;
456
+ const body = { ...payload, comparisons, retries: input.receipts.filter(receipt => receipt.attempt > 1).length, queueWaitDistribution: { count: waits.length, p50: percentile(.5), p95: percentile(.95), p99: percentile(.99), maximum: maximum(waits) },
457
+ passed: !input.stop && complete && comparisons.length > 0 && comparisons.every(c => c.pass) };
458
+ return { ...body, digest: decisionLoadManifestDigest(canonicalJson(body)) };
459
+ }
460
+ /** Self digest + exact manifest bytes + recomputed measurements + complete rollout + clean exact commit. */
461
+ export function verifyDecisionStagedLoadRecord(value, sourceCommit) {
462
+ try {
463
+ const r = value;
464
+ if (!r || r.schemaVersion !== 'decision-load-result/v1' || r.kind !== 'load-manifest-qualified' || r.mode !== 'staged-provider'
465
+ || r.execution !== 'live' || r.dirty !== false || !exactCommit(r.sourceCommit) || (sourceCommit !== undefined && sourceCommit !== r.sourceCommit)
466
+ || r.stop !== null || !r.passed || !finite(r.startedAtMs) || !r.host.networkPath || !r.host.cpuClass || !positive(r.host.memoryGiB))
467
+ return false;
468
+ const manifest = readDecisionLoadManifest(r.manifestBytes);
469
+ validateDecisionLoadManifestV3(manifest);
470
+ validateDecisionLoadPricing(r.pricing, manifest.model);
471
+ if (canonicalJson(manifest) !== canonicalJson(r.manifest) || r.manifestDigest !== decisionLoadManifestDigest(r.manifestBytes)
472
+ || manifest.duration.soakSeconds !== 900 || r.stages.length !== 3 || !r.receipts.length || r.samples.length < 2)
473
+ return false;
474
+ const { digest, ...body } = r;
475
+ if (digest !== decisionLoadManifestDigest(canonicalJson(body)))
476
+ return false;
477
+ const expectedPhases = ['shadow', 'canary', 'rollback'];
478
+ for (const [index, stage] of r.stages.entries()) {
479
+ const window = index === 0 ? manifest.rollout.shadowSeconds : index === 2 ? manifest.rollout.rollbackSeconds
480
+ : manifest.duration.loadSeconds + manifest.duration.spikeSeconds + manifest.duration.soakSeconds;
481
+ if (stage.phase !== expectedPhases[index] || stage.windowSeconds !== window
482
+ || stage.profileVersion !== (index === 2 ? manifest.rollout.previousProfileVersion : manifest.profileVersion)
483
+ || stage.observations.virtualDurationMs < window * 1000 || stage.observations.arrivals <= 0)
484
+ return false;
485
+ const receipts = r.receipts.filter(receipt => receipt.phase === stage.phase);
486
+ const expectedArrivals = decisionLoadArrivals(manifest, window);
487
+ const obs = stage.observations;
488
+ if (obs.arrivals !== expectedArrivals.length || obs.attempts !== receipts.length
489
+ || obs.completed + obs.failed + obs.shed + obs.cancelled !== obs.arrivals
490
+ || obs.maximumEligibleLaneWaitMs !== maximum(receipts.map(receipt => receipt.admission.queueDelayMs)))
491
+ return false;
492
+ for (const cls of ['quiet', 'noisy']) {
493
+ const expected = expectedArrivals.filter(arrival => arrival.principalClass === cls).length;
494
+ const admitted = new Set(receipts.filter(receipt => manifest.principals.find(p => p.id === receipt.principalId)?.class === cls).map(receipt => receipt.arrivalOrdinal)).size;
495
+ const ratio = expected ? Number((admitted / expected).toFixed(6)) : 1;
496
+ if (obs[cls === 'quiet' ? 'quietPrincipalAdmissionRatio' : 'noisyPrincipalAdmissionRatio'] !== ratio)
497
+ return false;
498
+ }
499
+ if (receipts.some(receipt => {
500
+ const expected = expectedArrivals[receipt.arrivalOrdinal];
501
+ return !expected || expected.principalId !== receipt.principalId || expected.providerId !== receipt.providerId || expected.tokens !== receipt.tokens;
502
+ }))
503
+ return false;
504
+ const scopedKeys = ['workspace', ...Object.keys(manifest.providers).map(id => `provider.${id}`), ...manifest.principals.map(p => `principal.${p.id}`)];
505
+ if (!stage.scopes || !scopedKeys.every(key => stage.scopes[key] && finite(stage.scopes[key].active) && finite(stage.scopes[key].queued)))
506
+ return false;
507
+ if (!receipts.some(receipt => manifest.principals.find(p => p.id === receipt.principalId)?.class === 'quiet')
508
+ || !receipts.some(receipt => manifest.principals.find(p => p.id === receipt.principalId)?.class === 'noisy'))
509
+ return false;
510
+ }
511
+ if (r.receipts.some(receipt => !manifest.principals.some(p => p.id === receipt.principalId) || !(receipt.providerId in manifest.providers)
512
+ || !positive(receipt.tokens) || !finite(receipt.costUsd) || !finite(receipt.admittedAtMs) || receipt.settledAtMs < receipt.admittedAtMs
513
+ || receipt.admission.decision !== 'admit' || receipt.costUsd !== price(receipt.tokens, r.pricing)))
514
+ return false;
515
+ if (r.usage.calls !== r.receipts.length || r.usage.tokens !== r.receipts.reduce((sum, receipt) => sum + receipt.tokens, 0)
516
+ || Math.abs(r.usage.usd - r.receipts.reduce((sum, receipt) => sum + receipt.costUsd, 0)) > 1e-9)
517
+ return false;
518
+ if (!r.samples.every((sample, index) => finite(sample.atMs) && finite(sample.residentMemoryMiB) && finite(sample.heapUsedMiB)
519
+ && finite(sample.cpuPercentOneCore) && finite(sample.active) && finite(sample.queued) && (index === 0 ? sample.atMs === 0 : sample.atMs >= r.samples[index - 1].atMs
520
+ && sample.atMs - r.samples[index - 1].atMs <= manifest.bounds.maximumSampleGapMs)))
521
+ return false;
522
+ if (r.samples.at(-1).atMs !== r.elapsedMs
523
+ || r.elapsedMs < r.stages.reduce((sum, stage) => sum + stage.windowSeconds * 1000, 0))
524
+ return false;
525
+ const [initial, change, rollback] = r.profileHistory;
526
+ const profileDigest = (workspace, providers) => decisionLoadManifestDigest(canonicalJson({ workspace, providers }));
527
+ if (r.profileHistory.length !== 3 || initial?.kind !== 'initial' || initial.profileVersion !== manifest.rollout.previousProfileVersion
528
+ || initial.digest !== profileDigest(manifest.rollout.workspace, manifest.rollout.providers)
529
+ || change?.kind !== 'change' || change.profileVersion !== manifest.profileVersion || change.digest !== profileDigest(manifest.workspace, manifest.providers)
530
+ || rollback?.kind !== 'rollback' || rollback.profileVersion !== initial.profileVersion || rollback.digest !== initial.digest)
531
+ return false;
532
+ const rebuilt = decisionStagedLoadResultRecord(r);
533
+ return rebuilt.passed && canonicalJson(rebuilt) === canonicalJson(r);
534
+ }
535
+ catch {
536
+ return false;
537
+ }
538
+ }
539
+ //# sourceMappingURL=load-staged.js.map