@aiwg/cli 2026.10.5 → 2026.10.7

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