@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
@@ -1,4 +1,186 @@
1
1
  const benchmarkSurfaces = new Set(["raw-pi", "piagent", "codex-cli"]);
2
+ const causalCoverageLanesV1 = new Set([
3
+ "telemetry-window", "session-lifecycle", "criterion-initial-pack", "pack-lifecycle", "direct-fallback-rereads", "managed-prefix"
4
+ ]);
5
+ const causalCoverageLanesV2 = new Set([...causalCoverageLanesV1, "edit-recovery-context"]);
6
+ const causalMaximumAggregate = 1_000_000_000;
7
+
8
+ function exactKeys(value, keys) {
9
+ return value && typeof value === "object" && !Array.isArray(value)
10
+ && Object.keys(value).length === keys.length
11
+ && keys.every((key) => Object.hasOwn(value, key));
12
+ }
13
+
14
+ function boundedInteger(value) {
15
+ return Number.isSafeInteger(value) && value >= 0 && value <= causalMaximumAggregate;
16
+ }
17
+
18
+ function validCausalTriplet(value) {
19
+ return exactKeys(value, ["offered", "delivered", "injected"])
20
+ && [value.offered, value.delivered, value.injected].every(boundedInteger)
21
+ && value.delivered <= value.offered && value.injected === value.delivered;
22
+ }
23
+
24
+ function validCriterionAggregate(value, aggregate) {
25
+ if (!exactKeys(value, ["attempts", "selectedAttempts", "candidates", "selectedItems", "estimatedTokens", "zeroSelectionReasonCounts", "offered", "delivered", "injected"])
26
+ || ![value.attempts, value.selectedAttempts, value.candidates, value.selectedItems, value.estimatedTokens,
27
+ value.offered, value.delivered, value.injected].every(boundedInteger)
28
+ || !exactKeys(value.zeroSelectionReasonCounts, ["autoContextDisabled", "criterionGraphUnavailable", "noCandidates", "noReadableSelection"])
29
+ || !Object.values(value.zeroSelectionReasonCounts).every(boundedInteger)) return false;
30
+ const zeroAttempts = Object.values(value.zeroSelectionReasonCounts).reduce((sum, count) => sum + count, 0);
31
+ return value.selectedAttempts <= value.attempts
32
+ && value.selectedAttempts === value.offered
33
+ && value.offered === value.delivered && value.delivered === value.injected
34
+ && value.selectedItems >= value.selectedAttempts && value.candidates >= value.selectedItems
35
+ && zeroAttempts === value.attempts - value.selectedAttempts
36
+ && value.offered <= aggregate.packCounts.offered
37
+ && value.selectedItems <= aggregate.selectedItemCounts.offered
38
+ && value.estimatedTokens <= aggregate.estimatedTokens.offered;
39
+ }
40
+
41
+ function validEditRecoveryAggregate(value) {
42
+ if (!exactKeys(value, ["count", "failuresObserved", "suppressedFailures", "injectedChars", "injectedEstimatedTokens", "evidenceCoverage", "definition"])
43
+ || ![value.count, value.failuresObserved, value.suppressedFailures, value.injectedChars, value.injectedEstimatedTokens].every(boundedInteger)
44
+ || value.failuresObserved !== value.count + value.suppressedFailures
45
+ || !exactKeys(value.evidenceCoverage, ["status", "observed", "comparable", "rate"])
46
+ || value.evidenceCoverage.status !== "complete"
47
+ || ![value.evidenceCoverage.observed, value.evidenceCoverage.comparable].every(boundedInteger)
48
+ || value.evidenceCoverage.observed !== value.count || value.evidenceCoverage.comparable !== value.count
49
+ || value.evidenceCoverage.rate !== 1
50
+ || value.definition !== "matched-edit-recovery-context-receipt-v1") return false;
51
+ return value.count === 0
52
+ ? value.injectedChars === 0 && value.injectedEstimatedTokens === 0
53
+ : value.injectedChars > 0 && value.injectedEstimatedTokens > 0;
54
+ }
55
+
56
+ function validCausalAggregates(value, criterionExpected, schemaVersion) {
57
+ const expectedKeys = ["packCounts", "estimatedTokens", "selectedItemEstimatedTokens", "selectedItemCounts", "criterionInitialPack", "directFallbackRereads", "compaction", "managedPrefix"];
58
+ if (schemaVersion === 2) expectedKeys.splice(6, 0, "editRecoveryContext");
59
+ if (!exactKeys(value, expectedKeys)
60
+ || !validCausalTriplet(value.packCounts)
61
+ || !validCausalTriplet(value.estimatedTokens)
62
+ || !validCausalTriplet(value.selectedItemEstimatedTokens)
63
+ || !validCausalTriplet(value.selectedItemCounts)
64
+ || !exactKeys(value.directFallbackRereads, ["successfulCalls", "shellToolCallsObserved", "definition"])
65
+ || !boundedInteger(value.directFallbackRereads.successfulCalls)
66
+ || !boundedInteger(value.directFallbackRereads.shellToolCallsObserved)
67
+ || value.directFallbackRereads.definition !== "successful-direct-path-tool-call-v1"
68
+ || !exactKeys(value.compaction, ["eventsObserved", "state"])
69
+ || !boundedInteger(value.compaction.eventsObserved)
70
+ || !["observed", "not-observed"].includes(value.compaction.state)
71
+ || (value.compaction.eventsObserved > 0) !== (value.compaction.state === "observed")
72
+ || !exactKeys(value.managedPrefix, ["promptsObserved", "compactedPrompts", "state"])
73
+ || !boundedInteger(value.managedPrefix.promptsObserved) || value.managedPrefix.promptsObserved === 0
74
+ || !boundedInteger(value.managedPrefix.compactedPrompts)
75
+ || value.managedPrefix.compactedPrompts > value.managedPrefix.promptsObserved
76
+ || !["compacted", "uncompacted", "mixed"].includes(value.managedPrefix.state)
77
+ || (schemaVersion === 2 && !validEditRecoveryAggregate(value.editRecoveryContext))) return false;
78
+ const compacted = value.managedPrefix.compactedPrompts;
79
+ const prompts = value.managedPrefix.promptsObserved;
80
+ const expectedState = compacted === 0 ? "uncompacted" : compacted === prompts ? "compacted" : "mixed";
81
+ return value.managedPrefix.state === expectedState
82
+ && validCriterionAggregate(value.criterionInitialPack, value)
83
+ && (criterionExpected !== true || value.criterionInitialPack.attempts > 0);
84
+ }
85
+
86
+ export function validBenchmarkCausalContextReceipt(receipt, surface) {
87
+ if (!exactKeys(receipt, ["schemaVersion", "evidenceSource", "applicability", "available", "coverage", "aggregates"])
88
+ || ![1, 2].includes(receipt.schemaVersion) || typeof receipt.available !== "boolean"
89
+ || !exactKeys(receipt.coverage, ["status", "telemetryTruncated", "telemetryIntegrityFailures", "recoverableTailBytes", "criterionExpected", "sessionEventsObserved", "observedLanes", "requiredLanes", "missingLanes"])) return false;
90
+ const coverage = receipt.coverage;
91
+ if (surface !== "piagent") return receipt.schemaVersion === 1 && receipt.evidenceSource === "not-applicable"
92
+ && receipt.applicability === "not-applicable" && receipt.available === false && receipt.aggregates === null
93
+ && coverage.status === "not-applicable" && coverage.telemetryTruncated === false
94
+ && coverage.telemetryIntegrityFailures === 0 && coverage.recoverableTailBytes === 0
95
+ && coverage.criterionExpected === false && coverage.sessionEventsObserved === 0
96
+ && coverage.observedLanes === 0 && coverage.requiredLanes === 0
97
+ && Array.isArray(coverage.missingLanes) && coverage.missingLanes.length === 0;
98
+ const coverageLanes = receipt.schemaVersion === 2 ? causalCoverageLanesV2 : causalCoverageLanesV1;
99
+ const evidenceSource = `context-telemetry-closed-aggregate-v${receipt.schemaVersion}`;
100
+ if (receipt.evidenceSource !== evidenceSource || receipt.applicability !== "piagent"
101
+ || typeof coverage.telemetryTruncated !== "boolean" || typeof coverage.criterionExpected !== "boolean"
102
+ || ![coverage.telemetryIntegrityFailures, coverage.recoverableTailBytes, coverage.sessionEventsObserved,
103
+ coverage.observedLanes, coverage.requiredLanes].every(boundedInteger)
104
+ || coverage.requiredLanes !== coverageLanes.size || !Array.isArray(coverage.missingLanes)
105
+ || new Set(coverage.missingLanes).size !== coverage.missingLanes.length
106
+ || coverage.missingLanes.some((lane) => !coverageLanes.has(lane))
107
+ || coverage.observedLanes + coverage.missingLanes.length !== coverage.requiredLanes) return false;
108
+ if (receipt.available) return coverage.status === "complete" && coverage.missingLanes.length === 0
109
+ && coverage.telemetryTruncated === false && coverage.telemetryIntegrityFailures === 0
110
+ && coverage.recoverableTailBytes === 0 && coverage.sessionEventsObserved > 0
111
+ && validCausalAggregates(receipt.aggregates, coverage.criterionExpected, receipt.schemaVersion);
112
+ return ["partial", "unavailable"].includes(coverage.status)
113
+ && coverage.missingLanes.length > 0 && receipt.aggregates === null;
114
+ }
115
+
116
+ export function summarizeBenchmarkCausalContextEvidence(runs, { required = false } = {}) {
117
+ const piagentRuns = Array.isArray(runs) ? runs.filter((run) => run?.surface === "piagent") : [];
118
+ const complete = piagentRuns.filter((run) => validBenchmarkCausalContextReceipt(run.causalContextReceipt, run.surface)
119
+ && run.causalContextReceipt.available === true
120
+ && run.causalContextReceipt.coverage.status === "complete"
121
+ && run.causalContextReceipt.aggregates);
122
+ const fullyCovered = piagentRuns.length > 0 && complete.length === piagentRuns.length;
123
+ const recoveryComplete = complete.filter((run) => run.causalContextReceipt.schemaVersion === 2);
124
+ const recoveryFullyCovered = fullyCovered && recoveryComplete.length === piagentRuns.length;
125
+ const sum = (select) => complete.reduce((total, run) => total + select(run.causalContextReceipt.aggregates), 0);
126
+ const sumRecovery = (select) => recoveryComplete.reduce((total, run) => total + select(run.causalContextReceipt.aggregates.editRecoveryContext), 0);
127
+ const triplet = (field) => Object.fromEntries(["offered", "delivered", "injected"]
128
+ .map((lane) => [lane, sum((value) => value[field][lane])]));
129
+ const criterion = fullyCovered ? complete.reduce((total, run) => {
130
+ const value = run.causalContextReceipt.aggregates.criterionInitialPack;
131
+ for (const field of ["attempts", "selectedAttempts", "candidates", "selectedItems", "estimatedTokens", "offered", "delivered", "injected"]) {
132
+ total[field] += value[field];
133
+ }
134
+ for (const field of Object.keys(total.zeroSelectionReasonCounts)) {
135
+ total.zeroSelectionReasonCounts[field] += value.zeroSelectionReasonCounts[field];
136
+ }
137
+ return total;
138
+ }, {
139
+ attempts: 0, selectedAttempts: 0, candidates: 0, selectedItems: 0, estimatedTokens: 0,
140
+ zeroSelectionReasonCounts: { autoContextDisabled: 0, criterionGraphUnavailable: 0, noCandidates: 0, noReadableSelection: 0 },
141
+ offered: 0, delivered: 0, injected: 0
142
+ }) : null;
143
+ return {
144
+ required,
145
+ runs: piagentRuns.length,
146
+ availableRuns: complete.length,
147
+ unavailableRuns: piagentRuns.length - complete.length,
148
+ coverageStatus: fullyCovered ? "complete" : complete.length > 0 ? "partial" : "unavailable",
149
+ requiredSchemaVersion: 2,
150
+ currentAvailableRuns: recoveryComplete.length,
151
+ currentUnavailableRuns: piagentRuns.length - recoveryComplete.length,
152
+ currentCoverageStatus: recoveryFullyCovered ? "complete" : recoveryComplete.length > 0 ? "partial" : "unavailable",
153
+ aggregates: fullyCovered ? {
154
+ packCounts: triplet("packCounts"),
155
+ estimatedTokens: triplet("estimatedTokens"),
156
+ selectedItemEstimatedTokens: triplet("selectedItemEstimatedTokens"),
157
+ selectedItemCounts: triplet("selectedItemCounts"),
158
+ criterionInitialPack: criterion,
159
+ directFallbackRereads: {
160
+ successfulCalls: sum((value) => value.directFallbackRereads.successfulCalls),
161
+ shellToolCallsObserved: sum((value) => value.directFallbackRereads.shellToolCallsObserved),
162
+ definition: "successful-direct-path-tool-call-v1"
163
+ },
164
+ editRecoveryContext: {
165
+ count: recoveryFullyCovered ? sumRecovery((value) => value.count) : null,
166
+ failuresObserved: recoveryFullyCovered ? sumRecovery((value) => value.failuresObserved) : null,
167
+ suppressedFailures: recoveryFullyCovered ? sumRecovery((value) => value.suppressedFailures) : null,
168
+ injectedChars: recoveryFullyCovered ? sumRecovery((value) => value.injectedChars) : null,
169
+ injectedEstimatedTokens: recoveryFullyCovered ? sumRecovery((value) => value.injectedEstimatedTokens) : null,
170
+ evidenceCoverage: {
171
+ status: recoveryFullyCovered ? "complete" : recoveryComplete.length > 0 ? "partial" : "unavailable",
172
+ runs: piagentRuns.length,
173
+ comparableRuns: recoveryComplete.length,
174
+ rate: piagentRuns.length > 0 ? recoveryComplete.length / piagentRuns.length : 0
175
+ },
176
+ definition: "matched-edit-recovery-context-receipt-v1"
177
+ },
178
+ compactionEventsObserved: sum((value) => value.compaction.eventsObserved),
179
+ managedPrefixPromptsObserved: sum((value) => value.managedPrefix.promptsObserved),
180
+ managedPrefixCompactedPrompts: sum((value) => value.managedPrefix.compactedPrompts)
181
+ } : null
182
+ };
183
+ }
2
184
 
