@piagent/platform 1.5.4 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/CHANGELOG.md +136 -0
  2. package/README.md +9 -8
  3. package/README.vi.md +9 -5
  4. package/adapters/web-frontend/profile.json +2 -4
  5. package/architecture/layers.json +18 -3
  6. package/benchmarks/deep-logic-v1/SPECIALIST_PROTOCOL.vi.md +122 -0
  7. package/benchmarks/deep-logic-v1/grade.mjs +272 -10
  8. package/benchmarks/deep-logic-v1/project/apps/admin/src/billing-summary.js +3 -0
  9. package/benchmarks/deep-logic-v1/project/benchmark-contract/public-smoke.test.js +166 -0
  10. package/benchmarks/deep-logic-v1/project/package.json +1 -1
  11. package/benchmarks/deep-logic-v1/project/packages/billing/src/close-period.js +3 -0
  12. package/benchmarks/deep-logic-v1/project/packages/billing/src/plan-timeline.js +3 -0
  13. package/benchmarks/deep-logic-v1/project/test/smoke.test.js +7 -1
  14. package/benchmarks/deep-logic-v1/prompts/budgeted-context-graph.md +2 -0
  15. package/benchmarks/deep-logic-v1/prompts/fair-dependency-scheduler.md +2 -0
  16. package/benchmarks/deep-logic-v1/prompts/layered-policy-resolution.md +2 -0
  17. package/benchmarks/deep-logic-v1/prompts/resumable-stream-assembly.md +3 -1
  18. package/benchmarks/deep-logic-v1/prompts/revision-event-reconciliation.md +2 -0
  19. package/benchmarks/deep-logic-v1/prompts/temporal-usage-billing-close.md +123 -0
  20. package/benchmarks/deep-logic-v1/prompts/transactional-config-merge.md +2 -0
  21. package/benchmarks/deep-logic-v1/suite.json +51 -3
  22. package/benchmarks/deep-logic-v1/variant.mjs +22 -1
  23. package/benchmarks/production-v1/spend-control.v1.json +68 -0
  24. package/benchmarks/production-v1/suite.json +42 -3
  25. package/catalog/capabilities.json +6 -6
  26. package/docs/command-reference-vietnamese.md +6 -6
  27. package/docs/context-engine.md +7 -1
  28. package/docs/distribution-standard.md +7 -7
  29. package/docs/en/architecture.md +1 -0
  30. package/docs/languages.json +4 -4
  31. package/docs/model-options.md +8 -5
  32. package/docs/operator-manual-vietnamese.md +13 -11
  33. package/docs/project-adapters.md +2 -2
  34. package/docs/publishing-for-teams.md +9 -0
  35. package/docs/quality-benchmark.md +271 -62
  36. package/docs/release-install-policy.md +10 -9
  37. package/docs/runtime-policy-design.md +4 -4
  38. package/docs/runtime-quality-baseline.md +13 -6
  39. package/docs/security-threat-model.md +2 -2
  40. package/docs/task-lifecycle-vietnamese.md +2 -2
  41. package/docs/team-onboarding.md +2 -2
  42. package/docs/usage-observability.md +7 -2
  43. package/docs/vi/architecture.md +1 -0
  44. package/docs-site/architecture.html +1 -1
  45. package/docs-site/benchmark.html +1 -1
  46. package/docs-site/commands.html +1 -1
  47. package/docs-site/context-engine.html +1 -1
  48. package/docs-site/en/architecture.html +1 -1
  49. package/docs-site/en/benchmark.html +1 -1
  50. package/docs-site/en/commands.html +1 -1
  51. package/docs-site/en/context-engine.html +1 -1
  52. package/docs-site/en/index.html +1 -1
  53. package/docs-site/en/mcp-approval.html +1 -1
  54. package/docs-site/en/mcp-auth.html +1 -1
  55. package/docs-site/en/mcp-servers.html +1 -1
  56. package/docs-site/en/mcp.html +1 -1
  57. package/docs-site/en/permissions.html +1 -1
  58. package/docs-site/en/profiles.html +1 -1
  59. package/docs-site/en/quickstart.html +1 -1
  60. package/docs-site/en/runtime.html +1 -1
  61. package/docs-site/en/scope.html +1 -1
  62. package/docs-site/en/security.html +1 -1
  63. package/docs-site/en/team.html +1 -1
  64. package/docs-site/en/whats-new.html +1 -1
  65. package/docs-site/en/workflows.html +1 -1
  66. package/docs-site/index.html +1 -1
  67. package/docs-site/mcp-approval.html +1 -1
  68. package/docs-site/mcp-auth.html +1 -1
  69. package/docs-site/mcp-servers.html +1 -1
  70. package/docs-site/mcp.html +1 -1
  71. package/docs-site/permissions.html +1 -1
  72. package/docs-site/profiles.html +1 -1
  73. package/docs-site/quickstart.html +1 -1
  74. package/docs-site/runtime.html +1 -1
  75. package/docs-site/scope.html +1 -1
  76. package/docs-site/security.html +1 -1
  77. package/docs-site/team.html +1 -1
  78. package/docs-site/whats-new.html +1 -1
  79. package/docs-site/workflows.html +1 -1
  80. package/evals/fixtures/benchmark-assurance-evidence.invalid.json +1 -1
  81. package/evals/fixtures/benchmark-assurance-evidence.valid.json +1 -1
  82. package/evals/fixtures/piagent-webui/session-live-state-v1.invalid.json +18 -0
  83. package/evals/fixtures/piagent-webui/session-live-state-v1.valid.json +27 -0
  84. package/evals/fs4-readiness-matrix.v1.json +2 -2
  85. package/evals/fs5-causal-arm.v1.json +2 -2
  86. package/evals/fs5-pilot-protocol.v1.json +2 -2
  87. package/evals/fs5-pilot-protocol.v4.json +6 -5
  88. package/evals/fs5-pilot-protocol.v5.json +7 -6
  89. package/evals/private-holdout-v1/public-exposure.v1.json +1 -1
  90. package/package.json +3 -1
  91. package/packages/piagent-core/benchmark/benchmark-assurance.js +4 -1
  92. package/packages/piagent-core/benchmark/benchmark-bootstrap.js +91 -9
  93. package/packages/piagent-core/benchmark/benchmark-claim-restrictions.js +38 -7
  94. package/packages/piagent-core/benchmark/benchmark-cli.js +7 -7
  95. package/packages/piagent-core/benchmark/benchmark-codex.js +3 -1
  96. package/packages/piagent-core/benchmark/benchmark-comparison.js +271 -2
  97. package/packages/piagent-core/benchmark/benchmark-core.js +732 -661
  98. package/packages/piagent-core/benchmark/benchmark-execution-guard.js +7 -5
  99. package/packages/piagent-core/benchmark/benchmark-forensics.js +439 -4
  100. package/packages/piagent-core/benchmark/benchmark-host-readiness.js +639 -0
  101. package/packages/piagent-core/benchmark/benchmark-matrix.js +22 -4
  102. package/packages/piagent-core/benchmark/benchmark-normalized-cost.js +317 -0
  103. package/packages/piagent-core/benchmark/benchmark-preflight.js +3 -1
  104. package/packages/piagent-core/benchmark/benchmark-process.js +6 -5
  105. package/packages/piagent-core/benchmark/benchmark-provider-wire.js +126 -0
  106. package/packages/piagent-core/benchmark/benchmark-record-validation.js +183 -0
  107. package/packages/piagent-core/benchmark/benchmark-report.js +116 -12
  108. package/packages/piagent-core/benchmark/benchmark-resume-recovery.js +14 -0
  109. package/packages/piagent-core/benchmark/benchmark-runner-policy.js +26 -0
  110. package/packages/piagent-core/benchmark/benchmark-stage-diagnostic.js +782 -0
  111. package/packages/piagent-core/benchmark/benchmark-statistics.js +64 -0
  112. package/packages/piagent-core/benchmark/benchmark-stop-policy.js +8 -5
  113. package/packages/piagent-core/benchmark/benchmark-suite-identity.js +31 -0
  114. package/packages/piagent-core/benchmark/benchmark-suite-runtime.js +13 -9
  115. package/packages/piagent-core/benchmark/benchmark-suite.js +128 -2
  116. package/packages/piagent-core/benchmark/benchmark-summary-support.js +376 -0
  117. package/packages/piagent-core/benchmark/benchmark-timing-diagnostics.js +971 -0
  118. package/packages/piagent-core/benchmark/benchmark-usage.js +311 -0
  119. package/packages/piagent-core/benchmark/benchmark-workflow.js +166 -0
  120. package/packages/piagent-core/docs/context-efficiency-improvement-plan.md +1080 -0
  121. package/packages/piagent-core/extensions/acceptance-contract-semantics.js +83 -69
  122. package/packages/piagent-core/extensions/acceptance-error-classes.js +160 -0
  123. package/packages/piagent-core/extensions/acceptance-executable-evidence.js +12 -9
  124. package/packages/piagent-core/extensions/acceptance-receipt.js +34 -11
  125. package/packages/piagent-core/extensions/acceptance-state-machine-evidence.js +518 -0
  126. package/packages/piagent-core/extensions/acceptance-test-binding-evidence.js +60 -0
  127. package/packages/piagent-core/extensions/context-efficiency-metrics.js +302 -0
  128. package/packages/piagent-core/extensions/context-efficiency-report.js +167 -0
  129. package/packages/piagent-core/extensions/context-engine.js +148 -145
  130. package/packages/piagent-core/extensions/context-evidence.js +48 -0
  131. package/packages/piagent-core/extensions/context-import-links.js +296 -0
  132. package/packages/piagent-core/extensions/context-telemetry-integrity.js +65 -0
  133. package/packages/piagent-core/extensions/criterion-context-pack.js +422 -7
  134. package/packages/piagent-core/extensions/criterion-graph.js +78 -8
  135. package/packages/piagent-core/extensions/guard-types.ts +3 -0
  136. package/packages/piagent-core/extensions/javascript-regex-evidence.js +32 -0
  137. package/packages/piagent-core/extensions/piagent-guard.ts +250 -43
  138. package/packages/piagent-core/extensions/policy-core.js +1 -1
  139. package/packages/piagent-core/extensions/task-contract-view.js +17 -3
  140. package/packages/piagent-core/extensions/task-lifecycle.js +7 -2
  141. package/packages/piagent-core/extensions/task-state.js +40 -134
  142. package/packages/piagent-core/extensions/verification-intelligence.js +3 -1
  143. package/packages/piagent-core/extensions/workspace-evidence-roots.js +157 -0
  144. package/packages/piagent-core/package.json +1 -1
  145. package/packages/piagent-core/policies/base-policy.json +3 -0
  146. package/packages/piagent-core/runtime/context/context-delivery.ts +103 -0
  147. package/packages/piagent-core/runtime/context/context-delta-shadow.ts +53 -0
  148. package/packages/piagent-core/runtime/context/context-efficiency-format.ts +47 -0
  149. package/packages/piagent-core/runtime/context/context-evidence-qualification.ts +32 -0
  150. package/packages/piagent-core/runtime/context/prefix-telemetry.ts +47 -0
  151. package/packages/piagent-core/runtime/context/repository-memory-hints.ts +27 -0
  152. package/packages/piagent-core/runtime/hooks/agent-prompt-telemetry.ts +56 -0
  153. package/packages/piagent-core/runtime/hooks/agent-start-hook.ts +162 -102
  154. package/packages/piagent-core/runtime/hooks/completion-hook.ts +5 -6
  155. package/packages/piagent-core/runtime/hooks/input-hook.ts +11 -1
  156. package/packages/piagent-core/runtime/hooks/session-hooks.ts +22 -2
  157. package/packages/piagent-core/runtime/hooks/session-start-hook.ts +7 -2
  158. package/packages/piagent-core/runtime/hooks/tool-result-content-guards.ts +95 -0
  159. package/packages/piagent-core/runtime/hooks/tool-result-hook.ts +84 -102
  160. package/packages/piagent-core/runtime/inspection/activity-event-adapter.ts +9 -3
  161. package/packages/piagent-core/runtime/inspection/activity-recovery.ts +104 -0
  162. package/packages/piagent-core/runtime/inspection/approval-broker.ts +29 -5
  163. package/packages/piagent-core/runtime/inspection/task-compaction-history.ts +1 -1
  164. package/packages/piagent-core/runtime/inspection/task-handoff-history.ts +1 -1
  165. package/packages/piagent-core/runtime/inspection/tool-failure-classification.ts +53 -0
  166. package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +34 -6
  167. package/packages/piagent-core/runtime/model/authenticated-catalog.ts +17 -9
  168. package/packages/piagent-core/runtime/model/openai-codex-reasoning.ts +83 -0
  169. package/packages/piagent-core/runtime/model/provider-wire-fingerprint.ts +238 -0
  170. package/packages/piagent-core/runtime/orchestration/role-policy.ts +1 -1
  171. package/packages/piagent-core/runtime/product/activity-inspector.ts +7 -2
  172. package/packages/piagent-core/runtime/product/efficiency-metrics.ts +4 -2
  173. package/packages/piagent-core/runtime/quality/exact-output-contract.ts +2 -1
  174. package/packages/piagent-core/runtime/quality/performance-assurance-signals.ts +23 -0
  175. package/packages/piagent-core/runtime/quality/performance-assurance.ts +6 -2
  176. package/packages/piagent-core/runtime/recovery/edit-recovery-context.ts +113 -0
  177. package/packages/piagent-core/runtime/recovery/edit-recovery-delivery.ts +42 -0
  178. package/packages/piagent-core/runtime/recovery/semantic-repair-handshake.ts +55 -2
  179. package/packages/piagent-core/runtime/recovery/semantic-repair-runtime.ts +55 -2
  180. package/packages/piagent-core/runtime/registration/context-commands.ts +66 -5
  181. package/packages/piagent-core/runtime/registration/policy-tools.ts +46 -11
  182. package/packages/piagent-core/runtime/registration/task-completion-tools.ts +49 -16
  183. package/packages/piagent-core/runtime/registration/task-start-guidance.ts +163 -0
  184. package/packages/piagent-core/runtime/registration/task-start-retry-helpers.ts +37 -0
  185. package/packages/piagent-core/runtime/registration/task-start-tool.ts +67 -62
  186. package/packages/piagent-core/runtime/session/runtime-state.ts +154 -2
  187. package/packages/piagent-core/runtime/session/system-prompt.ts +4 -4
  188. package/packages/piagent-core/runtime/tools/apply-patch-tool.ts +500 -0
  189. package/packages/piagent-core/runtime/trajectory/trajectory-runtime.ts +2 -1
  190. package/packages/piagent-core/runtime/workflows/task-intake.ts +43 -2
  191. package/packages/piagent-core/security/sensitive-data.js +13 -218
  192. package/packages/piagent-core/security/sensitive-project-file.js +42 -0
  193. package/packages/piagent-core/security/sensitive-source-expression.js +330 -0
  194. package/packages/piagent-core/security/sensitive-source-formats.js +394 -0
  195. package/packages/piagent-core/security/sensitive-text.js +234 -0
  196. package/packages/piagent-core/subagents/piagent-worker.md +1 -1
  197. package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-rD9WJKxs.js → MarkdownMessage-CxeZqTte.js} +1 -1
  198. package/packages/piagent-webui/dist/client/assets/index-DynIMe8I.js +176 -0
  199. package/packages/piagent-webui/dist/client/index.html +1 -1
  200. package/packages/piagent-webui/gateway/gateway-events.ts +109 -5
  201. package/packages/piagent-webui/gateway/gateway-service.ts +3 -0
  202. package/packages/piagent-webui/gateway/gateway-session-stream.ts +93 -7
  203. package/packages/piagent-webui/gateway/session-command-controller.ts +18 -3
  204. package/packages/piagent-webui/gateway/session-effective-options.ts +47 -0
  205. package/packages/piagent-webui/gateway/session-live-state.ts +21 -0
  206. package/packages/piagent-webui/gateway/session-operation-start.ts +5 -1
  207. package/packages/piagent-webui/gateway/session-operation-watchdog.ts +158 -0
  208. package/packages/piagent-webui/gateway/session-runtime-factory.ts +45 -0
  209. package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +139 -120
  210. package/packages/piagent-webui/server/loopback-server.ts +8 -0
  211. package/packages/piagent-webui/server/transcript-projection.ts +22 -4
  212. package/packages/piagent-webui/shared/text-visibility.ts +10 -0
  213. package/schemas/piagent-webui/catalog-v1.json +9 -0
  214. package/schemas/piagent-webui/gateway-protocol-v1.schema.json +53 -3
  215. package/schemas/piagent-webui/session-live-state-v1.schema.json +76 -0
  216. package/schemas/task-contract.schema.json +12 -1
  217. package/scripts/benchmark-runner-core.mjs +355 -359
  218. package/scripts/benchmark-runner-finalization.mjs +309 -0
  219. package/scripts/benchmark-runner-host-readiness.mjs +94 -0
  220. package/scripts/benchmark-runner-support.mjs +200 -0
  221. package/scripts/benchmark-session.mjs +95 -41
  222. package/scripts/configure-model-scope.sh +4 -3
  223. package/scripts/helper-evaluation.mjs +1 -1
  224. package/scripts/install-global.sh +2 -2
  225. package/scripts/pi-usage-history.mjs +37 -10
  226. package/scripts/piagent-dashboard.mjs +13 -1
  227. package/scripts/setup.sh +2 -2
  228. package/scripts/verify-local.sh +5 -1
  229. package/templates/global/settings.json +2 -1
  230. package/packages/piagent-webui/dist/client/assets/index-BZRFw1u6.js +0 -174
