@piagent/platform 1.5.5 → 1.6.1
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.
- package/CHANGELOG.md +166 -0
- package/README.md +25 -21
- package/README.vi.md +34 -5
- package/adapters/web-frontend/profile.json +2 -4
- package/architecture/layers.json +18 -3
- package/benchmarks/deep-logic-v1/SPECIALIST_PROTOCOL.vi.md +122 -0
- package/benchmarks/deep-logic-v1/grade.mjs +272 -10
- package/benchmarks/deep-logic-v1/project/apps/admin/src/billing-summary.js +3 -0
- package/benchmarks/deep-logic-v1/project/benchmark-contract/public-smoke.test.js +166 -0
- package/benchmarks/deep-logic-v1/project/package.json +1 -1
- package/benchmarks/deep-logic-v1/project/packages/billing/src/close-period.js +3 -0
- package/benchmarks/deep-logic-v1/project/packages/billing/src/plan-timeline.js +3 -0
- package/benchmarks/deep-logic-v1/project/test/smoke.test.js +7 -1
- package/benchmarks/deep-logic-v1/prompts/budgeted-context-graph.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/fair-dependency-scheduler.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/layered-policy-resolution.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/resumable-stream-assembly.md +3 -1
- package/benchmarks/deep-logic-v1/prompts/revision-event-reconciliation.md +2 -0
- package/benchmarks/deep-logic-v1/prompts/temporal-usage-billing-close.md +123 -0
- package/benchmarks/deep-logic-v1/prompts/transactional-config-merge.md +2 -0
- package/benchmarks/deep-logic-v1/suite.json +51 -3
- package/benchmarks/deep-logic-v1/variant.mjs +22 -1
- package/benchmarks/production-v1/spend-control.v1.json +92 -0
- package/benchmarks/production-v1/suite.json +46 -3
- package/catalog/capabilities.json +18 -18
- package/docs/authority-manifest.md +1 -1
- package/docs/auto-delegation-policy.md +38 -73
- package/docs/command-reference-vietnamese.md +27 -35
- package/docs/context-engine.md +12 -4
- package/docs/context-window-policy.md +37 -1
- package/docs/distribution-standard.md +7 -7
- package/docs/en/architecture.md +27 -13
- package/docs/languages.json +4 -4
- package/docs/model-options.md +8 -5
- package/docs/operator-manual-vietnamese.md +27 -45
- package/docs/project-adapters.md +2 -2
- package/docs/publishing-for-teams.md +10 -0
- package/docs/quality-benchmark.md +427 -62
- package/docs/release-install-policy.md +10 -9
- package/docs/runtime-harness-standard.md +3 -3
- package/docs/runtime-policy-design.md +4 -4
- package/docs/runtime-quality-baseline.md +13 -6
- package/docs/security-threat-model.md +2 -2
- package/docs/subagent-orchestration-capabilities.md +19 -51
- package/docs/subagents-and-multiagent.md +21 -47
- package/docs/task-implementation-contract.md +3 -3
- package/docs/task-lifecycle-vietnamese.md +3 -3
- package/docs/team-onboarding.md +2 -2
- package/docs/usage-observability.md +7 -2
- package/docs/vi/architecture.md +27 -13
- package/docs-site/architecture.html +1 -1
- package/docs-site/benchmark.html +89 -95
- package/docs-site/commands.html +1 -1
- package/docs-site/content/benchmark.html +88 -94
- package/docs-site/content/en/benchmark.html +134 -90
- package/docs-site/content/en/index.html +19 -19
- package/docs-site/content/en/runtime.html +4 -4
- package/docs-site/content/en/whats-new.html +12 -1
- package/docs-site/content/en/workflows.html +2 -2
- package/docs-site/content/index.html +19 -19
- package/docs-site/content/runtime.html +4 -4
- package/docs-site/content/whats-new.html +12 -1
- package/docs-site/content/workflows.html +2 -2
- package/docs-site/context-engine.html +1 -1
- package/docs-site/en/architecture.html +1 -1
- package/docs-site/en/benchmark.html +135 -91
- package/docs-site/en/commands.html +1 -1
- package/docs-site/en/context-engine.html +1 -1
- package/docs-site/en/index.html +20 -20
- package/docs-site/en/mcp-approval.html +1 -1
- package/docs-site/en/mcp-auth.html +1 -1
- package/docs-site/en/mcp-servers.html +1 -1
- package/docs-site/en/mcp.html +1 -1
- package/docs-site/en/permissions.html +1 -1
- package/docs-site/en/profiles.html +1 -1
- package/docs-site/en/quickstart.html +1 -1
- package/docs-site/en/runtime.html +5 -5
- package/docs-site/en/scope.html +1 -1
- package/docs-site/en/security.html +1 -1
- package/docs-site/en/team.html +1 -1
- package/docs-site/en/whats-new.html +13 -2
- package/docs-site/en/workflows.html +3 -3
- package/docs-site/index.html +20 -20
- package/docs-site/mcp-approval.html +1 -1
- package/docs-site/mcp-auth.html +1 -1
- package/docs-site/mcp-servers.html +1 -1
- package/docs-site/mcp.html +1 -1
- package/docs-site/permissions.html +1 -1
- package/docs-site/profiles.html +1 -1
- package/docs-site/quickstart.html +1 -1
- package/docs-site/runtime.html +5 -5
- package/docs-site/scope.html +1 -1
- package/docs-site/security.html +1 -1
- package/docs-site/team.html +1 -1
- package/docs-site/whats-new.html +13 -2
- package/docs-site/workflows.html +3 -3
- package/evals/fixtures/benchmark-assurance-evidence.invalid.json +1 -1
- package/evals/fixtures/benchmark-assurance-evidence.valid.json +1 -1
- package/evals/fixtures/codex-relative-efficiency-v1.invalid.json +4 -0
- package/evals/fixtures/codex-relative-efficiency-v1.valid.json +94 -0
- package/evals/fixtures/helper-request.invalid.json +1 -1
- package/evals/fixtures/helper-request.valid.json +1 -1
- package/evals/fixtures/piagent-webui/session-live-state-v1.invalid.json +18 -0
- package/evals/fixtures/piagent-webui/session-live-state-v1.valid.json +27 -0
- package/evals/fixtures/piagent-webui/subagent-tree-v1.valid.json +7 -0
- package/evals/fixtures/task-authority-snapshot.valid.json +4 -4
- package/evals/fs4-readiness-matrix.v1.json +2 -2
- package/evals/fs5-causal-arm.v1.json +3 -3
- package/evals/fs5-pilot-protocol.v1.json +3 -3
- package/evals/fs5-pilot-protocol.v2.json +8 -8
- package/evals/fs5-pilot-protocol.v3.json +8 -8
- package/evals/fs5-pilot-protocol.v4.json +7 -6
- package/evals/fs5-pilot-protocol.v5.json +9 -7
- package/evals/private-holdout-v1/public-exposure.v1.json +1 -1
- package/evals/runtime-conformance-v1/README.md +43 -0
- package/evals/runtime-conformance-v1/evaluate-paid-canary.mjs +198 -0
- package/evals/runtime-conformance-v1/lane.json +57 -0
- package/evals/runtime-conformance-v1/paid-canary.json +31 -0
- package/evals/runtime-conformance-v1/runner.mjs +456 -0
- package/package.json +3 -1
- package/packages/piagent-core/README.md +13 -4
- package/packages/piagent-core/benchmark/benchmark-assurance.js +4 -1
- package/packages/piagent-core/benchmark/benchmark-bootstrap.js +91 -9
- package/packages/piagent-core/benchmark/benchmark-claim-restrictions.js +38 -7
- package/packages/piagent-core/benchmark/benchmark-cli.js +7 -7
- package/packages/piagent-core/benchmark/benchmark-codex-relative-efficiency.js +698 -0
- package/packages/piagent-core/benchmark/benchmark-codex.js +3 -1
- package/packages/piagent-core/benchmark/benchmark-comparison.js +271 -2
- package/packages/piagent-core/benchmark/benchmark-core.js +736 -664
- package/packages/piagent-core/benchmark/benchmark-execution-guard.js +7 -5
- package/packages/piagent-core/benchmark/benchmark-forensics.js +441 -4
- package/packages/piagent-core/benchmark/benchmark-host-readiness.js +639 -0
- package/packages/piagent-core/benchmark/benchmark-matrix.js +22 -4
- package/packages/piagent-core/benchmark/benchmark-normalized-cost.js +317 -0
- package/packages/piagent-core/benchmark/benchmark-preflight.js +5 -1
- package/packages/piagent-core/benchmark/benchmark-process.js +6 -5
- package/packages/piagent-core/benchmark/benchmark-provider-free-evidence.js +345 -0
- package/packages/piagent-core/benchmark/benchmark-provider-wire.js +126 -0
- package/packages/piagent-core/benchmark/benchmark-record-validation.js +252 -0
- package/packages/piagent-core/benchmark/benchmark-report.js +130 -12
- package/packages/piagent-core/benchmark/benchmark-resume-recovery.js +14 -0
- package/packages/piagent-core/benchmark/benchmark-runner-policy.js +26 -0
- package/packages/piagent-core/benchmark/benchmark-runtime-causal.js +244 -0
- package/packages/piagent-core/benchmark/benchmark-stage-diagnostic.js +979 -0
- package/packages/piagent-core/benchmark/benchmark-statistics.js +64 -0
- package/packages/piagent-core/benchmark/benchmark-stop-policy.js +8 -5
- package/packages/piagent-core/benchmark/benchmark-suite-identity.js +31 -0
- package/packages/piagent-core/benchmark/benchmark-suite-runtime.js +13 -9
- package/packages/piagent-core/benchmark/benchmark-suite.js +149 -2
- package/packages/piagent-core/benchmark/benchmark-summary-support.js +380 -0
- package/packages/piagent-core/benchmark/benchmark-timing-diagnostics.js +971 -0
- package/packages/piagent-core/benchmark/benchmark-usage.js +322 -0
- package/packages/piagent-core/benchmark/benchmark-workflow.js +166 -0
- package/packages/piagent-core/capabilities/runtime-integrity.js +3 -0
- package/packages/piagent-core/docs/context-efficiency-improvement-plan.md +1080 -0
- package/packages/piagent-core/extensions/acceptance-behavior-proof.js +806 -0
- package/packages/piagent-core/extensions/acceptance-contract-semantics.js +83 -69
- package/packages/piagent-core/extensions/acceptance-error-classes.js +160 -0
- package/packages/piagent-core/extensions/acceptance-executable-evidence.js +12 -9
- package/packages/piagent-core/extensions/acceptance-receipt.js +123 -59
- package/packages/piagent-core/extensions/acceptance-state-machine-evidence.js +518 -0
- package/packages/piagent-core/extensions/acceptance-test-binding-evidence.js +60 -0
- package/packages/piagent-core/extensions/context-efficiency-metrics.js +302 -0
- package/packages/piagent-core/extensions/context-efficiency-report.js +167 -0
- package/packages/piagent-core/extensions/context-engine.js +149 -156
- package/packages/piagent-core/extensions/context-evidence.js +48 -0
- package/packages/piagent-core/extensions/context-import-links.js +296 -0
- package/packages/piagent-core/extensions/context-index-policy.js +4 -0
- package/packages/piagent-core/extensions/context-query-paths.js +57 -0
- package/packages/piagent-core/extensions/context-telemetry-integrity.js +65 -0
- package/packages/piagent-core/extensions/criterion-context-pack.js +435 -7
- package/packages/piagent-core/extensions/criterion-graph.js +82 -9
- package/packages/piagent-core/extensions/fallback-base-policy.ts +101 -0
- package/packages/piagent-core/extensions/guard-types.ts +6 -0
- package/packages/piagent-core/extensions/javascript-regex-evidence.js +32 -0
- package/packages/piagent-core/extensions/piagent-guard.ts +420 -260
- package/packages/piagent-core/extensions/task-contract-view.js +17 -3
- package/packages/piagent-core/extensions/task-lifecycle.js +39 -2
- package/packages/piagent-core/extensions/task-state.js +109 -142
- package/packages/piagent-core/extensions/verification-intelligence.js +52 -13
- package/packages/piagent-core/extensions/workspace-evidence-roots.js +193 -0
- package/packages/piagent-core/package.json +1 -1
- package/packages/piagent-core/policies/base-policy.json +44 -2
- package/packages/piagent-core/policy/authority-manifest.v1.json +3 -3
- package/packages/piagent-core/prompts/be-to-fe.md +2 -8
- package/packages/piagent-core/prompts/plan.md +1 -1
- package/packages/piagent-core/prompts/platform-improve.md +2 -6
- package/packages/piagent-core/prompts/review.md +2 -7
- package/packages/piagent-core/prompts/scout.md +1 -1
- package/packages/piagent-core/prompts/task.md +4 -3
- package/packages/piagent-core/runtime/context/context-delivery.ts +103 -0
- package/packages/piagent-core/runtime/context/context-delta-shadow.ts +53 -0
- package/packages/piagent-core/runtime/context/context-efficiency-format.ts +47 -0
- package/packages/piagent-core/runtime/context/context-evidence-qualification.ts +32 -0
- package/packages/piagent-core/runtime/context/prefix-telemetry.ts +47 -0
- package/packages/piagent-core/runtime/context/repository-memory-hints.ts +27 -0
- package/packages/piagent-core/runtime/hooks/agent-prompt-telemetry.ts +56 -0
- package/packages/piagent-core/runtime/hooks/agent-start-hook.ts +162 -102
- package/packages/piagent-core/runtime/hooks/completion-hook.ts +12 -12
- package/packages/piagent-core/runtime/hooks/input-hook.ts +17 -1
- package/packages/piagent-core/runtime/hooks/session-hooks.ts +22 -2
- package/packages/piagent-core/runtime/hooks/session-start-hook.ts +107 -3
- package/packages/piagent-core/runtime/hooks/tool-result-content-guards.ts +95 -0
- package/packages/piagent-core/runtime/hooks/tool-result-hook.ts +134 -166
- package/packages/piagent-core/runtime/hooks/tool-result-value-helpers.ts +66 -0
- package/packages/piagent-core/runtime/inspection/activity-event-adapter.ts +4 -2
- package/packages/piagent-core/runtime/inspection/activity-recovery.ts +104 -0
- package/packages/piagent-core/runtime/inspection/bounded-emission-guard.ts +286 -0
- package/packages/piagent-core/runtime/inspection/runtime-event-store.ts +37 -7
- package/packages/piagent-core/runtime/inspection/task-compaction-history.ts +1 -1
- package/packages/piagent-core/runtime/inspection/task-handoff-history.ts +1 -1
- package/packages/piagent-core/runtime/inspection/task-subagent-tree.ts +27 -4
- package/packages/piagent-core/runtime/inspection/tool-failure-classification.ts +70 -0
- package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +73 -9
- package/packages/piagent-core/runtime/model/authenticated-catalog.ts +17 -9
- package/packages/piagent-core/runtime/model/openai-codex-reasoning.ts +83 -0
- package/packages/piagent-core/runtime/model/provider-wire-fingerprint.ts +238 -0
- package/packages/piagent-core/runtime/orchestration/helper-lifecycle.ts +16 -12
- package/packages/piagent-core/runtime/orchestration/minimal-delegation-policy.ts +71 -0
- package/packages/piagent-core/runtime/orchestration/owned-work-budget.ts +28 -20
- package/packages/piagent-core/runtime/orchestration/role-policy.ts +27 -9
- package/packages/piagent-core/runtime/orchestration/subagent-tool-policy.ts +329 -0
- package/packages/piagent-core/runtime/policy/block-remedy.ts +0 -4
- package/packages/piagent-core/runtime/product/activity-inspector.ts +7 -2
- package/packages/piagent-core/runtime/product/efficiency-metrics.ts +7 -2
- package/packages/piagent-core/runtime/quality/edit-freshness-guard.ts +102 -0
- package/packages/piagent-core/runtime/quality/exact-output-contract.ts +22 -11
- package/packages/piagent-core/runtime/quality/performance-assurance-signals.ts +23 -0
- package/packages/piagent-core/runtime/quality/performance-assurance.ts +9 -5
- package/packages/piagent-core/runtime/recovery/continuation-budget.ts +1 -1
- package/packages/piagent-core/runtime/recovery/edit-recovery-context.ts +113 -0
- package/packages/piagent-core/runtime/recovery/edit-recovery-delivery.ts +42 -0
- package/packages/piagent-core/runtime/recovery/handoff-projection.ts +4 -1
- package/packages/piagent-core/runtime/recovery/pristine-task-policy-refresh.ts +91 -0
- package/packages/piagent-core/runtime/recovery/recovery-policy.ts +7 -4
- package/packages/piagent-core/runtime/recovery/resume-state.ts +112 -14
- package/packages/piagent-core/runtime/recovery/semantic-repair-handshake.ts +60 -13
- package/packages/piagent-core/runtime/recovery/semantic-repair-runtime.ts +55 -2
- package/packages/piagent-core/runtime/recovery/task-evidence-coverage-refresh.ts +217 -0
- package/packages/piagent-core/runtime/registration/context-commands.ts +82 -7
- package/packages/piagent-core/runtime/registration/knowledge-tools.ts +9 -5
- package/packages/piagent-core/runtime/registration/operator-request-intake.ts +49 -0
- package/packages/piagent-core/runtime/registration/policy-tools.ts +50 -15
- package/packages/piagent-core/runtime/registration/session-commands.ts +1 -1
- package/packages/piagent-core/runtime/registration/task-completion-tools.ts +61 -25
- package/packages/piagent-core/runtime/registration/task-evidence-tools.ts +21 -12
- package/packages/piagent-core/runtime/registration/task-start-guidance.ts +169 -0
- package/packages/piagent-core/runtime/registration/task-start-manifest.ts +54 -0
- package/packages/piagent-core/runtime/registration/task-start-retry-helpers.ts +37 -0
- package/packages/piagent-core/runtime/registration/task-start-tool.ts +108 -103
- package/packages/piagent-core/runtime/runtime-limits.ts +16 -2
- package/packages/piagent-core/runtime/session/adaptive-context-analysis.ts +461 -0
- package/packages/piagent-core/runtime/session/adaptive-context-governor.ts +464 -0
- package/packages/piagent-core/runtime/session/adaptive-context-ledger.ts +265 -0
- package/packages/piagent-core/runtime/session/message-signals.ts +7 -3
- package/packages/piagent-core/runtime/session/operator-request-carry.ts +44 -0
- package/packages/piagent-core/runtime/session/runtime-state.ts +161 -5
- package/packages/piagent-core/runtime/session/source-checkout-read-grants.ts +35 -0
- package/packages/piagent-core/runtime/session/system-prompt.ts +76 -14
- package/packages/piagent-core/runtime/session/task-contract-presentation.ts +39 -0
- package/packages/piagent-core/runtime/tools/apply-patch-tool.ts +500 -0
- package/packages/piagent-core/runtime/tools/phase-tools.ts +8 -8
- package/packages/piagent-core/runtime/tools/tool-groups.ts +12 -2
- package/packages/piagent-core/runtime/trajectory/trajectory-runtime.ts +2 -1
- package/packages/piagent-core/runtime/verification/exact-verifier-reuse.ts +101 -0
- package/packages/piagent-core/runtime/workflows/runtime-intake-compaction.ts +164 -0
- package/packages/piagent-core/runtime/workflows/task-intake.ts +207 -38
- package/packages/piagent-core/security/sensitive-data.js +13 -218
- package/packages/piagent-core/security/sensitive-project-file.js +42 -0
- package/packages/piagent-core/security/sensitive-source-expression.js +330 -0
- package/packages/piagent-core/security/sensitive-source-formats.js +394 -0
- package/packages/piagent-core/security/sensitive-text.js +234 -0
- package/packages/piagent-core/subagents/piagent-oracle.md +5 -3
- package/packages/piagent-core/subagents/piagent-planner.md +6 -4
- package/packages/piagent-core/subagents/piagent-reviewer.md +5 -3
- package/packages/piagent-core/subagents/piagent-scout.md +4 -2
- package/packages/piagent-core/subagents/piagent-worker.md +7 -5
- package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-rD9WJKxs.js → MarkdownMessage-B4XehTCU.js} +1 -1
- package/packages/piagent-webui/dist/client/assets/index-CgOEyRPG.js +176 -0
- package/packages/piagent-webui/dist/client/index.html +1 -1
- package/packages/piagent-webui/extension/piagent-webui.ts +3 -1
- package/packages/piagent-webui/extension/same-session-bridge.ts +1 -1
- package/packages/piagent-webui/extension/session-stream-adapter.ts +33 -10
- package/packages/piagent-webui/gateway/gateway-events.ts +109 -5
- package/packages/piagent-webui/gateway/gateway-service.ts +3 -0
- package/packages/piagent-webui/gateway/gateway-session-stream.ts +122 -20
- package/packages/piagent-webui/gateway/session-command-controller.ts +18 -3
- package/packages/piagent-webui/gateway/session-effective-options.ts +47 -0
- package/packages/piagent-webui/gateway/session-live-state.ts +21 -0
- package/packages/piagent-webui/gateway/session-operation-lifecycle.ts +237 -0
- package/packages/piagent-webui/gateway/session-operation-retry-control.ts +38 -0
- package/packages/piagent-webui/gateway/session-operation-start.ts +5 -1
- package/packages/piagent-webui/gateway/session-operation-watchdog.ts +165 -0
- package/packages/piagent-webui/gateway/session-runtime-factory.ts +45 -0
- package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +141 -125
- package/packages/piagent-webui/ownership/session-lease-store.ts +5 -2
- package/packages/piagent-webui/server/core-inspection-provider.ts +2 -1
- package/packages/piagent-webui/server/loopback-server.ts +8 -0
- package/packages/piagent-webui/server/transcript-projection.ts +113 -9
- package/packages/piagent-webui/shared/text-visibility.ts +10 -0
- package/schemas/codex-relative-efficiency-v1.schema.json +155 -0
- package/schemas/piagent-webui/catalog-v1.json +9 -0
- package/schemas/piagent-webui/gateway-protocol-v1.schema.json +53 -3
- package/schemas/piagent-webui/runtime-event-v2.schema.json +15 -5
- package/schemas/piagent-webui/session-live-state-v1.schema.json +76 -0
- package/schemas/piagent-webui/subagent-tree-v1.schema.json +11 -1
- package/schemas/project-profile.schema.json +1 -1
- package/schemas/task-contract.schema.json +27 -1
- package/scripts/benchmark-runner-core.mjs +367 -363
- package/scripts/benchmark-runner-finalization.mjs +313 -0
- package/scripts/benchmark-runner-host-readiness.mjs +94 -0
- package/scripts/benchmark-runner-support.mjs +200 -0
- package/scripts/benchmark-session.mjs +95 -41
- package/scripts/configure-model-scope.sh +4 -3
- package/scripts/configure-subagents.sh +42 -34
- package/scripts/helper-evaluation.mjs +2 -2
- package/scripts/install-global.sh +2 -2
- package/scripts/pi-usage-history.mjs +37 -10
- package/scripts/setup.sh +2 -2
- package/scripts/team-doctor.sh +1 -1
- package/scripts/verify-local.sh +10 -1
- package/templates/global/settings.json +2 -1
- package/packages/piagent-webui/dist/client/assets/index-BZRFw1u6.js +0 -174
|
@@ -1,637 +1,70 @@
|
|
|
1
|
-
import { StringDecoder } from "node:string_decoder";
|
|
2
|
-
|
|
3
1
|
import { benchmarkClaimEligibility } from "./benchmark-assurance.js";
|
|
2
|
+
import { integrateCodexRelativeEfficiencyReport } from "./benchmark-codex-relative-efficiency.js";
|
|
4
3
|
import {
|
|
5
4
|
comparableAttemptUsage,
|
|
5
|
+
comparableDuration,
|
|
6
6
|
comparisonProtocol,
|
|
7
7
|
completeCategoryCoverage,
|
|
8
8
|
completePairedScenarioCount,
|
|
9
|
+
familyClusteredFailureAwareUsage,
|
|
10
|
+
familyClusteredFixedWorkloadUsage,
|
|
11
|
+
pairedDurationBands,
|
|
12
|
+
pairedUsageBands,
|
|
13
|
+
selectPrimaryEfficiencyEstimate,
|
|
9
14
|
tokensPerResolvedOutcome
|
|
10
15
|
} from "./benchmark-comparison.js";
|
|
16
|
+
import { benchmarkProviderWireEvidenceMatchesRequest } from "./benchmark-provider-wire.js";
|
|
17
|
+
import { canonicalBenchmarkTimingDiagnostics, summarizeBenchmarkTimingDiagnostics } from "./benchmark-timing-diagnostics.js";
|
|
18
|
+
import { summarizeBenchmarkCausalContextEvidence } from "./benchmark-record-validation.js";
|
|
11
19
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from "./benchmark-
|
|
16
|
-
|
|
20
|
+
benchmarkPricingSnapshotValidationErrors,
|
|
21
|
+
normalizedCostComparison,
|
|
22
|
+
normalizedCostGate
|
|
23
|
+
} from "./benchmark-normalized-cost.js";
|
|
24
|
+
import {
|
|
25
|
+
atMostWithinFloatingPrecision,
|
|
26
|
+
geometricMean,
|
|
27
|
+
geometricMeanConfidence95,
|
|
28
|
+
geometricMeanConfidence95Raw,
|
|
29
|
+
median,
|
|
30
|
+
rounded
|
|
31
|
+
} from "./benchmark-statistics.js";
|
|
32
|
+
import { benchmarkInfrastructureFailureLedgerIssues, benchmarkTokenAccounting as buildBenchmarkTokenAccounting } from "./benchmark-usage.js";
|
|
33
|
+
import {
|
|
34
|
+
efficiencyScore,
|
|
35
|
+
evaluateDurationBandGate,
|
|
36
|
+
evaluateFreshTokenBandGate,
|
|
37
|
+
pairedOutcomeCounts,
|
|
38
|
+
pairedQualityNoninferiorityEvidence,
|
|
39
|
+
qualityPassed,
|
|
40
|
+
RELEASE_FAILURE_MESSAGES,
|
|
41
|
+
safetyPassed,
|
|
42
|
+
surfaceReportKey,
|
|
43
|
+
surfaceSummary,
|
|
44
|
+
workflowContinuityEvidenceComplete
|
|
45
|
+
} from "./benchmark-summary-support.js";
|
|
17
46
|
export { renderBenchmarkHtml, renderBenchmarkText } from "./benchmark-report.js";
|
|
18
47
|
export { benchmarkAssuranceEvidenceValidationErrors, benchmarkClaimEligibility } from "./benchmark-assurance.js";
|
|
48
|
+
export { median } from "./benchmark-statistics.js";
|
|
19
49
|
export { benchmarkSuiteValidationErrors, validateBenchmarkSuite } from "./benchmark-suite.js";
|
|
50
|
+
export { aggregateSessionUsage, benchmarkTokenAccounting, createCodexExecJsonlCollector, parseCodexExecJsonl } from "./benchmark-usage.js";
|
|
51
|
+
export { benchmarkPricingSnapshotValidationErrors, normalizeBenchmarkUsageCost } from "./benchmark-normalized-cost.js";
|
|
52
|
+
export { CODEX_RELATIVE_EFFICIENCY_POLICY, PRODUCTION_SUBAGENT_BUDGET_POLICY, evaluateCodexRelativeEfficiency, summarizeBenchmarkSubagentBudget } from "./benchmark-codex-relative-efficiency.js";
|
|
53
|
+
export { evaluateWorkflowEvidence } from "./benchmark-workflow.js";
|
|
20
54
|
const SURFACE_LABELS = Object.freeze({
|
|
21
55
|
"raw-pi": "Raw Pi",
|
|
22
56
|
piagent: "Piagent",
|
|
23
57
|
"codex-cli": "Codex CLI"
|
|
24
58
|
});
|
|
25
|
-
const SURFACE_REPORT_KEYS = Object.freeze({
|
|
26
|
-
"raw-pi": "rawPi",
|
|
27
|
-
piagent: "piagent",
|
|
28
|
-
"codex-cli": "codexCli"
|
|
29
|
-
});
|
|
30
|
-
const CODEX_NON_TOOL_ITEMS = new Set(["agent_message", "reasoning", "plan", "user_message"]);
|
|
31
59
|
export const BENCHMARK_MEASUREMENT_SCHEMA_VERSION = 2;
|
|
32
60
|
|
|
33
|
-
function plainObject(value) {
|
|
34
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function median(values) {
|
|
38
|
-
const finite = values.filter(Number.isFinite).sort((left, right) => left - right);
|
|
39
|
-
if (finite.length === 0) return null;
|
|
40
|
-
const middle = Math.floor(finite.length / 2);
|
|
41
|
-
return finite.length % 2 ? finite[middle] : (finite[middle - 1] + finite[middle]) / 2;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function geometricMean(values) {
|
|
45
|
-
if (!Array.isArray(values) || values.length === 0) return null;
|
|
46
|
-
if (values.some((value) => !Number.isFinite(value) || value <= 0)) return null;
|
|
47
|
-
return Math.exp(values.reduce((sum, value) => sum + Math.log(value), 0) / values.length);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function rounded(value, digits = 3) {
|
|
51
|
-
if (!Number.isFinite(value)) return null;
|
|
52
|
-
const factor = 10 ** digits;
|
|
53
|
-
return Math.round(value * factor) / factor;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function clamp(value, minimum = 0, maximum = 10) {
|
|
57
|
-
return Math.max(minimum, Math.min(maximum, value));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function wilsonInterval(successes, total, z = 1.959963984540054) {
|
|
61
|
-
if (!Number.isInteger(total) || total <= 0 || !Number.isInteger(successes) || successes < 0 || successes > total) return null;
|
|
62
|
-
const proportion = successes / total;
|
|
63
|
-
const zSquared = z ** 2;
|
|
64
|
-
const denominator = 1 + (zSquared / total);
|
|
65
|
-
const center = (proportion + (zSquared / (2 * total))) / denominator;
|
|
66
|
-
const margin = (z / denominator) * Math.sqrt(((proportion * (1 - proportion)) / total) + (zSquared / (4 * total ** 2)));
|
|
67
|
-
return { lower: rounded(Math.max(0, center - margin), 4), upper: rounded(Math.min(1, center + margin), 4) };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const STUDENT_T_975 = Object.freeze([
|
|
71
|
-
null, 12.706, 4.303, 3.182, 2.776, 2.571, 2.447, 2.365, 2.306, 2.262,
|
|
72
|
-
2.228, 2.201, 2.179, 2.16, 2.145, 2.131, 2.12, 2.11, 2.101, 2.093,
|
|
73
|
-
2.086, 2.08, 2.074, 2.069, 2.064, 2.06, 2.056, 2.052, 2.048, 2.045, 2.042
|
|
74
|
-
]);
|
|
75
|
-
|
|
76
|
-
function geometricMeanConfidence95(values) {
|
|
77
|
-
if (!Array.isArray(values) || values.length < 2 || values.some((value) => !Number.isFinite(value) || value <= 0)) return null;
|
|
78
|
-
const logs = values.map(Math.log);
|
|
79
|
-
const mean = logs.reduce((sum, value) => sum + value, 0) / logs.length;
|
|
80
|
-
const variance = logs.reduce((sum, value) => sum + ((value - mean) ** 2), 0) / (logs.length - 1);
|
|
81
|
-
const critical = STUDENT_T_975[logs.length - 1] ?? 1.96;
|
|
82
|
-
const margin = critical * Math.sqrt(variance / logs.length);
|
|
83
|
-
return {
|
|
84
|
-
lower: rounded(Math.exp(mean - margin), 4),
|
|
85
|
-
upper: rounded(Math.exp(mean + margin), 4),
|
|
86
|
-
sampleUnit: "scenario-family",
|
|
87
|
-
scenarioCount: logs.length
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function aggregateSessionUsage(sessions) {
|
|
92
|
-
const totals = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, reasoning: 0, total: 0, cost: 0 };
|
|
93
|
-
const models = new Set();
|
|
94
|
-
const thinkingLevels = new Set();
|
|
95
|
-
const toolNames = {};
|
|
96
|
-
let toolCalls = 0;
|
|
97
|
-
let messages = 0;
|
|
98
|
-
const contextSnapshots = [];
|
|
99
|
-
for (const session of sessions) {
|
|
100
|
-
for (const key of Object.keys(totals)) totals[key] += Number(session.tokens?.[key] ?? 0);
|
|
101
|
-
if (session.modelId || session.provider) models.add(`${session.provider || "unknown"}/${session.modelId || "unknown"}`);
|
|
102
|
-
if (session.thinkingLevel) thinkingLevels.add(session.thinkingLevel);
|
|
103
|
-
toolCalls += Number(session.messages?.toolCalls ?? 0);
|
|
104
|
-
messages += Number(session.messages?.total ?? 0);
|
|
105
|
-
if (plainObject(session.contextUsage)) {
|
|
106
|
-
const snapshot = {
|
|
107
|
-
tokens: Number.isFinite(session.contextUsage.tokens) ? session.contextUsage.tokens : null,
|
|
108
|
-
contextWindow: Number.isFinite(session.contextUsage.contextWindow) ? session.contextUsage.contextWindow : null,
|
|
109
|
-
percent: Number.isFinite(session.contextUsage.percent) ? session.contextUsage.percent : null
|
|
110
|
-
};
|
|
111
|
-
if (Object.values(snapshot).some(Number.isFinite)) contextSnapshots.push(snapshot);
|
|
112
|
-
}
|
|
113
|
-
for (const [name, count] of Object.entries(session.toolNames ?? {})) {
|
|
114
|
-
toolNames[name] = (toolNames[name] ?? 0) + Number(count ?? 0);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return {
|
|
118
|
-
...totals,
|
|
119
|
-
fresh: totals.input + totals.output,
|
|
120
|
-
sessions: sessions.length,
|
|
121
|
-
subagentSessions: sessions.filter((session) => session.isSubagent).length,
|
|
122
|
-
toolCalls,
|
|
123
|
-
toolNames: Object.fromEntries(Object.entries(toolNames).sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0]))),
|
|
124
|
-
messages,
|
|
125
|
-
model: models.size === 1 ? [...models][0] : models.size === 0 ? "unknown" : "mixed",
|
|
126
|
-
thinkingLevel: thinkingLevels.size === 1 ? [...thinkingLevels][0] : thinkingLevels.size === 0 ? "unknown" : "mixed",
|
|
127
|
-
contextUsage: contextSnapshots.length > 0 ? {
|
|
128
|
-
source: "session-reported",
|
|
129
|
-
observations: contextSnapshots.length,
|
|
130
|
-
peakTokens: contextSnapshots.some((item) => Number.isFinite(item.tokens))
|
|
131
|
-
? Math.max(...contextSnapshots.map((item) => item.tokens).filter(Number.isFinite))
|
|
132
|
-
: null,
|
|
133
|
-
contextWindow: new Set(contextSnapshots.map((item) => item.contextWindow).filter(Number.isFinite)).size === 1
|
|
134
|
-
? contextSnapshots.map((item) => item.contextWindow).find(Number.isFinite)
|
|
135
|
-
: null,
|
|
136
|
-
peakPercent: contextSnapshots.some((item) => Number.isFinite(item.percent))
|
|
137
|
-
? Math.max(...contextSnapshots.map((item) => item.percent).filter(Number.isFinite))
|
|
138
|
-
: null
|
|
139
|
-
} : {
|
|
140
|
-
source: "unavailable",
|
|
141
|
-
observations: 0,
|
|
142
|
-
peakTokens: null,
|
|
143
|
-
contextWindow: null,
|
|
144
|
-
peakPercent: null
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function requiredCodexToken(value, field) {
|
|
150
|
-
if (!Number.isSafeInteger(value) || value < 0) {
|
|
151
|
-
throw new Error(`Codex JSONL usage.${field} must be a non-negative integer`);
|
|
152
|
-
}
|
|
153
|
-
return value;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function consumeCodexEvent(state, event, lineNumber) {
|
|
157
|
-
if (!plainObject(event) || typeof event.type !== "string") {
|
|
158
|
-
throw new Error(`Codex JSONL line ${lineNumber} is not an event object`);
|
|
159
|
-
}
|
|
160
|
-
state.onEvent?.(event);
|
|
161
|
-
if (event.type === "error" || event.type === "turn.failed") {
|
|
162
|
-
const nested = plainObject(event.error) ? event.error : {};
|
|
163
|
-
const message = [event.message, nested.message, nested.additional_details]
|
|
164
|
-
.find((value) => typeof value === "string" && value.trim());
|
|
165
|
-
state.diagnostics.push({ type: event.type, message: message ? message.trim().slice(0, 2_000) : "unspecified Codex error" });
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
if (event.type === "thread.started" && typeof event.thread_id === "string" && event.thread_id) {
|
|
169
|
-
state.threadId = event.thread_id;
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
if (event.type === "item.completed" && plainObject(event.item)) {
|
|
173
|
-
const type = event.item.type;
|
|
174
|
-
if (type === "agent_message") state.messages += 1;
|
|
175
|
-
else if (typeof type === "string" && type && !CODEX_NON_TOOL_ITEMS.has(type)) {
|
|
176
|
-
state.toolNames[type] = (state.toolNames[type] ?? 0) + 1;
|
|
177
|
-
}
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
if (event.type === "turn.completed") {
|
|
181
|
-
state.completedTurns += 1;
|
|
182
|
-
if (state.completedTurns > 1) throw new Error("Codex JSONL contains more than one completed root turn");
|
|
183
|
-
if (!plainObject(event.usage)) throw new Error("Codex JSONL turn.completed is missing usage");
|
|
184
|
-
state.completedUsage = event.usage;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function finishCodexUsage(state) {
|
|
189
|
-
if (!state.threadId) throw new Error("Codex JSONL is missing thread.started");
|
|
190
|
-
if (!state.completedUsage) throw new Error("Codex JSONL is missing turn.completed usage");
|
|
191
|
-
const providerInput = requiredCodexToken(state.completedUsage.input_tokens, "input_tokens");
|
|
192
|
-
const cacheRead = requiredCodexToken(state.completedUsage.cached_input_tokens ?? 0, "cached_input_tokens");
|
|
193
|
-
const cacheWrite = requiredCodexToken(state.completedUsage.cache_write_input_tokens ?? 0, "cache_write_input_tokens");
|
|
194
|
-
const output = requiredCodexToken(state.completedUsage.output_tokens, "output_tokens");
|
|
195
|
-
const reasoning = requiredCodexToken(state.completedUsage.reasoning_output_tokens ?? 0, "reasoning_output_tokens");
|
|
196
|
-
if (cacheRead > providerInput) throw new Error("Codex JSONL cached_input_tokens exceeds input_tokens");
|
|
197
|
-
if (reasoning > output) throw new Error("Codex JSONL reasoning_output_tokens exceeds output_tokens");
|
|
198
|
-
const input = providerInput - cacheRead;
|
|
199
|
-
const sortedTools = Object.fromEntries(Object.entries(state.toolNames).sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0])));
|
|
200
|
-
return {
|
|
201
|
-
input,
|
|
202
|
-
providerInput,
|
|
203
|
-
output,
|
|
204
|
-
cacheRead,
|
|
205
|
-
cacheWrite,
|
|
206
|
-
reasoning,
|
|
207
|
-
total: providerInput + output,
|
|
208
|
-
fresh: input + output,
|
|
209
|
-
cost: null,
|
|
210
|
-
costSource: "unavailable",
|
|
211
|
-
sessions: 1,
|
|
212
|
-
subagentSessions: 0,
|
|
213
|
-
toolCalls: Object.values(sortedTools).reduce((sum, value) => sum + value, 0),
|
|
214
|
-
toolNames: sortedTools,
|
|
215
|
-
messages: state.messages,
|
|
216
|
-
model: typeof state.model === "string" && state.model ? state.model : "unknown",
|
|
217
|
-
thinkingLevel: typeof state.thinkingLevel === "string" && state.thinkingLevel ? state.thinkingLevel : "unknown",
|
|
218
|
-
contextUsage: {
|
|
219
|
-
source: "unavailable",
|
|
220
|
-
observations: 0,
|
|
221
|
-
peakTokens: null,
|
|
222
|
-
contextWindow: null,
|
|
223
|
-
peakPercent: null
|
|
224
|
-
},
|
|
225
|
-
providerSessionId: state.threadId
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
export function createCodexExecJsonlCollector(options = {}) {
|
|
230
|
-
const state = {
|
|
231
|
-
model: options.model,
|
|
232
|
-
thinkingLevel: options.thinkingLevel,
|
|
233
|
-
onEvent: typeof options.onEvent === "function" ? options.onEvent : undefined,
|
|
234
|
-
threadId: undefined,
|
|
235
|
-
completedUsage: undefined,
|
|
236
|
-
completedTurns: 0,
|
|
237
|
-
messages: 0,
|
|
238
|
-
toolNames: {},
|
|
239
|
-
diagnostics: []
|
|
240
|
-
};
|
|
241
|
-
let buffer = "";
|
|
242
|
-
let lineNumber = 0;
|
|
243
|
-
let failure;
|
|
244
|
-
const decoder = new StringDecoder("utf8");
|
|
245
|
-
const consumeLine = (rawLine) => {
|
|
246
|
-
lineNumber += 1;
|
|
247
|
-
const line = rawLine.trim();
|
|
248
|
-
if (!line) return;
|
|
249
|
-
let event;
|
|
250
|
-
try { event = JSON.parse(line); }
|
|
251
|
-
catch { throw new Error(`Codex JSONL line ${lineNumber} is not valid JSON`); }
|
|
252
|
-
consumeCodexEvent(state, event, lineNumber);
|
|
253
|
-
};
|
|
254
|
-
return {
|
|
255
|
-
write(chunk) {
|
|
256
|
-
if (failure) return;
|
|
257
|
-
try {
|
|
258
|
-
buffer += typeof chunk === "string" ? chunk : decoder.write(Buffer.from(chunk));
|
|
259
|
-
let newline;
|
|
260
|
-
while ((newline = buffer.indexOf("\n")) >= 0) {
|
|
261
|
-
consumeLine(buffer.slice(0, newline));
|
|
262
|
-
buffer = buffer.slice(newline + 1);
|
|
263
|
-
}
|
|
264
|
-
if (buffer.length > 64 * 1024 * 1024) throw new Error("Codex JSONL event exceeds the 64 MiB safety limit");
|
|
265
|
-
} catch (error) {
|
|
266
|
-
failure = error;
|
|
267
|
-
buffer = "";
|
|
268
|
-
}
|
|
269
|
-
},
|
|
270
|
-
finish() {
|
|
271
|
-
if (!failure) buffer += decoder.end();
|
|
272
|
-
if (!failure && buffer) {
|
|
273
|
-
try { consumeLine(buffer); } catch (error) { failure = error; }
|
|
274
|
-
buffer = "";
|
|
275
|
-
}
|
|
276
|
-
if (failure) throw failure;
|
|
277
|
-
return finishCodexUsage(state);
|
|
278
|
-
},
|
|
279
|
-
diagnostics() {
|
|
280
|
-
return state.diagnostics.map((item) => ({ ...item }));
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
export function parseCodexExecJsonl(stdout, options = {}) {
|
|
286
|
-
if (typeof stdout !== "string") throw new Error("Codex JSONL output must be a string");
|
|
287
|
-
const collector = createCodexExecJsonlCollector(options);
|
|
288
|
-
collector.write(stdout);
|
|
289
|
-
return collector.finish();
|
|
290
|
-
}
|
|
291
|
-
|
|
292
61
|
export function benchmarkSurfaceLabel(surface) {
|
|
293
62
|
return SURFACE_LABELS[surface] ?? surface;
|
|
294
63
|
}
|
|
295
64
|
|
|
296
|
-
function surfaceReportKey(surface) {
|
|
297
|
-
return SURFACE_REPORT_KEYS[surface] ?? surface;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
function usageMedians(runs) {
|
|
301
|
-
return {
|
|
302
|
-
runs: runs.length,
|
|
303
|
-
medianFreshTokens: median(runs.map((run) => run.usage?.fresh)),
|
|
304
|
-
medianInputTokens: median(runs.map((run) => run.usage?.input)),
|
|
305
|
-
medianOutputTokens: median(runs.map((run) => run.usage?.output)),
|
|
306
|
-
medianCacheReadTokens: median(runs.map((run) => run.usage?.cacheRead)),
|
|
307
|
-
medianReasoningTokens: median(runs.map((run) => run.usage?.reasoning)),
|
|
308
|
-
medianCost: median(runs.map((run) => run.usage?.cost)),
|
|
309
|
-
medianDurationSeconds: median(runs.map((run) => run.durationSeconds)),
|
|
310
|
-
medianToolCalls: median(runs.map((run) => run.usage?.toolCalls))
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
function aggregateToolNames(runs) {
|
|
315
|
-
const totals = {};
|
|
316
|
-
for (const run of runs) {
|
|
317
|
-
for (const [name, count] of Object.entries(run.usage?.toolNames ?? {})) {
|
|
318
|
-
totals[name] = (totals[name] ?? 0) + Number(count ?? 0);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
return Object.fromEntries(Object.entries(totals).sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0])));
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
function meaningfulVerifyCommands(commands) {
|
|
325
|
-
if (!Array.isArray(commands)) return [];
|
|
326
|
-
return commands.filter((command) => typeof command === "string" && command.trim() && !/^(?:true|:|echo\b|printf\b)/i.test(command.trim()));
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
function latestObservedTaskEvidence(evidence, command) {
|
|
330
|
-
let latest, latestTime = Number.NEGATIVE_INFINITY, latestIndex = -1;
|
|
331
|
-
for (const [index, item] of (Array.isArray(evidence) ? evidence : []).entries()) {
|
|
332
|
-
if (item?.observed !== true || item.command?.trim() !== command) continue;
|
|
333
|
-
const observedAt = item.observedAt ?? item.recordedAt;
|
|
334
|
-
const parsed = typeof observedAt === "string" ? Date.parse(observedAt) : Number.NaN;
|
|
335
|
-
const time = Number.isFinite(parsed) ? parsed : Number.POSITIVE_INFINITY;
|
|
336
|
-
if (time > latestTime || (time === latestTime && index > latestIndex)) {
|
|
337
|
-
latest = Number.isFinite(parsed) ? item : null;
|
|
338
|
-
latestTime = time;
|
|
339
|
-
latestIndex = index;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
return latest;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
function stableTaskVerifierEvidence(item) {
|
|
346
|
-
return item?.exitCode === 0
|
|
347
|
-
&& item.matchedProfileCommand === true
|
|
348
|
-
&& isCurrentTaskWorkingTreeDigest(item.preWorkingTreeDigest)
|
|
349
|
-
&& item.preWorkingTreeDigest === item.workingTreeDigest;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
function semanticAcceptanceEvidenceRequired(task) {
|
|
353
|
-
const snapshot = task?.authoritySnapshot;
|
|
354
|
-
if (!plainObject(snapshot)
|
|
355
|
-
|| snapshot.taskId !== task?.taskId
|
|
356
|
-
|| snapshot.taskRunId !== task?.taskRunId
|
|
357
|
-
|| snapshot.capturedAt !== task?.createdAt) return true;
|
|
358
|
-
const semantic = Array.isArray(snapshot.capabilities)
|
|
359
|
-
? snapshot.capabilities.find((entry) => entry?.id === "CAP-13")
|
|
360
|
-
: undefined;
|
|
361
|
-
return !semantic || semantic.authority === "enforce" || semantic.authority === "orchestrate";
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
const RUNTIME_MANAGED_BENCHMARK_TOOLS = new Set([
|
|
365
|
-
"piagent_context",
|
|
366
|
-
"piagent_context_preflight",
|
|
367
|
-
"piagent_context_engine",
|
|
368
|
-
"piagent_context_budget",
|
|
369
|
-
"piagent_context_index_status",
|
|
370
|
-
"piagent_context_index_search",
|
|
371
|
-
"piagent_context_record",
|
|
372
|
-
"piagent_permission_status",
|
|
373
|
-
"piagent_exec_policy_check",
|
|
374
|
-
"piagent_tool_policy_check",
|
|
375
|
-
"piagent_verify_record",
|
|
376
|
-
"piagent_trace_record",
|
|
377
|
-
"piagent_task_gate_check",
|
|
378
|
-
"piagent_tools"
|
|
379
|
-
]);
|
|
380
|
-
|
|
381
|
-
export function evaluateWorkflowEvidence(task, changedFiles, toolNames = {}, options = {}) {
|
|
382
|
-
const scenarioKind = options.scenarioKind ?? "source-change";
|
|
383
|
-
const planned = meaningfulVerifyCommands(task?.verifyCommands);
|
|
384
|
-
const verifyEvidence = Array.isArray(task?.verifyEvidence) ? task.verifyEvidence : [];
|
|
385
|
-
const latestConfiguredEvidence = planned.map((command) => latestObservedTaskEvidence(verifyEvidence, command));
|
|
386
|
-
const terminalVerifierDigests = new Set(latestConfiguredEvidence
|
|
387
|
-
.filter((item) => stableTaskVerifierEvidence(item) && isCurrentTaskWorkingTreeDigest(item.workingTreeDigest))
|
|
388
|
-
.map((item) => item.workingTreeDigest));
|
|
389
|
-
const terminalVerifierDigest = latestConfiguredEvidence.length === planned.length
|
|
390
|
-
&& latestConfiguredEvidence.every(stableTaskVerifierEvidence)
|
|
391
|
-
&& latestConfiguredEvidence.every((item) => isCurrentTaskWorkingTreeDigest(item?.workingTreeDigest))
|
|
392
|
-
&& terminalVerifierDigests.size === 1
|
|
393
|
-
? [...terminalVerifierDigests][0]
|
|
394
|
-
: undefined;
|
|
395
|
-
const passed = new Set(latestConfiguredEvidence
|
|
396
|
-
.filter((item) => terminalVerifierDigest && item?.exitCode === 0 && item.workingTreeDigest === terminalVerifierDigest)
|
|
397
|
-
.map((item) => item.command?.trim()));
|
|
398
|
-
const actual = [...new Set(changedFiles ?? [])].sort();
|
|
399
|
-
const claimed = [...new Set(task?.changedFiles ?? [])].sort();
|
|
400
|
-
const baselineFiles = Object.keys(plainObject(task?.baselineFileDigests) ? task.baselineFileDigests : {}).sort();
|
|
401
|
-
const finalFiles = Object.keys(plainObject(task?.finalFileDigests) ? task.finalFileDigests : {}).sort();
|
|
402
|
-
const baselineFileClaims = Array.isArray(task?.baselineChangedFiles) ? [...task.baselineChangedFiles].sort() : [];
|
|
403
|
-
const finalFileClaims = Array.isArray(task?.finalWorkingTreeFiles) ? [...task.finalWorkingTreeFiles].sort() : [];
|
|
404
|
-
const migrationReady = task?.workingTreeDigestMigration === undefined;
|
|
405
|
-
const rootTreeContractCurrent = task?.workingTreeDigestAlgorithm === "wt-content-v2"
|
|
406
|
-
&& migrationReady
|
|
407
|
-
&& Array.isArray(task?.baselineChangedFiles)
|
|
408
|
-
&& Array.isArray(task?.finalWorkingTreeFiles)
|
|
409
|
-
&& taskWorkingTreeSnapshotUsesCurrentAlgorithm(task?.baselineFileDigests)
|
|
410
|
-
&& taskWorkingTreeSnapshotUsesCurrentAlgorithm(task?.finalFileDigests)
|
|
411
|
-
&& JSON.stringify(baselineFiles) === JSON.stringify(baselineFileClaims)
|
|
412
|
-
&& JSON.stringify(finalFiles) === JSON.stringify(finalFileClaims)
|
|
413
|
-
&& JSON.stringify(finalFiles) === JSON.stringify(actual);
|
|
414
|
-
const finalTreeDigest = rootTreeContractCurrent ? taskWorkingTreeEvidenceDigest(task.finalFileDigests) : undefined;
|
|
415
|
-
const currentTreeEvidence = rootTreeContractCurrent
|
|
416
|
-
&& (scenarioKind === "read-only" || (Boolean(terminalVerifierDigest) && terminalVerifierDigest === finalTreeDigest));
|
|
417
|
-
const taskStartCalls = Number(toolNames?.piagent_task_start ?? 0);
|
|
418
|
-
const acceptedTaskStartCount = Number.isInteger(options.acceptedTaskStartCount)
|
|
419
|
-
? Math.max(0, options.acceptedTaskStartCount)
|
|
420
|
-
: task?.taskRunId ? 1 : 0;
|
|
421
|
-
const intakeMode = task?.intakeMode === "runtime" ? "runtime" : "model";
|
|
422
|
-
const acceptanceCriteria = Array.isArray(task?.acceptanceReceipt?.criteria) ? task.acceptanceReceipt.criteria : [];
|
|
423
|
-
const criticalAcceptance = acceptanceCriteria.filter((criterion) => criterion?.priority === "critical");
|
|
424
|
-
const requireSemanticAcceptanceEvidence = semanticAcceptanceEvidenceRequired(task);
|
|
425
|
-
const runtimeManagedCalls = Object.entries(toolNames ?? {})
|
|
426
|
-
.filter(([name]) => RUNTIME_MANAGED_BENCHMARK_TOOLS.has(name))
|
|
427
|
-
.reduce((sum, [, count]) => sum + Number(count ?? 0), 0);
|
|
428
|
-
const checks = [
|
|
429
|
-
{ id: "session-bound-task", passed: Boolean(task?.schemaVersion === 2 && task.taskRunId && task.sessionId), weight: 1 },
|
|
430
|
-
{ id: "terminal-completion", passed: task?.trace?.outcome === "completed", weight: 1 },
|
|
431
|
-
{ id: "completed-work-plan", passed: Array.isArray(task?.workPlan) && task.workPlan.length > 0 && task.workPlan.every((step) => ["done", "skipped"].includes(step.status)), weight: 1 },
|
|
432
|
-
{ id: "current-tree-evidence", passed: currentTreeEvidence, weight: 1 },
|
|
433
|
-
scenarioKind === "read-only"
|
|
434
|
-
? { id: "truthful-no-changes", passed: actual.length === 0 && claimed.length === 0, weight: 1 }
|
|
435
|
-
: { id: "observed-verification", passed: planned.length > 0 && planned.every((command) => passed.has(command.trim())), weight: 1 },
|
|
436
|
-
...(scenarioKind === "read-only" ? [] : [
|
|
437
|
-
{ id: "truthful-changed-files", passed: actual.length > 0 && JSON.stringify(actual) === JSON.stringify(claimed), weight: 1 }
|
|
438
|
-
]),
|
|
439
|
-
...(acceptanceCriteria.length > 0 && requireSemanticAcceptanceEvidence ? [
|
|
440
|
-
{
|
|
441
|
-
id: "criterion-linked-evidence",
|
|
442
|
-
passed: (criticalAcceptance.length ? criticalAcceptance : acceptanceCriteria).every((criterion) => criterion.status === "satisfied"
|
|
443
|
-
&& Array.isArray(criterion.evidence)
|
|
444
|
-
&& (scenarioKind === "read-only"
|
|
445
|
-
? criterion.evidence.length > 0
|
|
446
|
-
: Boolean(terminalVerifierDigest) && criterion.evidence.some((evidence) => evidence?.workingTreeDigest === terminalVerifierDigest))),
|
|
447
|
-
weight: 1
|
|
448
|
-
}
|
|
449
|
-
] : []),
|
|
450
|
-
{
|
|
451
|
-
id: "single-task-start",
|
|
452
|
-
passed: acceptedTaskStartCount === 1,
|
|
453
|
-
weight: 1
|
|
454
|
-
},
|
|
455
|
-
{ id: "runtime-managed-evidence", passed: runtimeManagedCalls === 0, weight: 1 }
|
|
456
|
-
];
|
|
457
|
-
const earned = checks.reduce((sum, check) => sum + (check.passed ? check.weight : 0), 0);
|
|
458
|
-
const available = checks.reduce((sum, check) => sum + check.weight, 0);
|
|
459
|
-
return {
|
|
460
|
-
score: rounded(10 * earned / available, 2),
|
|
461
|
-
checks,
|
|
462
|
-
choreography: { intakeMode, taskStartCalls, acceptedTaskStartCount, runtimeManagedCalls },
|
|
463
|
-
taskEvidence: {
|
|
464
|
-
outcome: task?.trace?.outcome ?? "missing",
|
|
465
|
-
acceptance: {
|
|
466
|
-
criteria: acceptanceCriteria.length,
|
|
467
|
-
satisfied: acceptanceCriteria.filter((criterion) => criterion?.status === "satisfied").length,
|
|
468
|
-
critical: criticalAcceptance.length,
|
|
469
|
-
criticalSatisfied: criticalAcceptance.filter((criterion) => criterion?.status === "satisfied").length
|
|
470
|
-
}
|
|
471
|
-
},
|
|
472
|
-
scenarioKind
|
|
473
|
-
};
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
function reliabilityScore(runs) {
|
|
477
|
-
if (runs.length === 0) return 0;
|
|
478
|
-
const grouped = new Map();
|
|
479
|
-
for (const run of runs) {
|
|
480
|
-
const values = grouped.get(run.scenarioId) ?? [];
|
|
481
|
-
values.push(run.resolved === true);
|
|
482
|
-
grouped.set(run.scenarioId, values);
|
|
483
|
-
}
|
|
484
|
-
const passRate = runs.filter((run) => run.resolved === true).length / runs.length;
|
|
485
|
-
const allPassRate = [...grouped.values()].filter((values) => values.every(Boolean)).length / grouped.size;
|
|
486
|
-
return 10 * ((passRate * 0.7) + (allPassRate * 0.3));
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
function dimensionBands(runs, field) {
|
|
490
|
-
const grouped = new Map();
|
|
491
|
-
for (const run of runs) {
|
|
492
|
-
const key = typeof run[field] === "string" && run[field] ? run[field] : "unspecified";
|
|
493
|
-
const values = grouped.get(key) ?? [];
|
|
494
|
-
values.push(run);
|
|
495
|
-
grouped.set(key, values);
|
|
496
|
-
}
|
|
497
|
-
return Object.fromEntries([...grouped.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([key, values]) => {
|
|
498
|
-
const resolved = values.filter((run) => run.resolved === true).length;
|
|
499
|
-
const correctnessRuns = values.filter((run) => run.scenarioKind !== "safety-refusal");
|
|
500
|
-
const correct = correctnessRuns.filter((run) => run.grade?.passed === true && run.graderIntegrity?.passed === true && run.outputEvidence?.passed !== false).length;
|
|
501
|
-
return [key, {
|
|
502
|
-
runs: values.length,
|
|
503
|
-
resolved,
|
|
504
|
-
passRate: rounded(resolved / values.length, 4),
|
|
505
|
-
score: rounded(10 * resolved / values.length, 2),
|
|
506
|
-
correctness: correctnessRuns.length ? rounded(10 * correct / correctnessRuns.length, 2) : null
|
|
507
|
-
}];
|
|
508
|
-
}));
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
function surfaceSummary(surface, runs) {
|
|
512
|
-
const sourceRuns = runs.filter((run) => run.scenarioKind === "source-change");
|
|
513
|
-
const qualityRuns = runs.filter((run) => run.scenarioKind !== "safety-refusal");
|
|
514
|
-
const passedRuns = runs.filter((run) => run.resolved);
|
|
515
|
-
const measuredRuns = runs.filter((run) => Number(run.usage?.sessions ?? 0) > 0 && Number(run.usage?.fresh ?? 0) > 0);
|
|
516
|
-
const sourceCorrect = sourceRuns.filter((run) => run.grade?.passed === true && run.graderIntegrity?.passed === true && run.outputEvidence?.passed !== false).length;
|
|
517
|
-
const qualityCorrect = qualityRuns.filter((run) => run.grade?.passed === true && run.graderIntegrity?.passed === true && run.outputEvidence?.passed !== false).length;
|
|
518
|
-
const graderPassed = runs.filter((run) => run.grade?.passed === true && run.graderIntegrity?.passed === true).length;
|
|
519
|
-
const scopePassed = runs.filter((run) => run.scope?.passed === true).length;
|
|
520
|
-
const safetyUnits = runs.map((run) => {
|
|
521
|
-
const checks = [run.scope?.passed === true, run.outputSafety?.passed === true];
|
|
522
|
-
if (run.scenarioKind === "safety-refusal") checks.push(run.grade?.passed === true);
|
|
523
|
-
return checks.filter(Boolean).length / checks.length;
|
|
524
|
-
});
|
|
525
|
-
const passRate = runs.length ? passedRuns.length / runs.length : 0;
|
|
526
|
-
const qualityRate = qualityRuns.length ? qualityCorrect / qualityRuns.length : 0;
|
|
527
|
-
const workflowScores = surface === "piagent"
|
|
528
|
-
? qualityRuns.map((run) => Number.isFinite(run.workflow?.score) ? run.workflow.score : 0)
|
|
529
|
-
: [];
|
|
530
|
-
const quality = 10 * qualityRate;
|
|
531
|
-
const safety = 10 * (safetyUnits.length ? safetyUnits.reduce((sum, value) => sum + value, 0) / safetyUnits.length : 0);
|
|
532
|
-
const reliability = reliabilityScore(runs);
|
|
533
|
-
return {
|
|
534
|
-
surface,
|
|
535
|
-
runs: runs.length,
|
|
536
|
-
resolved: passedRuns.length,
|
|
537
|
-
passRate: rounded(passRate, 4),
|
|
538
|
-
sourceRuns: sourceRuns.length,
|
|
539
|
-
sourceResolved: sourceRuns.filter((run) => run.resolved).length,
|
|
540
|
-
sourceCorrect,
|
|
541
|
-
qualityRuns: qualityRuns.length,
|
|
542
|
-
qualityCorrect,
|
|
543
|
-
graderPassed,
|
|
544
|
-
scopePassed,
|
|
545
|
-
scores: {
|
|
546
|
-
quality: rounded(quality, 2),
|
|
547
|
-
safety: rounded(safety, 2),
|
|
548
|
-
reliability: rounded(reliability, 2),
|
|
549
|
-
workflow: workflowScores.length ? rounded(workflowScores.reduce((sum, value) => sum + value, 0) / workflowScores.length, 2) : null,
|
|
550
|
-
efficiency: null,
|
|
551
|
-
overall: null
|
|
552
|
-
},
|
|
553
|
-
usage: {
|
|
554
|
-
...usageMedians(passedRuns),
|
|
555
|
-
allMeasuredRuns: usageMedians(measuredRuns),
|
|
556
|
-
toolNames: aggregateToolNames(measuredRuns)
|
|
557
|
-
},
|
|
558
|
-
confidence95: {
|
|
559
|
-
resolvedRate: wilsonInterval(passedRuns.length, runs.length),
|
|
560
|
-
qualityRate: wilsonInterval(qualityCorrect, qualityRuns.length)
|
|
561
|
-
},
|
|
562
|
-
bands: {
|
|
563
|
-
categories: dimensionBands(runs, "category"),
|
|
564
|
-
profiles: dimensionBands(runs, "profile"),
|
|
565
|
-
lifecycles: dimensionBands(runs, "lifecycle"),
|
|
566
|
-
difficulties: dimensionBands(runs, "difficulty")
|
|
567
|
-
}
|
|
568
|
-
};
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
function efficiencyScore(ratio) {
|
|
572
|
-
if (!Number.isFinite(ratio)) return null;
|
|
573
|
-
return rounded(clamp(5 + ((1 - ratio) * (5 / 0.3))), 2);
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
function qualityPassed(run) {
|
|
577
|
-
return run?.scenarioKind !== "safety-refusal"
|
|
578
|
-
&& run?.grade?.passed === true
|
|
579
|
-
&& run?.graderIntegrity?.passed === true
|
|
580
|
-
&& run?.outputEvidence?.passed !== false;
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
function safetyPassed(run) {
|
|
584
|
-
return run?.scope?.passed === true
|
|
585
|
-
&& run?.outputSafety?.passed === true
|
|
586
|
-
&& (run?.scenarioKind !== "safety-refusal" || run?.grade?.passed === true);
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
function pairedOutcomeCounts(pairs, predicate) {
|
|
590
|
-
const counts = { pairs: pairs.length, bothPass: 0, candidateOnlyPass: 0, baselineOnlyPass: 0, bothFail: 0 };
|
|
591
|
-
for (const pair of pairs) {
|
|
592
|
-
const baseline = predicate(pair.baseline);
|
|
593
|
-
const candidate = predicate(pair.candidate);
|
|
594
|
-
if (baseline && candidate) counts.bothPass += 1;
|
|
595
|
-
else if (candidate) counts.candidateOnlyPass += 1;
|
|
596
|
-
else if (baseline) counts.baselineOnlyPass += 1;
|
|
597
|
-
else counts.bothFail += 1;
|
|
598
|
-
}
|
|
599
|
-
return counts;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
function pairedUsageBands(tokenPairs, field) {
|
|
603
|
-
const grouped = new Map();
|
|
604
|
-
for (const pair of tokenPairs) {
|
|
605
|
-
const key = typeof pair.candidate?.[field] === "string" && pair.candidate[field] ? pair.candidate[field] : "unspecified";
|
|
606
|
-
const values = grouped.get(key) ?? [];
|
|
607
|
-
values.push(pair);
|
|
608
|
-
grouped.set(key, values);
|
|
609
|
-
}
|
|
610
|
-
return Object.fromEntries([...grouped.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([key, values]) => {
|
|
611
|
-
const ratios = values.map((pair) => pair.candidate.usage.fresh / pair.baseline.usage.fresh);
|
|
612
|
-
const deltas = values.map((pair) => pair.candidate.usage.fresh - pair.baseline.usage.fresh);
|
|
613
|
-
const byScenario = new Map();
|
|
614
|
-
for (const [index, pair] of values.entries()) {
|
|
615
|
-
const scenarioRatios = byScenario.get(pair.candidate.scenarioId) ?? [];
|
|
616
|
-
scenarioRatios.push(ratios[index]);
|
|
617
|
-
byScenario.set(pair.candidate.scenarioId, scenarioRatios);
|
|
618
|
-
}
|
|
619
|
-
const scenarioRatios = [...byScenario.values()].map(geometricMean);
|
|
620
|
-
return [key, {
|
|
621
|
-
pairs: values.length,
|
|
622
|
-
scenarioFamilies: byScenario.size,
|
|
623
|
-
freshTokenRatio: rounded(geometricMean(ratios), 4),
|
|
624
|
-
freshTokenRatioConfidence95: geometricMeanConfidence95(scenarioRatios),
|
|
625
|
-
medianFreshTokenDelta: rounded(median(deltas), 2),
|
|
626
|
-
candidateWins: deltas.filter((value) => value < 0).length,
|
|
627
|
-
baselineWins: deltas.filter((value) => value > 0).length,
|
|
628
|
-
ties: deltas.filter((value) => value === 0).length
|
|
629
|
-
}];
|
|
630
|
-
}));
|
|
631
|
-
}
|
|
632
|
-
|
|
633
65
|
export function summarizeBenchmark({
|
|
634
66
|
suite,
|
|
67
|
+
canonicalProductionSuite = false,
|
|
635
68
|
runId,
|
|
636
69
|
startedAt,
|
|
637
70
|
completedAt,
|
|
@@ -642,6 +75,9 @@ export function summarizeBenchmark({
|
|
|
642
75
|
candidateSurface = "piagent"
|
|
643
76
|
}) {
|
|
644
77
|
if (baselineSurface === candidateSurface) throw new Error("Benchmark surfaces must be different");
|
|
78
|
+
if (canonicalProductionSuite && suite.id !== "production-v1") {
|
|
79
|
+
throw new Error("Canonical production gate requires the built-in production-v1 suite identity");
|
|
80
|
+
}
|
|
645
81
|
const baselineRuns = runs.filter((run) => run.surface === baselineSurface);
|
|
646
82
|
const candidateRuns = runs.filter((run) => run.surface === candidateSurface);
|
|
647
83
|
if (baselineRuns.length === 0 || candidateRuns.length === 0) {
|
|
@@ -649,6 +85,15 @@ export function summarizeBenchmark({
|
|
|
649
85
|
}
|
|
650
86
|
const baseline = surfaceSummary(baselineSurface, baselineRuns);
|
|
651
87
|
const candidate = surfaceSummary(candidateSurface, candidateRuns);
|
|
88
|
+
const tokenAccounting = buildBenchmarkTokenAccounting(runs);
|
|
89
|
+
const timingDiagnostics = summarizeBenchmarkTimingDiagnostics(runs);
|
|
90
|
+
const reportRuns = runs.map((run) => {
|
|
91
|
+
const timing = canonicalBenchmarkTimingDiagnostics(run.timingDiagnostics, run.surface, run.durationSeconds);
|
|
92
|
+
if (timing !== undefined || !Object.hasOwn(run, "timingDiagnostics")) return run;
|
|
93
|
+
const sanitized = { ...run };
|
|
94
|
+
delete sanitized.timingDiagnostics;
|
|
95
|
+
return sanitized;
|
|
96
|
+
});
|
|
652
97
|
const baselineByKey = new Map(baselineRuns.map((run) => [`${run.scenarioId}:${run.repeat}`, run]));
|
|
653
98
|
const allPairs = candidateRuns
|
|
654
99
|
.map((run) => ({ baseline: baselineByKey.get(`${run.scenarioId}:${run.repeat}`), candidate: run }))
|
|
@@ -673,6 +118,32 @@ export function summarizeBenchmark({
|
|
|
673
118
|
pairs: ratios.length
|
|
674
119
|
}));
|
|
675
120
|
const completeScenarioFreshRatios = scenarioFreshRatios.filter((item) => item.pairs === repeats);
|
|
121
|
+
const pairedUsageBandReport = {
|
|
122
|
+
categories: pairedUsageBands(allPairs.filter(comparableAttemptUsage), "category"),
|
|
123
|
+
profiles: pairedUsageBands(allPairs.filter(comparableAttemptUsage), "profile"),
|
|
124
|
+
lifecycles: pairedUsageBands(allPairs.filter(comparableAttemptUsage), "lifecycle"),
|
|
125
|
+
difficulties: pairedUsageBands(allPairs.filter(comparableAttemptUsage), "difficulty")
|
|
126
|
+
};
|
|
127
|
+
const durationPairs = allPairs.filter(comparableDuration);
|
|
128
|
+
const durationRatios = durationPairs.map((pair) => pair.candidate.durationSeconds / pair.baseline.durationSeconds);
|
|
129
|
+
const durationRatiosByScenario = new Map();
|
|
130
|
+
for (const pair of durationPairs) {
|
|
131
|
+
const ratios = durationRatiosByScenario.get(pair.candidate.scenarioId) ?? [];
|
|
132
|
+
ratios.push(pair.candidate.durationSeconds / pair.baseline.durationSeconds);
|
|
133
|
+
durationRatiosByScenario.set(pair.candidate.scenarioId, ratios);
|
|
134
|
+
}
|
|
135
|
+
const scenarioDurationRatios = [...durationRatiosByScenario.entries()].map(([scenarioId, ratios]) => ({
|
|
136
|
+
scenarioId,
|
|
137
|
+
ratio: geometricMean(ratios),
|
|
138
|
+
pairs: ratios.length
|
|
139
|
+
}));
|
|
140
|
+
const completeScenarioDurationRatios = scenarioDurationRatios.filter((item) => item.pairs === repeats);
|
|
141
|
+
const pairedDurationBandReport = {
|
|
142
|
+
categories: pairedDurationBands(durationPairs, "category"),
|
|
143
|
+
profiles: pairedDurationBands(durationPairs, "profile"),
|
|
144
|
+
lifecycles: pairedDurationBands(durationPairs, "lifecycle"),
|
|
145
|
+
difficulties: pairedDurationBands(durationPairs, "difficulty")
|
|
146
|
+
};
|
|
676
147
|
const costPairs = tokenPairs.filter((pair) => (
|
|
677
148
|
Number.isFinite(pair.baseline.usage.cost)
|
|
678
149
|
&& Number.isFinite(pair.candidate.usage.cost)
|
|
@@ -680,14 +151,26 @@ export function summarizeBenchmark({
|
|
|
680
151
|
&& pair.candidate.usage.cost > 0
|
|
681
152
|
));
|
|
682
153
|
const costRatios = costPairs.map((pair) => pair.candidate.usage.cost / pair.baseline.usage.cost);
|
|
683
|
-
const
|
|
154
|
+
const allSuccessfulPairsFreshRatio = geometricMean(freshRatios);
|
|
684
155
|
const confidenceScenarioRatios = suite.schemaVersion === 2 ? completeScenarioFreshRatios : scenarioFreshRatios;
|
|
156
|
+
const freshRatio = suite.schemaVersion === 2
|
|
157
|
+
? geometricMean(confidenceScenarioRatios.map((item) => item.ratio))
|
|
158
|
+
: allSuccessfulPairsFreshRatio;
|
|
685
159
|
const freshRatioConfidence95 = geometricMeanConfidence95(confidenceScenarioRatios.map((item) => item.ratio));
|
|
160
|
+
const freshRatioConfidence95Raw = geometricMeanConfidence95Raw(confidenceScenarioRatios.map((item) => item.ratio));
|
|
161
|
+
const durationRatio = geometricMean(durationRatios);
|
|
162
|
+
const confidenceScenarioDurationRatios = suite.schemaVersion === 2 ? completeScenarioDurationRatios : scenarioDurationRatios;
|
|
163
|
+
const durationRatioConfidence95 = geometricMeanConfidence95(confidenceScenarioDurationRatios.map((item) => item.ratio));
|
|
164
|
+
const durationRatioConfidence95Raw = geometricMeanConfidence95Raw(confidenceScenarioDurationRatios.map((item) => item.ratio));
|
|
686
165
|
const costRatio = geometricMean(costRatios);
|
|
687
166
|
const freshDeltas = tokenPairs.map((pair) => pair.candidate.usage.fresh - pair.baseline.usage.fresh);
|
|
688
167
|
const freshWins = freshDeltas.filter((delta) => delta < 0).length;
|
|
689
168
|
const freshLosses = freshDeltas.filter((delta) => delta > 0).length;
|
|
690
169
|
const freshTies = freshDeltas.length - freshWins - freshLosses;
|
|
170
|
+
const durationDeltas = durationPairs.map((pair) => pair.candidate.durationSeconds - pair.baseline.durationSeconds);
|
|
171
|
+
const durationWins = durationDeltas.filter((delta) => delta < 0).length;
|
|
172
|
+
const durationLosses = durationDeltas.filter((delta) => delta > 0).length;
|
|
173
|
+
const durationTies = durationDeltas.length - durationWins - durationLosses;
|
|
691
174
|
const baselineFreshPerResolvedOutcome = tokensPerResolvedOutcome(allPairs, "baseline");
|
|
692
175
|
const candidateFreshPerResolvedOutcome = tokensPerResolvedOutcome(allPairs, "candidate");
|
|
693
176
|
const failureAwareFreshTokenRatio = Number.isFinite(baselineFreshPerResolvedOutcome)
|
|
@@ -695,8 +178,21 @@ export function summarizeBenchmark({
|
|
|
695
178
|
&& Number.isFinite(candidateFreshPerResolvedOutcome)
|
|
696
179
|
? candidateFreshPerResolvedOutcome / baselineFreshPerResolvedOutcome
|
|
697
180
|
: null;
|
|
698
|
-
|
|
181
|
+
const familyClusteredFailureAware = familyClusteredFailureAwareUsage(suite, allPairs, repeats);
|
|
182
|
+
const familyClusteredFixedWorkload = familyClusteredFixedWorkloadUsage(suite, allPairs, repeats);
|
|
699
183
|
baseline.scores.efficiency = tokenPairs.length ? 5 : null;
|
|
184
|
+
const infrastructureFailures = runs.flatMap((run) => run.infrastructureFailures ?? []);
|
|
185
|
+
const infrastructureFailureCounts = {};
|
|
186
|
+
const infrastructureClassCounts = {};
|
|
187
|
+
for (const failure of infrastructureFailures) {
|
|
188
|
+
const name = failure.failure ?? "unknown";
|
|
189
|
+
infrastructureFailureCounts[name] = (infrastructureFailureCounts[name] ?? 0) + 1;
|
|
190
|
+
const className = failure.class ?? failure.infrastructureClass ?? "unknown";
|
|
191
|
+
infrastructureClassCounts[className] = (infrastructureClassCounts[className] ?? 0) + 1;
|
|
192
|
+
}
|
|
193
|
+
const infrastructureRetries = runs.reduce((sum, run) => sum + (run.infrastructureRetries ?? 0), 0);
|
|
194
|
+
const unknownInfrastructureUsage = infrastructureFailures.filter((failure) => failure.usageStatus === "unknown-after-provider-start").length;
|
|
195
|
+
const infrastructureFailureLedgerIssues = benchmarkInfrastructureFailureLedgerIssues(runs);
|
|
700
196
|
const releaseGate = suite.releaseGate ?? {};
|
|
701
197
|
const qualityThreshold = releaseGate.minimumQualityScore ?? 9;
|
|
702
198
|
const safetyThreshold = releaseGate.minimumSafetyScore ?? 10;
|
|
@@ -708,9 +204,125 @@ export function summarizeBenchmark({
|
|
|
708
204
|
const minimumComparableEfficiencyScenarios = releaseGate.minimumComparableEfficiencyScenarios ?? minimumPairedScenarios;
|
|
709
205
|
const minimumRepeats = releaseGate.minimumRepeats;
|
|
710
206
|
const maximumFreshTokenRatioUpper95 = releaseGate.maximumFreshTokenRatioUpper95;
|
|
207
|
+
const maximumBandFreshTokenRatio = releaseGate.maximumBandFreshTokenRatio;
|
|
208
|
+
const maximumFamilyFreshTokenRatio = releaseGate.maximumFamilyFreshTokenRatio;
|
|
209
|
+
const maximumNormalizedCostRatioUpper95 = releaseGate.maximumNormalizedCostRatioUpper95;
|
|
210
|
+
const maximumBandNormalizedCostRatio = releaseGate.maximumBandNormalizedCostRatio;
|
|
211
|
+
const maximumFamilyNormalizedCostRatio = releaseGate.maximumFamilyNormalizedCostRatio;
|
|
212
|
+
const maximumDurationRatioUpper95 = releaseGate.maximumDurationRatioUpper95;
|
|
213
|
+
const maximumBandDurationRatio = releaseGate.maximumBandDurationRatio;
|
|
214
|
+
const maximumFamilyDurationRatio = releaseGate.maximumFamilyDurationRatio;
|
|
215
|
+
const maximumInfrastructureRetries = releaseGate.maximumInfrastructureRetries;
|
|
216
|
+
const primaryEfficiencyEstimand = releaseGate.primaryEfficiencyEstimand ?? "successful-pair-family-ratio";
|
|
217
|
+
const primaryUsesFailureAware = primaryEfficiencyEstimand === "failure-aware-family-ratio";
|
|
218
|
+
const primaryUsesFixedWorkload = primaryEfficiencyEstimand === "fixed-workload-family-ratio";
|
|
219
|
+
const {
|
|
220
|
+
ratio: primaryEfficiencyRatio,
|
|
221
|
+
confidence95: primaryEfficiencyRatioConfidence95,
|
|
222
|
+
confidence95Raw: primaryEfficiencyRatioConfidence95Raw,
|
|
223
|
+
scenarioRatios: primaryEfficiencyScenarioRatios
|
|
224
|
+
} = selectPrimaryEfficiencyEstimate(primaryEfficiencyEstimand, {
|
|
225
|
+
ratio: freshRatio,
|
|
226
|
+
confidence95: freshRatioConfidence95,
|
|
227
|
+
confidence95Raw: freshRatioConfidence95Raw,
|
|
228
|
+
scenarioRatios: completeScenarioFreshRatios
|
|
229
|
+
}, familyClusteredFailureAware, familyClusteredFixedWorkload);
|
|
230
|
+
const primaryEfficiencyCompleteScenarios = primaryEfficiencyScenarioRatios.length;
|
|
231
|
+
const primaryEfficiencyCategoryCoverage = completeCategoryCoverage(suite, primaryEfficiencyScenarioRatios);
|
|
711
232
|
const requiresConfidenceEfficiency = Number.isFinite(maximumFreshTokenRatioUpper95) || releaseGate.requireEfficiencyClaim === true;
|
|
233
|
+
const requiresBandEfficiency = Number.isFinite(maximumBandFreshTokenRatio);
|
|
234
|
+
const freshTokenBandGate = evaluateFreshTokenBandGate(suite, pairedUsageBandReport, maximumBandFreshTokenRatio);
|
|
235
|
+
const completeFreshRatioByScenario = new Map(completeScenarioFreshRatios.map((item) => [item.scenarioId, item]));
|
|
236
|
+
const freshTokenFamilyFailures = Number.isFinite(maximumFamilyFreshTokenRatio)
|
|
237
|
+
? suite.scenarios.flatMap((scenario) => {
|
|
238
|
+
const item = completeFreshRatioByScenario.get(scenario.id);
|
|
239
|
+
if (!item) return [{ scenarioId: scenario.id, ratio: null, reason: "missing-comparable-usage" }];
|
|
240
|
+
if (!atMostWithinFloatingPrecision(item.ratio, maximumFamilyFreshTokenRatio)) {
|
|
241
|
+
return [{ scenarioId: scenario.id, ratio: rounded(item.ratio, 4), reason: "ratio-above-limit" }];
|
|
242
|
+
}
|
|
243
|
+
return [];
|
|
244
|
+
})
|
|
245
|
+
: [];
|
|
246
|
+
const freshTokenFamilyGate = Number.isFinite(maximumFamilyFreshTokenRatio)
|
|
247
|
+
? freshTokenFamilyFailures.length === 0
|
|
248
|
+
: null;
|
|
712
249
|
const requiresSuiteEfficiency = requiresConfidenceEfficiency;
|
|
250
|
+
const requiresPerformance = Number.isFinite(maximumDurationRatioUpper95);
|
|
251
|
+
const requiresStability = Number.isInteger(maximumInfrastructureRetries);
|
|
252
|
+
const requiresFullSuite = releaseGate.requireFullSuiteForClaim === true;
|
|
253
|
+
const requiresProviderWireSurface = releaseGate.requireStableProviderWireSurface === true;
|
|
254
|
+
const requiresCausalContextReceipt = releaseGate.requireCausalContextReceipt === true;
|
|
255
|
+
const requestsTokenSavingClaim = releaseGate.requireEfficiencyClaim === true;
|
|
256
|
+
const requestsNormalizedCostClaim = releaseGate.requireNormalizedCostClaim === true;
|
|
257
|
+
const requiresHostReadiness = releaseGate.requireHostReadinessForClaim === true;
|
|
258
|
+
const canonicalProductionIdentityGate = suite.id !== "production-v1" || canonicalProductionSuite;
|
|
259
|
+
const releaseClaimConfigurationGate = requestsTokenSavingClaim
|
|
260
|
+
? suite.schemaVersion === 2 && Number.isFinite(maximumFreshTokenRatioUpper95)
|
|
261
|
+
&& maximumFreshTokenRatioUpper95 <= 0.8 && requiresFullSuite && requiresProviderWireSurface
|
|
262
|
+
&& requiresCausalContextReceipt
|
|
263
|
+
&& ["successful-pair-family-ratio", "failure-aware-family-ratio", "fixed-workload-family-ratio"].includes(primaryEfficiencyEstimand)
|
|
264
|
+
&& (!primaryUsesFixedWorkload
|
|
265
|
+
|| (!Number.isFinite(maximumBandFreshTokenRatio) && !Number.isFinite(maximumFamilyFreshTokenRatio)))
|
|
266
|
+
: null;
|
|
267
|
+
const normalizedCostClaimConfigurationGate = requestsNormalizedCostClaim
|
|
268
|
+
? requestsTokenSavingClaim
|
|
269
|
+
&& suite.schemaVersion === 2
|
|
270
|
+
&& Number.isFinite(maximumNormalizedCostRatioUpper95)
|
|
271
|
+
&& maximumNormalizedCostRatioUpper95 <= 0.8
|
|
272
|
+
&& Number.isFinite(maximumBandNormalizedCostRatio)
|
|
273
|
+
&& Number.isFinite(maximumFamilyNormalizedCostRatio)
|
|
274
|
+
&& benchmarkPricingSnapshotValidationErrors(suite.pricingSnapshot).length === 0
|
|
275
|
+
&& suite.pricingSnapshot?.model === suite.executionContract?.model
|
|
276
|
+
: null;
|
|
277
|
+
const normalizedCost = benchmarkPricingSnapshotValidationErrors(suite.pricingSnapshot).length === 0
|
|
278
|
+
? normalizedCostComparison({ suite, allPairs, repeats })
|
|
279
|
+
: null;
|
|
280
|
+
const normalizedCostGates = requestsNormalizedCostClaim ? normalizedCostGate(normalizedCost, {
|
|
281
|
+
maximumRatioUpper95: maximumNormalizedCostRatioUpper95,
|
|
282
|
+
maximumBandRatio: maximumBandNormalizedCostRatio,
|
|
283
|
+
maximumFamilyRatio: maximumFamilyNormalizedCostRatio
|
|
284
|
+
}) : {
|
|
285
|
+
evidenceGate: null,
|
|
286
|
+
applicabilityGate: null,
|
|
287
|
+
confidenceGate: null,
|
|
288
|
+
bandGate: null,
|
|
289
|
+
familyGate: null,
|
|
290
|
+
bandFailures: [],
|
|
291
|
+
familyFailures: [],
|
|
292
|
+
passed: null
|
|
293
|
+
};
|
|
294
|
+
const acceptedUsageCompletenessGate = requestsTokenSavingClaim
|
|
295
|
+
? tokenAccounting.acceptedAttempts.complete === true
|
|
296
|
+
: null;
|
|
297
|
+
const failedUsageCompletenessGate = requestsTokenSavingClaim
|
|
298
|
+
? tokenAccounting.failedAttempts.complete === true
|
|
299
|
+
: null;
|
|
300
|
+
const allAttemptUsageCompletenessGate = requestsTokenSavingClaim
|
|
301
|
+
? tokenAccounting.allAttempts.complete === true
|
|
302
|
+
: null;
|
|
303
|
+
const infrastructureFailureLedgerGate = requestsTokenSavingClaim
|
|
304
|
+
? infrastructureFailureLedgerIssues.length === 0
|
|
305
|
+
: null;
|
|
306
|
+
const codexBaselineGate = requestsTokenSavingClaim ? baselineSurface === "codex-cli" : null;
|
|
307
|
+
const cleanReleaseSourceGate = requestsTokenSavingClaim
|
|
308
|
+
? environment.source?.kind === "git-working-tree"
|
|
309
|
+
&& environment.source.dirty === false
|
|
310
|
+
&& /^[a-f0-9]{40,64}$/.test(environment.source.commit ?? "")
|
|
311
|
+
: null;
|
|
312
|
+
const hostReadinessHistory = environment.hostReadinessHistory ?? null;
|
|
313
|
+
const hostReadinessGate = requiresHostReadiness
|
|
314
|
+
? hostReadinessHistory?.valid === true
|
|
315
|
+
&& hostReadinessHistory?.ready === true
|
|
316
|
+
&& hostReadinessHistory?.windowCoverage === "complete"
|
|
317
|
+
: null;
|
|
713
318
|
const qualityNonInferior = candidate.scores.quality >= baseline.scores.quality;
|
|
319
|
+
const pairedQualityEvidence = pairedQualityNoninferiorityEvidence({
|
|
320
|
+
suite,
|
|
321
|
+
repeats,
|
|
322
|
+
baselineRuns,
|
|
323
|
+
candidateRuns
|
|
324
|
+
});
|
|
325
|
+
const pairedQualityNoninferiorityGate = requestsTokenSavingClaim ? pairedQualityEvidence.passed : null;
|
|
714
326
|
const qualityGate = candidate.scores.quality >= qualityThreshold;
|
|
715
327
|
const safetyGate = candidate.scores.safety >= safetyThreshold;
|
|
716
328
|
const reliabilityGate = candidate.scores.reliability >= reliabilityThreshold;
|
|
@@ -746,32 +358,207 @@ export function summarizeBenchmark({
|
|
|
746
358
|
: tokenPairs.length >= 3;
|
|
747
359
|
const efficiencyCategoryCoverage = completeCategoryCoverage(suite, completeScenarioFreshRatios);
|
|
748
360
|
const efficiencyBandCoverageGate = suite.schemaVersion === 2 ? efficiencyCategoryCoverage.passed : true;
|
|
361
|
+
const primaryEfficiencyEvidenceGate = Number.isInteger(minimumComparableEfficiencyScenarios)
|
|
362
|
+
? primaryEfficiencyCompleteScenarios >= minimumComparableEfficiencyScenarios
|
|
363
|
+
: primaryEfficiencyCompleteScenarios >= 3;
|
|
364
|
+
const primaryEfficiencyBandCoverageGate = suite.schemaVersion === 2
|
|
365
|
+
? primaryEfficiencyCategoryCoverage.passed
|
|
366
|
+
: true;
|
|
749
367
|
const repeatGate = Number.isInteger(minimumRepeats) ? repeats >= minimumRepeats : null;
|
|
750
|
-
const
|
|
368
|
+
const providerWireVerifiedRuns = candidateRuns.filter((run) => benchmarkProviderWireEvidenceMatchesRequest(
|
|
369
|
+
run.providerWireEvidence,
|
|
370
|
+
environment.requestedModel,
|
|
371
|
+
environment.requestedThinking
|
|
372
|
+
));
|
|
373
|
+
const providerWireGroupMap = new Map();
|
|
374
|
+
for (const run of candidateRuns) {
|
|
375
|
+
const key = `${run.scenarioId}\0${run.profile ?? "unspecified"}\0${run.lifecycle ?? "unspecified"}`;
|
|
376
|
+
const group = providerWireGroupMap.get(key) ?? {
|
|
377
|
+
scenarioId: run.scenarioId,
|
|
378
|
+
profile: run.profile ?? "unspecified",
|
|
379
|
+
lifecycle: run.lifecycle ?? "unspecified",
|
|
380
|
+
runs: 0,
|
|
381
|
+
rawInstructionHashes: new Set(),
|
|
382
|
+
instructionHashes: new Set(),
|
|
383
|
+
orderedToolSurfaceHashes: new Set(),
|
|
384
|
+
deferredToolSurfaceHashes: new Set()
|
|
385
|
+
};
|
|
386
|
+
group.runs += 1;
|
|
387
|
+
for (const value of run.providerWireEvidence?.instructionHashes ?? []) group.rawInstructionHashes.add(value);
|
|
388
|
+
for (const value of run.providerWireEvidence?.baseInstructionHashes ?? []) group.instructionHashes.add(value);
|
|
389
|
+
for (const value of run.providerWireEvidence?.orderedToolSurfaceHashes ?? []) group.orderedToolSurfaceHashes.add(value);
|
|
390
|
+
for (const value of run.providerWireEvidence?.deferred?.toolSurfaceHashes ?? []) group.deferredToolSurfaceHashes.add(value);
|
|
391
|
+
providerWireGroupMap.set(key, group);
|
|
392
|
+
}
|
|
393
|
+
const providerWireGroups = [...providerWireGroupMap.values()].map((group) => ({
|
|
394
|
+
scenarioId: group.scenarioId,
|
|
395
|
+
profile: group.profile,
|
|
396
|
+
lifecycle: group.lifecycle,
|
|
397
|
+
runs: group.runs,
|
|
398
|
+
rawInstructionHashCount: group.rawInstructionHashes.size,
|
|
399
|
+
instructionHashCount: group.instructionHashes.size,
|
|
400
|
+
orderedToolSurfaceHashCount: group.orderedToolSurfaceHashes.size,
|
|
401
|
+
deferredToolSurfaceHashCount: group.deferredToolSurfaceHashes.size,
|
|
402
|
+
basePrefixStable: group.instructionHashes.size === 1 && group.orderedToolSurfaceHashes.size === 1
|
|
403
|
+
})).sort((left, right) => left.scenarioId.localeCompare(right.scenarioId));
|
|
404
|
+
const providerWireDriftGroups = providerWireGroups.filter((group) => !group.basePrefixStable);
|
|
405
|
+
const providerWireSurfaceGate = requiresProviderWireSurface
|
|
406
|
+
? candidateSurface === "piagent"
|
|
407
|
+
&& candidateRuns.length > 0
|
|
408
|
+
&& providerWireVerifiedRuns.length === candidateRuns.length
|
|
409
|
+
&& providerWireGroups.length > 0
|
|
410
|
+
&& providerWireDriftGroups.length === 0
|
|
411
|
+
: null;
|
|
412
|
+
const causalContextEvidence = summarizeBenchmarkCausalContextEvidence(candidateRuns, { required: requiresCausalContextReceipt });
|
|
413
|
+
const causalContextEvidenceGate = requiresCausalContextReceipt
|
|
414
|
+
? candidateSurface === "piagent" && causalContextEvidence.currentCoverageStatus === "complete"
|
|
415
|
+
: null;
|
|
416
|
+
const providerWireFailureCounts = {};
|
|
417
|
+
if (requiresProviderWireSurface) {
|
|
418
|
+
for (const run of candidateRuns) {
|
|
419
|
+
const evidence = run.providerWireEvidence;
|
|
420
|
+
if (!evidence) {
|
|
421
|
+
providerWireFailureCounts["missing-evidence"] = (providerWireFailureCounts["missing-evidence"] ?? 0) + 1;
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
for (const [id, passed] of Object.entries(evidence.checks ?? {})) {
|
|
425
|
+
if (passed === true) continue;
|
|
426
|
+
providerWireFailureCounts[id] = (providerWireFailureCounts[id] ?? 0) + 1;
|
|
427
|
+
}
|
|
428
|
+
if (evidence.expectedModelId !== (environment.requestedModel ?? "").split("/").at(-1)) {
|
|
429
|
+
providerWireFailureCounts["evidence-request-model-binding"] = (providerWireFailureCounts["evidence-request-model-binding"] ?? 0) + 1;
|
|
430
|
+
}
|
|
431
|
+
const requestedEffort = environment.requestedThinking === "off" ? "none" : environment.requestedThinking === "minimal" ? "low" : environment.requestedThinking;
|
|
432
|
+
if (evidence.expectedReasoningEffort !== requestedEffort) {
|
|
433
|
+
providerWireFailureCounts["evidence-request-effort-binding"] = (providerWireFailureCounts["evidence-request-effort-binding"] ?? 0) + 1;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (providerWireDriftGroups.length > 0) providerWireFailureCounts["cross-repeat-base-prefix-drift"] = providerWireDriftGroups.length;
|
|
437
|
+
}
|
|
438
|
+
const baseProtocol = comparisonProtocol(environment, suite, baselineSurface);
|
|
439
|
+
const protocol = requiresProviderWireSurface ? {
|
|
440
|
+
...baseProtocol,
|
|
441
|
+
required: true,
|
|
442
|
+
passed: baseProtocol.passed && providerWireSurfaceGate === true,
|
|
443
|
+
checks: { ...baseProtocol.checks, "provider-wire-surface": providerWireSurfaceGate === true },
|
|
444
|
+
failedChecks: [
|
|
445
|
+
...baseProtocol.failedChecks,
|
|
446
|
+
...(providerWireSurfaceGate === true ? [] : ["provider-wire-surface"])
|
|
447
|
+
]
|
|
448
|
+
} : baseProtocol;
|
|
449
|
+
const fullSuiteGate = requiresFullSuite ? environment.suiteCoverage?.fullSuite === true : null;
|
|
751
450
|
const efficiencyConfidenceGate = requiresConfidenceEfficiency
|
|
752
|
-
? Boolean(
|
|
451
|
+
? Boolean(freshRatioConfidence95Raw
|
|
452
|
+
&& atMostWithinFloatingPrecision(freshRatioConfidence95Raw.upper, maximumFreshTokenRatioUpper95 ?? 1))
|
|
453
|
+
: null;
|
|
454
|
+
const primaryEfficiencyConfidenceGate = requiresConfidenceEfficiency
|
|
455
|
+
? Boolean(primaryEfficiencyRatioConfidence95Raw
|
|
456
|
+
&& atMostWithinFloatingPrecision(primaryEfficiencyRatioConfidence95Raw.upper, maximumFreshTokenRatioUpper95 ?? 1))
|
|
457
|
+
: null;
|
|
458
|
+
const primaryEfficiencyGate = requiresSuiteEfficiency
|
|
459
|
+
? primaryEfficiencyEvidenceGate
|
|
460
|
+
&& primaryEfficiencyBandCoverageGate
|
|
461
|
+
&& Number.isFinite(primaryEfficiencyRatio)
|
|
462
|
+
&& (!requiresConfidenceEfficiency || primaryEfficiencyConfidenceGate)
|
|
463
|
+
: null;
|
|
464
|
+
const performanceEvidenceGate = requiresPerformance
|
|
465
|
+
? completeScenarioDurationRatios.length >= (minimumPairedScenarios ?? 2)
|
|
466
|
+
: null;
|
|
467
|
+
const performancePointEstimateGate = requiresPerformance
|
|
468
|
+
? Number.isFinite(durationRatio) && atMostWithinFloatingPrecision(durationRatio, 1)
|
|
469
|
+
: null;
|
|
470
|
+
const performanceConfidenceGate = requiresPerformance
|
|
471
|
+
? Boolean(durationRatioConfidence95Raw
|
|
472
|
+
&& atMostWithinFloatingPrecision(durationRatioConfidence95Raw.upper, maximumDurationRatioUpper95))
|
|
473
|
+
: null;
|
|
474
|
+
const durationBandGate = evaluateDurationBandGate(suite, pairedDurationBandReport, maximumBandDurationRatio);
|
|
475
|
+
const completeDurationRatioByScenario = new Map(completeScenarioDurationRatios.map((item) => [item.scenarioId, item]));
|
|
476
|
+
const durationFamilyFailures = Number.isFinite(maximumFamilyDurationRatio)
|
|
477
|
+
? suite.scenarios.flatMap((scenario) => {
|
|
478
|
+
const item = completeDurationRatioByScenario.get(scenario.id);
|
|
479
|
+
if (!item) return [{ scenarioId: scenario.id, ratio: null, reason: "missing-comparable-duration" }];
|
|
480
|
+
if (!atMostWithinFloatingPrecision(item.ratio, maximumFamilyDurationRatio)) {
|
|
481
|
+
return [{ scenarioId: scenario.id, ratio: item.ratio, reason: "ratio-above-limit" }];
|
|
482
|
+
}
|
|
483
|
+
return [];
|
|
484
|
+
})
|
|
485
|
+
: [];
|
|
486
|
+
const durationFamilyGate = Number.isFinite(maximumFamilyDurationRatio)
|
|
487
|
+
? durationFamilyFailures.length === 0
|
|
488
|
+
: null;
|
|
489
|
+
const performanceGate = requiresPerformance
|
|
490
|
+
? performanceEvidenceGate
|
|
491
|
+
&& performancePointEstimateGate
|
|
492
|
+
&& performanceConfidenceGate
|
|
493
|
+
&& durationBandGate.passed !== false
|
|
494
|
+
&& durationFamilyGate !== false
|
|
495
|
+
: null;
|
|
496
|
+
const infrastructureRetryGate = requiresStability
|
|
497
|
+
? infrastructureRetries <= maximumInfrastructureRetries
|
|
498
|
+
: null;
|
|
499
|
+
const unknownInfrastructureUsageGate = requiresStability
|
|
500
|
+
? unknownInfrastructureUsage === 0
|
|
501
|
+
: null;
|
|
502
|
+
const stabilityGate = requiresStability || requiresProviderWireSurface
|
|
503
|
+
? infrastructureRetryGate !== false
|
|
504
|
+
&& unknownInfrastructureUsageGate !== false
|
|
505
|
+
&& infrastructureFailureLedgerGate !== false
|
|
506
|
+
&& providerWireSurfaceGate !== false
|
|
753
507
|
: null;
|
|
754
508
|
const pairedResolvedOutcomes = pairedOutcomeCounts(allPairs, (run) => run?.resolved === true);
|
|
755
509
|
const pairedRegressionGate = pairedResolvedOutcomes.baselineOnlyPass === 0;
|
|
510
|
+
const candidateContinuityFailures = candidateRuns.flatMap((run) => {
|
|
511
|
+
const failures = [];
|
|
512
|
+
if (run?.resolved !== true) failures.push("unresolved-outcome");
|
|
513
|
+
if (run?.scenarioKind !== "safety-refusal") {
|
|
514
|
+
if (!workflowContinuityEvidenceComplete(run?.workflow)) {
|
|
515
|
+
failures.push("workflow-evidence-incomplete-or-failed");
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return failures.length > 0 ? [{ scenarioId: run?.scenarioId ?? null, repeat: run?.repeat ?? null, failures }] : [];
|
|
519
|
+
});
|
|
520
|
+
const candidateTaskContinuityGate = candidateRuns.length > 0 && candidateContinuityFailures.length === 0;
|
|
756
521
|
const failureAwareEfficiencyGate = Number.isFinite(failureAwareFreshTokenRatio)
|
|
757
|
-
? failureAwareFreshTokenRatio
|
|
522
|
+
? atMostWithinFloatingPrecision(failureAwareFreshTokenRatio, maximumFreshTokenRatioUpper95 ?? 1)
|
|
758
523
|
: null;
|
|
524
|
+
const successfulPairEfficiencyRole = primaryUsesFixedWorkload ? "diagnostic" : "blocking";
|
|
525
|
+
const failureAwareEfficiencyRole = primaryUsesFixedWorkload ? "diagnostic" : "blocking";
|
|
526
|
+
const successfulPairEfficiencySupportGate = successfulPairEfficiencyRole === "diagnostic" || (
|
|
527
|
+
efficiencyEvidenceGate
|
|
528
|
+
&& efficiencyBandCoverageGate
|
|
529
|
+
&& Number.isFinite(freshRatio)
|
|
530
|
+
&& (!requiresConfidenceEfficiency || efficiencyConfidenceGate)
|
|
531
|
+
);
|
|
532
|
+
const failureAwareEfficiencySupportGate = failureAwareEfficiencyRole === "diagnostic"
|
|
533
|
+
|| failureAwareEfficiencyGate === true;
|
|
534
|
+
candidate.scores.efficiency = efficiencyScore(primaryEfficiencyRatio);
|
|
759
535
|
if (
|
|
760
536
|
qualityGate
|
|
761
537
|
&& safetyGate
|
|
762
538
|
&& reliabilityGate
|
|
763
539
|
&& qualityNonInferior
|
|
540
|
+
&& pairedQualityNoninferiorityGate !== false
|
|
764
541
|
&& workflowGate !== false
|
|
765
542
|
&& categoryGate !== false
|
|
766
543
|
&& outcomeScoreGate !== false
|
|
767
544
|
&& pairedRegressionGate
|
|
545
|
+
&& candidateTaskContinuityGate
|
|
768
546
|
&& protocol.passed
|
|
547
|
+
&& causalContextEvidenceGate !== false
|
|
548
|
+
&& fullSuiteGate !== false
|
|
549
|
+
&& stabilityGate !== false
|
|
550
|
+
&& acceptedUsageCompletenessGate !== false
|
|
551
|
+
&& allAttemptUsageCompletenessGate !== false
|
|
552
|
+
&& normalizedCostClaimConfigurationGate !== false
|
|
553
|
+
&& normalizedCostGates.passed !== false
|
|
769
554
|
&& outcomeEvidenceGate
|
|
770
|
-
&&
|
|
771
|
-
&&
|
|
772
|
-
&&
|
|
555
|
+
&& successfulPairEfficiencySupportGate
|
|
556
|
+
&& freshTokenBandGate.passed !== false
|
|
557
|
+
&& freshTokenFamilyGate !== false
|
|
558
|
+
&& failureAwareEfficiencySupportGate
|
|
559
|
+
&& primaryEfficiencyGate !== false
|
|
773
560
|
&& repeatGate !== false
|
|
774
|
-
&& (!
|
|
561
|
+
&& (!requiresPerformance || performanceGate)
|
|
775
562
|
&& candidate.scores.efficiency !== null
|
|
776
563
|
) {
|
|
777
564
|
const workflowScore = candidate.scores.workflow ?? 10;
|
|
@@ -784,23 +571,41 @@ export function summarizeBenchmark({
|
|
|
784
571
|
);
|
|
785
572
|
}
|
|
786
573
|
const tokenClaimAllowed = Boolean(safetyGate
|
|
574
|
+
&& requestsTokenSavingClaim
|
|
575
|
+
&& canonicalProductionIdentityGate
|
|
576
|
+
&& releaseClaimConfigurationGate
|
|
577
|
+
&& codexBaselineGate
|
|
578
|
+
&& cleanReleaseSourceGate
|
|
579
|
+
&& hostReadinessGate !== false
|
|
787
580
|
&& qualityGate
|
|
788
581
|
&& reliabilityGate
|
|
789
582
|
&& qualityNonInferior
|
|
583
|
+
&& pairedQualityNoninferiorityGate !== false
|
|
790
584
|
&& workflowGate !== false
|
|
791
585
|
&& categoryGate !== false
|
|
792
586
|
&& outcomeScoreGate !== false
|
|
793
587
|
&& pairedRegressionGate
|
|
588
|
+
&& candidateTaskContinuityGate
|
|
794
589
|
&& protocol.passed
|
|
590
|
+
&& causalContextEvidenceGate !== false
|
|
591
|
+
&& fullSuiteGate !== false
|
|
592
|
+
&& stabilityGate !== false
|
|
593
|
+
&& acceptedUsageCompletenessGate !== false
|
|
594
|
+
&& allAttemptUsageCompletenessGate !== false
|
|
595
|
+
&& normalizedCostClaimConfigurationGate !== false
|
|
596
|
+
&& normalizedCostGates.passed !== false
|
|
795
597
|
&& outcomeEvidenceGate
|
|
796
|
-
&&
|
|
797
|
-
&&
|
|
598
|
+
&& successfulPairEfficiencySupportGate
|
|
599
|
+
&& freshTokenBandGate.passed !== false
|
|
600
|
+
&& freshTokenFamilyGate !== false
|
|
798
601
|
&& repeatGate !== false
|
|
799
|
-
&&
|
|
800
|
-
&&
|
|
801
|
-
&& (
|
|
602
|
+
&& failureAwareEfficiencySupportGate
|
|
603
|
+
&& primaryEfficiencyGate
|
|
604
|
+
&& (!requiresPerformance || performanceGate));
|
|
802
605
|
const releaseFailures = [
|
|
606
|
+
!canonicalProductionIdentityGate ? "canonical-production-identity" : null,
|
|
803
607
|
!qualityNonInferior ? "quality-regression" : null,
|
|
608
|
+
requestsTokenSavingClaim && !pairedQualityNoninferiorityGate ? "paired-quality-noninferiority" : null,
|
|
804
609
|
!qualityGate ? "quality" : null,
|
|
805
610
|
!safetyGate ? "safety" : null,
|
|
806
611
|
!reliabilityGate ? "reliability" : null,
|
|
@@ -808,17 +613,45 @@ export function summarizeBenchmark({
|
|
|
808
613
|
categoryGate === false ? "category" : null,
|
|
809
614
|
outcomeScoreGate === false ? "outcome-score-floor" : null,
|
|
810
615
|
!pairedRegressionGate ? "paired-candidate-regression" : null,
|
|
811
|
-
!
|
|
616
|
+
!candidateTaskContinuityGate ? "candidate-task-continuity" : null,
|
|
617
|
+
!baseProtocol.passed ? "comparison-protocol" : null,
|
|
618
|
+
requiresProviderWireSurface && !providerWireSurfaceGate ? "provider-wire-surface" : null,
|
|
619
|
+
requiresCausalContextReceipt && !causalContextEvidenceGate ? "causal-context-evidence" : null,
|
|
620
|
+
requestsTokenSavingClaim && !releaseClaimConfigurationGate ? "release-claim-configuration" : null,
|
|
621
|
+
requestsNormalizedCostClaim && !normalizedCostClaimConfigurationGate ? "normalized-cost-configuration" : null,
|
|
622
|
+
requestsTokenSavingClaim && !codexBaselineGate ? "codex-baseline" : null,
|
|
623
|
+
requestsTokenSavingClaim && !cleanReleaseSourceGate ? "clean-release-source" : null,
|
|
624
|
+
requiresHostReadiness && !hostReadinessGate ? "host-readiness-history" : null,
|
|
625
|
+
requiresFullSuite && fullSuiteGate === false ? "full-suite" : null,
|
|
626
|
+
requiresStability && !infrastructureRetryGate ? "infrastructure-retries" : null,
|
|
627
|
+
requiresStability && !unknownInfrastructureUsageGate ? "unknown-infrastructure-usage" : null,
|
|
628
|
+
requestsTokenSavingClaim && !acceptedUsageCompletenessGate ? "accepted-usage-completeness" : null,
|
|
629
|
+
requestsTokenSavingClaim && !allAttemptUsageCompletenessGate ? "all-attempt-usage-completeness" : null,
|
|
630
|
+
requestsTokenSavingClaim && !infrastructureFailureLedgerGate ? "infrastructure-failure-ledger" : null,
|
|
631
|
+
requestsNormalizedCostClaim && !normalizedCostGates.evidenceGate ? "normalized-cost-evidence" : null,
|
|
632
|
+
requestsNormalizedCostClaim && !normalizedCostGates.applicabilityGate ? "normalized-cost-pricing-applicability" : null,
|
|
633
|
+
requestsNormalizedCostClaim && normalizedCostGates.evidenceGate && !normalizedCostGates.confidenceGate ? "normalized-cost-confidence" : null,
|
|
634
|
+
requestsNormalizedCostClaim && !normalizedCostGates.bandGate ? "normalized-cost-band-ratio" : null,
|
|
635
|
+
requestsNormalizedCostClaim && !normalizedCostGates.familyGate ? "normalized-cost-family-ratio" : null,
|
|
812
636
|
!outcomeEvidenceGate ? "paired-outcome-evidence" : null,
|
|
813
|
-
requiresSuiteEfficiency && !efficiencyEvidenceGate ? "efficiency-evidence" : null,
|
|
814
|
-
requiresSuiteEfficiency && !efficiencyBandCoverageGate ? "efficiency-category-coverage" : null,
|
|
815
|
-
|
|
637
|
+
requiresSuiteEfficiency && successfulPairEfficiencyRole === "blocking" && !efficiencyEvidenceGate ? "efficiency-evidence" : null,
|
|
638
|
+
requiresSuiteEfficiency && successfulPairEfficiencyRole === "blocking" && !efficiencyBandCoverageGate ? "efficiency-category-coverage" : null,
|
|
639
|
+
requiresBandEfficiency && !freshTokenBandGate.passed ? "efficiency-band-ratio" : null,
|
|
640
|
+
Number.isFinite(maximumFamilyFreshTokenRatio) && !freshTokenFamilyGate ? "efficiency-family-ratio" : null,
|
|
641
|
+
requiresSuiteEfficiency && failureAwareEfficiencyRole === "blocking" && !failureAwareEfficiencyGate ? "failure-aware-efficiency" : null,
|
|
642
|
+
requiresSuiteEfficiency && !primaryEfficiencyGate ? "primary-efficiency" : null,
|
|
816
643
|
repeatGate === false ? "repeat-count" : null,
|
|
817
|
-
requiresConfidenceEfficiency && !efficiencyConfidenceGate ? "efficiency-confidence" : null
|
|
644
|
+
requiresConfidenceEfficiency && successfulPairEfficiencyRole === "blocking" && !efficiencyConfidenceGate ? "efficiency-confidence" : null,
|
|
645
|
+
requiresPerformance && !performanceEvidenceGate ? "performance-evidence" : null,
|
|
646
|
+
requiresPerformance && performanceEvidenceGate && !performancePointEstimateGate ? "performance-point-regression" : null,
|
|
647
|
+
requiresPerformance && performanceEvidenceGate && performancePointEstimateGate && !performanceConfidenceGate ? "performance-confidence" : null,
|
|
648
|
+
Number.isFinite(maximumBandDurationRatio) && !durationBandGate.passed ? "performance-band-ratio" : null,
|
|
649
|
+
Number.isFinite(maximumFamilyDurationRatio) && !durationFamilyGate ? "performance-family-ratio" : null
|
|
818
650
|
].filter(Boolean);
|
|
819
651
|
const suiteGate = suite.schemaVersion === 2 ? {
|
|
820
652
|
passed: releaseFailures.length === 0,
|
|
821
653
|
failures: releaseFailures,
|
|
654
|
+
failureReasons: releaseFailures.map((id) => ({ id, message: RELEASE_FAILURE_MESSAGES[id] ?? id })),
|
|
822
655
|
thresholds: {
|
|
823
656
|
quality: qualityThreshold,
|
|
824
657
|
safety: safetyThreshold,
|
|
@@ -828,22 +661,76 @@ export function summarizeBenchmark({
|
|
|
828
661
|
outcomeScoreExclusive: outcomeScoreThresholdExclusive ?? null,
|
|
829
662
|
pairedOutcomeScenarios: minimumPairedScenarios ?? null,
|
|
830
663
|
comparableEfficiencyScenarios: minimumComparableEfficiencyScenarios ?? null,
|
|
664
|
+
primaryEfficiencyEstimand,
|
|
831
665
|
repeats: minimumRepeats ?? null,
|
|
832
|
-
freshTokenRatioUpper95: maximumFreshTokenRatioUpper95 ?? null
|
|
666
|
+
freshTokenRatioUpper95: maximumFreshTokenRatioUpper95 ?? null,
|
|
667
|
+
bandFreshTokenRatio: maximumBandFreshTokenRatio ?? null,
|
|
668
|
+
familyFreshTokenRatio: maximumFamilyFreshTokenRatio ?? null,
|
|
669
|
+
normalizedCostRatioUpper95: maximumNormalizedCostRatioUpper95 ?? null,
|
|
670
|
+
bandNormalizedCostRatio: maximumBandNormalizedCostRatio ?? null,
|
|
671
|
+
familyNormalizedCostRatio: maximumFamilyNormalizedCostRatio ?? null,
|
|
672
|
+
durationRatioPointEstimate: requiresPerformance ? 1 : null,
|
|
673
|
+
durationRatioUpper95: maximumDurationRatioUpper95 ?? null,
|
|
674
|
+
bandDurationRatio: maximumBandDurationRatio ?? null,
|
|
675
|
+
familyDurationRatio: maximumFamilyDurationRatio ?? null,
|
|
676
|
+
infrastructureRetries: maximumInfrastructureRetries ?? null,
|
|
677
|
+
tokenSavingClaimUpper95Maximum: requestsTokenSavingClaim ? 0.8 : null,
|
|
678
|
+
baselineSurface: requestsTokenSavingClaim ? "codex-cli" : null,
|
|
679
|
+
cleanSource: requestsTokenSavingClaim,
|
|
680
|
+
hostReadinessHistory: requiresHostReadiness,
|
|
681
|
+
requireFullSuite: requiresFullSuite,
|
|
682
|
+
stableProviderWireSurface: requiresProviderWireSurface,
|
|
683
|
+
causalContextReceipt: requiresCausalContextReceipt,
|
|
684
|
+
canonicalProductionIdentityRequired: suite.id === "production-v1"
|
|
685
|
+
},
|
|
686
|
+
observed: {
|
|
687
|
+
completeOutcomeScenarios,
|
|
688
|
+
completeEfficiencyScenarios: completeScenarioFreshRatios.length,
|
|
689
|
+
completeDurationScenarios: completeScenarioDurationRatios.length,
|
|
690
|
+
pairedQualityExpectedPairs: pairedQualityEvidence.expectedPairs,
|
|
691
|
+
pairedQualityObservedPairs: pairedQualityEvidence.observedPairs,
|
|
692
|
+
pairedQualityComparablePairs: pairedQualityEvidence.comparablePairs,
|
|
693
|
+
pairedQualityFailures: pairedQualityEvidence.failures,
|
|
694
|
+
repeats,
|
|
695
|
+
freshTokenRatioUpper95: freshRatioConfidence95Raw?.upper ?? null,
|
|
696
|
+
bandFreshTokenRatioFailures: freshTokenBandGate.failures,
|
|
697
|
+
familyFreshTokenRatioFailures: freshTokenFamilyFailures,
|
|
698
|
+
acceptedUsageExactAttempts: tokenAccounting.acceptedAttempts.exactAttempts,
|
|
699
|
+
acceptedUsageAttempts: tokenAccounting.acceptedAttempts.attempts,
|
|
700
|
+
normalizedCostRatio: normalizedCost?.ratio ?? null,
|
|
701
|
+
normalizedCostRatioUpper95: normalizedCost?.ratioConfidence95Raw?.upper ?? null,
|
|
702
|
+
normalizedCostBandFailures: normalizedCostGates.bandFailures,
|
|
703
|
+
normalizedCostFamilyFailures: normalizedCostGates.familyFailures,
|
|
704
|
+
normalizedCostApplicabilityFailures: normalizedCost?.applicabilityFailures ?? [],
|
|
705
|
+
primaryEfficiencyCompleteScenarios,
|
|
706
|
+
primaryEfficiencyRatio: rounded(primaryEfficiencyRatio, 4),
|
|
707
|
+
primaryEfficiencyRatioUpper95: primaryEfficiencyRatioConfidence95Raw?.upper ?? null,
|
|
708
|
+
durationRatio: rounded(durationRatio, 4),
|
|
709
|
+
durationRatioUpper95: durationRatioConfidence95Raw?.upper ?? null,
|
|
710
|
+
durationBandFailures: durationBandGate.failures,
|
|
711
|
+
durationFamilyFailures,
|
|
712
|
+
infrastructureRetries,
|
|
713
|
+
unknownInfrastructureUsage,
|
|
714
|
+
baselineSurface,
|
|
715
|
+
sourceKind: environment.source?.kind ?? null,
|
|
716
|
+
sourceCommit: environment.source?.commit ?? null,
|
|
717
|
+
sourceDirty: environment.source?.dirty ?? null,
|
|
718
|
+
hostReadinessValidReceipts: hostReadinessHistory?.validReceiptCount ?? null,
|
|
719
|
+
hostReadinessReceipts: hostReadinessHistory?.receiptCount ?? null,
|
|
720
|
+
hostReadinessCoverage: hostReadinessHistory?.windowCoverage ?? null,
|
|
721
|
+
fullSuite: environment.suiteCoverage?.fullSuite ?? null,
|
|
722
|
+
canonicalProductionIdentity: canonicalProductionSuite,
|
|
723
|
+
providerWireVerifiedRuns: providerWireVerifiedRuns.length,
|
|
724
|
+
providerWireRuns: candidateRuns.length,
|
|
725
|
+
providerWireGroups: providerWireGroups.length,
|
|
726
|
+
providerWireDriftGroups: providerWireDriftGroups.length,
|
|
727
|
+
causalContextAvailableRuns: causalContextEvidence.currentAvailableRuns,
|
|
728
|
+
causalContextRuns: causalContextEvidence.runs,
|
|
729
|
+
causalContextRequiredSchemaVersion: causalContextEvidence.requiredSchemaVersion
|
|
833
730
|
}
|
|
834
731
|
} : null;
|
|
835
732
|
const baselineKey = surfaceReportKey(baselineSurface);
|
|
836
733
|
const candidateKey = surfaceReportKey(candidateSurface);
|
|
837
|
-
const infrastructureFailures = runs.flatMap((run) => run.infrastructureFailures ?? []);
|
|
838
|
-
const infrastructureFailureCounts = {};
|
|
839
|
-
const infrastructureClassCounts = {};
|
|
840
|
-
for (const failure of infrastructureFailures) {
|
|
841
|
-
const name = failure.failure ?? "unknown";
|
|
842
|
-
infrastructureFailureCounts[name] = (infrastructureFailureCounts[name] ?? 0) + 1;
|
|
843
|
-
const className = failure.class ?? failure.infrastructureClass ?? "unknown";
|
|
844
|
-
infrastructureClassCounts[className] = (infrastructureClassCounts[className] ?? 0) + 1;
|
|
845
|
-
}
|
|
846
|
-
const infrastructureRetries = runs.reduce((sum, run) => sum + (run.infrastructureRetries ?? 0), 0);
|
|
847
734
|
const claimEligibility = benchmarkClaimEligibility({
|
|
848
735
|
suite,
|
|
849
736
|
environment,
|
|
@@ -851,7 +738,7 @@ export function summarizeBenchmark({
|
|
|
851
738
|
protocolPassed: protocol.passed,
|
|
852
739
|
tokenClaimAllowed
|
|
853
740
|
});
|
|
854
|
-
return {
|
|
741
|
+
return integrateCodexRelativeEfficiencyReport({
|
|
855
742
|
schemaVersion: 2,
|
|
856
743
|
measurementSchemaVersion: BENCHMARK_MEASUREMENT_SCHEMA_VERSION,
|
|
857
744
|
runId,
|
|
@@ -868,32 +755,49 @@ export function summarizeBenchmark({
|
|
|
868
755
|
failureCounts: infrastructureFailureCounts,
|
|
869
756
|
classCounts: infrastructureClassCounts
|
|
870
757
|
},
|
|
758
|
+
tokenAccounting,
|
|
759
|
+
timingDiagnostics,
|
|
871
760
|
surfaces: { [baselineKey]: baseline, [candidateKey]: candidate },
|
|
872
761
|
comparison: {
|
|
873
762
|
baselineSurface,
|
|
874
763
|
candidateSurface,
|
|
875
764
|
purpose: claimEligibility.comparisonPurpose,
|
|
876
765
|
usageEstimator: "paired-geometric-mean-ratio",
|
|
766
|
+
durationEstimator: "paired-geometric-mean-ratio-clustered-by-scenario-family",
|
|
877
767
|
failureAwareUsageEstimator: "total-comparable-attempt-fresh-tokens-per-resolved-outcome",
|
|
768
|
+
failureAwareFamilyUsageEstimator: "geometric-mean-of-family-total-comparable-attempt-fresh-tokens-per-resolved-outcome-ratios",
|
|
769
|
+
fixedWorkloadUsageEstimator: "geometric-mean-of-family-total-exact-scheduled-workload-ratios",
|
|
770
|
+
fixedWorkloadEstimatorVersion: 1,
|
|
878
771
|
pairedOutcomeScenarios: completeOutcomeScenarios,
|
|
879
772
|
pairedSuccessfulRuns: pairs.length,
|
|
880
773
|
pairedUsageRuns: tokenPairs.length,
|
|
881
774
|
pairedUsageScenarios: scenarioFreshRatios.length,
|
|
882
775
|
pairedCompleteScenarios: completeScenarioFreshRatios.length,
|
|
776
|
+
pairedDurationRuns: durationPairs.length,
|
|
777
|
+
pairedDurationScenarios: scenarioDurationRatios.length,
|
|
778
|
+
pairedCompleteDurationScenarios: completeScenarioDurationRatios.length,
|
|
779
|
+
pairedDurationBands: pairedDurationBandReport,
|
|
883
780
|
pairedCostRuns: costPairs.length,
|
|
781
|
+
normalizedCost,
|
|
782
|
+
normalizedCostClaimConfigurationGate,
|
|
783
|
+
normalizedCostEvidenceGate: normalizedCostGates.evidenceGate,
|
|
784
|
+
normalizedCostPricingApplicabilityGate: normalizedCostGates.applicabilityGate,
|
|
785
|
+
normalizedCostConfidenceGate: normalizedCostGates.confidenceGate,
|
|
786
|
+
normalizedCostBandGate: normalizedCostGates.bandGate,
|
|
787
|
+
normalizedCostBandFailures: normalizedCostGates.bandFailures,
|
|
788
|
+
normalizedCostFamilyGate: normalizedCostGates.familyGate,
|
|
789
|
+
normalizedCostFamilyFailures: normalizedCostGates.familyFailures,
|
|
790
|
+
normalizedCostGate: normalizedCostGates.passed,
|
|
884
791
|
pairedOutcomes: {
|
|
885
792
|
resolved: pairedResolvedOutcomes,
|
|
886
793
|
quality: pairedOutcomeCounts(allPairs.filter((pair) => pair.candidate.scenarioKind !== "safety-refusal"), qualityPassed),
|
|
887
794
|
safety: pairedOutcomeCounts(allPairs, safetyPassed)
|
|
888
795
|
},
|
|
889
|
-
pairedUsageBands:
|
|
890
|
-
categories: pairedUsageBands(tokenPairs, "category"),
|
|
891
|
-
profiles: pairedUsageBands(tokenPairs, "profile"),
|
|
892
|
-
lifecycles: pairedUsageBands(tokenPairs, "lifecycle"),
|
|
893
|
-
difficulties: pairedUsageBands(tokenPairs, "difficulty")
|
|
894
|
-
},
|
|
796
|
+
pairedUsageBands: pairedUsageBandReport,
|
|
895
797
|
pairedFreshTokenWins: { [candidateKey]: freshWins, [baselineKey]: freshLosses, ties: freshTies },
|
|
896
798
|
medianPairedFreshTokenDelta: rounded(median(freshDeltas), 2),
|
|
799
|
+
pairedDurationWins: { [candidateKey]: durationWins, [baselineKey]: durationLosses, ties: durationTies },
|
|
800
|
+
medianPairedDurationDeltaSeconds: rounded(median(durationDeltas), 2),
|
|
897
801
|
medianFreshTokens: { [baselineKey]: baselineFresh, [candidateKey]: candidateFresh },
|
|
898
802
|
medianCost: { [baselineKey]: baselineCost, [candidateKey]: candidateCost },
|
|
899
803
|
freshTokensPerResolvedOutcome: {
|
|
@@ -901,12 +805,69 @@ export function summarizeBenchmark({
|
|
|
901
805
|
[candidateKey]: rounded(candidateFreshPerResolvedOutcome, 2)
|
|
902
806
|
},
|
|
903
807
|
failureAwareFreshTokenRatio: rounded(failureAwareFreshTokenRatio, 4),
|
|
808
|
+
failureAwareFamilyFreshTokenRatio: rounded(familyClusteredFailureAware.ratio, 4),
|
|
809
|
+
failureAwareFamilyFreshTokenRatioConfidence95: familyClusteredFailureAware.confidence95,
|
|
810
|
+
failureAwareFamilyFreshTokenRatioConfidence95Raw: familyClusteredFailureAware.confidence95Raw,
|
|
811
|
+
failureAwareFamilyCoverage: {
|
|
812
|
+
complete: familyClusteredFailureAware.complete,
|
|
813
|
+
expectedScenarioFamilies: familyClusteredFailureAware.expectedScenarioFamilies,
|
|
814
|
+
usableScenarioFamilies: familyClusteredFailureAware.usableScenarioFamilies,
|
|
815
|
+
sampleUnit: familyClusteredFailureAware.sampleUnit,
|
|
816
|
+
scenarioIds: familyClusteredFailureAware.scenarioIds
|
|
817
|
+
},
|
|
818
|
+
failureAwareFamilyRatios: familyClusteredFailureAware.families,
|
|
819
|
+
fixedWorkloadFamilyFreshTokenRatio: rounded(familyClusteredFixedWorkload.ratio, 4),
|
|
820
|
+
fixedWorkloadFamilyFreshTokenRatioRaw: familyClusteredFixedWorkload.ratio,
|
|
821
|
+
fixedWorkloadFamilyFreshTokenRatioConfidence95: familyClusteredFixedWorkload.confidence95,
|
|
822
|
+
fixedWorkloadFamilyFreshTokenRatioConfidence95Raw: familyClusteredFixedWorkload.confidence95Raw,
|
|
823
|
+
fixedWorkloadAggregateFreshTokenRatio: rounded(familyClusteredFixedWorkload.aggregateFreshTokenRatio, 4),
|
|
824
|
+
fixedWorkloadFamilyCoverage: {
|
|
825
|
+
complete: familyClusteredFixedWorkload.complete,
|
|
826
|
+
expectedScenarioFamilies: familyClusteredFixedWorkload.expectedScenarioFamilies,
|
|
827
|
+
usableScenarioFamilies: familyClusteredFixedWorkload.usableScenarioFamilies,
|
|
828
|
+
expectedAttemptsPerFamily: familyClusteredFixedWorkload.expectedAttemptsPerFamily,
|
|
829
|
+
sampleUnit: familyClusteredFixedWorkload.sampleUnit,
|
|
830
|
+
outcomeConditioning: familyClusteredFixedWorkload.outcomeConditioning,
|
|
831
|
+
aggregation: familyClusteredFixedWorkload.aggregation,
|
|
832
|
+
attemptPolicy: familyClusteredFixedWorkload.attemptPolicy,
|
|
833
|
+
scenarioIds: familyClusteredFixedWorkload.scenarioIds
|
|
834
|
+
},
|
|
835
|
+
fixedWorkloadFamilyRatios: familyClusteredFixedWorkload.families,
|
|
836
|
+
allSuccessfulPairsFreshTokenRatio: rounded(allSuccessfulPairsFreshRatio, 4),
|
|
904
837
|
freshTokenRatio: rounded(freshRatio, 4),
|
|
838
|
+
freshTokenRatioRaw: freshRatio,
|
|
905
839
|
freshTokenRatioConfidence95: freshRatioConfidence95,
|
|
840
|
+
freshTokenRatioConfidence95Raw: freshRatioConfidence95Raw,
|
|
841
|
+
freshTokenRatioSample: {
|
|
842
|
+
sampleUnit: "scenario-family",
|
|
843
|
+
scenarioCount: confidenceScenarioRatios.length,
|
|
844
|
+
scenarioIds: confidenceScenarioRatios.map((item) => item.scenarioId)
|
|
845
|
+
},
|
|
846
|
+
primaryEfficiencyEstimand,
|
|
847
|
+
primaryEfficiencyRatio: rounded(primaryEfficiencyRatio, 4),
|
|
848
|
+
primaryEfficiencyRatioRaw: primaryEfficiencyRatio,
|
|
849
|
+
primaryEfficiencyRatioConfidence95,
|
|
850
|
+
primaryEfficiencyRatioConfidence95Raw,
|
|
851
|
+
primaryEfficiencySample: {
|
|
852
|
+
sampleUnit: "scenario-family",
|
|
853
|
+
scenarioCount: primaryEfficiencyCompleteScenarios,
|
|
854
|
+
scenarioIds: primaryEfficiencyScenarioRatios.map((item) => item.scenarioId),
|
|
855
|
+
outcomeConditioning: primaryUsesFixedWorkload ? "none" : "resolved-outcome-conditioned"
|
|
856
|
+
},
|
|
857
|
+
primaryEfficiencyDeltaPercent: Number.isFinite(primaryEfficiencyRatio)
|
|
858
|
+
? rounded((primaryEfficiencyRatio - 1) * 100, 2)
|
|
859
|
+
: null,
|
|
906
860
|
freshTokenDeltaPercent: Number.isFinite(freshRatio) ? rounded((freshRatio - 1) * 100, 2) : null,
|
|
861
|
+
durationRatio: rounded(durationRatio, 4),
|
|
862
|
+
durationRatioRaw: durationRatio,
|
|
863
|
+
durationRatioConfidence95,
|
|
864
|
+
durationRatioConfidence95Raw,
|
|
865
|
+
durationDeltaPercent: Number.isFinite(durationRatio) ? rounded((durationRatio - 1) * 100, 2) : null,
|
|
907
866
|
costRatio: rounded(costRatio, 4),
|
|
908
867
|
costDeltaPercent: Number.isFinite(costRatio) ? rounded((costRatio - 1) * 100, 2) : null,
|
|
909
868
|
qualityNonInferior,
|
|
869
|
+
pairedQualityNoninferiorityGate,
|
|
870
|
+
pairedQualityEvidence,
|
|
910
871
|
qualityGate,
|
|
911
872
|
safetyGate,
|
|
912
873
|
reliabilityGate,
|
|
@@ -916,16 +877,65 @@ export function summarizeBenchmark({
|
|
|
916
877
|
outcomeScoreGate,
|
|
917
878
|
outcomeScoreFailures,
|
|
918
879
|
pairedRegressionGate,
|
|
880
|
+
candidateTaskContinuityGate,
|
|
881
|
+
candidateContinuityFailures,
|
|
919
882
|
comparisonProtocolGate: protocol,
|
|
883
|
+
providerWireSurfaceGate,
|
|
884
|
+
causalContextEvidenceGate,
|
|
885
|
+
causalContextEvidence,
|
|
886
|
+
providerWireEvidence: {
|
|
887
|
+
required: requiresProviderWireSurface,
|
|
888
|
+
runs: candidateRuns.length,
|
|
889
|
+
verifiedRuns: providerWireVerifiedRuns.length,
|
|
890
|
+
groups: providerWireGroups,
|
|
891
|
+
driftGroups: providerWireDriftGroups,
|
|
892
|
+
failureCounts: providerWireFailureCounts,
|
|
893
|
+
deferredChangesAreBaseDrift: false
|
|
894
|
+
},
|
|
895
|
+
releaseClaimConfigurationGate,
|
|
896
|
+
canonicalProductionIdentityGate,
|
|
897
|
+
codexBaselineGate,
|
|
898
|
+
cleanReleaseSourceGate,
|
|
899
|
+
hostReadinessGate,
|
|
900
|
+
fullSuiteGate,
|
|
920
901
|
outcomeEvidenceGate,
|
|
921
902
|
efficiencyEvidenceGate,
|
|
903
|
+
successfulPairEfficiencyRole,
|
|
904
|
+
successfulPairEfficiencySupportGate,
|
|
922
905
|
efficiencyBandCoverageGate,
|
|
923
906
|
efficiencyCategoryCoverage,
|
|
907
|
+
freshTokenBandGate: freshTokenBandGate.passed,
|
|
908
|
+
freshTokenBandFailures: freshTokenBandGate.failures,
|
|
909
|
+
freshTokenFamilyGate,
|
|
910
|
+
freshTokenFamilyFailures,
|
|
924
911
|
failureAwareEfficiencyGate,
|
|
912
|
+
failureAwareEfficiencyRole,
|
|
913
|
+
failureAwareEfficiencySupportGate,
|
|
914
|
+
primaryEfficiencyEvidenceGate,
|
|
915
|
+
primaryEfficiencyBandCoverageGate,
|
|
916
|
+
primaryEfficiencyCategoryCoverage,
|
|
917
|
+
primaryEfficiencyConfidenceGate,
|
|
918
|
+
primaryEfficiencyGate,
|
|
925
919
|
repeatGate,
|
|
926
920
|
efficiencyConfidenceGate,
|
|
921
|
+
performanceEvidenceGate,
|
|
922
|
+
performancePointEstimateGate,
|
|
923
|
+
performanceConfidenceGate,
|
|
924
|
+
durationBandGate: durationBandGate.passed,
|
|
925
|
+
durationBandFailures: durationBandGate.failures,
|
|
926
|
+
durationFamilyGate,
|
|
927
|
+
durationFamilyFailures,
|
|
928
|
+
performanceGate,
|
|
929
|
+
infrastructureRetryGate,
|
|
930
|
+
unknownInfrastructureUsageGate,
|
|
931
|
+
acceptedUsageCompletenessGate,
|
|
932
|
+
failedUsageCompletenessGate,
|
|
933
|
+
allAttemptUsageCompletenessGate,
|
|
934
|
+
infrastructureFailureLedgerGate,
|
|
935
|
+
infrastructureFailureLedgerIssues,
|
|
936
|
+
stabilityGate,
|
|
927
937
|
suiteGate,
|
|
928
|
-
productionGate:
|
|
938
|
+
productionGate: canonicalProductionSuite ? suiteGate : null,
|
|
929
939
|
tokenClaimAllowed,
|
|
930
940
|
claimEligibility
|
|
931
941
|
},
|
|
@@ -934,29 +944,91 @@ export function summarizeBenchmark({
|
|
|
934
944
|
? "safety-gate-failed"
|
|
935
945
|
: !qualityNonInferior
|
|
936
946
|
? "quality-regression"
|
|
947
|
+
: pairedQualityNoninferiorityGate === false
|
|
948
|
+
? "paired-quality-noninferiority-gate-failed"
|
|
937
949
|
: !qualityGate
|
|
938
950
|
? "quality-gate-failed"
|
|
939
951
|
: !reliabilityGate
|
|
940
952
|
? "reliability-gate-failed"
|
|
941
|
-
: !
|
|
953
|
+
: !baseProtocol.passed
|
|
942
954
|
? "comparison-protocol-gate-failed"
|
|
943
955
|
: workflowGate === false
|
|
944
956
|
? "workflow-gate-failed"
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
:
|
|
958
|
-
|
|
957
|
+
: categoryGate === false
|
|
958
|
+
? "category-gate-failed"
|
|
959
|
+
: outcomeScoreGate === false
|
|
960
|
+
? "outcome-score-floor-gate-failed"
|
|
961
|
+
: !pairedRegressionGate
|
|
962
|
+
? "paired-candidate-regression"
|
|
963
|
+
: !candidateTaskContinuityGate
|
|
964
|
+
? "candidate-task-continuity-gate-failed"
|
|
965
|
+
: !canonicalProductionIdentityGate
|
|
966
|
+
? "canonical-production-identity-gate-failed"
|
|
967
|
+
: requestsTokenSavingClaim && releaseClaimConfigurationGate === false
|
|
968
|
+
? "release-claim-configuration-gate-failed"
|
|
969
|
+
: requestsTokenSavingClaim && codexBaselineGate === false
|
|
970
|
+
? "codex-baseline-gate-failed"
|
|
971
|
+
: requestsTokenSavingClaim && cleanReleaseSourceGate === false
|
|
972
|
+
? "clean-release-source-gate-failed"
|
|
973
|
+
: requiresHostReadiness && hostReadinessGate === false
|
|
974
|
+
? "host-readiness-history-gate-failed"
|
|
975
|
+
: requiresProviderWireSurface && providerWireSurfaceGate === false
|
|
976
|
+
? "provider-wire-surface-gate-failed"
|
|
977
|
+
: requiresCausalContextReceipt && causalContextEvidenceGate === false
|
|
978
|
+
? "causal-context-evidence-gate-failed"
|
|
979
|
+
: fullSuiteGate === false
|
|
980
|
+
? "full-suite-gate-failed"
|
|
981
|
+
: requiresStability && infrastructureRetryGate === false
|
|
982
|
+
? "stability-infrastructure-retry-gate-failed"
|
|
983
|
+
: requiresStability && unknownInfrastructureUsageGate === false
|
|
984
|
+
? "stability-unknown-usage-gate-failed"
|
|
985
|
+
: requestsTokenSavingClaim && infrastructureFailureLedgerGate === false
|
|
986
|
+
? "stability-failure-ledger-gate-failed"
|
|
987
|
+
: requestsTokenSavingClaim && acceptedUsageCompletenessGate === false
|
|
988
|
+
? "accepted-usage-completeness-gate-failed"
|
|
989
|
+
: requestsTokenSavingClaim && allAttemptUsageCompletenessGate === false
|
|
990
|
+
? "all-attempt-usage-completeness-gate-failed"
|
|
991
|
+
: requestsNormalizedCostClaim && normalizedCostClaimConfigurationGate === false
|
|
992
|
+
? "normalized-cost-configuration-gate-failed"
|
|
993
|
+
: requestsNormalizedCostClaim && normalizedCostGates.applicabilityGate === false
|
|
994
|
+
? "normalized-cost-pricing-applicability-gate-failed"
|
|
995
|
+
: requestsNormalizedCostClaim && normalizedCostGates.evidenceGate === false
|
|
996
|
+
? "normalized-cost-evidence-gate-failed"
|
|
997
|
+
: requestsNormalizedCostClaim && normalizedCostGates.confidenceGate === false
|
|
998
|
+
? "normalized-cost-confidence-gate-failed"
|
|
999
|
+
: requestsNormalizedCostClaim && normalizedCostGates.bandGate === false
|
|
1000
|
+
? "normalized-cost-band-ratio-gate-failed"
|
|
1001
|
+
: requestsNormalizedCostClaim && normalizedCostGates.familyGate === false
|
|
1002
|
+
? "normalized-cost-family-ratio-gate-failed"
|
|
1003
|
+
: !outcomeEvidenceGate
|
|
1004
|
+
? "paired-outcome-evidence-gate-failed"
|
|
1005
|
+
: repeatGate === false
|
|
1006
|
+
? "repeat-gate-failed"
|
|
1007
|
+
: primaryUsesFixedWorkload && primaryEfficiencyGate === false
|
|
1008
|
+
? "primary-efficiency-gate-failed"
|
|
1009
|
+
: requiresPerformance && performanceEvidenceGate === false
|
|
1010
|
+
? "performance-evidence-gate-failed"
|
|
1011
|
+
: requiresPerformance && performancePointEstimateGate === false
|
|
1012
|
+
? "performance-point-regression"
|
|
1013
|
+
: requiresPerformance && performanceConfidenceGate === false
|
|
1014
|
+
? "performance-confidence-gate-failed"
|
|
1015
|
+
: durationBandGate.passed === false
|
|
1016
|
+
? "performance-band-ratio-gate-failed"
|
|
1017
|
+
: durationFamilyGate === false
|
|
1018
|
+
? "performance-family-ratio-gate-failed"
|
|
1019
|
+
: requiresBandEfficiency && freshTokenBandGate.passed === false
|
|
1020
|
+
? "efficiency-band-ratio-gate-failed"
|
|
1021
|
+
: freshTokenFamilyGate === false
|
|
1022
|
+
? "efficiency-family-ratio-gate-failed"
|
|
1023
|
+
: requiresConfidenceEfficiency
|
|
1024
|
+
&& successfulPairEfficiencyRole === "blocking"
|
|
1025
|
+
&& efficiencyConfidenceGate === false
|
|
1026
|
+
? "efficiency-confidence-gate-failed"
|
|
1027
|
+
: tokenClaimAllowed
|
|
1028
|
+
? `${candidateSurface}-more-efficient`
|
|
1029
|
+
: "observational-efficiency-only",
|
|
1030
|
+
note: `Raw metrics and hidden verifier results are authoritative. Fixed-workload efficiency includes every predeclared paired attempt, including exact provider-started failed-attempt usage, without conditioning token measurement on task outcome; quality and continuity remain independent hard gates. Successful-pair efficiency uses matched ${benchmarkSurfaceLabel(candidateSurface)}/${benchmarkSurfaceLabel(baselineSurface)} resolved-outcome ratios; failure-aware effort divides every comparable attempt by resolved outcomes. Normalized cost is API-equivalent text-token input/cache/output cost from the versioned suite pricing snapshot and exact token buckets, never OAuth/provider-billed or tool-specific total cost. Duration compares all matched runs with compatible model and effort evidence. Provider-wire evidence verifies the requested model and effort plus stable base instructions/tools within each scenario/profile/lifecycle across repeats; deferred tool-search batches are reported separately. Confidence intervals cluster repeats by scenario family. Claim scope is ${claimEligibility.achievedTier}; generated value variants are not treated as independent task families.`
|
|
959
1031
|
},
|
|
960
|
-
runs
|
|
961
|
-
};
|
|
1032
|
+
runs: reportRuns
|
|
1033
|
+
}, suite);
|
|
962
1034
|
}
|