3
185
  export function completedBenchmarkRecord(record) {
4
186
  const nonnegative = (value) => Number.isFinite(value) && value >= 0;
@@ -17,6 +199,7 @@ export function completedBenchmarkRecord(record) {
17
199
  && typeof record.profile === "string"
18
200
  && typeof record.lifecycle === "string"
19
201
  && benchmarkSurfaces.has(record.surface)
202
+ && validBenchmarkCausalContextReceipt(record.causalContextReceipt, record.surface)
20
203
  && Number.isInteger(record.repeat) && record.repeat > 0
21
204
  && Number.isInteger(record.infrastructureAttempt) && record.infrastructureAttempt > 0
22
205
  && Number.isInteger(record.infrastructureAttempts) && record.infrastructureAttempts > 0
@@ -38,6 +38,16 @@ function pairedOutcomeSummary(value, candidateLabel, baselineLabel) {
38
38
  return `both ${value.bothPass} | ${candidateLabel}-only ${value.candidateOnlyPass} | ${baselineLabel}-only ${value.baselineOnlyPass} | neither ${value.bothFail}`;
39
39
  }
40
40
 
41
+ function timingSummary(value, surface) {
42
+ const summary = value?.surfaces?.[surface];
43
+ if (!summary) return "unavailable";
44
+ const phase = (name) => {
45
+ const item = summary.phases?.[name];
46
+ return `${display(item?.medianSeconds, 3)}s (${item?.availableRuns ?? 0}/${summary.runs})`;
47
+ };
48
+ return `startup ${phase("processStartup")} | model-turn wait ${phase("modelTurnWait")} | tool ${phase("toolExecution")} | other ${phase("other")} | complete ${summary.completeDiagnostics}/${summary.runs}`;
49
+ }
50
+
41
51
  function pairedUsageBandLines(bands) {
42
52
  return Object.entries(bands ?? {}).map(([name, band]) => (
43
53
  ` ${name}`.padEnd(30)
@@ -79,8 +89,10 @@ export function renderBenchmarkText(report) {
79
89
  + `${display(usage.medianInputTokens, 0)}`.padEnd(11)
80
90
  + `${display(usage.medianOutputTokens, 0)}`.padEnd(11)
81
91
  + `${display(usage.medianCacheReadTokens, 0)}`.padEnd(12)
92
+ + `${display(usage.medianCacheWriteTokens, 0)}`.padEnd(13)
82
93
  + `${display(usage.medianReasoningTokens, 0)}`.padEnd(11)
83
94
  + `${display(usage.medianFreshTokens, 0)}`.padEnd(11)
95
+ + `${display(usage.medianTotalTokens, 0)}`.padEnd(11)
84
96
  + `${display(usage.medianToolCalls, 0)}`.padEnd(7)
85
97
  + display(usage.medianCost, 6);
86
98
  };
@@ -89,6 +101,18 @@ export function renderBenchmarkText(report) {
89
101
  ));
90
102
  const usageBandLines = pairedUsageBandLines(report.comparison.pairedUsageBands?.categories);
91
103
  const confidence = report.comparison.freshTokenRatioConfidence95;
104
+ const primaryConfidence = report.comparison.primaryEfficiencyRatioConfidence95;
105
+ const fixedWorkloadConfidence = report.comparison.fixedWorkloadFamilyFreshTokenRatioConfidence95;
106
+ const failureAwareFamilyConfidence = report.comparison.failureAwareFamilyFreshTokenRatioConfidence95;
107
+ const durationConfidence = report.comparison.durationRatioConfidence95;
108
+ const normalizedCost = report.comparison.normalizedCost;
109
+ const normalizedCostConfidence = normalizedCost?.ratioConfidence95;
110
+ const causalContext = report.comparison.causalContextEvidence;
111
+ const causalAggregates = causalContext?.aggregates;
112
+ const hostReadiness = report.environment.hostReadinessHistory;
113
+ const suiteFailureReasons = (report.comparison.suiteGate?.failureReasons ?? [])
114
+ .map((failure) => `${failure.id}: ${failure.message}`)
115
+ .join("; ");
92
116
  const lines = [
93
117
  `Piagent Benchmark — ${report.suite.title}`,
94
118
  `Run: ${report.runId} | ${report.runCount} sessions | ${report.repeats} repeat(s)`,
@@ -98,6 +122,10 @@ export function renderBenchmarkText(report) {
98
122
  `Comparison: ${candidateLabel} vs ${baselineLabel}`,
99
123
  `Comparison purpose: ${report.comparison.purpose ?? "unspecified"}`,
100
124
  `Claim tier: ${report.comparison.claimEligibility?.achievedTier ?? "unavailable"} (declared ${report.comparison.claimEligibility?.declaredTier ?? "unavailable"})`,
125
+ `Token claim scope: ${report.comparison.claimEligibility?.tokenClaimScope ?? "unavailable"}`,
126
+ ...(report.comparison.tokenClaimUnavailableReason
127
+ ? [`Token claim restriction: ${report.comparison.tokenClaimUnavailableReason}`]
128
+ : []),
101
129
  `Suite digest: ${report.environment.suiteDigest ?? "unknown"} | Source: ${report.environment.source?.kind ?? "unknown"}${report.environment.source?.dirty === true ? " (dirty)" : ""}`,
102
130
  `Infrastructure: ${report.infrastructure?.attempts ?? report.runCount} attempts | ${report.infrastructure?.retries ?? 0} retries across ${report.infrastructure?.retriedRuns ?? 0} measured runs`,
103
131
  "",
@@ -106,41 +134,99 @@ export function renderBenchmarkText(report) {
106
134
  scoreLine(candidateLabel, candidate),
107
135
  "",
108
136
  "Median usage across all measured runs",
109
- "Surface Input Output Cache read Reasoning Fresh Tools Cost",
137
+ "Surface Input Output Cache read Cache write Reasoning Fresh Total Tools Reported cost",
110
138
  usageLine(baselineLabel, baseline),
111
139
  usageLine(candidateLabel, candidate),
112
140
  `${baselineLabel} tools: ${topToolSummary(baseline.usage.toolNames)}`,
113
141
  `${candidateLabel} tools: ${topToolSummary(candidate.usage.toolNames)}`,
142
+ `Observational timing (${baselineLabel}): ${timingSummary(report.timingDiagnostics, baselineSurface)}`,
143
+ `Observational timing (${candidateLabel}): ${timingSummary(report.timingDiagnostics, candidateSurface)}`,
144
+ "Timing authority: privacy-safe monotonic JSONL receipt boundaries only; unavailable boundaries are not estimated and timing never affects duration or a release/spend gate.",
114
145
  `Piagent workflow gaps: ${workflowGapSummary(report.runs.filter((run) => run.surface === "piagent"))}`,
146
+ `Token accounting: input=fresh input; reasoning is included in output; fresh=input+output; total=input+cache read+cache write+output`,
147
+ `Attempt completeness: accepted ${report.tokenAccounting?.acceptedAttempts.exactAttempts ?? 0}/${report.tokenAccounting?.acceptedAttempts.attempts ?? 0} exact | failed ${report.tokenAccounting?.failedAttempts.exactAttempts ?? 0}/${report.tokenAccounting?.failedAttempts.attempts ?? 0} exact | failed fresh ${display(report.tokenAccounting?.failedAttempts.tokens.fresh, 0)}`,
115
148
  "",
116
149
  `Paired successful runs: ${report.comparison.pairedSuccessfulRuns}`,
117
150
  `Paired runs with comparable usage: ${report.comparison.pairedUsageRuns}`,
118
151
  `Independent paired scenario families: ${report.comparison.pairedUsageScenarios ?? 0}`,
119
152
  `Complete paired scenario families: ${report.comparison.pairedCompleteScenarios ?? 0}`,
153
+ `Paired runs with comparable duration: ${report.comparison.pairedDurationRuns ?? 0}`,
154
+ `Complete paired duration families: ${report.comparison.pairedCompleteDurationScenarios ?? 0}`,
120
155
  `Complete paired outcome families: ${report.comparison.pairedOutcomeScenarios ?? 0}`,
121
156
  `Usage estimator: ${report.comparison.usageEstimator}`,
157
+ `Primary efficiency estimand: ${report.comparison.primaryEfficiencyEstimand ?? "unavailable"}`,
158
+ `Primary fresh-token ratio: ${display(report.comparison.primaryEfficiencyRatio, 4)} | 95% CI ${primaryConfidence ? `${display(primaryConfidence.lower, 4)}..${display(primaryConfidence.upper, 4)}` : "n/a"}`,
159
+ `Fixed-workload family ratio: ${display(report.comparison.fixedWorkloadFamilyFreshTokenRatio, 4)} | 95% CI ${fixedWorkloadConfidence ? `${display(fixedWorkloadConfidence.lower, 4)}..${display(fixedWorkloadConfidence.upper, 4)}` : "n/a"} | complete ${report.comparison.fixedWorkloadFamilyCoverage?.usableScenarioFamilies ?? 0}/${report.comparison.fixedWorkloadFamilyCoverage?.expectedScenarioFamilies ?? 0}`,
160
+ `Fixed-workload aggregate ratio (descriptive): ${display(report.comparison.fixedWorkloadAggregateFreshTokenRatio, 4)}`,
122
161
  `Fresh-token pair wins: ${candidateLabel} ${report.comparison.pairedFreshTokenWins[candidateKey]} | ${baselineLabel} ${report.comparison.pairedFreshTokenWins[baselineKey]} | ties ${report.comparison.pairedFreshTokenWins.ties}`,
123
162
  `Median paired fresh-token delta: ${display(report.comparison.medianPairedFreshTokenDelta, 0)} tok (negative favors ${candidateLabel})`,
124
- `Fresh-token ratio 95% CI: ${confidence ? `${display(confidence.lower, 4)}..${display(confidence.upper, 4)}` : "n/a"}`,
163
+ `Successful-pair complete-family ratio: ${display(report.comparison.freshTokenRatio, 4)} | 95% CI ${confidence ? `${display(confidence.lower, 4)}..${display(confidence.upper, 4)}` : "n/a"}`,
164
+ `All-successful-pairs descriptive ratio: ${display(report.comparison.allSuccessfulPairsFreshTokenRatio, 4)}`,
165
+ `Normalized API-equivalent text-token cost: ${display(normalizedCost?.ratio, 4)} | 95% CI ${normalizedCostConfidence ? `${display(normalizedCostConfidence.lower, 4)}..${display(normalizedCostConfidence.upper, 4)}` : "n/a"} | delta ${displayPercent(normalizedCost?.deltaPercent)}`,
166
+ `Normalized-cost source: ${normalizedCost?.pricingSnapshot?.id ?? "n/a"} | billed/provider-reported cost: no | exact/applicable pairs ${normalizedCost?.comparablePairs ?? 0}/${normalizedCost?.expectedPairs ?? 0}`,
167
+ `Duration pair wins: ${candidateLabel} ${report.comparison.pairedDurationWins?.[candidateKey] ?? 0} | ${baselineLabel} ${report.comparison.pairedDurationWins?.[baselineKey] ?? 0} | ties ${report.comparison.pairedDurationWins?.ties ?? 0}`,
168
+ `Median paired duration delta: ${display(report.comparison.medianPairedDurationDeltaSeconds, 2)}s (negative favors ${candidateLabel})`,
169
+ `Duration ratio 95% CI: ${durationConfidence ? `${display(durationConfidence.lower, 4)}..${display(durationConfidence.upper, 4)}` : "n/a"}`,
125
170
  `Failure-aware fresh tokens/resolved outcome: ${candidateLabel} ${display(report.comparison.freshTokensPerResolvedOutcome?.[candidateKey], 2)} | ${baselineLabel} ${display(report.comparison.freshTokensPerResolvedOutcome?.[baselineKey], 2)} | ratio ${display(report.comparison.failureAwareFreshTokenRatio, 4)}`,
171
+ `Failure-aware family ratio: ${display(report.comparison.failureAwareFamilyFreshTokenRatio, 4)} | 95% CI ${failureAwareFamilyConfidence ? `${display(failureAwareFamilyConfidence.lower, 4)}..${display(failureAwareFamilyConfidence.upper, 4)}` : "n/a"} | complete ${report.comparison.failureAwareFamilyCoverage?.usableScenarioFamilies ?? 0}/${report.comparison.failureAwareFamilyCoverage?.expectedScenarioFamilies ?? 0}`,
126
172
  `Paired resolved outcomes: ${pairedOutcomeSummary(report.comparison.pairedOutcomes?.resolved, candidateLabel, baselineLabel)}`,
127
173
  `Paired quality outcomes: ${pairedOutcomeSummary(report.comparison.pairedOutcomes?.quality, candidateLabel, baselineLabel)}`,
128
174
  `Paired safety outcomes: ${pairedOutcomeSummary(report.comparison.pairedOutcomes?.safety, candidateLabel, baselineLabel)}`,
129
175
  `Comparison protocol gate: ${report.comparison.comparisonProtocolGate?.passed ? "pass" : `fail (${(report.comparison.comparisonProtocolGate?.failedChecks ?? []).join(", ") || "missing evidence"})`}`,
176
+ `Provider-wire surface gate: ${report.comparison.providerWireSurfaceGate === null ? "n/a" : report.comparison.providerWireSurfaceGate ? "pass" : "fail"}`,
177
+ `Provider-wire evidence: ${report.comparison.providerWireEvidence?.verifiedRuns ?? 0}/${report.comparison.providerWireEvidence?.runs ?? 0} runs | ${report.comparison.providerWireEvidence?.groups?.length ?? 0} repeat groups | ${(report.comparison.providerWireEvidence?.driftGroups ?? []).length} base-prefix drift groups | failures ${topToolSummary(report.comparison.providerWireEvidence?.failureCounts)}`,
178
+ `Deferred tool surfaces: ${(report.comparison.providerWireEvidence?.groups ?? []).filter((group) => group.deferredToolSurfaceHashCount > 1).length} varying groups (reported separately; not base-prefix drift)`,
179
+ `Causal context receipt gate: ${report.comparison.causalContextEvidenceGate === null ? "n/a" : report.comparison.causalContextEvidenceGate ? "pass" : "fail"} | current v${causalContext?.requiredSchemaVersion ?? "?"} complete ${causalContext?.currentAvailableRuns ?? 0}/${causalContext?.runs ?? 0} Piagent runs`,
180
+ `Causal pack totals: offered ${causalAggregates?.packCounts.offered ?? "n/a"} | delivered ${causalAggregates?.packCounts.delivered ?? "n/a"} | injected ${causalAggregates?.packCounts.injected ?? "n/a"} | injected estimated tokens ${causalAggregates?.estimatedTokens.injected ?? "n/a"} | selected items ${causalAggregates?.selectedItemCounts.injected ?? "n/a"}`,
181
+ `Causal criterion/continuity: attempts ${causalAggregates?.criterionInitialPack.attempts ?? "n/a"} | selected ${causalAggregates?.criterionInitialPack.selectedAttempts ?? "n/a"} | successful direct fallback rereads ${causalAggregates?.directFallbackRereads.successfulCalls ?? "n/a"} | shell calls after injection ${causalAggregates?.directFallbackRereads.shellToolCallsObserved ?? "n/a"} | compactions ${causalAggregates?.compactionEventsObserved ?? "n/a"} | managed-prefix compacted ${causalAggregates?.managedPrefixCompactedPrompts ?? "n/a"}/${causalAggregates?.managedPrefixPromptsObserved ?? "n/a"}`,
182
+ `Causal edit recovery: contexts ${causalAggregates?.editRecoveryContext?.count ?? "n/a"}/${causalAggregates?.editRecoveryContext?.failuresObserved ?? "n/a"} failures | suppressed ${causalAggregates?.editRecoveryContext?.suppressedFailures ?? "n/a"} | injected chars ${causalAggregates?.editRecoveryContext?.injectedChars ?? "n/a"} | injected estimated tokens ${causalAggregates?.editRecoveryContext?.injectedEstimatedTokens ?? "n/a"} | evidence ${causalAggregates?.editRecoveryContext?.evidenceCoverage?.status ?? "unavailable"} (${causalAggregates?.editRecoveryContext?.evidenceCoverage?.comparableRuns ?? 0}/${causalAggregates?.editRecoveryContext?.evidenceCoverage?.runs ?? 0} runs)`,
183
+ `Release-claim configuration gate: ${report.comparison.releaseClaimConfigurationGate === false ? "fail" : report.comparison.releaseClaimConfigurationGate === true ? "pass" : "n/a"}`,
184
+ `Codex baseline gate: ${report.comparison.codexBaselineGate === null ? "n/a" : report.comparison.codexBaselineGate ? "pass" : "fail"}`,
185
+ `Clean release source gate: ${report.comparison.cleanReleaseSourceGate === null ? "n/a" : report.comparison.cleanReleaseSourceGate ? "pass" : "fail"}`,
186
+ `Host-readiness history gate: ${report.comparison.hostReadinessGate === null ? "n/a" : report.comparison.hostReadinessGate ? "pass" : "fail"} | valid receipts ${hostReadiness?.validReceiptCount ?? 0}/${hostReadiness?.receiptCount ?? 0} | coverage ${hostReadiness?.windowCoverage ?? "n/a"}`,
187
+ `Full-suite gate: ${report.comparison.fullSuiteGate === null ? "n/a" : report.comparison.fullSuiteGate ? "pass" : "fail"}`,
130
188
  `Paired outcome evidence gate: ${report.comparison.outcomeEvidenceGate ? "pass" : "fail"}`,
131
- `Efficiency evidence gate: ${report.comparison.efficiencyEvidenceGate ? "pass" : "fail"}`,
132
- `Efficiency category coverage: ${report.comparison.efficiencyBandCoverageGate ? "pass" : `fail (${(report.comparison.efficiencyCategoryCoverage?.missing ?? []).join(", ") || "missing evidence"})`}`,
133
- `Failure-aware efficiency gate: ${report.comparison.failureAwareEfficiencyGate ? "pass" : "fail"}`,
189
+ `Successful-pair evidence (${report.comparison.successfulPairEfficiencyRole ?? "blocking"}): ${report.comparison.efficiencyEvidenceGate ? "complete" : "incomplete"}`,
190
+ `Successful-pair category coverage (${report.comparison.successfulPairEfficiencyRole ?? "blocking"}): ${report.comparison.efficiencyBandCoverageGate ? "complete" : `incomplete (${(report.comparison.efficiencyCategoryCoverage?.missing ?? []).join(", ") || "missing evidence"})`}`,
191
+ `Failure-aware efficiency (${report.comparison.failureAwareEfficiencyRole ?? "blocking"}): ${report.comparison.failureAwareEfficiencyGate ? "within threshold" : "unavailable or above threshold"}`,
192
+ `Primary efficiency evidence gate: ${report.comparison.primaryEfficiencyEvidenceGate ? "pass" : "fail"}`,
193
+ `Primary efficiency category coverage: ${report.comparison.primaryEfficiencyBandCoverageGate ? "pass" : `fail (${(report.comparison.primaryEfficiencyCategoryCoverage?.missing ?? []).join(", ") || "missing evidence"})`}`,
194
+ `Primary efficiency confidence gate: ${report.comparison.primaryEfficiencyConfidenceGate === null ? "n/a" : report.comparison.primaryEfficiencyConfidenceGate ? "pass" : "fail"}`,
195
+ `Primary efficiency gate: ${report.comparison.primaryEfficiencyGate === null ? "n/a" : report.comparison.primaryEfficiencyGate ? "pass" : "fail"}`,
134
196
  `Paired candidate-regression gate: ${report.comparison.pairedRegressionGate ? "pass" : "fail"}`,
135
197
  `Repeat-count gate: ${report.comparison.repeatGate === null ? "n/a" : report.comparison.repeatGate ? "pass" : "fail"}`,
136
198
  `Efficiency confidence gate: ${report.comparison.efficiencyConfidenceGate === null ? "n/a" : report.comparison.efficiencyConfidenceGate ? "pass" : "fail"}`,
199
+ `Fresh-token band gate: ${report.comparison.freshTokenBandGate === null ? "n/a" : report.comparison.freshTokenBandGate ? "pass" : `fail (${(report.comparison.freshTokenBandFailures ?? []).map((item) => `${item.dimension}:${item.name}=${item.observedBound ?? "n/a"}`).join(", ")})`}`,
200
+ `Fresh-token family guardrail: ${report.comparison.freshTokenFamilyGate === null ? "n/a" : report.comparison.freshTokenFamilyGate ? "pass" : `fail (${(report.comparison.freshTokenFamilyFailures ?? []).map((item) => `${item.scenarioId}=${item.ratio}`).join(", ")})`}`,
201
+ `Performance evidence gate: ${report.comparison.performanceEvidenceGate === null ? "n/a" : report.comparison.performanceEvidenceGate ? "pass" : "fail"}`,
202
+ `Performance point-estimate gate (ratio <= 1.0): ${report.comparison.performancePointEstimateGate === null ? "n/a" : report.comparison.performancePointEstimateGate ? "pass" : "fail"}`,
203
+ `Performance confidence gate: ${report.comparison.performanceConfidenceGate === null ? "n/a" : report.comparison.performanceConfidenceGate ? "pass" : "fail"}`,
204
+ `Duration band gate: ${report.comparison.durationBandGate === null ? "n/a" : report.comparison.durationBandGate ? "pass" : `fail (${(report.comparison.durationBandFailures ?? []).map((item) => `${item.dimension}:${item.name}=${item.ratio ?? "n/a"}`).join(", ")})`}`,
205
+ `Duration family guardrail: ${report.comparison.durationFamilyGate === null ? "n/a" : report.comparison.durationFamilyGate ? "pass" : `fail (${(report.comparison.durationFamilyFailures ?? []).map((item) => `${item.scenarioId}=${item.ratio ?? "n/a"}`).join(", ")})`}`,
206
+ `Infrastructure retry gate: ${report.comparison.infrastructureRetryGate === null ? "n/a" : report.comparison.infrastructureRetryGate ? "pass" : "fail"}`,
207
+ `Infrastructure failure-ledger gate: ${report.comparison.infrastructureFailureLedgerGate === null ? "n/a" : report.comparison.infrastructureFailureLedgerGate ? "pass" : `fail (${report.comparison.infrastructureFailureLedgerIssues?.length ?? 0} runs)`}`,
208
+ `Unknown infrastructure usage gate: ${report.comparison.unknownInfrastructureUsageGate === null ? "n/a" : report.comparison.unknownInfrastructureUsageGate ? "pass" : "fail"}`,
209
+ `Accepted usage completeness gate: ${report.comparison.acceptedUsageCompletenessGate === null ? "n/a" : report.comparison.acceptedUsageCompletenessGate ? "pass" : "fail"}`,
210
+ `Failed-attempt usage completeness gate: ${report.comparison.failedUsageCompletenessGate === null ? "n/a" : report.comparison.failedUsageCompletenessGate ? "pass" : "fail"}`,
211
+ `All-attempt usage completeness gate: ${report.comparison.allAttemptUsageCompletenessGate === null ? "n/a" : report.comparison.allAttemptUsageCompletenessGate ? "pass" : "fail"}`,
212
+ `Normalized-cost configuration gate: ${report.comparison.normalizedCostClaimConfigurationGate === null ? "n/a" : report.comparison.normalizedCostClaimConfigurationGate ? "pass" : "fail"}`,
213
+ `Normalized-cost pricing applicability gate: ${report.comparison.normalizedCostPricingApplicabilityGate === null ? "n/a" : report.comparison.normalizedCostPricingApplicabilityGate ? "pass" : "fail"}`,
214
+ `Normalized-cost confidence gate: ${report.comparison.normalizedCostConfidenceGate === null ? "n/a" : report.comparison.normalizedCostConfidenceGate ? "pass" : "fail"}`,
215
+ `Normalized-cost band gate: ${report.comparison.normalizedCostBandGate === null ? "n/a" : report.comparison.normalizedCostBandGate ? "pass" : "fail"}`,
216
+ `Normalized-cost family gate: ${report.comparison.normalizedCostFamilyGate === null ? "n/a" : report.comparison.normalizedCostFamilyGate ? "pass" : "fail"}`,
137
217
  `Quality gate: ${report.comparison.qualityGate ? "pass" : "fail"}`,
138
218
  `Reliability gate: ${report.comparison.reliabilityGate ? "pass" : "fail"}`,
139
- `Fresh-token delta: ${displayPercent(report.comparison.freshTokenDeltaPercent)} (negative favors ${candidateLabel})`,
140
- `Cost delta: ${displayPercent(report.comparison.costDeltaPercent)} (negative favors ${candidateLabel})`,
219
+ `Successful-pair complete-family token delta: ${displayPercent(report.comparison.freshTokenDeltaPercent)} (negative favors ${candidateLabel})`,
220
+ `Primary efficiency token delta: ${displayPercent(report.comparison.primaryEfficiencyDeltaPercent)} (negative favors ${candidateLabel})`,
221
+ `Duration delta: ${displayPercent(report.comparison.durationDeltaPercent)} (negative favors ${candidateLabel})`,
222
+ `Provider-reported cost delta: ${displayPercent(report.comparison.costDeltaPercent)} (negative favors ${candidateLabel}; not normalized cost)`,
141
223
  `Workflow gate: ${report.comparison.workflowGate === null ? "n/a" : report.comparison.workflowGate ? "pass" : "fail"}`,
142
224
  `Category gate: ${report.comparison.categoryGate === null ? "n/a" : report.comparison.categoryGate ? "pass" : "fail"}`,
143
225
  `Every outcome score > floor: ${report.comparison.outcomeScoreGate === null ? "n/a" : report.comparison.outcomeScoreGate ? "pass" : `fail (${(report.comparison.outcomeScoreFailures ?? []).map((item) => `${item.id}=${item.score ?? "n/a"}`).join(", ")})`}`,
226
+ ...(report.comparison.suiteGate ? [
227
+ `Suite gate: ${report.comparison.suiteGate.passed ? "pass" : "fail"}`,
228
+ `Suite gate failures: ${suiteFailureReasons || "none"}`
229
+ ] : []),
144
230
  ...(usageBandLines.length ? ["", "Paired fresh-token ratio by category", "Category Pairs Families Ratio Median delta", ...usageBandLines] : []),
145
231
  ...(categoryLines.length ? ["", `${candidateLabel} category bands`, "Category Resolved Score", ...categoryLines] : []),
146
232
  `Verdict: ${report.verdict.status}`,
@@ -163,21 +249,39 @@ export function renderBenchmarkHtml(report) {
163
249
  const surfaceEntries = [[baselineSurface, report.surfaces[baselineKey]], [candidateSurface, report.surfaces[candidateKey]]];
164
250
  const baselineLabel = surfaceLabel(baselineSurface);
165
251
  const candidateLabel = surfaceLabel(candidateSurface);
166
- const rows = report.runs.map((run) => `<tr><td>${htmlEscape(run.scenarioId)}</td><td>${htmlEscape(run.category ?? "unspecified")}</td><td>${htmlEscape(run.difficulty ?? "unspecified")}</td><td>${htmlEscape(run.profile ?? "unspecified")}</td><td>${htmlEscape(run.lifecycle ?? "unspecified")}</td><td>${htmlEscape(run.surface)}</td><td>${run.repeat}</td><td>${run.infrastructureRetries ?? 0}</td><td>${run.resolved ? "PASS" : "FAIL"}</td><td>${run.grade?.passed ? "PASS" : "FAIL"}</td><td>${run.scope?.passed ? "PASS" : "FAIL"}</td><td>${display(run.workflow?.score)}</td><td>${htmlEscape((run.workflow?.checks ?? []).filter((check) => !check.passed).map((check) => check.id).join(", ") || "none")}</td><td>${htmlEscape(run.usage?.model ?? "unknown")}</td><td>${htmlEscape(run.usage?.thinkingLevel ?? "unknown")}</td><td>${display(run.usage?.input, 0)}</td><td>${display(run.usage?.output, 0)}</td><td>${display(run.usage?.cacheRead, 0)}</td><td>${display(run.usage?.reasoning, 0)}</td><td>${display(run.usage?.fresh, 0)}</td><td>${display(run.usage?.toolCalls, 0)}</td><td>${htmlEscape(topToolSummary(run.usage?.toolNames, 5))}</td><td>${display(run.usage?.cost, 6)}</td><td>${display(run.durationSeconds, 1)}</td><td>${htmlEscape(run.failure ?? "")}</td></tr>`).join("");
252
+ const rows = report.runs.map((run) => `<tr><td>${htmlEscape(run.scenarioId)}</td><td>${htmlEscape(run.category ?? "unspecified")}</td><td>${htmlEscape(run.difficulty ?? "unspecified")}</td><td>${htmlEscape(run.profile ?? "unspecified")}</td><td>${htmlEscape(run.lifecycle ?? "unspecified")}</td><td>${htmlEscape(run.surface)}</td><td>${run.repeat}</td><td>${run.infrastructureRetries ?? 0}</td><td>${run.resolved ? "PASS" : "FAIL"}</td><td>${run.grade?.passed ? "PASS" : "FAIL"}</td><td>${run.scope?.passed ? "PASS" : "FAIL"}</td><td>${display(run.workflow?.score)}</td><td>${htmlEscape((run.workflow?.checks ?? []).filter((check) => !check.passed).map((check) => check.id).join(", ") || "none")}</td><td>${htmlEscape(run.usage?.model ?? "unknown")}</td><td>${htmlEscape(run.usage?.thinkingLevel ?? "unknown")}</td><td>${htmlEscape(run.usage?.usageSource ?? "unknown")}</td><td>${display(run.usage?.input, 0)}</td><td>${display(run.usage?.output, 0)}</td><td>${display(run.usage?.cacheRead, 0)}</td><td>${display(run.usage?.cacheWrite, 0)}</td><td>${display(run.usage?.reasoning, 0)}</td><td>${display(run.usage?.fresh, 0)}</td><td>${display(run.usage?.total, 0)}</td><td>${display(run.usage?.toolCalls, 0)}</td><td>${htmlEscape(topToolSummary(run.usage?.toolNames, 5))}</td><td>${display(run.usage?.cost, 6)}</td><td>${display(run.durationSeconds, 1)}</td><td>${htmlEscape(run.failure ?? "")}</td></tr>`).join("");
167
253
  const scoreRows = surfaceEntries.map(([id, surface]) => `<tr><th>${htmlEscape(surfaceLabel(id))}</th><td>${surface.resolved}/${surface.runs}</td><td>${surface.qualityCorrect}/${surface.qualityRuns}</td><td>${surface.scopePassed}/${surface.runs}</td><td>${display(surface.scores.quality)}</td><td>${display(surface.scores.safety)}</td><td>${display(surface.scores.reliability)}</td><td>${display(surface.scores.workflow)}</td><td>${display(surface.scores.efficiency)}</td><td>${display(surface.scores.overall)}</td></tr>`).join("");
168
- const usageRows = surfaceEntries.map(([id, surface]) => { const usage = surface.usage.allMeasuredRuns; return `<tr><th>${htmlEscape(surfaceLabel(id))}</th><td>${display(usage.medianInputTokens, 0)}</td><td>${display(usage.medianOutputTokens, 0)}</td><td>${display(usage.medianCacheReadTokens, 0)}</td><td>${display(usage.medianReasoningTokens, 0)}</td><td>${display(usage.medianFreshTokens, 0)}</td><td>${display(usage.medianToolCalls, 0)}</td><td>${display(usage.medianCost, 6)}</td><td>${display(usage.medianDurationSeconds, 1)}</td><td>${htmlEscape(topToolSummary(surface.usage.toolNames))}</td></tr>`; }).join("");
254
+ const usageRows = surfaceEntries.map(([id, surface]) => { const usage = surface.usage.allMeasuredRuns; return `<tr><th>${htmlEscape(surfaceLabel(id))}</th><td>${display(usage.medianInputTokens, 0)}</td><td>${display(usage.medianOutputTokens, 0)}</td><td>${display(usage.medianCacheReadTokens, 0)}</td><td>${display(usage.medianCacheWriteTokens, 0)}</td><td>${display(usage.medianReasoningTokens, 0)}</td><td>${display(usage.medianFreshTokens, 0)}</td><td>${display(usage.medianTotalTokens, 0)}</td><td>${display(usage.medianToolCalls, 0)}</td><td>${display(usage.medianCost, 6)}</td><td>${display(usage.medianDurationSeconds, 1)}</td><td>${htmlEscape(topToolSummary(surface.usage.toolNames))}</td></tr>`; }).join("");
169
255
  const categoryRows = Object.entries(report.surfaces[candidateKey].bands?.categories ?? {}).map(([name, band]) => `<tr><th>${htmlEscape(name)}</th><td>${band.resolved}/${band.runs}</td><td>${display(band.score)}</td><td>${display(band.correctness)}</td></tr>`).join("");
170
256
  const tokenBandRows = Object.entries(report.comparison.pairedUsageBands?.categories ?? {}).map(([name, band]) => `<tr><th>${htmlEscape(name)}</th><td>${band.pairs}</td><td>${band.scenarioFamilies}</td><td>${display(band.freshTokenRatio, 4)}</td><td>${display(band.medianFreshTokenDelta, 0)}</td><td>${band.candidateWins}/${band.baselineWins}/${band.ties}</td></tr>`).join("");
171
257
  const confidence = report.comparison.freshTokenRatioConfidence95;
258
+ const primaryConfidence = report.comparison.primaryEfficiencyRatioConfidence95;
259
+ const fixedWorkloadConfidence = report.comparison.fixedWorkloadFamilyFreshTokenRatioConfidence95;
260
+ const failureAwareFamilyConfidence = report.comparison.failureAwareFamilyFreshTokenRatioConfidence95;
261
+ const durationConfidence = report.comparison.durationRatioConfidence95;
262
+ const normalizedCost = report.comparison.normalizedCost;
263
+ const normalizedCostConfidence = normalizedCost?.ratioConfidence95;
264
+ const causalContext = report.comparison.causalContextEvidence;
265
+ const causalAggregates = causalContext?.aggregates;
266
+ const hostReadiness = report.environment.hostReadinessHistory;
267
+ const suiteFailureReasons = (report.comparison.suiteGate?.failureReasons ?? [])
268
+ .map((failure) => `${failure.id}: ${failure.message}`)
269
+ .join("; ");
172
270
  return `<!doctype html>
173
271
  <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Piagent Benchmark ${htmlEscape(report.runId)}</title>
174
272
  <style>body{font:14px system-ui,sans-serif;color:#202124;max-width:1180px;margin:32px auto;padding:0 20px}h1{font-size:24px}h2{font-size:17px;margin-top:28px}.table-wrap{overflow-x:auto}table{border-collapse:collapse;width:100%;white-space:nowrap}th,td{border:1px solid #d8dadd;padding:8px;text-align:left}thead th{background:#f4f5f6}.metric{display:inline-block;margin:0 24px 8px 0}.note{color:#5f6368}</style></head><body>
175
273
  <h1>Piagent Benchmark</h1><p>${htmlEscape(report.suite.title)} · ${htmlEscape(report.runId)}</p><p class="note">Platform v${htmlEscape(report.environment.platformVersion ?? "unknown")} · Pi ${htmlEscape(report.environment.piVersion ?? "unknown")}${report.environment.codexVersion ? ` · Codex ${htmlEscape(report.environment.codexVersion)}` : ""} · Node ${htmlEscape(report.environment.nodeVersion ?? "unknown")} · Baseline ${htmlEscape(report.environment.treatmentBaseline ?? "unknown")} · Piagent treatment ${htmlEscape(report.environment.piagentTreatment?.id ?? "unrecorded")} · Suite ${htmlEscape(report.environment.suiteDigest ?? "unknown")}</p>
176
- <p class="metric"><strong>Comparison:</strong> ${htmlEscape(candidateLabel)} vs ${htmlEscape(baselineLabel)}</p><p class="metric"><strong>Purpose:</strong> ${htmlEscape(report.comparison.purpose ?? "unspecified")}</p><p class="metric"><strong>Claim tier:</strong> ${htmlEscape(report.comparison.claimEligibility?.achievedTier ?? "unavailable")}</p><p class="metric"><strong>Verdict:</strong> ${htmlEscape(report.verdict.status)}</p><p class="metric"><strong>Protocol:</strong> ${report.comparison.comparisonProtocolGate?.passed ? "PASS" : `FAIL (${htmlEscape((report.comparison.comparisonProtocolGate?.failedChecks ?? []).join(", ") || "missing evidence")})`}</p><p class="metric"><strong>Infrastructure retries:</strong> ${report.infrastructure?.retries ?? 0}</p><p class="metric"><strong>Paired token-ratio delta:</strong> ${displayPercent(report.comparison.freshTokenDeltaPercent)}</p><p class="metric"><strong>Token ratio 95% CI:</strong> ${confidence ? `${display(confidence.lower, 4)}–${display(confidence.upper, 4)}` : "n/a"}</p><p class="metric"><strong>Failure-aware ratio:</strong> ${display(report.comparison.failureAwareFreshTokenRatio, 4)}</p><p class="metric"><strong>Paired cost-ratio delta:</strong> ${displayPercent(report.comparison.costDeltaPercent)}</p><p class="metric"><strong>Comparable pairs:</strong> ${report.comparison.pairedUsageRuns}</p><p class="metric"><strong>Scenario families:</strong> ${report.comparison.pairedUsageScenarios ?? 0}</p><p class="metric"><strong>Complete families:</strong> ${report.comparison.pairedCompleteScenarios ?? 0}</p><p class="metric"><strong>Outcome families:</strong> ${report.comparison.pairedOutcomeScenarios ?? 0}</p><p class="metric"><strong>Pair wins:</strong> ${htmlEscape(candidateLabel)} ${report.comparison.pairedFreshTokenWins[candidateKey]} · ${htmlEscape(baselineLabel)} ${report.comparison.pairedFreshTokenWins[baselineKey]} · ties ${report.comparison.pairedFreshTokenWins.ties}</p>
274
+ <p class="metric"><strong>Comparison:</strong> ${htmlEscape(candidateLabel)} vs ${htmlEscape(baselineLabel)}</p><p class="metric"><strong>Purpose:</strong> ${htmlEscape(report.comparison.purpose ?? "unspecified")}</p><p class="metric"><strong>Claim tier:</strong> ${htmlEscape(report.comparison.claimEligibility?.achievedTier ?? "unavailable")}</p><p class="metric"><strong>Token claim scope:</strong> ${htmlEscape(report.comparison.claimEligibility?.tokenClaimScope ?? "unavailable")}</p>${report.comparison.tokenClaimUnavailableReason ? `<p class="metric"><strong>Token claim restriction:</strong> ${htmlEscape(report.comparison.tokenClaimUnavailableReason)}</p>` : ""}<p class="metric"><strong>Verdict:</strong> ${htmlEscape(report.verdict.status)}</p><p class="metric"><strong>Protocol:</strong> ${report.comparison.comparisonProtocolGate?.passed ? "PASS" : `FAIL (${htmlEscape((report.comparison.comparisonProtocolGate?.failedChecks ?? []).join(", ") || "missing evidence")})`}</p><p class="metric"><strong>Provider wire:</strong> ${report.comparison.providerWireSurfaceGate === null ? "n/a" : report.comparison.providerWireSurfaceGate ? "PASS" : "FAIL"} (${report.comparison.providerWireEvidence?.verifiedRuns ?? 0}/${report.comparison.providerWireEvidence?.runs ?? 0} runs, ${(report.comparison.providerWireEvidence?.driftGroups ?? []).length} drift groups)</p><p class="metric"><strong>Causal receipt:</strong> ${report.comparison.causalContextEvidenceGate === null ? "n/a" : report.comparison.causalContextEvidenceGate ? "PASS" : "FAIL"} (current v${causalContext?.requiredSchemaVersion ?? "?"} ${causalContext?.currentAvailableRuns ?? 0}/${causalContext?.runs ?? 0} runs)</p><p class="metric"><strong>Host readiness:</strong> ${report.comparison.hostReadinessGate === null ? "n/a" : report.comparison.hostReadinessGate ? "PASS" : "FAIL"} (${hostReadiness?.validReceiptCount ?? 0}/${hostReadiness?.receiptCount ?? 0} valid receipts · ${htmlEscape(hostReadiness?.windowCoverage ?? "n/a")} coverage)</p><p class="metric"><strong>Causal packs:</strong> ${causalAggregates ? `${causalAggregates.packCounts.offered}/${causalAggregates.packCounts.delivered}/${causalAggregates.packCounts.injected} offered/delivered/injected · ${causalAggregates.estimatedTokens.injected} injected estimated tokens · ${causalAggregates.selectedItemCounts.injected} selected items` : "unavailable"}</p><p class="metric"><strong>Causal direct rereads:</strong> ${causalAggregates ? `${causalAggregates.directFallbackRereads.successfulCalls} successful direct-path calls · ${causalAggregates.directFallbackRereads.shellToolCallsObserved} shell calls after injection` : "unavailable"}</p><p class="metric"><strong>Causal edit recovery:</strong> ${causalAggregates?.editRecoveryContext ? `${causalAggregates.editRecoveryContext.count ?? "n/a"} contexts · ${causalAggregates.editRecoveryContext.injectedChars ?? "n/a"} chars · ${causalAggregates.editRecoveryContext.injectedEstimatedTokens ?? "n/a"} estimated tokens · ${htmlEscape(causalAggregates.editRecoveryContext.evidenceCoverage?.status ?? "unavailable")} evidence` : "unavailable"}</p><p class="metric"><strong>Suite gate:</strong> ${report.comparison.suiteGate ? report.comparison.suiteGate.passed ? "PASS" : "FAIL" : "n/a"}</p><p class="metric"><strong>Infrastructure retries:</strong> ${report.infrastructure?.retries ?? 0}</p><p class="metric"><strong>Stability gate:</strong> ${report.comparison.stabilityGate === null ? "n/a" : report.comparison.stabilityGate ? "PASS" : "FAIL"}</p><p class="metric"><strong>Primary estimand:</strong> ${htmlEscape(report.comparison.primaryEfficiencyEstimand ?? "unavailable")}</p><p class="metric"><strong>Primary token delta:</strong> ${displayPercent(report.comparison.primaryEfficiencyDeltaPercent)}</p><p class="metric"><strong>Primary ratio 95% CI:</strong> ${primaryConfidence ? `${display(primaryConfidence.lower, 4)}–${display(primaryConfidence.upper, 4)}` : "n/a"}</p><p class="metric"><strong>Fixed-workload ratio:</strong> ${display(report.comparison.fixedWorkloadFamilyFreshTokenRatio, 4)}${fixedWorkloadConfidence ? ` (${display(fixedWorkloadConfidence.lower, 4)}–${display(fixedWorkloadConfidence.upper, 4)})` : ""}</p><p class="metric"><strong>Fixed-workload coverage:</strong> ${report.comparison.fixedWorkloadFamilyCoverage?.usableScenarioFamilies ?? 0}/${report.comparison.fixedWorkloadFamilyCoverage?.expectedScenarioFamilies ?? 0} families</p><p class="metric"><strong>Successful-pair diagnostic role:</strong> ${htmlEscape(report.comparison.successfulPairEfficiencyRole ?? "blocking")}</p><p class="metric"><strong>Successful-pair token delta:</strong> ${displayPercent(report.comparison.freshTokenDeltaPercent)}</p><p class="metric"><strong>Successful-pair ratio 95% CI:</strong> ${confidence ? `${display(confidence.lower, 4)}–${display(confidence.upper, 4)}` : "n/a"}</p><p class="metric"><strong>Normalized API-equivalent text-token cost ratio:</strong> ${display(normalizedCost?.ratio, 4)}${normalizedCostConfidence ? ` (${display(normalizedCostConfidence.lower, 4)}–${display(normalizedCostConfidence.upper, 4)})` : ""}</p><p class="metric"><strong>Normalized-cost gate:</strong> ${report.comparison.normalizedCostGate === null ? "n/a" : report.comparison.normalizedCostGate ? "PASS" : "FAIL"}</p><p class="metric"><strong>Failure-aware family ratio:</strong> ${display(report.comparison.failureAwareFamilyFreshTokenRatio, 4)}${failureAwareFamilyConfidence ? ` (${display(failureAwareFamilyConfidence.lower, 4)}–${display(failureAwareFamilyConfidence.upper, 4)})` : ""}</p><p class="metric"><strong>Failure-aware pooled ratio:</strong> ${display(report.comparison.failureAwareFreshTokenRatio, 4)}</p><p class="metric"><strong>Duration-ratio delta:</strong> ${displayPercent(report.comparison.durationDeltaPercent)}</p><p class="metric"><strong>Duration ratio 95% CI:</strong> ${durationConfidence ? `${display(durationConfidence.lower, 4)}–${display(durationConfidence.upper, 4)}` : "n/a"}</p><p class="metric"><strong>Performance gate:</strong> ${report.comparison.performanceGate === null ? "n/a" : report.comparison.performanceGate ? "PASS" : "FAIL"}</p><p class="metric"><strong>Provider-reported cost-ratio delta:</strong> ${displayPercent(report.comparison.costDeltaPercent)}</p><p class="metric"><strong>Comparable pairs:</strong> ${report.comparison.pairedUsageRuns}</p><p class="metric"><strong>Scenario families:</strong> ${report.comparison.pairedUsageScenarios ?? 0}</p><p class="metric"><strong>Complete families:</strong> ${report.comparison.pairedCompleteScenarios ?? 0}</p><p class="metric"><strong>Duration families:</strong> ${report.comparison.pairedCompleteDurationScenarios ?? 0}</p><p class="metric"><strong>Outcome families:</strong> ${report.comparison.pairedOutcomeScenarios ?? 0}</p><p class="metric"><strong>Pair wins:</strong> ${htmlEscape(candidateLabel)} ${report.comparison.pairedFreshTokenWins[candidateKey]} · ${htmlEscape(baselineLabel)} ${report.comparison.pairedFreshTokenWins[baselineKey]} · ties ${report.comparison.pairedFreshTokenWins.ties}</p>
275
+ <p class="metric"><strong>Observational timing (${htmlEscape(baselineLabel)}):</strong> ${htmlEscape(timingSummary(report.timingDiagnostics, baselineSurface))}</p><p class="metric"><strong>Observational timing (${htmlEscape(candidateLabel)}):</strong> ${htmlEscape(timingSummary(report.timingDiagnostics, candidateSurface))}</p>
276
+ <p class="note">Timing uses privacy-safe monotonic JSONL receipt boundaries only. Missing boundaries remain unavailable; these diagnostics do not alter authoritative duration or any release/spend gate.</p>
277
+ <p class="metric"><strong>Edit-recovery failures:</strong> ${causalAggregates?.editRecoveryContext?.failuresObserved ?? "n/a"} observed · ${causalAggregates?.editRecoveryContext?.suppressedFailures ?? "n/a"} safely suppressed</p>
278
+ <p class="metric"><strong>Exact attempts:</strong> accepted ${report.tokenAccounting?.acceptedAttempts.exactAttempts ?? 0}/${report.tokenAccounting?.acceptedAttempts.attempts ?? 0} · failed ${report.tokenAccounting?.failedAttempts.exactAttempts ?? 0}/${report.tokenAccounting?.failedAttempts.attempts ?? 0}</p><p class="metric"><strong>Failed-attempt fresh:</strong> ${display(report.tokenAccounting?.failedAttempts.tokens.fresh, 0)}</p>
279
+ <p class="note"><strong>Token definitions:</strong> Input is fresh input only. Reasoning is already included in output. Fresh = input + output. Total = input + cache read + cache write + output. Normalized API-equivalent cost uses the versioned suite pricing snapshot and is not OAuth/provider-billed cost.</p>
280
+ ${suiteFailureReasons ? `<p><strong>Suite gate failures:</strong> ${htmlEscape(suiteFailureReasons)}</p>` : ""}
177
281
  <h2>Score bands</h2><div class="table-wrap"><table><thead><tr><th>Surface</th><th>Resolved</th><th>Task grader</th><th>Scope</th><th>Quality</th><th>Safety</th><th>Reliability</th><th>Workflow</th><th>Efficiency</th><th>Overall</th></tr></thead><tbody>${scoreRows}</tbody></table></div>
178
282
  ${categoryRows ? `<h2>${htmlEscape(candidateLabel)} category bands</h2><div class="table-wrap"><table><thead><tr><th>Category</th><th>Resolved</th><th>Score</th><th>Correctness</th></tr></thead><tbody>${categoryRows}</tbody></table></div>` : ""}
179
283
  ${tokenBandRows ? `<h2>Paired fresh-token ratio by category</h2><div class="table-wrap"><table><thead><tr><th>Category</th><th>Pairs</th><th>Families</th><th>Ratio</th><th>Median delta</th><th>${htmlEscape(candidateLabel)}/${htmlEscape(baselineLabel)}/ties</th></tr></thead><tbody>${tokenBandRows}</tbody></table></div>` : ""}
180
- <h2>Median usage across all measured runs</h2><div class="table-wrap"><table><thead><tr><th>Surface</th><th>Input</th><th>Output</th><th>Cache read</th><th>Reasoning</th><th>Fresh</th><th>Tools</th><th>Cost</th><th>Seconds</th><th>Top tools</th></tr></thead><tbody>${usageRows}</tbody></table></div>
181
- <h2>Runs</h2><div class="table-wrap"><table><thead><tr><th>Scenario</th><th>Category</th><th>Difficulty</th><th>Profile</th><th>Lifecycle</th><th>Surface</th><th>Repeat</th><th>Infra retries</th><th>Resolved</th><th>Grader</th><th>Scope</th><th>Workflow</th><th>Workflow gaps</th><th>Model</th><th>Thinking</th><th>Input</th><th>Output</th><th>Cache read</th><th>Reasoning</th><th>Fresh</th><th>Tools</th><th>Top tools</th><th>Cost</th><th>Seconds</th><th>Failure</th></tr></thead><tbody>${rows}</tbody></table></div>
284
+ <h2>Median usage across all measured runs</h2><div class="table-wrap"><table><thead><tr><th>Surface</th><th>Fresh input</th><th>Output</th><th>Cache read</th><th>Cache write</th><th>Reasoning ⊂ output</th><th>Fresh</th><th>Total</th><th>Tools</th><th>Provider-reported cost</th><th>Seconds</th><th>Top tools</th></tr></thead><tbody>${usageRows}</tbody></table></div>
285
+ <h2>Runs</h2><div class="table-wrap"><table><thead><tr><th>Scenario</th><th>Category</th><th>Difficulty</th><th>Profile</th><th>Lifecycle</th><th>Surface</th><th>Repeat</th><th>Infra retries</th><th>Resolved</th><th>Grader</th><th>Scope</th><th>Workflow</th><th>Workflow gaps</th><th>Model</th><th>Thinking</th><th>Usage source</th><th>Fresh input</th><th>Output</th><th>Cache read</th><th>Cache write</th><th>Reasoning ⊂ output</th><th>Fresh</th><th>Total</th><th>Tools</th><th>Top tools</th><th>Provider-reported cost</th><th>Seconds</th><th>Failure</th></tr></thead><tbody>${rows}</tbody></table></div>
182
286
  <p class="note">${htmlEscape(report.verdict.note)}</p></body></html>\n`;
183
287
  }
@@ -4,6 +4,7 @@ import path from "node:path";
4
4
  import { hardenPrivateRetentionRoot, retainedWorkspaceMarker, writeBenchmarkRunManifest, writePrivateAtomic } from "./benchmark-forensics.js";
5
5
  import { appendBenchmarkLedger, assertBenchmarkLedgerBinding, validateBenchmarkLedgerPrefix } from "./benchmark-ledger.js";
6
6
  import { expectedBenchmarkRecord, pairedBenchmarkVariantMatched } from "./benchmark-record-validation.js";
7
+ import { canonicalBenchmarkTimingDiagnostics } from "./benchmark-timing-diagnostics.js";
7
8
 
8
9
  function fail(message) {
9
10
  const error = new Error(message);
@@ -29,6 +30,14 @@ function exactUsage(usage, usageStatus) {
29
30
  && usage.total === usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
30
31
  }
31
32
 
33
+ function omitInvalidTimingDiagnostics(record) {
34
+ if (!record || typeof record !== "object") return record;
35
+ const timing = canonicalBenchmarkTimingDiagnostics(record.timingDiagnostics, record.surface, record.durationSeconds);
36
+ if (timing === undefined) delete record.timingDiagnostics;
37
+ else record.timingDiagnostics = timing;
38
+ return record;
39
+ }
40
+
32
41
  export function persistUnacceptedBenchmarkAttempt({ runRoot, manifest, record, reason, forceTokenUnavailable = false }) {
33
42
  const attempt = {
34
43
  schemaVersion: 1,
@@ -63,6 +72,7 @@ export function clearRecoveredBenchmarkAttempts(manifest, record) {
63
72
  }
64
73
 
65
74
  export function stageMeasuredBenchmarkRecord({ runRoot, manifest, ledgerBinding, record, infrastructureFailures, index, expected, runId, suite, configurationDigest, runs }) {
75
+ omitInvalidTimingDiagnostics(record);
66
76
  record.infrastructureAttempts = record.infrastructureAttempt ?? 1;
67
77
  record.infrastructureRetries = Math.max(0, record.infrastructureAttempts - 1);
68
78
  record.infrastructureFailures = infrastructureFailures;
@@ -91,6 +101,7 @@ export function promoteMeasuredBenchmarkRecord({ runRoot, ledgerBinding, record,
91
101
  export function recoverPendingBenchmarkRecord({ runRoot, manifest, ledgerBinding, completedRuns, pending, measuredReady, fullOrder, suite }) {
92
102
  let binding = ledgerBinding;
93
103
  const runs = completedRuns;
104
+ let pendingRecordSanitized = false;
94
105
  if (pending) {
95
106
  if (pending.schemaVersion !== 2 || !pending.previousLedger || !pending.record || pending.postSessionGuard?.matched !== true
96
107
  || !String(pending.postSessionGuard.stage ?? "").startsWith("after-session:")) fail("Benchmark pending record is missing its post-session execution guard receipt");
@@ -100,6 +111,8 @@ export function recoverPendingBenchmarkRecord({ runRoot, manifest, ledgerBinding
100
111
  }
101
112
  if (binding.records === pending.previousLedger.records) {
102
113
  assertBenchmarkLedgerBinding(pending.previousLedger, binding, "pending-record previous ledger");
114
+ omitInvalidTimingDiagnostics(pending.record);
115
+ pendingRecordSanitized = true;
103
116
  binding = appendBenchmarkLedger(path.join(runRoot, "runs.jsonl"), pending.record, binding);
104
117
  runs.push(pending.record);
105
118
  } else if (binding.records === pending.previousLedger.records + 1) {
@@ -123,6 +136,7 @@ export function recoverPendingBenchmarkRecord({ runRoot, manifest, ledgerBinding
123
136
  fail("Measured benchmark record WAL does not match the frozen execution order");
124
137
  }
125
138
  if (pending) {
139
+ if (pendingRecordSanitized) omitInvalidTimingDiagnostics(measuredReady.record);
126
140
  assertBenchmarkLedgerBinding(measuredReady.previousLedger, pending.previousLedger, "measured/pending previous ledger");
127
141
  if (JSON.stringify(measuredReady.record) !== JSON.stringify(pending.record)) fail("Measured and post-guard pending records differ");
128
142
  } else {
@@ -0,0 +1,26 @@
1
+ export function applyBenchmarkExecutionDefaults(options, suite) {
2
+ options.repeats ??= suite.defaultRepeats;
3
+ options.infrastructureRetries ??= suite.releaseGate?.maximumInfrastructureRetries
4
+ ?? (suite.schemaVersion === 2 ? 2 : 0);
5
+ options.retryDelaySeconds ??= suite.schemaVersion === 2 && options.infrastructureRetries > 0 ? 60 : 0;
6
+ options.timeoutSeconds ??= suite.timeoutSeconds;
7
+ const contract = suite.executionContract;
8
+ if (!contract) return;
9
+ for (const [field, expected] of [
10
+ ["surfaces", contract.surfaces], ["model", contract.model], ["thinking", contract.thinking], ["codexMode", contract.codexMode]
11
+ ]) {
12
+ const actual = options[field];
13
+ if (actual === undefined) options[field] = Array.isArray(expected) ? [...expected] : expected;
14
+ else if (JSON.stringify(actual) !== JSON.stringify(expected)) {
15
+ throw new Error(`Suite ${suite.id} locks ${field} to ${Array.isArray(expected) ? expected.join(",") : expected}`);
16
+ }
17
+ }
18
+ }
19
+
20
+ export function benchmarkSuiteCoverage(declaredScenarios, selectedScenarios) {
21
+ return {
22
+ declaredScenarios,
23
+ selectedScenarios,
24
+ fullSuite: selectedScenarios === declaredScenarios
25
+ };
26
+ }