@@ -0,0 +1,64 @@
1
+ export function median(values) {
2
+ const finite = values.filter(Number.isFinite).sort((left, right) => left - right);
3
+ if (finite.length === 0) return null;
4
+ const middle = Math.floor(finite.length / 2);
5
+ return finite.length % 2 ? finite[middle] : (finite[middle - 1] + finite[middle]) / 2;
6
+ }
7
+
8
+ export function geometricMean(values) {
9
+ if (!Array.isArray(values) || values.length === 0) return null;
10
+ if (values.some((value) => !Number.isFinite(value) || value <= 0)) return null;
11
+ return Math.exp(values.reduce((sum, value) => sum + Math.log(value), 0) / values.length);
12
+ }
13
+
14
+ export function rounded(value, digits = 3) {
15
+ if (!Number.isFinite(value)) return null;
16
+ const factor = 10 ** digits;
17
+ return Math.round(value * factor) / factor;
18
+ }
19
+
20
+ export function clamp(value, minimum = 0, maximum = 10) {
21
+ return Math.max(minimum, Math.min(maximum, value));
22
+ }
23
+
24
+ export function wilsonInterval(successes, total, z = 1.959963984540054) {
25
+ if (!Number.isInteger(total) || total <= 0 || !Number.isInteger(successes) || successes < 0 || successes > total) return null;
26
+ const proportion = successes / total;
27
+ const zSquared = z ** 2;
28
+ const denominator = 1 + (zSquared / total);
29
+ const center = (proportion + (zSquared / (2 * total))) / denominator;
30
+ const margin = (z / denominator) * Math.sqrt(((proportion * (1 - proportion)) / total) + (zSquared / (4 * total ** 2)));
31
+ return { lower: rounded(Math.max(0, center - margin), 4), upper: rounded(Math.min(1, center + margin), 4) };
32
+ }
33
+
34
+ const STUDENT_T_975 = Object.freeze([
35
+ null, 12.706, 4.303, 3.182, 2.776, 2.571, 2.447, 2.365, 2.306, 2.262,
36
+ 2.228, 2.201, 2.179, 2.16, 2.145, 2.131, 2.12, 2.11, 2.101, 2.093,
37
+ 2.086, 2.08, 2.074, 2.069, 2.064, 2.06, 2.056, 2.052, 2.048, 2.045, 2.042
38
+ ]);
39
+
40
+ export function geometricMeanConfidence95Raw(values) {
41
+ if (!Array.isArray(values) || values.length < 2 || values.some((value) => !Number.isFinite(value) || value <= 0)) return null;
42
+ const logs = values.map(Math.log);
43
+ const mean = logs.reduce((sum, value) => sum + value, 0) / logs.length;
44
+ const variance = logs.reduce((sum, value) => sum + ((value - mean) ** 2), 0) / (logs.length - 1);
45
+ const critical = STUDENT_T_975[logs.length - 1] ?? 1.96;
46
+ const margin = critical * Math.sqrt(variance / logs.length);
47
+ return {
48
+ lower: Math.exp(mean - margin),
49
+ upper: Math.exp(mean + margin),
50
+ sampleUnit: "scenario-family",
51
+ scenarioCount: logs.length
52
+ };
53
+ }
54
+
55
+ export function geometricMeanConfidence95(values) {
56
+ const interval = geometricMeanConfidence95Raw(values);
57
+ return interval ? { ...interval, lower: rounded(interval.lower, 4), upper: rounded(interval.upper, 4) } : null;
58
+ }
59
+
60
+ export function atMostWithinFloatingPrecision(value, maximum) {
61
+ if (!Number.isFinite(value) || !Number.isFinite(maximum)) return false;
62
+ const tolerance = Number.EPSILON * Math.max(1, Math.abs(value), Math.abs(maximum)) * 8;
63
+ return value <= maximum || Math.abs(value - maximum) <= tolerance;
64
+ }
@@ -5,11 +5,14 @@ function samePair(left, right) {
5
5
  function outcomeFailure(run, floor) {
6
6
  if (run?.surface !== "piagent") return null;
7
7
  if (run?.resolved !== true) return "unresolved-outcome";
8
- if (run.scenarioKind !== "safety-refusal" && (!Number.isFinite(run.grade?.score) || run.grade.score <= floor)) {
9
- return "quality-outcome-floor";
10
- }
11
- if (run.scenarioKind !== "safety-refusal"
12
- && (!Number.isFinite(run.workflow?.score) || run.workflow.score <= floor)) return "workflow-outcome-floor";
8
+ if (run?.scope?.passed !== true) return "scope-safety-evidence-failed";
9
+ if (run?.outputSafety?.passed !== true) return "output-safety-evidence-failed";
10
+ if (run.scenarioKind === "safety-refusal") return run?.grade?.passed === true ? null : "safety-refusal-grade-failed";
11
+ if (run?.grade?.passed !== true) return "quality-grade-failed";
12
+ if (run?.graderIntegrity?.passed !== true) return "grader-integrity-failed";
13
+ if (run?.outputEvidence?.passed === false) return "output-evidence-failed";
14
+ if (!Number.isFinite(run.grade?.score) || run.grade.score <= floor) return "quality-outcome-floor";
15
+ if (!Number.isFinite(run.workflow?.score) || run.workflow.score <= floor) return "workflow-outcome-floor";
13
16
  return null;
14
17
  }
15
18
 
@@ -0,0 +1,31 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ export const BUILT_IN_BENCHMARK_SUITE_IDS = Object.freeze([
5
+ "core-v1",
6
+ "capability-v1",
7
+ "e2-framework-v1",
8
+ "deep-logic-v1",
9
+ "production-v1"
10
+ ]);
11
+
12
+ const reservedSuiteIds = new Set(BUILT_IN_BENCHMARK_SUITE_IDS);
13
+
14
+ export function isReservedBenchmarkSuiteId(value) {
15
+ return reservedSuiteIds.has(value);
16
+ }
17
+
18
+ export function builtInBenchmarkSuiteManifest(packageRoot, suiteId) {
19
+ return isReservedBenchmarkSuiteId(suiteId)
20
+ ? path.join(packageRoot, "benchmarks", suiteId, "suite.json")
21
+ : null;
22
+ }
23
+
24
+ export function canonicalBuiltInBenchmarkSuiteId(packageRoot, manifestPath) {
25
+ const resolvedManifest = fs.realpathSync(manifestPath);
26
+ for (const suiteId of BUILT_IN_BENCHMARK_SUITE_IDS) {
27
+ const candidate = builtInBenchmarkSuiteManifest(packageRoot, suiteId);
28
+ if (fs.existsSync(candidate) && fs.realpathSync(candidate) === resolvedManifest) return suiteId;
29
+ }
30
+ return null;
31
+ }
@@ -5,6 +5,11 @@ import path from "node:path";
5
5
  import { benchmarkAssuranceEvidenceValidationErrors } from "./benchmark-core.js";
6
6
  import { validateBenchmarkSuite } from "./benchmark-suite.js";
7
7
  import { assertBenchmarkModuleGraphBound } from "./benchmark-suite-assets.js";
8
+ import {
9
+ builtInBenchmarkSuiteManifest,
10
+ canonicalBuiltInBenchmarkSuiteId,
11
+ isReservedBenchmarkSuiteId
12
+ } from "./benchmark-suite-identity.js";
8
13
 
9
14
  function fail(message) {
10
15
  const error = new Error(message);
@@ -18,14 +23,7 @@ function inside(parent, target) {
18
23
  }
19
24
 
20
25
  export function loadBenchmarkSuite(input, packageRoot) {
21
- const builtIn = new Map([
22
- ["core-v1", path.join(packageRoot, "benchmarks", "core-v1", "suite.json")],
23
- ["capability-v1", path.join(packageRoot, "benchmarks", "capability-v1", "suite.json")],
24
- ["e2-framework-v1", path.join(packageRoot, "benchmarks", "e2-framework-v1", "suite.json")],
25
- ["deep-logic-v1", path.join(packageRoot, "benchmarks", "deep-logic-v1", "suite.json")],
26
- ["production-v1", path.join(packageRoot, "benchmarks", "production-v1", "suite.json")]
27
- ]);
28
- const candidate = builtIn.get(input) ?? path.resolve(input);
26
+ const candidate = builtInBenchmarkSuiteManifest(packageRoot, input) ?? path.resolve(input);
29
27
  const manifestPath = fs.existsSync(candidate) && fs.statSync(candidate).isDirectory()
30
28
  ? path.join(candidate, "suite.json")
31
29
  : candidate;
@@ -33,7 +31,13 @@ export function loadBenchmarkSuite(input, packageRoot) {
33
31
  try { raw = JSON.parse(fs.readFileSync(manifestPath, "utf8")); }
34
32
  catch (error) { fail(`Cannot read benchmark suite ${manifestPath}: ${error.message}`); }
35
33
  const suite = validateBenchmarkSuite(raw);
36
- return { suite, manifestPath: fs.realpathSync(manifestPath), suiteRoot: fs.realpathSync(path.dirname(manifestPath)) };
34
+ const resolvedManifestPath = fs.realpathSync(manifestPath);
35
+ const builtInId = canonicalBuiltInBenchmarkSuiteId(packageRoot, resolvedManifestPath);
36
+ if (builtInId && suite.id !== builtInId) fail(`Built-in benchmark suite identity mismatch: expected ${builtInId}, found ${suite.id}`);
37
+ if (!builtInId && isReservedBenchmarkSuiteId(suite.id)) {
38
+ fail(`Benchmark suite id ${suite.id} is reserved for its canonical built-in suite`);
39
+ }
40
+ return { suite, manifestPath: resolvedManifestPath, suiteRoot: fs.realpathSync(path.dirname(resolvedManifestPath)), builtInId };
37
41
  }
38
42
 
39
43
  export function resolveBenchmarkSuiteEntry(suiteRoot, relativePath, kind) {
@@ -1,8 +1,9 @@
1
1
  import { benchmarkAssuranceValidationErrors } from "./benchmark-assurance.js";
2
+ import { benchmarkPricingSnapshotValidationErrors } from "./benchmark-normalized-cost.js";
2
3
 
3
4
  const SUITE_FIELDS = new Set([
4
5
  "schemaVersion", "id", "title", "description", "profile", "defaultRepeats", "timeoutSeconds",
5
- "assurance", "releaseGate", "scenarios"
6
+ "assurance", "releaseGate", "executionContract", "pricingSnapshot", "scenarios"
6
7
  ]);
7
8
  const SCENARIO_FIELDS = new Set([
8
9
  "id", "title", "description", "kind", "fixture", "prompt", "grader", "allowedChanges",
@@ -12,11 +13,24 @@ const SCENARIO_FIELDS = new Set([
12
13
  const RELEASE_GATE_FIELDS = new Set([
13
14
  "minimumQualityScore", "minimumSafetyScore", "minimumReliabilityScore", "minimumWorkflowScore",
14
15
  "minimumCategoryScore", "minimumOutcomeScoreExclusive", "minimumPairedScenarios", "minimumRepeats",
15
- "minimumComparableEfficiencyScenarios", "maximumFreshTokenRatioUpper95", "requireEfficiencyClaim"
16
+ "minimumComparableEfficiencyScenarios", "maximumFreshTokenRatioUpper95", "maximumDurationRatioUpper95",
17
+ "maximumBandDurationRatio", "maximumFamilyDurationRatio",
18
+ "maximumBandFreshTokenRatio", "maximumFamilyFreshTokenRatio",
19
+ "maximumNormalizedCostRatioUpper95", "maximumBandNormalizedCostRatio", "maximumFamilyNormalizedCostRatio",
20
+ "maximumInfrastructureRetries", "primaryEfficiencyEstimand", "requireEfficiencyClaim", "requireFullSuiteForClaim",
21
+ "requireStableProviderWireSurface", "requireNormalizedCostClaim", "requireHostReadinessForClaim",
22
+ "requireCausalContextReceipt"
16
23
  ]);
24
+ const EXECUTION_CONTRACT_FIELDS = new Set(["surfaces", "model", "thinking", "codexMode"]);
25
+ const THINKING_LEVELS = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
17
26
  const SCENARIO_KINDS = new Set(["source-change", "read-only", "safety-refusal"]);
18
27
  const SCENARIO_DIFFICULTIES = new Set(["small", "medium", "large"]);
19
28
  const SCENARIO_LIFECYCLES = new Set(["steady-state", "cold-start"]);
29
+ const PRIMARY_EFFICIENCY_ESTIMANDS = new Set([
30
+ "successful-pair-family-ratio",
31
+ "failure-aware-family-ratio",
32
+ "fixed-workload-family-ratio"
33
+ ]);
20
34
  const ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
21
35
 
22
36
  function plainObject(value) {
@@ -86,13 +100,96 @@ export function benchmarkSuiteValidationErrors(input) {
86
100
  if (minimumRepeats !== undefined && (!Number.isInteger(minimumRepeats) || minimumRepeats < 1 || minimumRepeats > 10)) {
87
101
  errors.push("releaseGate.minimumRepeats must be between 1 and 10");
88
102
  }
103
+ const maximumInfrastructureRetries = input.releaseGate.maximumInfrastructureRetries;
104
+ if (maximumInfrastructureRetries !== undefined && (!Number.isInteger(maximumInfrastructureRetries) || maximumInfrastructureRetries < 0 || maximumInfrastructureRetries > 1_000)) {
105
+ errors.push("releaseGate.maximumInfrastructureRetries must be between 0 and 1000");
106
+ }
89
107
  const maximumRatio = input.releaseGate.maximumFreshTokenRatioUpper95;
90
108
  if (maximumRatio !== undefined && (!Number.isFinite(maximumRatio) || maximumRatio <= 0 || maximumRatio > 10)) {
91
109
  errors.push("releaseGate.maximumFreshTokenRatioUpper95 must be greater than 0 and at most 10");
92
110
  }
111
+ const maximumBandRatio = input.releaseGate.maximumBandFreshTokenRatio;
112
+ if (maximumBandRatio !== undefined && (!Number.isFinite(maximumBandRatio) || maximumBandRatio <= 0 || maximumBandRatio > 10)) {
113
+ errors.push("releaseGate.maximumBandFreshTokenRatio must be greater than 0 and at most 10");
114
+ }
115
+ const maximumFamilyRatio = input.releaseGate.maximumFamilyFreshTokenRatio;
116
+ if (maximumFamilyRatio !== undefined && (!Number.isFinite(maximumFamilyRatio) || maximumFamilyRatio <= 0 || maximumFamilyRatio > 10)) {
117
+ errors.push("releaseGate.maximumFamilyFreshTokenRatio must be greater than 0 and at most 10");
118
+ }
119
+ const maximumDurationRatio = input.releaseGate.maximumDurationRatioUpper95;
120
+ if (maximumDurationRatio !== undefined && (!Number.isFinite(maximumDurationRatio) || maximumDurationRatio <= 0 || maximumDurationRatio > 10)) {
121
+ errors.push("releaseGate.maximumDurationRatioUpper95 must be greater than 0 and at most 10");
122
+ }
123
+ for (const field of ["maximumBandDurationRatio", "maximumFamilyDurationRatio"]) {
124
+ const value = input.releaseGate[field];
125
+ if (value !== undefined && (!Number.isFinite(value) || value <= 0 || value > 10)) {
126
+ errors.push(`releaseGate.${field} must be greater than 0 and at most 10`);
127
+ }
128
+ }
129
+ for (const field of [
130
+ "maximumNormalizedCostRatioUpper95", "maximumBandNormalizedCostRatio", "maximumFamilyNormalizedCostRatio"
131
+ ]) {
132
+ const value = input.releaseGate[field];
133
+ if (value !== undefined && (!Number.isFinite(value) || value <= 0 || value > 10)) {
134
+ errors.push(`releaseGate.${field} must be greater than 0 and at most 10`);
135
+ }
136
+ }
93
137
  if (input.releaseGate.requireEfficiencyClaim !== undefined && typeof input.releaseGate.requireEfficiencyClaim !== "boolean") {
94
138
  errors.push("releaseGate.requireEfficiencyClaim must be a boolean");
95
139
  }
140
+ if (input.releaseGate.primaryEfficiencyEstimand !== undefined
141
+ && !PRIMARY_EFFICIENCY_ESTIMANDS.has(input.releaseGate.primaryEfficiencyEstimand)) {
142
+ errors.push("releaseGate.primaryEfficiencyEstimand is invalid");
143
+ }
144
+ if (input.releaseGate.primaryEfficiencyEstimand === "fixed-workload-family-ratio") {
145
+ for (const field of ["maximumBandFreshTokenRatio", "maximumFamilyFreshTokenRatio"]) {
146
+ if (input.releaseGate[field] !== undefined) {
147
+ errors.push(`releaseGate.${field} is incompatible with fixed-workload-family-ratio; use the full-suite primary confidence gate`);
148
+ }
149
+ }
150
+ }
151
+ if (input.releaseGate.requireFullSuiteForClaim !== undefined && typeof input.releaseGate.requireFullSuiteForClaim !== "boolean") {
152
+ errors.push("releaseGate.requireFullSuiteForClaim must be a boolean");
153
+ }
154
+ if (input.releaseGate.requireStableProviderWireSurface !== undefined && typeof input.releaseGate.requireStableProviderWireSurface !== "boolean") {
155
+ errors.push("releaseGate.requireStableProviderWireSurface must be a boolean");
156
+ }
157
+ if (input.releaseGate.requireNormalizedCostClaim !== undefined && typeof input.releaseGate.requireNormalizedCostClaim !== "boolean") {
158
+ errors.push("releaseGate.requireNormalizedCostClaim must be a boolean");
159
+ }
160
+ if (input.releaseGate.requireHostReadinessForClaim !== undefined && typeof input.releaseGate.requireHostReadinessForClaim !== "boolean") {
161
+ errors.push("releaseGate.requireHostReadinessForClaim must be a boolean");
162
+ }
163
+ if (input.releaseGate.requireCausalContextReceipt !== undefined && typeof input.releaseGate.requireCausalContextReceipt !== "boolean") {
164
+ errors.push("releaseGate.requireCausalContextReceipt must be a boolean");
165
+ }
166
+ }
167
+ }
168
+ if (input.pricingSnapshot !== undefined) {
169
+ errors.push(...benchmarkPricingSnapshotValidationErrors(input.pricingSnapshot));
170
+ if (plainObject(input.executionContract) && input.pricingSnapshot?.model !== input.executionContract.model) {
171
+ errors.push("pricingSnapshot.model must match executionContract.model");
172
+ }
173
+ }
174
+ if (input.executionContract !== undefined) {
175
+ if (!plainObject(input.executionContract)) errors.push("executionContract must be an object");
176
+ else {
177
+ for (const field of Object.keys(input.executionContract)) {
178
+ if (!EXECUTION_CONTRACT_FIELDS.has(field)) errors.push(`executionContract has unsupported field ${field}`);
179
+ }
180
+ const contract = input.executionContract;
181
+ if (!Array.isArray(contract.surfaces)
182
+ || contract.surfaces.length !== 2
183
+ || contract.surfaces[0] !== "piagent"
184
+ || contract.surfaces[1] !== "codex-cli") {
185
+ errors.push("executionContract.surfaces must be exactly piagent,codex-cli");
186
+ }
187
+ requiredString(contract.model, "executionContract.model", errors);
188
+ if (typeof contract.model === "string" && !/^[^/\s]+\/[^/\s]+$/.test(contract.model)) {
189
+ errors.push("executionContract.model must use provider/model form");
190
+ }
191
+ if (!THINKING_LEVELS.has(contract.thinking)) errors.push("executionContract.thinking is invalid");
192
+ if (contract.codexMode !== "controlled") errors.push("executionContract.codexMode must be controlled");
96
193
  }
97
194
  }
98
195
  if (input.schemaVersion === 2 && (!plainObject(input.assurance) || !plainObject(input.releaseGate))) {
@@ -101,6 +198,35 @@ export function benchmarkSuiteValidationErrors(input) {
101
198
  if (input.schemaVersion === 2 && input.releaseGate?.requireEfficiencyClaim === true && !Number.isInteger(input.releaseGate?.minimumComparableEfficiencyScenarios)) {
102
199
  errors.push("schemaVersion 2 efficiency claims require releaseGate.minimumComparableEfficiencyScenarios");
103
200
  }
201
+ if (input.schemaVersion === 2 && input.releaseGate?.requireEfficiencyClaim === true
202
+ && (!Number.isFinite(input.releaseGate?.maximumFreshTokenRatioUpper95) || input.releaseGate.maximumFreshTokenRatioUpper95 > 0.8)) {
203
+ errors.push("schemaVersion 2 token-saving claims require releaseGate.maximumFreshTokenRatioUpper95 at or below 0.8");
204
+ }
205
+ if (input.schemaVersion === 2 && input.releaseGate?.requireEfficiencyClaim === true && input.releaseGate?.requireFullSuiteForClaim !== true) {
206
+ errors.push("schemaVersion 2 token-saving claims require releaseGate.requireFullSuiteForClaim true");
207
+ }
208
+ if (input.schemaVersion === 2 && input.releaseGate?.requireEfficiencyClaim === true && input.releaseGate?.requireStableProviderWireSurface !== true) {
209
+ errors.push("schemaVersion 2 token-saving claims require releaseGate.requireStableProviderWireSurface true");
210
+ }
211
+ if (input.schemaVersion === 2 && input.releaseGate?.requireEfficiencyClaim === true && input.releaseGate?.requireCausalContextReceipt !== true) {
212
+ errors.push("schemaVersion 2 token-saving claims require releaseGate.requireCausalContextReceipt true");
213
+ }
214
+ if (input.schemaVersion === 2 && input.releaseGate?.requireNormalizedCostClaim === true) {
215
+ if (!plainObject(input.pricingSnapshot)) errors.push("schemaVersion 2 normalized-cost claims require pricingSnapshot");
216
+ if (!Number.isFinite(input.releaseGate.maximumNormalizedCostRatioUpper95)
217
+ || input.releaseGate.maximumNormalizedCostRatioUpper95 > 0.8) {
218
+ errors.push("schemaVersion 2 normalized-cost claims require releaseGate.maximumNormalizedCostRatioUpper95 at or below 0.8");
219
+ }
220
+ if (!Number.isFinite(input.releaseGate.maximumBandNormalizedCostRatio)) {
221
+ errors.push("schemaVersion 2 normalized-cost claims require releaseGate.maximumBandNormalizedCostRatio");
222
+ }
223
+ if (!Number.isFinite(input.releaseGate.maximumFamilyNormalizedCostRatio)) {
224
+ errors.push("schemaVersion 2 normalized-cost claims require releaseGate.maximumFamilyNormalizedCostRatio");
225
+ }
226
+ if (input.releaseGate.requireEfficiencyClaim !== true) {
227
+ errors.push("schemaVersion 2 normalized-cost claims require releaseGate.requireEfficiencyClaim true");
228
+ }
229
+ }
104
230
  if (!Array.isArray(input.scenarios) || input.scenarios.length === 0 || input.scenarios.length > 50) {
105
231
  errors.push("scenarios must contain between 1 and 50 entries");
106
232
  return errors;