@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,26 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import crypto from "node:crypto";
|
|
3
3
|
import fs from "node:fs";
|
|
4
|
-
import os from "node:os";
|
|
5
4
|
import path from "node:path";
|
|
6
|
-
import
|
|
7
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
8
6
|
|
|
9
|
-
import {
|
|
10
|
-
aggregateSessionUsage, benchmarkSurfaceLabel,
|
|
11
|
-
renderBenchmarkHtml,
|
|
12
|
-
renderBenchmarkText,
|
|
13
|
-
summarizeBenchmark
|
|
14
|
-
} from "../packages/piagent-core/benchmark/benchmark-core.js";
|
|
7
|
+
import { aggregateSessionUsage, benchmarkSurfaceLabel } from "../packages/piagent-core/benchmark/benchmark-core.js";
|
|
15
8
|
import { benchmarkUsage, parseBenchmarkArgs } from "../packages/piagent-core/benchmark/benchmark-cli.js";
|
|
16
9
|
import { codexModelName, codexThinkingEffort } from "../packages/piagent-core/benchmark/benchmark-codex.js";
|
|
17
|
-
import { benchmarkTrustChecklist } from "../packages/piagent-core/benchmark/benchmark-matrix.js";
|
|
18
|
-
import { applyBenchmarkClaimRestrictions } from "../packages/piagent-core/benchmark/benchmark-claim-restrictions.js";
|
|
19
10
|
import { benchmarkEnvironment, benchmarkEnvironmentPolicy, comparisonSurfaces, createCodexRuntime, piagentTreatment } from "../packages/piagent-core/benchmark/benchmark-runtime.js";
|
|
20
11
|
import { assertBenchmarkPiCredentialReady, assertBenchmarkPiCredentialWritebackPolicy, cleanupBenchmarkPiRuntimeHome, createBenchmarkPiRuntimeHome, resetBenchmarkPiRuntimeEphemeralState, withBenchmarkPiCredentialWriteback } from "../packages/piagent-core/benchmark/benchmark-pi-home.js";
|
|
21
12
|
import { benchmarkPreflight, benchmarkPreflightReceipt } from "../packages/piagent-core/benchmark/benchmark-preflight.js";
|
|
13
|
+
import { prepareProductionProviderFreeEvidence, productionProviderFreeEvidenceError } from "../packages/piagent-core/benchmark/benchmark-provider-free-evidence.js";
|
|
14
|
+
import { applyBenchmarkExecutionDefaults } from "../packages/piagent-core/benchmark/benchmark-runner-policy.js";
|
|
22
15
|
import {
|
|
23
|
-
cleanupUnretainedWorkspaces,
|
|
24
16
|
appendPrivateJsonl,
|
|
25
17
|
createBenchmarkCandidateGuard,
|
|
26
18
|
loadReplayFailurePlan,
|
|
@@ -28,7 +20,6 @@ import {
|
|
|
28
20
|
safeInfrastructureDiagnostic,
|
|
29
21
|
writeBenchmarkAbort,
|
|
30
22
|
writeBenchmarkRunManifest,
|
|
31
|
-
writePrivate,
|
|
32
23
|
writePrivateAtomic
|
|
33
24
|
} from "../packages/piagent-core/benchmark/benchmark-forensics.js";
|
|
34
25
|
import { benchmarkBootstrapCandidateIndex, benchmarkBootstrapMetadata } from "../packages/piagent-core/benchmark/benchmark-bootstrap.js";
|
|
@@ -37,8 +28,16 @@ import { benchmarkCommandIdentity } from "../packages/piagent-core/benchmark/ben
|
|
|
37
28
|
import { benchmarkTreeIdentity } from "../packages/piagent-core/benchmark/benchmark-tree-identity.js";
|
|
38
29
|
import { completedBenchmarkRecord, expectedBenchmarkRecord } from "../packages/piagent-core/benchmark/benchmark-record-validation.js";
|
|
39
30
|
import { pairedOutcomeFloorStop } from "../packages/piagent-core/benchmark/benchmark-stop-policy.js";
|
|
31
|
+
import {
|
|
32
|
+
approveProductionStageControl,
|
|
33
|
+
buildBenchmarkStageDiagnostic,
|
|
34
|
+
createProductionStageControl,
|
|
35
|
+
durablePairedOutcomeFloorStop,
|
|
36
|
+
productionGuardBindingMatches, productionSpendControlValidationErrors,
|
|
37
|
+
productionStageResumeDisposition
|
|
38
|
+
} from "../packages/piagent-core/benchmark/benchmark-stage-diagnostic.js";
|
|
40
39
|
import { loadBenchmarkAssuranceEvidence, loadBenchmarkSuite, resolveBenchmarkSuiteEntry, validateBenchmarkSuiteFiles } from "../packages/piagent-core/benchmark/benchmark-suite-runtime.js";
|
|
41
|
-
import { appendBenchmarkLedger, assertBenchmarkLedgerBinding,
|
|
40
|
+
import { appendBenchmarkLedger, assertBenchmarkLedgerBinding, emptyBenchmarkLedgerBinding, inspectBenchmarkLedger, validateBenchmarkLedgerPrefix } from "../packages/piagent-core/benchmark/benchmark-ledger.js";
|
|
42
41
|
import { acquireBenchmarkRunLock } from "../packages/piagent-core/benchmark/benchmark-run-lock.js";
|
|
43
42
|
import { createBenchmarkProcessController } from "../packages/piagent-core/benchmark/benchmark-process.js";
|
|
44
43
|
import {
|
|
@@ -49,7 +48,33 @@ import {
|
|
|
49
48
|
recoverPendingBenchmarkRecord,
|
|
50
49
|
stageMeasuredBenchmarkRecord
|
|
51
50
|
} from "../packages/piagent-core/benchmark/benchmark-resume-recovery.js";
|
|
51
|
+
import { finalizeBenchmarkRun } from "./benchmark-runner-finalization.mjs";
|
|
52
|
+
import {
|
|
53
|
+
benchmarkRunKey,
|
|
54
|
+
confirmPlan,
|
|
55
|
+
createRunId,
|
|
56
|
+
defaultOutputRoot,
|
|
57
|
+
ensureEmptyOutput,
|
|
58
|
+
executionOrder,
|
|
59
|
+
fail,
|
|
60
|
+
formatDuration,
|
|
61
|
+
frozenRuntimeCommandsForFinalization,
|
|
62
|
+
invokedAsEntrypoint,
|
|
63
|
+
isLegacyInvocation,
|
|
64
|
+
loadResumeState,
|
|
65
|
+
pairedChunk,
|
|
66
|
+
privateDirectory,
|
|
67
|
+
readJsonFile,
|
|
68
|
+
samePairedBlock,
|
|
69
|
+
sameStringList
|
|
70
|
+
} from "./benchmark-runner-support.mjs";
|
|
52
71
|
import { runBenchmarkSession } from "./benchmark-session.mjs";
|
|
72
|
+
import {
|
|
73
|
+
assertBenchmarkHostReadinessStartReady,
|
|
74
|
+
assertExistingBenchmarkHostReadiness,
|
|
75
|
+
benchmarkHostReadinessPolicyDigest,
|
|
76
|
+
collectReadyBenchmarkHostReadiness
|
|
77
|
+
} from "./benchmark-runner-host-readiness.mjs";
|
|
53
78
|
export { parseBenchmarkArgs };
|
|
54
79
|
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
55
80
|
const packageManifest = JSON.parse(fs.readFileSync(path.join(packageRoot, "package.json"), "utf8"));
|
|
@@ -58,11 +83,6 @@ const bootstrapCandidateIndex = bootstrapMetadata ? benchmarkBootstrapCandidateI
|
|
|
58
83
|
let interruptedSignal;
|
|
59
84
|
const processController = createBenchmarkProcessController(() => Boolean(interruptedSignal));
|
|
60
85
|
const runCommand = processController.run;
|
|
61
|
-
function fail(message, code = 2) {
|
|
62
|
-
const error = new Error(message);
|
|
63
|
-
error.exitCode = code;
|
|
64
|
-
throw error;
|
|
65
|
-
}
|
|
66
86
|
|
|
67
87
|
function installSignalForwarding() {
|
|
68
88
|
const handlers = new Map();
|
|
@@ -80,159 +100,10 @@ function installSignalForwarding() {
|
|
|
80
100
|
};
|
|
81
101
|
}
|
|
82
102
|
|
|
83
|
-
function isLegacyInvocation(argv) {
|
|
84
|
-
return argv.includes("--record") || argv.includes("--init");
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function privateDirectory(target) {
|
|
88
|
-
fs.mkdirSync(target, { recursive: true, mode: 0o700 });
|
|
89
|
-
try { fs.chmodSync(target, 0o700); } catch { /* Non-POSIX filesystem. */ }
|
|
90
|
-
return target;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function defaultOutputRoot() {
|
|
94
|
-
if (bootstrapMetadata?.defaultOutputRoot) return bootstrapMetadata.defaultOutputRoot;
|
|
95
|
-
const agentRoot = process.env.PI_CODING_AGENT_DIR || path.join(os.homedir(), ".pi", "agent");
|
|
96
|
-
return path.join(agentRoot, "benchmarks", "piagent");
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function createRunId(suiteId) {
|
|
100
|
-
const timestamp = new Date().toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
101
|
-
return `${suiteId}-${timestamp}-${crypto.randomBytes(3).toString("hex")}`;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function ensureEmptyOutput(target) {
|
|
105
|
-
if (fs.existsSync(target) && fs.readdirSync(target).length > 0) fail(`Output directory is not empty: ${target}`, 1);
|
|
106
|
-
return privateDirectory(target);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function benchmarkRunKey(value) {
|
|
110
|
-
return `${value.scenarioId ?? value.scenario?.id}\0${value.surface}\0${value.repeat}`;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function samePairedBlock(left, right) {
|
|
114
|
-
return left?.scenario?.id === right?.scenario?.id && left?.repeat === right?.repeat;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function pairedChunk(order, maximum) {
|
|
118
|
-
if (maximum === undefined || order.length <= maximum) return order;
|
|
119
|
-
let length = maximum;
|
|
120
|
-
while (length > 0 && samePairedBlock(order[length - 1], order[length])) length -= 1;
|
|
121
|
-
if (length === 0) fail(`--max-sessions ${maximum} would split the first paired benchmark block; increase the chunk size`, 1);
|
|
122
|
-
return order.slice(0, length);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function readJsonFile(file, label) {
|
|
126
|
-
try {
|
|
127
|
-
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
128
|
-
} catch (error) {
|
|
129
|
-
fail(`Cannot read ${label} ${file}: ${error.message}`, 1);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function resolveResumeRunRoot(input) {
|
|
134
|
-
const target = path.resolve(input);
|
|
135
|
-
try {
|
|
136
|
-
const stat = fs.statSync(target);
|
|
137
|
-
if (stat.isDirectory()) return target;
|
|
138
|
-
if (stat.isFile()) return path.dirname(target);
|
|
139
|
-
} catch (error) {
|
|
140
|
-
fail(`Cannot resume benchmark; path does not exist: ${target}`, 1);
|
|
141
|
-
}
|
|
142
|
-
fail(`Cannot resume benchmark; path is not a file or directory: ${target}`, 1);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function loadResumeState(input) {
|
|
146
|
-
const runRoot = resolveResumeRunRoot(input);
|
|
147
|
-
const releaseRunLock = acquireBenchmarkRunLock(runRoot, "resume-pending");
|
|
148
|
-
try {
|
|
149
|
-
const manifestPath = path.join(runRoot, "run-manifest.json");
|
|
150
|
-
if (!fs.existsSync(manifestPath)) {
|
|
151
|
-
fail(`Cannot resume ${runRoot}: missing run-manifest.json. This run was created before resume metadata was written, so its root seed cannot be recovered safely. Start a new run with --max-sessions or --max-runtime-minutes to make it resumable.`, 1);
|
|
152
|
-
}
|
|
153
|
-
const manifest = readJsonFile(manifestPath, "benchmark resume manifest");
|
|
154
|
-
if (fs.existsSync(path.join(runRoot, "stopped.json"))) fail(`Cannot resume ${runRoot}: the paired release stop is terminal`, 1);
|
|
155
|
-
if (manifest?.schemaVersion !== 1 || typeof manifest.runId !== "string") {
|
|
156
|
-
fail(`Cannot resume ${runRoot}: run-manifest.json has an unsupported shape`, 1);
|
|
157
|
-
}
|
|
158
|
-
const ledger = benchmarkLedgerCheckpoint(
|
|
159
|
-
manifest.ledger,
|
|
160
|
-
inspectBenchmarkLedger(path.join(runRoot, "runs.jsonl")),
|
|
161
|
-
"benchmark resume ledger"
|
|
162
|
-
);
|
|
163
|
-
const pendingPath = path.join(runRoot, "pending-record.json");
|
|
164
|
-
const pendingRecord = fs.existsSync(pendingPath) ? readJsonFile(pendingPath, "benchmark pending record") : null;
|
|
165
|
-
const measuredPath = path.join(runRoot, "measured-record-ready.json");
|
|
166
|
-
const measuredReady = fs.existsSync(measuredPath) ? readJsonFile(measuredPath, "measured benchmark record") : null;
|
|
167
|
-
return {
|
|
168
|
-
runRoot,
|
|
169
|
-
manifest,
|
|
170
|
-
completedRuns: ledger.records,
|
|
171
|
-
ledgerBinding: ledger.binding,
|
|
172
|
-
recoveredLedgerSuffix: ledger.recovered,
|
|
173
|
-
pendingRecord,
|
|
174
|
-
measuredReady,
|
|
175
|
-
releaseRunLock
|
|
176
|
-
};
|
|
177
|
-
} catch (error) {
|
|
178
|
-
releaseRunLock();
|
|
179
|
-
throw error;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function sameStringList(left, right) {
|
|
184
|
-
return Array.isArray(left)
|
|
185
|
-
&& Array.isArray(right)
|
|
186
|
-
&& left.length === right.length
|
|
187
|
-
&& left.every((value, index) => value === right[index]);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function formatDuration(ms) {
|
|
191
|
-
const totalSeconds = Math.max(0, Math.round(ms / 1_000));
|
|
192
|
-
const hours = Math.floor(totalSeconds / 3600);
|
|
193
|
-
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
194
|
-
const seconds = totalSeconds % 60;
|
|
195
|
-
if (hours > 0) return `${hours}h${String(minutes).padStart(2, "0")}m`;
|
|
196
|
-
if (minutes > 0) return `${minutes}m${String(seconds).padStart(2, "0")}s`;
|
|
197
|
-
return `${seconds}s`;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function executionOrder(suite, repeats, surfaces, rootSeed) {
|
|
201
|
-
const order = [];
|
|
202
|
-
for (let repeat = 1; repeat <= repeats; repeat += 1) {
|
|
203
|
-
const scenarios = suite.schemaVersion === 2
|
|
204
|
-
? [...suite.scenarios].sort((left, right) => {
|
|
205
|
-
const rank = (scenario) => crypto.createHmac("sha256", rootSeed).update(`order\0${repeat}\0${scenario.id}`).digest("hex");
|
|
206
|
-
return rank(left).localeCompare(rank(right));
|
|
207
|
-
})
|
|
208
|
-
: suite.scenarios;
|
|
209
|
-
for (const [index, scenario] of scenarios.entries()) {
|
|
210
|
-
const reverse = suite.schemaVersion === 2
|
|
211
|
-
? (crypto.createHmac("sha256", rootSeed).update(`surface\0${repeat}\0${scenario.id}`).digest()[0] & 1) === 1
|
|
212
|
-
: (repeat + index) % 2 !== 0;
|
|
213
|
-
const ordered = reverse ? [...surfaces].reverse() : surfaces;
|
|
214
|
-
for (const surface of ordered) order.push({ scenario, surface, repeat });
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
return order;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
async function confirmPlan(message) {
|
|
221
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) fail("Refusing to start billed model runs without --yes in a non-interactive terminal", 1);
|
|
222
|
-
const terminal = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
223
|
-
try {
|
|
224
|
-
const answer = await terminal.question(`${message}\nContinue? [y/N] `);
|
|
225
|
-
return /^(?:y|yes)$/i.test(answer.trim());
|
|
226
|
-
} finally {
|
|
227
|
-
terminal.close();
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
103
|
async function runLegacy(argv) {
|
|
232
104
|
const result = await runCommand("bash", [path.join(packageRoot, "scripts", "quality-benchmark.sh"), ...argv], { cwd: process.cwd(), inherit: true });
|
|
233
105
|
process.exitCode = result.code;
|
|
234
106
|
}
|
|
235
|
-
|
|
236
107
|
async function main() {
|
|
237
108
|
const argv = process.argv.slice(2);
|
|
238
109
|
if (isLegacyInvocation(argv)) return runLegacy(argv);
|
|
@@ -264,6 +135,7 @@ async function main() {
|
|
|
264
135
|
options.timeoutSeconds = manifest.timeoutSeconds;
|
|
265
136
|
options.infrastructureRetries = manifest.infrastructureRetries;
|
|
266
137
|
options.retryDelaySeconds = manifest.retryDelaySeconds;
|
|
138
|
+
options.stopAfterFailedPair = manifest.stopAfterFailedPair === true;
|
|
267
139
|
options.output = resumeState.runRoot;
|
|
268
140
|
}
|
|
269
141
|
if (options.replayFailures) {
|
|
@@ -283,14 +155,43 @@ async function main() {
|
|
|
283
155
|
evidenceComplete: bootstrapMetadata?.replay?.evidenceComplete ?? replay.source.evidenceComplete
|
|
284
156
|
};
|
|
285
157
|
}
|
|
286
|
-
if (bootstrapMetadata?.suite?.
|
|
158
|
+
if (bootstrapMetadata?.suite?.builtInId) options.suite = bootstrapMetadata.suite.builtInId;
|
|
159
|
+
else if (bootstrapMetadata?.suite?.snapshot) options.suite = bootstrapMetadata.suite.snapshot;
|
|
287
160
|
if (options.help) {
|
|
288
161
|
process.stdout.write(benchmarkUsage);
|
|
289
162
|
return;
|
|
290
163
|
}
|
|
291
164
|
piagentTreatment(options.piagentTreatment);
|
|
292
|
-
const { suite, manifestPath, suiteRoot } = loadBenchmarkSuite(options.suite, packageRoot);
|
|
165
|
+
const { suite, manifestPath, suiteRoot, builtInId } = loadBenchmarkSuite(options.suite, packageRoot);
|
|
293
166
|
validateBenchmarkSuiteFiles(suite, suiteRoot);
|
|
167
|
+
if (bootstrapMetadata && bootstrapMetadata.suite.builtInId !== builtInId) {
|
|
168
|
+
fail("Frozen benchmark suite origin no longer matches its canonical built-in identity", 1);
|
|
169
|
+
}
|
|
170
|
+
const canonicalProductionSuite = builtInId === "production-v1";
|
|
171
|
+
const productionSpendControlPath = path.join(suiteRoot, "spend-control.v1.json");
|
|
172
|
+
const productionSpendControl = canonicalProductionSuite || fs.existsSync(productionSpendControlPath)
|
|
173
|
+
? readJsonFile(productionSpendControlPath, "production spend-control contract")
|
|
174
|
+
: null;
|
|
175
|
+
const productionExpectedSessions = productionSpendControl
|
|
176
|
+
&& Number.isSafeInteger(productionSpendControl.execution?.repeats)
|
|
177
|
+
&& Array.isArray(productionSpendControl.execution?.surfaces)
|
|
178
|
+
? suite.scenarios.length * productionSpendControl.execution.repeats * productionSpendControl.execution.surfaces.length
|
|
179
|
+
: undefined;
|
|
180
|
+
const productionSpendControlErrors = productionSpendControl
|
|
181
|
+
? productionSpendControlValidationErrors(productionSpendControl, {
|
|
182
|
+
suiteId: suite.id,
|
|
183
|
+
expectedSessions: productionExpectedSessions,
|
|
184
|
+
requireHostReadiness: canonicalProductionSuite
|
|
185
|
+
&& suite.releaseGate?.requireHostReadinessForClaim === true
|
|
186
|
+
})
|
|
187
|
+
: [];
|
|
188
|
+
if (productionSpendControlErrors.length > 0) {
|
|
189
|
+
fail(`Production spend-control contract is invalid (${productionSpendControlErrors.join(", ")})`, 1);
|
|
190
|
+
}
|
|
191
|
+
const productionAllStageBoundaries = productionSpendControl
|
|
192
|
+
? productionSpendControl.stages.map((stage) => stage.cumulativeSessions)
|
|
193
|
+
: [];
|
|
194
|
+
const productionStageBoundaries = productionAllStageBoundaries.slice(1);
|
|
294
195
|
const assuranceEvidence = loadBenchmarkAssuranceEvidence(suite, suiteRoot);
|
|
295
196
|
const declaredScenarioCount = suite.scenarios.length;
|
|
296
197
|
if (options.scenarioIds) {
|
|
@@ -305,12 +206,24 @@ async function main() {
|
|
|
305
206
|
if (missing.length) fail(`Replay report references unknown scenario: ${missing.join(", ")}`, 1);
|
|
306
207
|
suite.scenarios = [...new Set(options.replayRuns.map((run) => run.scenarioId))].map((id) => byId.get(id));
|
|
307
208
|
}
|
|
308
|
-
options
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
209
|
+
applyBenchmarkExecutionDefaults(options, suite);
|
|
210
|
+
const productionFullMatrixRequested = Boolean(productionSpendControl)
|
|
211
|
+
&& !options.replayRuns
|
|
212
|
+
&& suite.scenarios.length === declaredScenarioCount;
|
|
213
|
+
if (productionFullMatrixRequested) {
|
|
214
|
+
const spendExecution = productionSpendControl.execution;
|
|
215
|
+
if (options.seed === undefined) options.seed = productionSpendControl.rootSeed;
|
|
216
|
+
if (options.seed !== productionSpendControl.rootSeed) fail("Production spend control requires its frozen root seed", 1);
|
|
217
|
+
if (!sameStringList(options.surfaces, spendExecution.surfaces)) fail("Production spend control requires its frozen surface order", 1);
|
|
218
|
+
if ((options.model ?? null) !== spendExecution.model) fail("Production spend control requires its frozen model", 1);
|
|
219
|
+
if ((options.thinking ?? null) !== spendExecution.thinking) fail("Production spend control requires its frozen thinking level", 1);
|
|
220
|
+
if (options.repeats !== spendExecution.repeats) fail("Production spend control requires its frozen repeat count", 1);
|
|
221
|
+
if (options.infrastructureRetries !== spendExecution.infrastructureRetries) fail("Production spend control requires zero infrastructure retries", 1);
|
|
222
|
+
}
|
|
312
223
|
if (options.stopAfterFailedPair && !Number.isFinite(suite.releaseGate?.minimumOutcomeScoreExclusive)) fail("--stop-after-failed-pair requires a suite outcome floor", 1);
|
|
313
224
|
if (options.surfaces.includes("codex-cli")) {
|
|
225
|
+
options.model = options.model ?? "openai-codex/gpt-5.6-luna";
|
|
226
|
+
options.thinking = options.thinking ?? "medium";
|
|
314
227
|
codexModelName(options.model);
|
|
315
228
|
codexThinkingEffort(options.thinking);
|
|
316
229
|
}
|
|
@@ -334,9 +247,28 @@ async function main() {
|
|
|
334
247
|
repeat: run.repeat
|
|
335
248
|
}))
|
|
336
249
|
: executionOrder(suite, options.repeats, options.surfaces, rootSeed);
|
|
250
|
+
const productionSpendControlled = productionFullMatrixRequested;
|
|
251
|
+
const productionHostReadinessRequired = productionSpendControlled
|
|
252
|
+
&& canonicalProductionSuite
|
|
253
|
+
&& suite.releaseGate?.requireHostReadinessForClaim === true;
|
|
254
|
+
const productionHostReadinessPolicy = productionHostReadinessRequired
|
|
255
|
+
? productionSpendControl.hostReadiness
|
|
256
|
+
: null;
|
|
257
|
+
const productionHostReadinessPolicyDigest = productionHostReadinessRequired
|
|
258
|
+
? benchmarkHostReadinessPolicyDigest(productionHostReadinessPolicy)
|
|
259
|
+
: null;
|
|
260
|
+
const productionReleaseClaimRun = productionSpendControlled
|
|
261
|
+
&& suite.schemaVersion === 2
|
|
262
|
+
&& suite.releaseGate?.requireEfficiencyClaim === true
|
|
263
|
+
&& suite.releaseGate?.requireFullSuiteForClaim === true;
|
|
264
|
+
if (productionSpendControlled && productionStageBoundaries.at(-1) !== fullOrder.length) {
|
|
265
|
+
fail("Production spend control final stage does not match the frozen full execution order", 1);
|
|
266
|
+
}
|
|
267
|
+
let deferredProductionStageApproval;
|
|
337
268
|
if (resumeState) {
|
|
338
269
|
const manifest = resumeState.manifest;
|
|
339
270
|
if (manifest.suiteDigest !== suiteDigest) fail("Cannot resume benchmark: suite files changed since the original run", 1);
|
|
271
|
+
if (productionSpendControlled && !productionGuardBindingMatches(manifest, productionSpendControl)) fail("Cannot resume production benchmark: frozen production guard binding is missing or changed", 1);
|
|
340
272
|
if (manifest.rootSeed !== rootSeed) fail("Cannot resume benchmark: root seed mismatch", 1);
|
|
341
273
|
if (manifest.repeats !== options.repeats) fail("Cannot resume benchmark: repeat count mismatch", 1);
|
|
342
274
|
if (!sameStringList(manifest.surfaces, options.surfaces)) fail("Cannot resume benchmark: surface list mismatch", 1);
|
|
@@ -381,7 +313,104 @@ async function main() {
|
|
|
381
313
|
});
|
|
382
314
|
throw provenanceError;
|
|
383
315
|
}
|
|
316
|
+
const recoveredTerminalStop = durablePairedOutcomeFloorStop({
|
|
317
|
+
enabled: options.stopAfterFailedPair,
|
|
318
|
+
suite,
|
|
319
|
+
runs: resumeState.completedRuns,
|
|
320
|
+
fullOrder
|
|
321
|
+
});
|
|
322
|
+
if (recoveredTerminalStop) {
|
|
323
|
+
for (const marker of ["paused.json", "stage-diagnostic.json", "interrupted.json", "aborted.json"]) {
|
|
324
|
+
fs.rmSync(path.join(resumeState.runRoot, marker), { force: true });
|
|
325
|
+
}
|
|
326
|
+
writePrivateAtomic(path.join(resumeState.runRoot, "stopped.json"), `${JSON.stringify({
|
|
327
|
+
...recoveredTerminalStop,
|
|
328
|
+
runId: manifest.runId,
|
|
329
|
+
completedRuns: resumeState.completedRuns.length,
|
|
330
|
+
expectedRuns: fullOrder.length,
|
|
331
|
+
stoppedAt: new Date().toISOString(),
|
|
332
|
+
resumeAllowed: false,
|
|
333
|
+
recoveredFromAcceptedLedger: true,
|
|
334
|
+
ledger: resumeState.ledgerBinding,
|
|
335
|
+
provenanceStamp: candidateGuard.stamp("resume-terminal-floor")
|
|
336
|
+
}, null, 2)}\n`);
|
|
337
|
+
fail("Cannot resume benchmark: the accepted ledger already contains a terminal paired outcome-floor failure", 1);
|
|
338
|
+
}
|
|
339
|
+
if (productionSpendControlled) {
|
|
340
|
+
if (productionHostReadinessRequired) {
|
|
341
|
+
if (manifest.hostReadinessPolicyDigest !== productionHostReadinessPolicyDigest
|
|
342
|
+
&& resumeState.completedRuns.length < fullOrder.length) {
|
|
343
|
+
fail("Cannot resume production benchmark: host-readiness policy binding is missing or changed. Start a new staged run.", 1);
|
|
344
|
+
}
|
|
345
|
+
if (resumeState.completedRuns.length < fullOrder.length) {
|
|
346
|
+
assertExistingBenchmarkHostReadiness({
|
|
347
|
+
policy: productionHostReadinessPolicy,
|
|
348
|
+
receipts: manifest.hostReadinessReceipts,
|
|
349
|
+
completedRuns: resumeState.completedRuns.length,
|
|
350
|
+
authorizedThroughRuns: manifest.stageControl?.authorizedThroughRuns,
|
|
351
|
+
runId: manifest.runId,
|
|
352
|
+
configurationDigest: manifest.configurationDigest,
|
|
353
|
+
stageBoundaries: productionAllStageBoundaries
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
const stageDisposition = productionStageResumeDisposition(manifest.stageControl, {
|
|
358
|
+
completedRuns: resumeState.completedRuns.length,
|
|
359
|
+
ledger: resumeState.ledgerBinding,
|
|
360
|
+
stageBoundaries: productionAllStageBoundaries
|
|
361
|
+
});
|
|
362
|
+
if (!stageDisposition.passed) {
|
|
363
|
+
fail(`Cannot resume production benchmark: invalid durable stage-control state (${stageDisposition.errors.join(", ")}). Start a new staged run.`, 1);
|
|
364
|
+
}
|
|
365
|
+
if (stageDisposition.requiresStageGate && resumeState.completedRuns.length < fullOrder.length) {
|
|
366
|
+
const recoveredBoundaryReason = `max-sessions:recovered:${resumeState.completedRuns.length}`;
|
|
367
|
+
const resumeStageDiagnostic = buildBenchmarkStageDiagnostic({
|
|
368
|
+
runId: manifest.runId,
|
|
369
|
+
reason: manifest.stageControl.pendingBoundary?.reason ?? recoveredBoundaryReason,
|
|
370
|
+
runs: resumeState.completedRuns,
|
|
371
|
+
fullOrder,
|
|
372
|
+
candidateSurface: comparison.candidateSurface,
|
|
373
|
+
baselineSurface: comparison.baselineSurface,
|
|
374
|
+
requestedModel: options.model,
|
|
375
|
+
requestedThinking: options.thinking,
|
|
376
|
+
suite,
|
|
377
|
+
manifest,
|
|
378
|
+
hostReadinessPolicy: productionHostReadinessPolicy,
|
|
379
|
+
hostReadinessStageBoundaries: productionAllStageBoundaries
|
|
380
|
+
});
|
|
381
|
+
writePrivateAtomic(path.join(resumeState.runRoot, "stage-diagnostic.json"), `${JSON.stringify(resumeStageDiagnostic, null, 2)}\n`);
|
|
382
|
+
if (!resumeStageDiagnostic.stageAdvanceAllowed) {
|
|
383
|
+
fail(`Cannot resume production benchmark: the provider-free stage gate blocked further paid sessions (${resumeStageDiagnostic.blockingReasons.join(", ")}). Fix the candidate and start a new staged run.`, 1);
|
|
384
|
+
}
|
|
385
|
+
const currentWindow = manifest.stageControl.authorizedThroughRuns;
|
|
386
|
+
const nextAuthorizedThroughRuns = resumeState.completedRuns.length < currentWindow
|
|
387
|
+
? currentWindow
|
|
388
|
+
: productionStageBoundaries.find((boundary) => boundary > resumeState.completedRuns.length);
|
|
389
|
+
if (!Number.isSafeInteger(nextAuthorizedThroughRuns)) {
|
|
390
|
+
fail("Cannot resume production benchmark: no bounded spend-control window remains", 1);
|
|
391
|
+
}
|
|
392
|
+
const requiredResumeSessions = nextAuthorizedThroughRuns - resumeState.completedRuns.length;
|
|
393
|
+
if (!options.dryRun && options.maxSessions !== requiredResumeSessions) {
|
|
394
|
+
fail(`Production spend control requires --max-sessions ${requiredResumeSessions} for the next authorized window; durable stage state was not changed.`, 1);
|
|
395
|
+
}
|
|
396
|
+
if (!options.dryRun) {
|
|
397
|
+
deferredProductionStageApproval = {
|
|
398
|
+
completedRuns: resumeState.completedRuns.length,
|
|
399
|
+
authorizedThroughRuns: nextAuthorizedThroughRuns
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
} else if (stageDisposition.requiresStageGate) {
|
|
403
|
+
// A crash after the final accepted record must not change the verdict by
|
|
404
|
+
// applying an early-stage heuristic. The complete report gates the same
|
|
405
|
+
// frozen ledger without starting another provider session.
|
|
406
|
+
manifest.ledger = resumeState.ledgerBinding;
|
|
407
|
+
writeBenchmarkRunManifest(resumeState.runRoot, manifest);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
384
410
|
}
|
|
411
|
+
const productionFinalizationOnly = productionSpendControlled
|
|
412
|
+
&& Boolean(resumeState)
|
|
413
|
+
&& resumeState.completedRuns.length === fullOrder.length;
|
|
385
414
|
const pendingOrder = resumeState
|
|
386
415
|
? fullOrder.filter((item) => !resumeState.completedKeys.has(benchmarkRunKey(item)))
|
|
387
416
|
: fullOrder;
|
|
@@ -416,24 +445,64 @@ async function main() {
|
|
|
416
445
|
const codexPlan = options.surfaces.includes("codex-cli")
|
|
417
446
|
? `\n codex: ${options.codexMode} mode · model ${codexModelName(options.model)} · effort ${codexThinkingEffort(options.thinking)}${options.codexMode === "controlled" ? " · isolated home" : ""}`
|
|
418
447
|
: "";
|
|
448
|
+
const nativeWarning = options.surfaces.includes("codex-cli") && options.codexMode === "native"
|
|
449
|
+
? "\nNative Codex mode loads the operator's global AGENTS.md, configuration, rules, hooks, MCP servers, and plugins."
|
|
450
|
+
: "";
|
|
419
451
|
if (options.dryRun) {
|
|
420
452
|
process.stdout.write(`${plan}${codexPlan}\n manifest: ${manifestPath}\nDRY RUN: no model session started.\n`);
|
|
421
453
|
return;
|
|
422
454
|
}
|
|
455
|
+
if (productionSpendControlled) {
|
|
456
|
+
if (options.stopAfterFailedPair !== productionSpendControl.execution.stopAfterFailedPair) {
|
|
457
|
+
fail("Production spend control requires --stop-after-failed-pair before any provider session", 1);
|
|
458
|
+
}
|
|
459
|
+
const completedRuns = resumeState?.completedRuns.length ?? 0;
|
|
460
|
+
const authorizedThroughRuns = deferredProductionStageApproval?.authorizedThroughRuns
|
|
461
|
+
?? resumeState?.manifest.stageControl?.authorizedThroughRuns
|
|
462
|
+
?? productionStageBoundaries[0];
|
|
463
|
+
const requiredChunkSessions = authorizedThroughRuns - completedRuns;
|
|
464
|
+
if (!options.preflightOnly && !productionFinalizationOnly
|
|
465
|
+
&& (!Number.isSafeInteger(requiredChunkSessions) || requiredChunkSessions <= 0
|
|
466
|
+
|| options.maxSessions !== requiredChunkSessions)) {
|
|
467
|
+
fail(`Production spend control requires --max-sessions ${requiredChunkSessions} for the current authorized window; refusing an unbounded or oversized paid chunk.`, 1);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
423
470
|
if (!bootstrapMetadata) fail("Modern billed benchmarks must start through scripts/benchmark-runner.mjs so execution assets are frozen", 1);
|
|
471
|
+
if (productionReleaseClaimRun && bootstrapMetadata.sourceIdentity.dirty !== false) {
|
|
472
|
+
fail("Production benchmark requires a clean release source before auth, tool preflight, or any provider session", 1);
|
|
473
|
+
}
|
|
424
474
|
if (options.replayFailures && bootstrapMetadata.replay?.evidenceComplete !== true) {
|
|
425
475
|
fail("Billed replay requires the original run-manifest.json and runs.jsonl beside the source report", 1);
|
|
426
476
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
477
|
+
if (!options.preflightOnly) {
|
|
478
|
+
if (productionFinalizationOnly) {
|
|
479
|
+
process.stdout.write(`${plan}${codexPlan}\n mode: provider-free finalization of the complete frozen ledger\n`);
|
|
480
|
+
} else if (options.yes) {
|
|
481
|
+
process.stdout.write(`${plan}${codexPlan}${nativeWarning}\n`);
|
|
482
|
+
} else if (!(await confirmPlan(`${plan}${codexPlan}${nativeWarning}\nThis may use paid model quota.`))) {
|
|
483
|
+
process.stdout.write("Benchmark cancelled; no model session started.\n");
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
const runId = resumeState?.manifest.runId ?? createRunId(suite.id);
|
|
488
|
+
const runtimeCommands = productionFinalizationOnly
|
|
489
|
+
? frozenRuntimeCommandsForFinalization(resumeState.manifest, options.surfaces)
|
|
490
|
+
: {
|
|
491
|
+
pi: benchmarkCommandIdentity(piCommand, { cwd: bootstrapMetadata?.originalCwd ?? process.cwd() }),
|
|
492
|
+
codex: options.surfaces.includes("codex-cli")
|
|
493
|
+
? benchmarkCommandIdentity(codexCommand, { cwd: bootstrapMetadata?.originalCwd ?? process.cwd() })
|
|
494
|
+
: null,
|
|
495
|
+
node: benchmarkCommandIdentity(process.execPath),
|
|
496
|
+
git: benchmarkCommandIdentity("git"),
|
|
497
|
+
bash: benchmarkCommandIdentity("bash")
|
|
498
|
+
};
|
|
436
499
|
const environmentPolicy = benchmarkEnvironmentPolicy();
|
|
500
|
+
const configurationPiAgentHome = productionFinalizationOnly
|
|
501
|
+
? resumeState.manifest.piAgentHome?.identity
|
|
502
|
+
: bootstrapMetadata.piAgentHome.identity;
|
|
503
|
+
const configurationCodexCredential = productionFinalizationOnly
|
|
504
|
+
? resumeState.manifest.codexCredentialIdentity ?? null
|
|
505
|
+
: bootstrapMetadata.codexCredential?.identity ?? null;
|
|
437
506
|
const configuration = {
|
|
438
507
|
schemaVersion: 1,
|
|
439
508
|
source: bootstrapMetadata.sourceIdentity,
|
|
@@ -442,8 +511,9 @@ async function main() {
|
|
|
442
511
|
runtimeDependencyDigest: bootstrapMetadata.runtimeDependencies?.digest ?? null,
|
|
443
512
|
runtimeCommands,
|
|
444
513
|
environmentPolicy,
|
|
445
|
-
|
|
446
|
-
|
|
514
|
+
...(productionHostReadinessRequired ? { hostReadinessPolicyDigest: productionHostReadinessPolicyDigest } : {}),
|
|
515
|
+
piAgentHome: configurationPiAgentHome,
|
|
516
|
+
codexCredential: configurationCodexCredential,
|
|
447
517
|
rootSeedDigest,
|
|
448
518
|
surfaces: options.surfaces,
|
|
449
519
|
model: options.model ?? null,
|
|
@@ -459,6 +529,10 @@ async function main() {
|
|
|
459
529
|
order: fullOrder.map((item) => ({ scenarioId: item.scenario.id, surface: item.surface, repeat: item.repeat }))
|
|
460
530
|
};
|
|
461
531
|
const configurationDigest = crypto.createHash("sha256").update(JSON.stringify(configuration)).digest("hex");
|
|
532
|
+
const source = bootstrapMetadata?.sourceIdentity;
|
|
533
|
+
if (!source) fail("Modern benchmark is missing its frozen Git source identity", 1);
|
|
534
|
+
const { receipt: providerFreeEvidence, binding: providerFreeEvidenceBinding } = await prepareProductionProviderFreeEvidence({
|
|
535
|
+
required: productionSpendControl?.productionGuards?.providerFreeEvidence?.requiredBeforeFirstPaidSession === true, packageRoot, bootstrapMetadata, candidateProvenance: candidateGuard.provenance, configurationDigest, runCommand, resumedReceipt: resumeState ? resumeState.manifest.providerFreeEvidence ?? null : undefined });
|
|
462
536
|
piCommand = runtimeCommands.pi.resolvedPath;
|
|
463
537
|
if (runtimeCommands.codex) codexCommand = runtimeCommands.codex.resolvedPath;
|
|
464
538
|
if (resumeState && JSON.stringify(resumeState.manifest.runtimeCommands ?? null) !== JSON.stringify(runtimeCommands)) {
|
|
@@ -475,48 +549,79 @@ async function main() {
|
|
|
475
549
|
completedKeys: resumeState.completedKeys
|
|
476
550
|
});
|
|
477
551
|
}
|
|
552
|
+
let hostReadinessReceipt = null;
|
|
553
|
+
const currentAuthorizedThroughRuns = resumeState?.manifest.stageControl?.authorizedThroughRuns
|
|
554
|
+
?? productionStageBoundaries[0];
|
|
555
|
+
const nextAuthorizedThroughRuns = deferredProductionStageApproval?.authorizedThroughRuns
|
|
556
|
+
?? currentAuthorizedThroughRuns;
|
|
557
|
+
if (productionHostReadinessRequired && !productionFinalizationOnly) {
|
|
558
|
+
hostReadinessReceipt = await collectReadyBenchmarkHostReadiness({
|
|
559
|
+
policy: productionHostReadinessPolicy,
|
|
560
|
+
completedRuns: resumeState?.completedRuns.length ?? 0,
|
|
561
|
+
authorizedThroughRuns: nextAuthorizedThroughRuns,
|
|
562
|
+
runId,
|
|
563
|
+
configurationDigest,
|
|
564
|
+
stageBoundaries: productionAllStageBoundaries,
|
|
565
|
+
existingReceipts: resumeState?.manifest.hostReadinessReceipts ?? []
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
const assertHostReadinessStartReady = () => assertBenchmarkHostReadinessStartReady(hostReadinessReceipt, {
|
|
569
|
+
policy: productionHostReadinessPolicy,
|
|
570
|
+
runId,
|
|
571
|
+
configurationDigest
|
|
572
|
+
});
|
|
478
573
|
const executionGuard = createBenchmarkExecutionGuard({
|
|
479
574
|
candidateGuard,
|
|
480
575
|
suiteRoot,
|
|
481
576
|
suiteIdentity: bootstrapMetadata?.suite?.identity ?? suiteIdentity,
|
|
482
|
-
piAgentHome: bootstrapMetadata?.piAgentHome,
|
|
483
|
-
codexCredential: bootstrapMetadata?.codexCredential,
|
|
577
|
+
piAgentHome: productionFinalizationOnly ? null : bootstrapMetadata?.piAgentHome,
|
|
578
|
+
codexCredential: productionFinalizationOnly ? null : bootstrapMetadata?.codexCredential,
|
|
484
579
|
runtimeDependencies: bootstrapMetadata?.runtimeDependencies,
|
|
485
|
-
commands: runtimeCommands
|
|
580
|
+
commands: runtimeCommands,
|
|
581
|
+
verifyCommandAssets: !productionFinalizationOnly
|
|
486
582
|
});
|
|
487
|
-
assertBenchmarkPiCredentialReady(bootstrapMetadata.piAgentHome.credentialReadiness, options.model);
|
|
488
|
-
assertBenchmarkPiCredentialWritebackPolicy(bootstrapMetadata.piAgentHome);
|
|
489
|
-
piRuntimeHome = createBenchmarkPiRuntimeHome(bootstrapMetadata.piAgentHome);
|
|
490
|
-
const preflightAssetError = executionGuard.check("before-preflight", [piRuntimeHome]);
|
|
491
|
-
if (preflightAssetError) throw preflightAssetError;
|
|
492
|
-
codexRuntime = createCodexRuntime(options);
|
|
493
583
|
let runtime;
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
584
|
+
let codexCredentialBridge;
|
|
585
|
+
if (productionFinalizationOnly) {
|
|
586
|
+
runtime = resumeState.manifest.preflightRuntime;
|
|
587
|
+
if (!runtime || typeof runtime.gitVersion !== "string" || typeof runtime.piVersion !== "string"
|
|
588
|
+
|| !Array.isArray(runtime.codexDisabledFeatures)
|
|
589
|
+
|| (options.surfaces.includes("codex-cli") && typeof runtime.codexVersion !== "string")) {
|
|
590
|
+
fail("Cannot finalize production benchmark provider-free: frozen preflight runtime evidence is missing or invalid", 1);
|
|
591
|
+
}
|
|
592
|
+
codexCredentialBridge = resumeState.manifest.codexCredentialBridge ?? null;
|
|
593
|
+
const finalizationAssetError = executionGuard.check("provider-free-finalization");
|
|
594
|
+
if (finalizationAssetError) throw finalizationAssetError;
|
|
595
|
+
} else {
|
|
596
|
+
assertBenchmarkPiCredentialReady(bootstrapMetadata.piAgentHome.credentialReadiness, options.model);
|
|
597
|
+
assertBenchmarkPiCredentialWritebackPolicy(bootstrapMetadata.piAgentHome);
|
|
598
|
+
piRuntimeHome = createBenchmarkPiRuntimeHome(bootstrapMetadata.piAgentHome);
|
|
599
|
+
const preflightAssetError = executionGuard.check("before-preflight", [piRuntimeHome]);
|
|
600
|
+
if (preflightAssetError) throw preflightAssetError;
|
|
601
|
+
codexRuntime = createCodexRuntime(options);
|
|
602
|
+
try { runtime = await withBenchmarkPiCredentialWriteback(bootstrapMetadata.piAgentHome, piRuntimeHome, () => benchmarkPreflight({ runCommand, packageRoot, piCommand, piEnvironment: benchmarkEnvironment({ PI_CODING_AGENT_DIR: piRuntimeHome.path }), codexCommand, gitCommand: runtimeCommands.git.resolvedPath, surfaces: options.surfaces, codexMode: options.codexMode, codexRuntime })); }
|
|
603
|
+
catch (error) { preservePiRuntime ||= error.code === "BENCHMARK_PI_CREDENTIAL_RECONCILIATION_FAILED"; throw error; }
|
|
604
|
+
const postPreflightAssetError = executionGuard.check("after-preflight", [piRuntimeHome]);
|
|
605
|
+
if (postPreflightAssetError) throw postPreflightAssetError;
|
|
606
|
+
resetBenchmarkPiRuntimeEphemeralState(piRuntimeHome);
|
|
607
|
+
codexCredentialBridge = codexRuntime.credentialBridge;
|
|
608
|
+
if (resumeState && resumeState.manifest.preflightRuntime !== undefined
|
|
609
|
+
&& JSON.stringify(resumeState.manifest.preflightRuntime) !== JSON.stringify(runtime)) {
|
|
610
|
+
fail("Cannot resume benchmark: provider-free preflight runtime evidence changed since the original run", 1);
|
|
611
|
+
}
|
|
612
|
+
if (resumeState && resumeState.manifest.codexCredentialBridge !== undefined
|
|
613
|
+
&& resumeState.manifest.codexCredentialBridge !== codexCredentialBridge) {
|
|
614
|
+
fail("Cannot resume benchmark: Codex credential bridge changed since the original run", 1);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
assertHostReadinessStartReady();
|
|
501
618
|
if (options.preflightOnly) {
|
|
502
|
-
const receipt = benchmarkPreflightReceipt({ packageVersion: packageManifest.version, source, candidateProvenance: candidateGuard.report(), suite, suiteDigest, runtimeDependencies: bootstrapMetadata.runtimeDependencies, runtimeCommands, environmentPolicy, configurationDigest, rootSeedDigest, options, runtime });
|
|
619
|
+
const receipt = benchmarkPreflightReceipt({ packageVersion: packageManifest.version, source, candidateProvenance: candidateGuard.report(), suite, suiteDigest, runtimeDependencies: bootstrapMetadata.runtimeDependencies, runtimeCommands, environmentPolicy, configurationDigest, rootSeedDigest, options, runtime, hostReadinessPolicyDigest: productionHostReadinessPolicyDigest, hostReadiness: hostReadinessReceipt, providerFreeEvidence });
|
|
503
620
|
process.stdout.write(options.json ? `${JSON.stringify(receipt, null, 2)}\n` : `${plan}${codexPlan}\nPREFLIGHT READY: no model session started.\n${JSON.stringify(receipt, null, 2)}\n`);
|
|
504
621
|
return;
|
|
505
622
|
}
|
|
506
|
-
const nativeWarning = options.surfaces.includes("codex-cli") && options.codexMode === "native"
|
|
507
|
-
? "\nNative Codex mode loads the operator's global AGENTS.md, configuration, rules, hooks, MCP servers, and plugins."
|
|
508
|
-
: "";
|
|
509
|
-
if (options.yes) {
|
|
510
|
-
process.stdout.write(`${plan}${codexPlan}${nativeWarning}\n`);
|
|
511
|
-
} else {
|
|
512
|
-
if (!(await confirmPlan(`${plan}${codexPlan}${nativeWarning}\nThis may use paid model quota.`))) {
|
|
513
|
-
process.stdout.write("Benchmark cancelled; no model session started.\n");
|
|
514
|
-
return;
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
623
|
candidateGuard.freeze();
|
|
518
|
-
const
|
|
519
|
-
const output = options.output ?? path.join(defaultOutputRoot(), runId);
|
|
624
|
+
const output = options.output ?? path.join(defaultOutputRoot(bootstrapMetadata), runId);
|
|
520
625
|
const runRoot = resumeState ? privateDirectory(output) : ensureEmptyOutput(output);
|
|
521
626
|
releaseRunLock ??= acquireBenchmarkRunLock(runRoot, runId);
|
|
522
627
|
privateDirectory(path.join(runRoot, "workspaces"));
|
|
@@ -535,13 +640,17 @@ async function main() {
|
|
|
535
640
|
suite: {
|
|
536
641
|
id: suite.id,
|
|
537
642
|
source: bootstrapMetadata?.suite?.origin ?? manifestPath,
|
|
538
|
-
manifestPath: bootstrapMetadata?.suite?.snapshot ? bootstrapMetadata.suite.origin : null
|
|
643
|
+
manifestPath: bootstrapMetadata?.suite?.snapshot ? bootstrapMetadata.suite.origin : null,
|
|
644
|
+
builtInId
|
|
539
645
|
},
|
|
540
646
|
suiteDigest,
|
|
541
647
|
suiteIdentity,
|
|
542
648
|
candidateProvenance: candidateGuard.provenance,
|
|
543
649
|
runtimeDependencies: bootstrapMetadata?.runtimeDependencies ?? null,
|
|
544
650
|
runtimeCommands,
|
|
651
|
+
preflightRuntime: runtime,
|
|
652
|
+
codexCredentialIdentity: bootstrapMetadata.codexCredential?.identity ?? null,
|
|
653
|
+
codexCredentialBridge,
|
|
545
654
|
configurationDigest,
|
|
546
655
|
environmentPolicy,
|
|
547
656
|
piAgentHome: {
|
|
@@ -569,13 +678,39 @@ async function main() {
|
|
|
569
678
|
retryDelaySeconds: options.retryDelaySeconds,
|
|
570
679
|
stopAfterFailedPair: options.stopAfterFailedPair,
|
|
571
680
|
scenarioIds: options.scenarioIds ?? null,
|
|
681
|
+
...(productionSpendControlled ? {
|
|
682
|
+
productionGuards: productionSpendControl.productionGuards,
|
|
683
|
+
providerFreeEvidence,
|
|
684
|
+
stageControl: createProductionStageControl({
|
|
685
|
+
authorizedThroughRuns: productionStageBoundaries[0],
|
|
686
|
+
generatedAt: startedAt
|
|
687
|
+
}),
|
|
688
|
+
...(productionHostReadinessRequired ? {
|
|
689
|
+
hostReadinessPolicyDigest: productionHostReadinessPolicyDigest,
|
|
690
|
+
hostReadinessReceipts: []
|
|
691
|
+
} : {})
|
|
692
|
+
} : {}),
|
|
572
693
|
order: fullOrder.map((item) => ({
|
|
573
694
|
scenarioId: item.scenario.id,
|
|
574
695
|
surface: item.surface,
|
|
575
696
|
repeat: item.repeat
|
|
576
697
|
}))
|
|
577
698
|
};
|
|
699
|
+
assertHostReadinessStartReady();
|
|
700
|
+
if (productionSpendControlled && deferredProductionStageApproval) {
|
|
701
|
+
manifest.stageControl = approveProductionStageControl(manifest.stageControl, deferredProductionStageApproval);
|
|
702
|
+
}
|
|
703
|
+
if (productionHostReadinessRequired && hostReadinessReceipt) {
|
|
704
|
+
manifest.hostReadinessPolicyDigest = productionHostReadinessPolicyDigest;
|
|
705
|
+
manifest.hostReadinessReceipts = [...(manifest.hostReadinessReceipts ?? []), hostReadinessReceipt];
|
|
706
|
+
}
|
|
578
707
|
writeBenchmarkRunManifest(runRoot, manifest);
|
|
708
|
+
if (resumeState) {
|
|
709
|
+
fs.rmSync(path.join(runRoot, "stage-diagnostic.json"), { force: true });
|
|
710
|
+
if (productionSpendControlled && manifest.stageControl?.state === "window-authorized") {
|
|
711
|
+
fs.rmSync(path.join(runRoot, "paused.json"), { force: true });
|
|
712
|
+
}
|
|
713
|
+
}
|
|
579
714
|
const fullIndexByKey = new Map(fullOrder.map((item, index) => [benchmarkRunKey(item), index + 1]));
|
|
580
715
|
const wallStartedAt = Date.now();
|
|
581
716
|
const runtimeDeadline = options.maxRuntimeMinutes === undefined
|
|
@@ -782,150 +917,24 @@ async function main() {
|
|
|
782
917
|
}
|
|
783
918
|
let finalizationReceipt;
|
|
784
919
|
if (!interruptedSignal && !fatalRunError) {
|
|
920
|
+
if (productionSpendControl?.productionGuards?.providerFreeEvidence?.requiredBeforeFirstPaidSession === true) {
|
|
921
|
+
fatalRunError ??= productionProviderFreeEvidenceError(manifest.providerFreeEvidence, providerFreeEvidenceBinding, "final production provider-free evidence");
|
|
922
|
+
}
|
|
785
923
|
finalizationReceipt = executionGuard.receipt("finalization", [piRuntimeHome]);
|
|
786
|
-
fatalRunError
|
|
924
|
+
fatalRunError ??= finalizationReceipt.error;
|
|
787
925
|
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
const provenanceStamp = finalizationReceipt?.stamp ?? fatalExecutionReceipt?.stamp ?? executionGuard.stamp("fatal", piRuntimeHome ? [piRuntimeHome] : []);
|
|
800
|
-
if (!preservePiRuntime) cleanupBenchmarkPiRuntimeHome(bootstrapMetadata.piAgentHome, piRuntimeHome);
|
|
801
|
-
piRuntimeHome = undefined;
|
|
802
|
-
recoverOrphanedBenchmarkAttempts({ runRoot, manifest, fullOrder, completedKeys: new Set(runs.map(benchmarkRunKey)) });
|
|
803
|
-
cleanupUnretainedWorkspaces(runRoot, options.keepWorkspaces);
|
|
804
|
-
const provenanceFailure = writeBenchmarkAbort(runRoot, { runId, completedRuns: runs.filter(completedBenchmarkRecord).length, expectedRuns: fullOrder.length }, fatalRunError, {
|
|
805
|
-
ledger: ledgerBinding,
|
|
806
|
-
provenanceStamp
|
|
807
|
-
});
|
|
808
|
-
process.stderr.write(provenanceFailure
|
|
809
|
-
? `Benchmark aborted because candidate provenance changed. Partial ledger: ${ledgerPath}\n`
|
|
810
|
-
: `Benchmark aborted after an infrastructure error. Partial ledger: ${ledgerPath}\n`);
|
|
811
|
-
process.exitCode = 1;
|
|
812
|
-
return;
|
|
813
|
-
}
|
|
814
|
-
if (terminalStop) {
|
|
815
|
-
cleanupBenchmarkPiRuntimeHome(bootstrapMetadata.piAgentHome, piRuntimeHome); piRuntimeHome = undefined;
|
|
816
|
-
cleanupUnretainedWorkspaces(runRoot, options.keepWorkspaces);
|
|
817
|
-
for (const marker of ["paused.json", "interrupted.json", "aborted.json"]) fs.rmSync(path.join(runRoot, marker), { force: true });
|
|
818
|
-
writePrivateAtomic(path.join(runRoot, "stopped.json"), `${JSON.stringify({ ...terminalStop, runId, completedRuns: runs.filter(completedBenchmarkRecord).length, expectedRuns: fullOrder.length, stoppedAt: new Date().toISOString(), resumeAllowed: false, ledger: ledgerBinding, provenanceStamp: finalizationReceipt.stamp }, null, 2)}\n`);
|
|
819
|
-
process.stderr.write(`Benchmark terminal-stopped after paired outcome-floor failure. Partial ledger: ${ledgerPath}\n`);
|
|
820
|
-
process.exitCode = 1;
|
|
821
|
-
return;
|
|
822
|
-
}
|
|
823
|
-
const completedRuns = runs.filter(completedBenchmarkRecord);
|
|
824
|
-
if (completedRuns.length < fullOrder.length) {
|
|
825
|
-
piRuntimeHome = undefined;
|
|
826
|
-
cleanupUnretainedWorkspaces(runRoot, options.keepWorkspaces);
|
|
827
|
-
const paused = {
|
|
828
|
-
schemaVersion: 1,
|
|
829
|
-
runId,
|
|
830
|
-
reason: pauseReason ?? "partial-run",
|
|
831
|
-
completedRuns: completedRuns.length,
|
|
832
|
-
expectedRuns: fullOrder.length,
|
|
833
|
-
remainingRuns: fullOrder.length - completedRuns.length,
|
|
834
|
-
pausedAt: new Date().toISOString(),
|
|
835
|
-
resumeCommand: `piagent-benchmark --resume ${runRoot} --yes`,
|
|
836
|
-
ledger: ledgerBinding,
|
|
837
|
-
provenanceStamp: executionGuard.stamp("paused")
|
|
838
|
-
};
|
|
839
|
-
writePrivateAtomic(path.join(runRoot, "paused.json"), `${JSON.stringify(paused, null, 2)}\n`);
|
|
840
|
-
process.stdout.write(`Benchmark paused after ${completedRuns.length}/${fullOrder.length} completed sessions (${paused.reason}).\nResume: ${paused.resumeCommand}\nPartial ledger: ${ledgerPath}\n`);
|
|
841
|
-
return;
|
|
842
|
-
}
|
|
843
|
-
cleanupBenchmarkPiRuntimeHome(bootstrapMetadata.piAgentHome, piRuntimeHome); piRuntimeHome = undefined;
|
|
844
|
-
const report = summarizeBenchmark({
|
|
845
|
-
suite,
|
|
846
|
-
runId,
|
|
847
|
-
startedAt,
|
|
848
|
-
completedAt: new Date().toISOString(),
|
|
849
|
-
repeats: options.repeats,
|
|
850
|
-
environment: {
|
|
851
|
-
platformVersion: packageManifest.version,
|
|
852
|
-
suiteDigest,
|
|
853
|
-
variantRootSeed: suite.scenarios.some((scenario) => scenario.variantGenerator) ? rootSeed : null,
|
|
854
|
-
variantRootSeedDigest: suite.scenarios.some((scenario) => scenario.variantGenerator) ? rootSeedDigest : null,
|
|
855
|
-
executionOrder: suite.schemaVersion === 2 ? "seeded-paired-block-randomized" : "paired-alternating",
|
|
856
|
-
replaySource: options.replaySource ?? null,
|
|
857
|
-
profile: suite.profile,
|
|
858
|
-
requestedModel: options.model ?? null,
|
|
859
|
-
requestedThinking: options.thinking ?? null,
|
|
860
|
-
piagentTreatment: piagentTreatment(options.piagentTreatment),
|
|
861
|
-
treatmentBaseline: lifecycles.length === 1 && lifecycles[0] === "steady-state"
|
|
862
|
-
? options.surfaces.includes("codex-cli")
|
|
863
|
-
? "piagent-initialized-and-onboarded; codex-clean-fixture"
|
|
864
|
-
: "initialized-and-onboarded"
|
|
865
|
-
: "scenario-defined-mixed-lifecycle",
|
|
866
|
-
timeoutSeconds: options.timeoutSeconds,
|
|
867
|
-
nodeVersion: process.version,
|
|
868
|
-
piVersion: runtime.piVersion,
|
|
869
|
-
codexVersion: runtime.codexVersion ?? null,
|
|
870
|
-
codexMode: options.surfaces.includes("codex-cli") ? options.codexMode : null,
|
|
871
|
-
codexAuth: runtime.codexAuth ?? null,
|
|
872
|
-
codexIsolation: options.surfaces.includes("codex-cli")
|
|
873
|
-
? options.codexMode === "controlled" ? "per-session-temporary-home" : "operator-home"
|
|
874
|
-
: null,
|
|
875
|
-
codexCredentialBridge: options.surfaces.includes("codex-cli") ? codexRuntime.credentialBridge : null,
|
|
876
|
-
codexGlobalInstructions: options.surfaces.includes("codex-cli")
|
|
877
|
-
? options.codexMode === "controlled" ? "excluded" : "operator-home"
|
|
878
|
-
: null,
|
|
879
|
-
piGlobalInstructions: "excluded",
|
|
880
|
-
piAgentHome: manifest.piAgentHome,
|
|
881
|
-
usageIntegrity: manifest.tokenClaimsUnavailableReason ?? "measured",
|
|
882
|
-
codexDisabledFeatures: runtime.codexDisabledFeatures,
|
|
883
|
-
surfaces: options.surfaces,
|
|
884
|
-
scenarioSelection: options.scenarioIds ?? null,
|
|
885
|
-
surfaceModels: options.surfaces.includes("codex-cli") ? {
|
|
886
|
-
piagent: options.model,
|
|
887
|
-
"codex-cli": codexModelName(options.model)
|
|
888
|
-
} : { "raw-pi": options.model ?? null, piagent: options.model ?? null },
|
|
889
|
-
modelParityEvidence: options.surfaces.includes("codex-cli") ? "command-line-pinned" : "session-reported",
|
|
890
|
-
gitVersion: runtime.gitVersion,
|
|
891
|
-
source,
|
|
892
|
-
candidateProvenance: candidateGuard.report(),
|
|
893
|
-
suiteIdentity,
|
|
894
|
-
runtimeCommands,
|
|
895
|
-
configurationDigest,
|
|
896
|
-
environmentPolicy,
|
|
897
|
-
runtimeDependencies: bootstrapMetadata?.runtimeDependencies ?? null,
|
|
898
|
-
assuranceEvidence
|
|
899
|
-
},
|
|
900
|
-
runs: completedRuns,
|
|
901
|
-
...comparison
|
|
926
|
+
finalizeBenchmarkRun({
|
|
927
|
+
assuranceEvidence, bootstrapMetadata, candidateGuard, canonicalProductionSuite,
|
|
928
|
+
codexCredentialBridge, comparison, configurationDigest, declaredScenarioCount,
|
|
929
|
+
detachPiRuntimeHome: () => { piRuntimeHome = undefined; },
|
|
930
|
+
environmentPolicy, executionGuard, fatalExecutionReceipt, fatalRunError,
|
|
931
|
+
finalizationReceipt, fullOrder, interruptedSignal, ledgerBinding, ledgerPath,
|
|
932
|
+
lifecycles, manifest, options, packageVersion: packageManifest.version,
|
|
933
|
+
pauseReason, piRuntimeHome, preservePiRuntime,
|
|
934
|
+
productionAllStageBoundaries, productionHostReadinessPolicy, productionSpendControlled, rootSeed, rootSeedDigest,
|
|
935
|
+
runId, runRoot, runs, runtime, runtimeCommands, source, startedAt, suite,
|
|
936
|
+
suiteDigest, suiteIdentity, terminalStop
|
|
902
937
|
});
|
|
903
|
-
report.ledger = ledgerBinding;
|
|
904
|
-
applyBenchmarkClaimRestrictions(report, { tokenReason: manifest.tokenClaimsUnavailableReason, replaySource: options.replaySource, codexMode: options.codexMode, surfaces: options.surfaces });
|
|
905
|
-
report.trustChecklist = benchmarkTrustChecklist(report);
|
|
906
|
-
const text = renderBenchmarkText(report);
|
|
907
|
-
const reportLedger = inspectBenchmarkLedger(ledgerPath);
|
|
908
|
-
assertBenchmarkLedgerBinding(ledgerBinding, reportLedger.binding, "benchmark report ledger");
|
|
909
|
-
validateBenchmarkLedgerPrefix(reportLedger.records, fullOrder, (record, index, expected) => expectedBenchmarkRecord(record, index, expected, runId, suite, configurationDigest));
|
|
910
|
-
writePrivate(path.join(runRoot, "report.html"), renderBenchmarkHtml(report));
|
|
911
|
-
writePrivate(path.join(runRoot, "summary.txt"), text);
|
|
912
|
-
cleanupUnretainedWorkspaces(runRoot, options.keepWorkspaces);
|
|
913
|
-
const prepublishReceipt = executionGuard.receipt("prepublish");
|
|
914
|
-
const prepublishError = prepublishReceipt.error;
|
|
915
|
-
if (prepublishError) { writeBenchmarkAbort(runRoot, { runId, completedRuns: completedRuns.length, expectedRuns: fullOrder.length }, prepublishError, { ledger: ledgerBinding, provenanceStamp: prepublishReceipt.stamp }); throw prepublishError; }
|
|
916
|
-
for (const marker of ["paused.json", "interrupted.json", "aborted.json", "stopped.json"]) fs.rmSync(path.join(runRoot, marker), { force: true });
|
|
917
|
-
writePrivateAtomic(path.join(runRoot, "report.json"), `${JSON.stringify(report, null, 2)}\n`);
|
|
918
|
-
process.stdout.write(options.json ? `${JSON.stringify(report, null, 2)}\n` : text);
|
|
919
|
-
process.stdout.write(`Reports: ${runRoot}\n`);
|
|
920
|
-
if (
|
|
921
|
-
report.comparison.qualityGate === false
|
|
922
|
-
|| report.comparison.safetyGate === false
|
|
923
|
-
|| report.comparison.reliabilityGate === false
|
|
924
|
-
|| report.comparison.qualityNonInferior === false
|
|
925
|
-
|| report.comparison.workflowGate === false
|
|
926
|
-
|| report.comparison.categoryGate === false
|
|
927
|
-
|| report.comparison.suiteGate?.passed === false
|
|
928
|
-
) process.exitCode = 1;
|
|
929
938
|
} finally {
|
|
930
939
|
releaseRunLock?.();
|
|
931
940
|
codexRuntime?.cleanup();
|
|
@@ -933,12 +942,7 @@ async function main() {
|
|
|
933
942
|
}
|
|
934
943
|
}
|
|
935
944
|
|
|
936
|
-
|
|
937
|
-
try { return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(process.argv[1] || ""); }
|
|
938
|
-
catch { return import.meta.url === pathToFileURL(process.argv[1] || "").href; }
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
if (invokedAsEntrypoint()) {
|
|
945
|
+
if (invokedAsEntrypoint(import.meta.url, process.argv[1])) {
|
|
942
946
|
main().catch((error) => {
|
|
943
947
|
console.error(`FAIL: ${error.message}`);
|
|
944
948
|
process.exit(error.exitCode ?? 1);
|