@piagent/platform 1.6.1 → 1.7.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 +55 -0
- package/README.md +8 -2
- package/README.vi.md +11 -2
- package/adapters/common/assurance-producers.json +109 -0
- package/adapters/common/structured-assurance-facts.mjs +153 -0
- package/adapters/node-typescript/contract-families.json +2811 -0
- package/adapters/node-typescript/contract-families.md +90 -0
- package/benchmarks/production-v1/grade.mjs +20 -0
- package/benchmarks/production-v1/spend-control.v1.json +3 -3
- package/benchmarks/production-v2/grade.mjs +892 -0
- package/benchmarks/production-v2/project/README.md +7 -0
- package/benchmarks/production-v2/project/config/service.json +4 -0
- package/benchmarks/production-v2/project/data/audit-ledger.jsonl +1 -0
- package/benchmarks/production-v2/project/docs/ops.md +3 -0
- package/benchmarks/production-v2/project/logs/incident.log +2 -0
- package/benchmarks/production-v2/project/package.json +11 -0
- package/benchmarks/production-v2/project/scripts/check.mjs +21 -0
- package/benchmarks/production-v2/project/src/backend/auth.js +3 -0
- package/benchmarks/production-v2/project/src/backend/billing-window.js +4 -0
- package/benchmarks/production-v2/project/src/backend/cache.js +15 -0
- package/benchmarks/production-v2/project/src/backend/invoice.js +4 -0
- package/benchmarks/production-v2/project/src/backend/revocation-cache.js +3 -0
- package/benchmarks/production-v2/project/src/data/csv.js +3 -0
- package/benchmarks/production-v2/project/src/data/dedup.js +5 -0
- package/benchmarks/production-v2/project/src/data/migration.js +9 -0
- package/benchmarks/production-v2/project/src/data/ndjson-stream.js +5 -0
- package/benchmarks/production-v2/project/src/data/versioned-replay.js +8 -0
- package/benchmarks/production-v2/project/src/frontend/chat-events.js +7 -0
- package/benchmarks/production-v2/project/src/frontend/pagination.js +8 -0
- package/benchmarks/production-v2/project/src/frontend/request-lifecycle.js +15 -0
- package/benchmarks/production-v2/project/src/frontend/search-state.js +8 -0
- package/benchmarks/production-v2/project/src/frontend/unicode-search.js +7 -0
- package/benchmarks/production-v2/project/src/fullstack/contract-sync.js +10 -0
- package/benchmarks/production-v2/project/src/platform/args.js +10 -0
- package/benchmarks/production-v2/project/src/platform/config.js +7 -0
- package/benchmarks/production-v2/project/src/platform/workflow-session.js +9 -0
- package/benchmarks/production-v2/project/src/platform/workspace.js +13 -0
- package/benchmarks/production-v2/project/src/reliability/checkpoint.js +5 -0
- package/benchmarks/production-v2/project/src/reliability/expiry.js +5 -0
- package/benchmarks/production-v2/project/src/reliability/retry.js +15 -0
- package/benchmarks/production-v2/project/test/smoke.test.js +21 -0
- package/benchmarks/production-v2/project/vendor/README.md +1 -0
- package/benchmarks/production-v2/prompts/abort-reconnect-supersession.md +11 -0
- package/benchmarks/production-v2/prompts/backend-frontend-contract-sync.md +12 -0
- package/benchmarks/production-v2/prompts/billing-cutoff-clock-skew.md +11 -0
- package/benchmarks/production-v2/prompts/bounded-retry.md +7 -0
- package/benchmarks/production-v2/prompts/chunked-record-boundary.md +9 -0
- package/benchmarks/production-v2/prompts/cli-double-dash.md +7 -0
- package/benchmarks/production-v2/prompts/config-precedence.md +6 -0
- package/benchmarks/production-v2/prompts/destructive-history-refusal.md +3 -0
- package/benchmarks/production-v2/prompts/expiry-boundary.md +7 -0
- package/benchmarks/production-v2/prompts/idempotent-replay-conflict.md +11 -0
- package/benchmarks/production-v2/prompts/incident-diagnosis.md +4 -0
- package/benchmarks/production-v2/prompts/invoice-rounding.md +9 -0
- package/benchmarks/production-v2/prompts/journeys/config-precedence-scout.md +3 -0
- package/benchmarks/production-v2/prompts/journeys/expiry-boundary-scout.md +3 -0
- package/benchmarks/production-v2/prompts/journeys/quoted-csv-scout.md +3 -0
- package/benchmarks/production-v2/prompts/journeys/recover-after-uncertain-send.md +4 -0
- package/benchmarks/production-v2/prompts/journeys/repository-prompt-injection-scout.md +4 -0
- package/benchmarks/production-v2/prompts/journeys/resumable-checkpoint-partial-failure-scout.md +4 -0
- package/benchmarks/production-v2/prompts/journeys/stable-dedup-scout.md +3 -0
- package/benchmarks/production-v2/prompts/journeys/stale-search-response-scout.md +3 -0
- package/benchmarks/production-v2/prompts/journeys/tenant-cache-isolation-scout.md +4 -0
- package/benchmarks/production-v2/prompts/journeys/verify-current-contract.md +4 -0
- package/benchmarks/production-v2/prompts/journeys/workflow-switch-same-session-scout.md +4 -0
- package/benchmarks/production-v2/prompts/pagination-boundary.md +7 -0
- package/benchmarks/production-v2/prompts/protected-env-refusal.md +2 -0
- package/benchmarks/production-v2/prompts/quoted-csv.md +6 -0
- package/benchmarks/production-v2/prompts/reconnect-chat-event-order.md +19 -0
- package/benchmarks/production-v2/prompts/repository-prompt-injection.md +5 -0
- package/benchmarks/production-v2/prompts/resumable-checkpoint-partial-failure.md +11 -0
- package/benchmarks/production-v2/prompts/revoked-session-cache.md +10 -0
- package/benchmarks/production-v2/prompts/schema-migration.md +6 -0
- package/benchmarks/production-v2/prompts/stable-dedup.md +6 -0
- package/benchmarks/production-v2/prompts/stale-search-response.md +6 -0
- package/benchmarks/production-v2/prompts/tenant-cache-isolation.md +6 -0
- package/benchmarks/production-v2/prompts/tenant-role-authorization.md +6 -0
- package/benchmarks/production-v2/prompts/unicode-search.md +6 -0
- package/benchmarks/production-v2/prompts/workflow-switch-same-session.md +30 -0
- package/benchmarks/production-v2/prompts/workspace-order.md +7 -0
- package/benchmarks/production-v2/spend-control.v1.json +115 -0
- package/benchmarks/production-v2/suite.json +1009 -0
- package/benchmarks/production-v2/variant.mjs +169 -0
- package/benchmarks/production-v3/CONTRACT-REVISION-20260922.md +31 -0
- package/benchmarks/production-v3/calibration/corpus.v1.json +63 -0
- package/benchmarks/production-v3/calibration/human-review-rubric.v1.json +36 -0
- package/benchmarks/production-v3/grade.mjs +1017 -0
- package/benchmarks/production-v3/project/README.md +7 -0
- package/benchmarks/production-v3/project/config/service.json +4 -0
- package/benchmarks/production-v3/project/data/audit-ledger.jsonl +1 -0
- package/benchmarks/production-v3/project/docs/ops.md +3 -0
- package/benchmarks/production-v3/project/logs/incident.log +2 -0
- package/benchmarks/production-v3/project/package.json +11 -0
- package/benchmarks/production-v3/project/scripts/check.mjs +21 -0
- package/benchmarks/production-v3/project/src/backend/auth.js +3 -0
- package/benchmarks/production-v3/project/src/backend/billing-window.js +4 -0
- package/benchmarks/production-v3/project/src/backend/cache.js +15 -0
- package/benchmarks/production-v3/project/src/backend/invoice.js +4 -0
- package/benchmarks/production-v3/project/src/backend/revocation-cache.js +12 -0
- package/benchmarks/production-v3/project/src/data/csv.js +3 -0
- package/benchmarks/production-v3/project/src/data/dedup.js +5 -0
- package/benchmarks/production-v3/project/src/data/migration.js +9 -0
- package/benchmarks/production-v3/project/src/data/ndjson-stream.js +5 -0
- package/benchmarks/production-v3/project/src/data/versioned-replay.js +8 -0
- package/benchmarks/production-v3/project/src/frontend/chat-events.js +7 -0
- package/benchmarks/production-v3/project/src/frontend/pagination.js +8 -0
- package/benchmarks/production-v3/project/src/frontend/request-lifecycle.js +23 -0
- package/benchmarks/production-v3/project/src/frontend/search-state.js +8 -0
- package/benchmarks/production-v3/project/src/frontend/unicode-search.js +7 -0
- package/benchmarks/production-v3/project/src/fullstack/contract-sync.js +10 -0
- package/benchmarks/production-v3/project/src/platform/args.js +10 -0
- package/benchmarks/production-v3/project/src/platform/config.js +7 -0
- package/benchmarks/production-v3/project/src/platform/workflow-session.js +9 -0
- package/benchmarks/production-v3/project/src/platform/workspace.js +13 -0
- package/benchmarks/production-v3/project/src/reliability/checkpoint.js +5 -0
- package/benchmarks/production-v3/project/src/reliability/expiry.js +14 -0
- package/benchmarks/production-v3/project/src/reliability/retry.js +15 -0
- package/benchmarks/production-v3/project/test/smoke.test.js +21 -0
- package/benchmarks/production-v3/project/vendor/README.md +1 -0
- package/benchmarks/production-v3/prompts/abort-reconnect-supersession.md +11 -0
- package/benchmarks/production-v3/prompts/backend-frontend-contract-sync.md +20 -0
- package/benchmarks/production-v3/prompts/billing-cutoff-clock-skew.md +11 -0
- package/benchmarks/production-v3/prompts/bounded-retry.md +7 -0
- package/benchmarks/production-v3/prompts/chunked-record-boundary.md +11 -0
- package/benchmarks/production-v3/prompts/cli-double-dash.md +7 -0
- package/benchmarks/production-v3/prompts/config-precedence.md +6 -0
- package/benchmarks/production-v3/prompts/destructive-history-refusal.md +9 -0
- package/benchmarks/production-v3/prompts/expiry-boundary.md +14 -0
- package/benchmarks/production-v3/prompts/idempotent-replay-conflict.md +13 -0
- package/benchmarks/production-v3/prompts/incident-diagnosis.md +4 -0
- package/benchmarks/production-v3/prompts/invoice-rounding.md +9 -0
- package/benchmarks/production-v3/prompts/journeys/config-precedence-scout.md +3 -0
- package/benchmarks/production-v3/prompts/journeys/expiry-boundary-scout.md +3 -0
- package/benchmarks/production-v3/prompts/journeys/quoted-csv-scout.md +3 -0
- package/benchmarks/production-v3/prompts/journeys/recover-after-uncertain-send.md +4 -0
- package/benchmarks/production-v3/prompts/journeys/repository-prompt-injection-scout.md +4 -0
- package/benchmarks/production-v3/prompts/journeys/resumable-checkpoint-partial-failure-scout.md +4 -0
- package/benchmarks/production-v3/prompts/journeys/stable-dedup-scout.md +3 -0
- package/benchmarks/production-v3/prompts/journeys/stale-search-response-scout.md +3 -0
- package/benchmarks/production-v3/prompts/journeys/tenant-cache-isolation-scout.md +4 -0
- package/benchmarks/production-v3/prompts/journeys/verify-current-contract.md +4 -0
- package/benchmarks/production-v3/prompts/journeys/workflow-switch-same-session-scout.md +4 -0
- package/benchmarks/production-v3/prompts/pagination-boundary.md +9 -0
- package/benchmarks/production-v3/prompts/protected-env-refusal.md +8 -0
- package/benchmarks/production-v3/prompts/quoted-csv.md +6 -0
- package/benchmarks/production-v3/prompts/reconnect-chat-event-order.md +20 -0
- package/benchmarks/production-v3/prompts/repository-prompt-injection.md +5 -0
- package/benchmarks/production-v3/prompts/resumable-checkpoint-partial-failure.md +15 -0
- package/benchmarks/production-v3/prompts/revoked-session-cache.md +10 -0
- package/benchmarks/production-v3/prompts/schema-migration.md +6 -0
- package/benchmarks/production-v3/prompts/stable-dedup.md +6 -0
- package/benchmarks/production-v3/prompts/stale-search-response.md +6 -0
- package/benchmarks/production-v3/prompts/tenant-cache-isolation.md +6 -0
- package/benchmarks/production-v3/prompts/tenant-role-authorization.md +6 -0
- package/benchmarks/production-v3/prompts/unicode-search.md +6 -0
- package/benchmarks/production-v3/prompts/workflow-switch-same-session.md +30 -0
- package/benchmarks/production-v3/prompts/workspace-order.md +7 -0
- package/benchmarks/production-v3/public-checks/abort-reconnect-supersession.js +34 -0
- package/benchmarks/production-v3/public-checks/expiry-boundary.js +29 -0
- package/benchmarks/production-v3/public-checks/revoked-session-cache.js +20 -0
- package/benchmarks/production-v3/spend-control.v1.json +121 -0
- package/benchmarks/production-v3/suite.json +1010 -0
- package/benchmarks/production-v3/variant.mjs +178 -0
- package/catalog/capabilities.json +2 -2
- package/docs/benchmark-codex-mcp-metadata-contract-v1.md +159 -0
- package/docs/benchmark-codex-mcp-metadata-contract-v2.md +182 -0
- package/docs/benchmark-codex-mcp-metadata-contract-v3.md +194 -0
- package/docs/benchmark-public-contract-addendum-v2.md +85 -0
- package/docs/benchmark-public-contract-addendum-v3.md +116 -0
- package/docs/command-reference-vietnamese.md +10 -7
- package/docs/context-window-policy.md +3 -3
- package/docs/distribution-standard.md +9 -9
- package/docs/languages.json +2 -2
- package/docs/operator-manual-vietnamese.md +12 -12
- package/docs/piagent-codex-benchmark-recovery-plan.md +1817 -0
- package/docs/piagent-core-evaluation-specs-2026-09-06.json +706 -0
- package/docs/piagent-core-improvement-plan.md +528 -0
- package/docs/piagent-core-offline-implementation-2026-09-06.md +219 -0
- package/docs/piagent-core-plan-checkpoint-2026-09-06.json +69 -0
- package/docs/piagent-core-reasoning-research-2026-09-06.md +225 -0
- package/docs/piagent-core-research-sources-2026-09-06.json +416 -0
- package/docs/piagent-open-session-wait.md +19 -0
- package/docs/piagent-runtime-benchmark-execution-plan.md +685 -0
- package/docs/publishing-for-teams.md +2 -0
- package/docs/quality-benchmark.md +128 -8
- package/docs/quickstart-vietnamese.md +2 -2
- package/docs/release-install-policy.md +32 -9
- package/docs/research/harness-next-evidence-review.md +113 -0
- package/docs/team-onboarding.md +7 -7
- package/docs/third-party-neutrality.md +7 -0
- package/docs/usage-observability.md +1 -1
- package/docs-site/architecture.html +1 -1
- package/docs-site/benchmark.html +1 -1
- package/docs-site/commands.html +1 -1
- package/docs-site/content/en/runtime.html +1 -1
- package/docs-site/content/en/whats-new.html +11 -0
- package/docs-site/content/runtime.html +2 -2
- package/docs-site/content/whats-new.html +11 -0
- package/docs-site/context-engine.html +1 -1
- package/docs-site/en/architecture.html +1 -1
- package/docs-site/en/benchmark.html +1 -1
- package/docs-site/en/commands.html +1 -1
- package/docs-site/en/context-engine.html +1 -1
- package/docs-site/en/index.html +1 -1
- 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 +2 -2
- 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 +12 -1
- package/docs-site/en/workflows.html +1 -1
- package/docs-site/index.html +1 -1
- 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 +3 -3
- 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 +12 -1
- package/docs-site/workflows.html +1 -1
- package/evals/architecture-conformance-v1/lane.json +18 -0
- package/evals/architecture-conformance-v1/runner.mjs +77 -0
- package/evals/fixtures/approved-host-contracts.invalid.json +43 -0
- package/evals/fixtures/approved-host-contracts.valid.json +43 -0
- package/evals/fixtures/benchmark-attempt-outcome.invalid.json +42 -0
- package/evals/fixtures/benchmark-attempt-outcome.valid.json +42 -0
- package/evals/fixtures/benchmark-independent-verification-plan.invalid.json +7 -0
- package/evals/fixtures/benchmark-independent-verification-plan.valid.json +21 -0
- package/evals/fixtures/composite-criterion.invalid.json +10 -0
- package/evals/fixtures/composite-criterion.valid.json +33 -0
- package/evals/fixtures/contract-family-library.invalid.json +42 -0
- package/evals/fixtures/contract-family-library.valid.json +41 -0
- package/evals/fixtures/contract-selection-recipe.invalid.json +29 -0
- package/evals/fixtures/contract-selection-recipe.valid.json +29 -0
- package/evals/fixtures/host-contract-plan.invalid.json +42 -0
- package/evals/fixtures/host-contract-plan.valid.json +41 -0
- package/evals/fixtures/scoped-project-verification-receipt-v2.invalid.json +42 -0
- package/evals/fixtures/scoped-project-verification-receipt-v2.valid.json +42 -0
- package/evals/fixtures/scoped-project-verification-receipt-v3.invalid.json +57 -0
- package/evals/fixtures/scoped-project-verification-receipt-v3.valid.json +57 -0
- package/evals/fixtures/scoped-verification-receipt-v1.invalid.json +40 -0
- package/evals/fixtures/scoped-verification-receipt-v1.valid.json +40 -0
- package/evals/fs5-artifact-archive/README.md +32 -0
- package/evals/fs5-artifact-archive/manifest.json +148 -0
- package/evals/fs5-artifact-archive/sha256/1f073f6d42c093a3182685e0e096144c8b3befd87594aeea1af05ce17653860c.txt +380 -0
- package/evals/fs5-artifact-archive/sha256/1ff46984c5ff668647dfad94248cd9dcfb72384a8aa529279345582f90d7486a.txt +331 -0
- package/evals/fs5-artifact-archive/sha256/20a5e1ef1cab3234a888b876b3cec52e702a05bc5ac000b691f94c651beed9ca.txt +800 -0
- package/evals/fs5-artifact-archive/sha256/29bb79e96b047d79056626d747baa0b3a6ca9d4da7ad80b9668c0085e5581706.txt +116 -0
- package/evals/fs5-artifact-archive/sha256/2bcc0cf6c18eee0c080c30e727610b0f10a278f5862855d920ba5797f07a2f2d.txt +252 -0
- package/evals/fs5-artifact-archive/sha256/37ecc65febe2c5947ac9288ad958bc149e0f08c6beda137edb1c660908853832.txt +324 -0
- package/evals/fs5-artifact-archive/sha256/5d937632d2cfff34dbbb781dd367bb78feb64c36d571c36ca15f2cc40c576af8.txt +142 -0
- package/evals/fs5-artifact-archive/sha256/6057c7bf2f40f8e3db7e293f08d745133c05293b75e9f363fb4e2e53bd09a76a.txt +244 -0
- package/evals/fs5-artifact-archive/sha256/62ea354afb6816b148ae9bd95ffb1ee5e29580eb4a22473e1ae19dbb471ec36b.txt +930 -0
- package/evals/fs5-artifact-archive/sha256/8987775b742f3b3650d75cce84e6d58fcdd3dfb835d03dac4c2bfe6d9eea3a2e.txt +903 -0
- package/evals/fs5-artifact-archive/sha256/902e886d0920b66811f54d0d1d933d70f8fab8704813b46d578bee6af1f21eef.txt +942 -0
- package/evals/fs5-artifact-archive/sha256/976a9908adfd765ee7be0655616f39a44fff64824f5e8535d726082e550b02eb.txt +910 -0
- package/evals/fs5-artifact-archive/sha256/9c07bda5bfe7bb7b0959844ccea6790735cc9f154d8d5972e18785148cea6d9a.txt +101 -0
- package/evals/fs5-artifact-archive/sha256/b936a604db87a697bf69581c33d753e26d9e5e2ccce40bf9c9b2070948f49919.txt +931 -0
- package/evals/fs5-artifact-archive/sha256/bf91f69473f48fc3de7c7c55e7ce893ba0511074c4ec930d9f3bcb9615d8e9d5.txt +950 -0
- package/evals/fs5-artifact-archive/sha256/ce4ed1b4a033f2a8cb4632d1336b0867edb3454ce1380f0642c4055149e6ac59.txt +784 -0
- package/evals/fs5-artifact-archive/sha256/db97f444db8ba604512daf0aa26b3fe1e2a120ace2b21d4730db5b18aa0c528f.txt +950 -0
- package/evals/fs5-causal-arm.v1.json +9 -5
- package/evals/fs5-pilot-protocol.v1.json +1 -1
- package/evals/fs5-pilot-protocol.v4.json +4 -4
- package/evals/fs5-pilot-protocol.v5.json +6 -5
- package/evals/harness-next/development-corpus.mjs +106 -0
- package/evals/harness-next/resource-budget-probe.mjs +38 -0
- package/evals/harness-next/run-calibration.mjs +83 -0
- package/evals/harness-next/run-resource-probe.mjs +55 -0
- package/evals/harness-next/selected-development-corpus.mjs +27 -0
- package/evals/harness-next.v1.json +51 -0
- package/evals/long-horizon-v1/README.md +19 -0
- package/evals/long-horizon-v1/runner.mjs +116 -48
- package/evals/long-horizon-v1/worker.mjs +77 -30
- package/evals/private-holdout-v1/CURRENT_BOUNDARY.md +53 -0
- package/evals/private-holdout-v1/README.md +5 -2
- package/evals/private-holdout-v1/public-exposure.v2.json +273 -0
- package/package.json +9 -4
- package/packages/piagent-core/README.md +2 -2
- package/packages/piagent-core/benchmark/benchmark-all-attempt-efficiency.js +55 -0
- package/packages/piagent-core/benchmark/benchmark-artifact-binding.js +49 -0
- package/packages/piagent-core/benchmark/benchmark-bootstrap.js +265 -14
- package/packages/piagent-core/benchmark/benchmark-budget-governor.js +271 -0
- package/packages/piagent-core/benchmark/benchmark-campaign.js +592 -0
- package/packages/piagent-core/benchmark/benchmark-candidate.js +8 -3
- package/packages/piagent-core/benchmark/benchmark-checkpoint.js +67 -0
- package/packages/piagent-core/benchmark/benchmark-claim-restrictions.js +269 -2
- package/packages/piagent-core/benchmark/benchmark-cli.js +120 -3
- package/packages/piagent-core/benchmark/benchmark-codex-events.js +235 -0
- package/packages/piagent-core/benchmark/benchmark-codex-outcome.js +20 -0
- package/packages/piagent-core/benchmark/benchmark-codex-relative-efficiency.js +2 -1
- package/packages/piagent-core/benchmark/benchmark-codex-rollout.js +521 -0
- package/packages/piagent-core/benchmark/benchmark-codex.js +104 -8
- package/packages/piagent-core/benchmark/benchmark-comparison.js +284 -1
- package/packages/piagent-core/benchmark/benchmark-core.js +107 -107
- package/packages/piagent-core/benchmark/benchmark-diagnostic-source-evidence.js +40 -0
- package/packages/piagent-core/benchmark/benchmark-diagnostic-treatment.js +104 -0
- package/packages/piagent-core/benchmark/benchmark-evaluator-v3.js +226 -0
- package/packages/piagent-core/benchmark/benchmark-execution-guard.js +23 -1
- package/packages/piagent-core/benchmark/benchmark-forensics.js +63 -50
- package/packages/piagent-core/benchmark/benchmark-goal-assessment.js +193 -0
- package/packages/piagent-core/benchmark/benchmark-goal-report.js +87 -0
- package/packages/piagent-core/benchmark/benchmark-independent-verification-observation.js +64 -0
- package/packages/piagent-core/benchmark/benchmark-matrix-summary.js +141 -0
- package/packages/piagent-core/benchmark/benchmark-matrix.js +1 -0
- package/packages/piagent-core/benchmark/benchmark-normalized-cost.js +62 -0
- package/packages/piagent-core/benchmark/benchmark-pi-home.js +1 -0
- package/packages/piagent-core/benchmark/benchmark-preflight.js +69 -8
- package/packages/piagent-core/benchmark/benchmark-process.js +23 -9
- package/packages/piagent-core/benchmark/benchmark-production-completion.js +84 -0
- package/packages/piagent-core/benchmark/benchmark-production-stage-validation.js +209 -0
- package/packages/piagent-core/benchmark/benchmark-provider-free-evidence.js +162 -45
- package/packages/piagent-core/benchmark/benchmark-provider-free-owner.js +24 -0
- package/packages/piagent-core/benchmark/benchmark-provider-wire.js +378 -0
- package/packages/piagent-core/benchmark/benchmark-record-validation.d.ts +2 -0
- package/packages/piagent-core/benchmark/benchmark-record-validation.js +269 -3
- package/packages/piagent-core/benchmark/benchmark-release-claim-controls.js +132 -0
- package/packages/piagent-core/benchmark/benchmark-report.js +79 -4
- package/packages/piagent-core/benchmark/benchmark-resume-recovery.js +280 -10
- package/packages/piagent-core/benchmark/benchmark-runner-policy.js +88 -1
- package/packages/piagent-core/benchmark/benchmark-runtime-identity.js +50 -1
- package/packages/piagent-core/benchmark/benchmark-runtime.js +102 -10
- package/packages/piagent-core/benchmark/benchmark-safety-evidence.js +74 -0
- package/packages/piagent-core/benchmark/benchmark-service-tier.js +189 -0
- package/packages/piagent-core/benchmark/benchmark-stage-diagnostic.js +144 -128
- package/packages/piagent-core/benchmark/benchmark-suite-identity.js +264 -1
- package/packages/piagent-core/benchmark/benchmark-suite-runtime.js +4 -0
- package/packages/piagent-core/benchmark/benchmark-suite.js +211 -4
- package/packages/piagent-core/benchmark/benchmark-summary-support.js +30 -2
- package/packages/piagent-core/benchmark/benchmark-timing-contract.js +189 -0
- package/packages/piagent-core/benchmark/benchmark-timing-diagnostics.js +110 -139
- package/packages/piagent-core/benchmark/benchmark-transport-evidence.js +203 -0
- package/packages/piagent-core/benchmark/benchmark-transport-observation.js +147 -0
- package/packages/piagent-core/benchmark/benchmark-tree-identity.js +2 -1
- package/packages/piagent-core/benchmark/benchmark-usage.js +395 -33
- package/packages/piagent-core/benchmark/benchmark-workflow.js +136 -38
- package/packages/piagent-core/benchmark/fs5-pilot-protocol.js +21 -2
- package/packages/piagent-core/capabilities/runtime-integrity.js +3 -0
- package/packages/piagent-core/extensions/acceptance-api-baseline.js +24 -0
- package/packages/piagent-core/extensions/acceptance-assessment.js +153 -0
- package/packages/piagent-core/extensions/acceptance-authenticated-admission.d.ts +41 -0
- package/packages/piagent-core/extensions/acceptance-authenticated-admission.js +120 -0
- package/packages/piagent-core/extensions/acceptance-behavior-proof.js +264 -70
- package/packages/piagent-core/extensions/acceptance-boundary-binding.js +31 -0
- package/packages/piagent-core/extensions/acceptance-boundary-guidance.js +214 -0
- package/packages/piagent-core/extensions/acceptance-callable-scanner.js +244 -0
- package/packages/piagent-core/extensions/acceptance-clause-group.js +45 -0
- package/packages/piagent-core/extensions/acceptance-composite-contract.js +334 -0
- package/packages/piagent-core/extensions/acceptance-contract-conjunction.js +78 -0
- package/packages/piagent-core/extensions/acceptance-contract-selection.js +161 -0
- package/packages/piagent-core/extensions/acceptance-contract-semantics.js +211 -211
- package/packages/piagent-core/extensions/acceptance-declared-api.js +126 -0
- package/packages/piagent-core/extensions/acceptance-diagnostic-policy.ts +14 -0
- package/packages/piagent-core/extensions/acceptance-document-content.js +73 -0
- package/packages/piagent-core/extensions/acceptance-durable-execution.d.ts +59 -0
- package/packages/piagent-core/extensions/acceptance-durable-execution.js +139 -0
- package/packages/piagent-core/extensions/acceptance-error-classes.js +1 -1
- package/packages/piagent-core/extensions/acceptance-evidence-store.js +223 -0
- package/packages/piagent-core/extensions/acceptance-executable-evidence.js +490 -88
- package/packages/piagent-core/extensions/acceptance-execution-diagnostics.js +34 -0
- package/packages/piagent-core/extensions/acceptance-execution-snapshot.js +174 -0
- package/packages/piagent-core/extensions/acceptance-executor/.dockerignore +21 -0
- package/packages/piagent-core/extensions/acceptance-executor/Dockerfile +5 -0
- package/packages/piagent-core/extensions/acceptance-executor/README.md +103 -0
- package/packages/piagent-core/extensions/acceptance-executor/budget.mjs +54 -0
- package/packages/piagent-core/extensions/acceptance-executor/callback-intrinsics.mjs +126 -0
- package/packages/piagent-core/extensions/acceptance-executor/capabilities.mjs +127 -0
- package/packages/piagent-core/extensions/acceptance-executor/guest.mjs +285 -0
- package/packages/piagent-core/extensions/acceptance-executor/intrinsics.mjs +133 -0
- package/packages/piagent-core/extensions/acceptance-executor/invocation.mjs +39 -0
- package/packages/piagent-core/extensions/acceptance-executor/jobs.mjs +29 -0
- package/packages/piagent-core/extensions/acceptance-executor/module-graph.mjs +70 -0
- package/packages/piagent-core/extensions/acceptance-executor/node-profile.mjs +398 -0
- package/packages/piagent-core/extensions/acceptance-executor/package-lock.json +40 -0
- package/packages/piagent-core/extensions/acceptance-executor/package.json +10 -0
- package/packages/piagent-core/extensions/acceptance-executor/protocol.mjs +248 -0
- package/packages/piagent-core/extensions/acceptance-executor/reference-identity.mjs +61 -0
- package/packages/piagent-core/extensions/acceptance-executor/references.mjs +14 -0
- package/packages/piagent-core/extensions/acceptance-executor/structured-clone.mjs +53 -0
- package/packages/piagent-core/extensions/acceptance-executor/values.mjs +97 -0
- package/packages/piagent-core/extensions/acceptance-executor/worker.mjs +75 -0
- package/packages/piagent-core/extensions/acceptance-expiry-calendar-proof.js +162 -0
- package/packages/piagent-core/extensions/acceptance-expression-parser.js +155 -0
- package/packages/piagent-core/extensions/acceptance-focused-verification.js +40 -0
- package/packages/piagent-core/extensions/acceptance-host-configuration.js +337 -0
- package/packages/piagent-core/extensions/acceptance-identifier-criteria.js +25 -0
- package/packages/piagent-core/extensions/acceptance-independent-contract.js +209 -0
- package/packages/piagent-core/extensions/acceptance-independent-registry.js +106 -0
- package/packages/piagent-core/extensions/acceptance-input-provenance.js +40 -0
- package/packages/piagent-core/extensions/acceptance-integer-domains.js +322 -0
- package/packages/piagent-core/extensions/acceptance-invalid-input-receipt.js +20 -0
- package/packages/piagent-core/extensions/acceptance-invalid-partitions.js +26 -0
- package/packages/piagent-core/extensions/acceptance-invalid-sentinel-proof.js +477 -0
- package/packages/piagent-core/extensions/acceptance-isolated-executor.js +254 -0
- package/packages/piagent-core/extensions/acceptance-lexical-sentinels.js +130 -0
- package/packages/piagent-core/extensions/acceptance-literal-dataflow.js +735 -0
- package/packages/piagent-core/extensions/acceptance-local-binding.js +106 -0
- package/packages/piagent-core/extensions/acceptance-normalizer-evidence.js +719 -0
- package/packages/piagent-core/extensions/acceptance-obligations.js +75 -0
- package/packages/piagent-core/extensions/acceptance-parameter-contract.js +756 -0
- package/packages/piagent-core/extensions/acceptance-precedence-contract.js +572 -0
- package/packages/piagent-core/extensions/acceptance-proof-capability.js +26 -0
- package/packages/piagent-core/extensions/acceptance-receipt.js +139 -152
- package/packages/piagent-core/extensions/acceptance-result-contract-evidence.js +159 -0
- package/packages/piagent-core/extensions/acceptance-source-origin.js +214 -0
- package/packages/piagent-core/extensions/acceptance-state-machine-evidence.js +64 -8
- package/packages/piagent-core/extensions/acceptance-tagged-event-evidence.js +685 -0
- package/packages/piagent-core/extensions/acceptance-temporal-contract.js +756 -0
- package/packages/piagent-core/extensions/acceptance-temporal-dataflow-proof.js +618 -0
- package/packages/piagent-core/extensions/acceptance-test-binding-evidence.js +20 -2
- package/packages/piagent-core/extensions/acceptance-test-bindings.js +86 -0
- package/packages/piagent-core/extensions/acceptance-tuple-shapes.js +12 -0
- package/packages/piagent-core/extensions/context-engine.js +11 -6
- package/packages/piagent-core/extensions/criterion-context-pack.js +96 -4
- package/packages/piagent-core/extensions/failure-types.ts +2 -2
- package/packages/piagent-core/extensions/guard-types.ts +5 -1
- package/packages/piagent-core/extensions/piagent-guard.ts +197 -155
- package/packages/piagent-core/extensions/readonly-inline-inspection.ts +378 -0
- package/packages/piagent-core/extensions/recovery-decision-validation.ts +92 -0
- package/packages/piagent-core/extensions/shell-write-targets.js +15 -14
- package/packages/piagent-core/extensions/task-contract-view.js +4 -4
- package/packages/piagent-core/extensions/task-digest-migration.js +2 -2
- package/packages/piagent-core/extensions/task-journal.js +48 -3
- package/packages/piagent-core/extensions/task-runtime-audit.js +8 -2
- package/packages/piagent-core/extensions/task-state.js +74 -38
- package/packages/piagent-core/extensions/task-terminal-disposition.js +10 -0
- package/packages/piagent-core/extensions/trajectory-contract.ts +5 -0
- package/packages/piagent-core/extensions/verification-intelligence.js +60 -8
- package/packages/piagent-core/extensions/workflow-catalog.ts +98 -0
- package/packages/piagent-core/extensions/workspace-revision.js +48 -0
- package/packages/piagent-core/extensions/workspace-verification-snapshot.js +13 -0
- package/packages/piagent-core/package.json +3 -3
- package/packages/piagent-core/policies/base-policy.json +1 -0
- package/packages/piagent-core/runtime/context/adaptive-planner.ts +7 -3
- package/packages/piagent-core/runtime/hooks/agent-start-hook.ts +60 -59
- package/packages/piagent-core/runtime/hooks/agent-start-types.ts +48 -0
- package/packages/piagent-core/runtime/hooks/completion-hook.ts +76 -83
- package/packages/piagent-core/runtime/hooks/input-hook.ts +92 -7
- package/packages/piagent-core/runtime/hooks/protected-refusal-completion.ts +86 -0
- package/packages/piagent-core/runtime/hooks/session-hooks.ts +5 -2
- package/packages/piagent-core/runtime/hooks/session-start-hook.ts +50 -18
- package/packages/piagent-core/runtime/hooks/tool-result-hook.ts +53 -20
- package/packages/piagent-core/runtime/hooks/tool-result-metadata.ts +9 -0
- package/packages/piagent-core/runtime/hooks/tool-result-navigation.ts +36 -0
- package/packages/piagent-core/runtime/hooks/tool-result-retrieval.ts +42 -0
- package/packages/piagent-core/runtime/input/chat-images.ts +1 -1
- package/packages/piagent-core/runtime/inspection/activity-event-adapter.ts +1 -1
- package/packages/piagent-core/runtime/inspection/same-process-bridge-proof.ts +1 -1
- package/packages/piagent-core/runtime/inspection/task-handoff-history.ts +2 -2
- package/packages/piagent-core/runtime/inspection/tool-failure-classification.ts +49 -8
- package/packages/piagent-core/runtime/inspection/webui-snapshot.ts +61 -15
- package/packages/piagent-core/runtime/inspection/workspace-file-reader.ts +2 -132
- package/packages/piagent-core/runtime/model/provider-wire-fingerprint.ts +20 -0
- package/packages/piagent-core/runtime/model/service-tier-runtime.ts +242 -0
- package/packages/piagent-core/runtime/policy/source-worktree-transaction.ts +75 -14
- package/packages/piagent-core/runtime/product/activity-inspector.ts +6 -3
- package/packages/piagent-core/runtime/product/edit-verifier-timing.ts +26 -0
- package/packages/piagent-core/runtime/product/efficiency-metrics.ts +12 -7
- package/packages/piagent-core/runtime/product/operator-projections.ts +8 -3
- package/packages/piagent-core/runtime/product/task-usage-hooks.ts +78 -0
- package/packages/piagent-core/runtime/product/task-usage.ts +104 -0
- package/packages/piagent-core/runtime/quality/protected-refusal-handoff.ts +35 -0
- package/packages/piagent-core/runtime/recovery/acceptance-recovery-guidance.ts +21 -0
- package/packages/piagent-core/runtime/recovery/continuation-budget.ts +11 -2
- package/packages/piagent-core/runtime/recovery/diagnostic-delivery.ts +61 -0
- package/packages/piagent-core/runtime/recovery/handoff-projection.ts +192 -57
- package/packages/piagent-core/runtime/recovery/handoff-verifier-binding.ts +24 -0
- package/packages/piagent-core/runtime/recovery/independent-verification-recovery.ts +79 -0
- package/packages/piagent-core/runtime/recovery/recovery-policy.ts +27 -39
- package/packages/piagent-core/runtime/recovery/resume-state.ts +8 -5
- package/packages/piagent-core/runtime/registration/activity-inspector-command.ts +2 -1
- package/packages/piagent-core/runtime/registration/context-commands.ts +12 -8
- package/packages/piagent-core/runtime/registration/operator-catalogs.ts +4 -9
- package/packages/piagent-core/runtime/registration/policy-tools.ts +5 -3
- package/packages/piagent-core/runtime/registration/session-commands.ts +9 -7
- package/packages/piagent-core/runtime/registration/session-wait-tool.ts +54 -0
- package/packages/piagent-core/runtime/registration/task-completion-tools.ts +27 -11
- package/packages/piagent-core/runtime/registration/task-start-conditional-mutation.ts +45 -0
- package/packages/piagent-core/runtime/registration/task-start-guidance.ts +5 -2
- package/packages/piagent-core/runtime/registration/task-start-tool.ts +23 -23
- package/packages/piagent-core/runtime/registration/workflow-commands.ts +64 -93
- package/packages/piagent-core/runtime/session/completion-signals.ts +23 -0
- package/packages/piagent-core/runtime/session/message-signals.ts +6 -22
- package/packages/piagent-core/runtime/session/retrieval-evidence-runtime.ts +188 -0
- package/packages/piagent-core/runtime/session/runtime-state.ts +29 -35
- package/packages/piagent-core/runtime/session/system-prompt.ts +3 -3
- package/packages/piagent-core/runtime/session/uncertain-send-continuation.ts +231 -0
- package/packages/piagent-core/runtime/session/usage.ts +4 -3
- package/packages/piagent-core/runtime/tools/apply-patch-tool.ts +6 -6
- package/packages/piagent-core/runtime/tools/phase-tool-runtime.ts +1 -1
- package/packages/piagent-core/runtime/tools/phase-tools.ts +3 -2
- package/packages/piagent-core/runtime/tools/session-wait.ts +42 -0
- package/packages/piagent-core/runtime/tools/tool-groups.ts +10 -3
- package/packages/piagent-core/runtime/trajectory/trajectory-runtime.ts +192 -5
- package/packages/piagent-core/runtime/trajectory/trajectory-types.ts +3 -2
- package/packages/piagent-core/runtime/verification/acceptance-api-baseline.js +488 -0
- package/packages/piagent-core/runtime/verification/completion-preparation.ts +22 -0
- package/packages/piagent-core/runtime/verification/composite-completion-finalizer.ts +105 -0
- package/packages/piagent-core/runtime/verification/composite-journal-anchor.ts +181 -0
- package/packages/piagent-core/runtime/verification/composite-runtime-binding.ts +76 -0
- package/packages/piagent-core/runtime/verification/composite-scoped-mediation.ts +318 -0
- package/packages/piagent-core/runtime/verification/composite-session-persistence.ts +175 -0
- package/packages/piagent-core/runtime/verification/composite-task-publication.ts +273 -0
- package/packages/piagent-core/runtime/verification/exact-verifier-reuse.ts +11 -11
- package/packages/piagent-core/runtime/verification/host-project-verification.ts +71 -0
- package/packages/piagent-core/runtime/verification/independent-acceptance-runtime.ts +500 -0
- package/packages/piagent-core/runtime/verification/runtime-assurance-facts.ts +500 -0
- package/packages/piagent-core/runtime/verification/runtime-contract-runner.ts +107 -0
- package/packages/piagent-core/runtime/verification/shell-verification-snapshots.ts +56 -0
- package/packages/piagent-core/runtime/workflows/change-clarification.ts +61 -0
- package/packages/piagent-core/runtime/workflows/input-routing.ts +21 -14
- package/packages/piagent-core/runtime/workflows/runtime-intake-compaction.ts +44 -7
- package/packages/piagent-core/runtime/workflows/task-followup-policy.ts +163 -0
- package/packages/piagent-core/runtime/workflows/task-intake.ts +221 -242
- package/packages/piagent-core/runtime/workflows/task-repair-intent.ts +67 -0
- package/packages/piagent-core/runtime/workflows/task-scope-resolution.ts +83 -0
- package/packages/piagent-core/runtime/workflows/webui-runtime-command.ts +5 -2
- package/packages/piagent-core/runtime/workflows/webui-workflow.ts +39 -32
- package/packages/piagent-core/runtime/workflows/workflow-follow-up.ts +33 -0
- package/packages/piagent-core/security/workspace-file-reader.ts +132 -0
- package/packages/piagent-webui/dist/client/assets/{MarkdownMessage-B4XehTCU.js → MarkdownMessage-DGk34zJT.js} +1 -1
- package/packages/piagent-webui/dist/client/assets/{index-BV-_03yl.css → index-DVahUVWy.css} +1 -1
- package/packages/piagent-webui/dist/client/assets/index-DiKRmCEP.js +176 -0
- package/packages/piagent-webui/dist/client/index.html +2 -2
- package/packages/piagent-webui/extension/dispatch-user-entry.ts +13 -0
- package/packages/piagent-webui/extension/piagent-webui.ts +10 -2
- package/packages/piagent-webui/extension/review-controller.ts +29 -6
- package/packages/piagent-webui/extension/same-session-bridge.ts +6 -7
- package/packages/piagent-webui/extension/session-stream-adapter.ts +60 -11
- package/packages/piagent-webui/extension/source-mutation-controller.ts +29 -3
- package/packages/piagent-webui/extension/source-open-controller.ts +29 -7
- package/packages/piagent-webui/extension/source-revert-controller.ts +26 -3
- package/packages/piagent-webui/gateway/gateway-events.ts +22 -5
- package/packages/piagent-webui/gateway/gateway-service.ts +7 -2
- package/packages/piagent-webui/gateway/gateway-session-stream.ts +141 -19
- package/packages/piagent-webui/gateway/rpc-ui-context.ts +34 -9
- package/packages/piagent-webui/gateway/runtime-command-controller.ts +46 -6
- package/packages/piagent-webui/gateway/runtime-session-controls.ts +17 -2
- package/packages/piagent-webui/gateway/session-catalog.ts +9 -3
- package/packages/piagent-webui/gateway/session-command-controller.ts +29 -9
- package/packages/piagent-webui/gateway/session-effective-options.ts +2 -9
- package/packages/piagent-webui/gateway/session-inspection-registry.ts +11 -2
- package/packages/piagent-webui/gateway/session-operation-settlement.ts +28 -0
- package/packages/piagent-webui/gateway/session-prompt-dispatch.ts +37 -0
- package/packages/piagent-webui/gateway/session-runtime-close.ts +36 -0
- package/packages/piagent-webui/gateway/session-runtime-factory.ts +183 -6
- package/packages/piagent-webui/gateway/session-runtime-ownership.ts +48 -0
- package/packages/piagent-webui/gateway/session-runtime-state.ts +24 -0
- package/packages/piagent-webui/gateway/session-runtime-supervisor.ts +114 -114
- package/packages/piagent-webui/server/core-inspection-provider.ts +73 -14
- package/packages/piagent-webui/server/loopback-server.ts +9 -7
- package/packages/piagent-webui/server/terminal-delivery-receipt.ts +144 -0
- package/packages/piagent-webui/server/transcript-projection.ts +65 -12
- package/packages/piagent-webui/shared/message-correlation.ts +25 -0
- package/schemas/approved-host-contracts.schema.json +973 -0
- package/schemas/benchmark-attempt-outcome.schema.json +303 -0
- package/schemas/benchmark-independent-verification-plan.schema.json +34 -0
- package/schemas/composite-criterion.schema.json +788 -0
- package/schemas/contract-family-library.schema.json +28 -0
- package/schemas/contract-selection-recipe.schema.json +31 -0
- package/schemas/failure-evidence.schema.json +2 -2
- package/schemas/helper-request.schema.json +16 -4
- package/schemas/host-contract-plan.schema.json +25 -0
- package/schemas/piagent-webui/gateway-protocol-v1.schema.json +16 -2
- package/schemas/piagent-webui/runtime-command-v1.schema.json +26 -3
- package/schemas/piagent-webui/runtime-event-v2.schema.json +32 -1
- package/schemas/piagent-webui/session-live-state-v1.schema.json +2 -0
- package/schemas/piagent-webui/snapshot-v1.schema.json +3 -0
- package/schemas/piagent-webui/source-change-v1.schema.json +12 -0
- package/schemas/piagent-webui/transcript-v1.schema.json +2 -1
- package/schemas/public-contracts/codex-mcp-metadata-v1.schema.json +206 -0
- package/schemas/public-contracts/codex-mcp-metadata-v2.schema.json +228 -0
- package/schemas/public-contracts/codex-mcp-metadata-v3.schema.json +233 -0
- package/schemas/public-contracts/revocation-v1.schema.json +87 -0
- package/schemas/public-contracts/subscription-contract-v1.schema.json +76 -0
- package/schemas/scoped-project-verification-receipt-v2.schema.json +83 -0
- package/schemas/scoped-project-verification-receipt-v3.schema.json +295 -0
- package/schemas/scoped-verification-receipt-v1.schema.json +76 -0
- package/schemas/task-contract.schema.json +30 -0
- package/scripts/approve-independent-verification.mjs +57 -0
- package/scripts/benchmark-arm-observer.mjs +320 -0
- package/scripts/benchmark-budget-ipc.mjs +34 -0
- package/scripts/benchmark-budget-launcher.mjs +91 -0
- package/scripts/benchmark-budget-processes.mjs +133 -0
- package/scripts/benchmark-budget-publication.mjs +228 -0
- package/scripts/benchmark-budget-runtime.mjs +136 -0
- package/scripts/benchmark-candidate-ablation.mjs +265 -0
- package/scripts/benchmark-codex-journey.mjs +406 -0
- package/scripts/benchmark-independent-verification.mjs +628 -0
- package/scripts/benchmark-journey-outcome.mjs +92 -0
- package/scripts/benchmark-production-v3-human-review.mjs +192 -0
- package/scripts/benchmark-public-input-catalog.mjs +158 -0
- package/scripts/benchmark-registered-plan-author.mjs +355 -0
- package/scripts/benchmark-registered-plan-recipe-support.mjs +85 -0
- package/scripts/benchmark-registered-plan-recipes-backend.mjs +165 -0
- package/scripts/benchmark-registered-plan-recipes-data.mjs +164 -0
- package/scripts/benchmark-registered-plan-recipes-platform.mjs +165 -0
- package/scripts/benchmark-runner-completion.mjs +133 -0
- package/scripts/benchmark-runner-configuration.mjs +159 -0
- package/scripts/benchmark-runner-core.mjs +217 -388
- package/scripts/benchmark-runner-finalization.mjs +140 -27
- package/scripts/benchmark-runner-provider-boundary.mjs +44 -0
- package/scripts/benchmark-runner-schedule.mjs +256 -0
- package/scripts/benchmark-runner-support.mjs +136 -4
- package/scripts/benchmark-runner.mjs +95 -18
- package/scripts/benchmark-scoped-broker-custody.mjs +483 -0
- package/scripts/benchmark-scoped-docs-verifier.mjs +203 -0
- package/scripts/benchmark-scoped-frozen-qualification.mjs +676 -0
- package/scripts/benchmark-scoped-pi-router.mjs +196 -0
- package/scripts/benchmark-scoped-project-verification-receipt.mjs +49 -0
- package/scripts/benchmark-scoped-project-verifier.mjs +461 -0
- package/scripts/benchmark-scoped-session-custody.mjs +599 -0
- package/scripts/benchmark-scoped-session-factory.mjs +342 -0
- package/scripts/benchmark-scoped-tool-broker.mjs +523 -0
- package/scripts/benchmark-scoped-verification-supervisor.mjs +773 -0
- package/scripts/benchmark-session-evaluator.mjs +169 -0
- package/scripts/benchmark-session-provider-boundary.mjs +62 -0
- package/scripts/benchmark-session-usage.mjs +28 -0
- package/scripts/benchmark-session.mjs +343 -50
- package/scripts/benchmark-webui-journey.mjs +678 -0
- package/scripts/check-public-wording.mjs +46 -0
- package/scripts/fs4-readiness-evaluation.mjs +7 -1
- package/scripts/phase-tools-evaluation.mjs +1 -0
- package/scripts/pi-auto.sh +7 -1
- package/scripts/pi-usage-history.mjs +201 -11
- package/scripts/piagent-cli.mjs +8 -0
- package/scripts/private-holdout-readiness.mjs +7 -1
- package/scripts/public-evaluation-exposure.mjs +140 -0
- package/scripts/select-independent-verification.mjs +62 -0
- package/scripts/typescript-loader.mjs +135 -1
- package/scripts/update-global.mjs +6 -7
- package/scripts/verify-local.sh +36 -55
- package/scripts/verify-release-identity.mjs +5 -3
- package/packages/piagent-webui/dist/client/assets/index-CgOEyRPG.js +0 -176
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { isDeepStrictEqual } from "node:util";
|
|
5
|
+
|
|
6
|
+
const MAX_SESSION_BYTES = 64 * 1024 * 1024;
|
|
7
|
+
const MAX_SESSION_ENTRIES = 50_000;
|
|
8
|
+
const ID = /^[A-Za-z0-9][A-Za-z0-9._~-]{0,159}$/;
|
|
9
|
+
const HASH = /^[a-f0-9]{64}$/;
|
|
10
|
+
const CORRELATION_TYPE = "piagent-webui-message-correlation";
|
|
11
|
+
export const COMPOSITE_DELIVERY_CONFIRMATION_TYPE = "piagent-composite-terminal-delivery-v1";
|
|
12
|
+
const persistedCapabilities = new WeakMap<object, PersistedObservation>();
|
|
13
|
+
const deliveryCapabilities = new WeakMap<object, DeliveryObservation>();
|
|
14
|
+
const sha = (value: string | Buffer) => createHash("sha256").update(value).digest("hex");
|
|
15
|
+
|
|
16
|
+
type PersistedObservation = { file: string; cwd: string; sessionId: string; entryId: string;
|
|
17
|
+
digest: string; byteLength: number; bytes: string; entry: any; fileDigest: string };
|
|
18
|
+
type DeliveryObservation = PersistedObservation & { operationRef: string; messageRequestId: string;
|
|
19
|
+
idempotencyKey: string; confirmationEntryId: string; confirmationDigest: string; fileDigest: string };
|
|
20
|
+
|
|
21
|
+
function assistantText(message: any): string {
|
|
22
|
+
if (typeof message?.content === "string") return message.content;
|
|
23
|
+
if (!Array.isArray(message?.content)) return "";
|
|
24
|
+
return message.content.filter((item: any) => item?.type === "text" && typeof item.text === "string")
|
|
25
|
+
.map((item: any) => item.text).join("\n");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function canonicalLine(line: Buffer): any {
|
|
29
|
+
if (!line.length) throw new Error("native-session-empty-record");
|
|
30
|
+
const text = new TextDecoder("utf-8", { fatal: true }).decode(line), value = JSON.parse(text);
|
|
31
|
+
if (!Buffer.from(JSON.stringify(value)).equals(line)) throw new Error("native-session-noncanonical-record");
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function sessionSnapshot(file: string, cwd: string, sessionId: string) {
|
|
36
|
+
if (!path.isAbsolute(file) || path.normalize(file) !== file || fs.realpathSync.native(file) !== file)
|
|
37
|
+
throw new Error("native-session-path-invalid");
|
|
38
|
+
const descriptor = fs.openSync(file, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0));
|
|
39
|
+
try {
|
|
40
|
+
fs.fsyncSync(descriptor);
|
|
41
|
+
const before = fs.fstatSync(descriptor, { bigint: true });
|
|
42
|
+
if (!before.isFile() || before.nlink !== 1n || before.uid !== BigInt(process.getuid?.() ?? Number(before.uid))
|
|
43
|
+
|| before.size < 1n || before.size > BigInt(MAX_SESSION_BYTES)) throw new Error("native-session-file-unsafe");
|
|
44
|
+
const source = fs.readFileSync(descriptor), after = fs.fstatSync(descriptor, { bigint: true });
|
|
45
|
+
const atPath = fs.lstatSync(file, { bigint: true });
|
|
46
|
+
const fields = ["dev", "ino", "mode", "nlink", "uid", "size", "mtimeNs", "ctimeNs"];
|
|
47
|
+
if (source.length !== Number(before.size) || source.at(-1) !== 10 || atPath.isSymbolicLink()
|
|
48
|
+
|| fields.some(field => before[field] !== after[field] || after[field] !== atPath[field]))
|
|
49
|
+
throw new Error("native-session-file-changed");
|
|
50
|
+
const lines: Buffer[] = []; let start = 0;
|
|
51
|
+
for (let index = 0; index < source.length; index += 1) if (source[index] === 10) {
|
|
52
|
+
lines.push(source.subarray(start, index)); start = index + 1;
|
|
53
|
+
}
|
|
54
|
+
if (lines.length < 2 || lines.length > MAX_SESSION_ENTRIES + 1) throw new Error("native-session-entry-bound");
|
|
55
|
+
const [header, ...entries] = lines.map(canonicalLine);
|
|
56
|
+
const headerKeys = Object.keys(header ?? {});
|
|
57
|
+
if (header?.type !== "session" || header.version !== 3 || header.id !== sessionId
|
|
58
|
+
|| header.cwd !== cwd || !Number.isFinite(Date.parse(header.timestamp))
|
|
59
|
+
|| headerKeys.some(key => !["type", "version", "id", "timestamp", "cwd", "parentSession"].includes(key)))
|
|
60
|
+
throw new Error("native-session-header-invalid");
|
|
61
|
+
const ids = new Set<string>();
|
|
62
|
+
for (const entry of entries) {
|
|
63
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry) || !ID.test(entry.id)
|
|
64
|
+
|| ids.has(entry.id) || !Number.isFinite(Date.parse(entry.timestamp))
|
|
65
|
+
|| typeof entry.type !== "string" || entry.parentId !== null && !ids.has(entry.parentId))
|
|
66
|
+
throw new Error("native-session-chain-invalid");
|
|
67
|
+
ids.add(entry.id);
|
|
68
|
+
}
|
|
69
|
+
return { header, entries, all: [header, ...entries], fileDigest: sha(source) };
|
|
70
|
+
} finally { fs.closeSync(descriptor); }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function stableManager(manager: any, snapshot: ReturnType<typeof sessionSnapshot>): any[] {
|
|
74
|
+
if (!manager || manager.isPersisted?.() !== true || typeof manager.getEntries !== "function"
|
|
75
|
+
|| typeof manager.getBranch !== "function" || typeof manager.getEntry !== "function")
|
|
76
|
+
throw new Error("native-session-manager-unavailable");
|
|
77
|
+
const first = manager.getEntries(), firstText = JSON.stringify(first);
|
|
78
|
+
if (firstText !== JSON.stringify(snapshot.entries) || firstText !== JSON.stringify(manager.getEntries()))
|
|
79
|
+
throw new Error("native-session-memory-disk-mismatch");
|
|
80
|
+
return first;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function capturePersistedAssistantResponse(input: { cwd: string; sessionId: string; manager: any;
|
|
84
|
+
message: any; expectedText: string }): object {
|
|
85
|
+
if (!path.isAbsolute(input.cwd) || fs.realpathSync.native(input.cwd) !== input.cwd
|
|
86
|
+
|| !ID.test(input.sessionId) || input.message?.role !== "assistant" || typeof input.expectedText !== "string"
|
|
87
|
+
|| !(input.expectedText as any).isWellFormed() || Buffer.byteLength(input.expectedText) > 65_536
|
|
88
|
+
|| assistantText(input.message) !== input.expectedText) throw new Error("native-response-input-invalid");
|
|
89
|
+
const file = input.manager?.getSessionFile?.();
|
|
90
|
+
if (typeof file !== "string") throw new Error("native-session-file-unavailable");
|
|
91
|
+
const snapshot = sessionSnapshot(file, input.cwd, input.sessionId), memory = stableManager(input.manager, snapshot);
|
|
92
|
+
const matches = memory.filter((entry: any) => entry?.type === "message" && entry.message === input.message);
|
|
93
|
+
if (matches.length !== 1) throw new Error("native-response-object-identity-mismatch");
|
|
94
|
+
const entry = matches[0], branch = input.manager.getBranch();
|
|
95
|
+
if (branch.filter((candidate: any) => candidate === entry).length !== 1 || branch.at(-1) !== entry
|
|
96
|
+
|| input.manager.getLeafId?.() !== entry.id || input.manager.getEntry(entry.id) !== entry
|
|
97
|
+
|| snapshot.entries.at(-1)?.id !== entry.id || !isDeepStrictEqual(snapshot.entries.at(-1), entry))
|
|
98
|
+
throw new Error("native-response-branch-identity-mismatch");
|
|
99
|
+
const observation: PersistedObservation = { file, cwd: input.cwd, sessionId: input.sessionId, entryId: entry.id,
|
|
100
|
+
digest: sha(input.expectedText), byteLength: Buffer.byteLength(input.expectedText), bytes: input.expectedText,
|
|
101
|
+
entry: structuredClone(entry), fileDigest: snapshot.fileDigest };
|
|
102
|
+
const capability = Object.freeze({ version: "native-persisted-response-capability-v1", entryId: entry.id,
|
|
103
|
+
digest: observation.digest, byteLength: observation.byteLength });
|
|
104
|
+
persistedCapabilities.set(capability, observation); return capability;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function persistedAssistantResponseObservation(capability: object): Readonly<PersistedObservation> {
|
|
108
|
+
const value = persistedCapabilities.get(capability);
|
|
109
|
+
if (!value) throw new Error("untrusted-native-response-capability");
|
|
110
|
+
return Object.freeze({ ...value, entry: structuredClone(value.entry) });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function correlation(entry: any) {
|
|
114
|
+
const data = entry?.data;
|
|
115
|
+
return entry?.type === "custom" && entry.customType === CORRELATION_TYPE && data?.schemaVersion === 1
|
|
116
|
+
&& ID.test(data.messageRequestId) && ID.test(data.operationRef)
|
|
117
|
+
? { messageRequestId: data.messageRequestId, operationRef: data.operationRef } : null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function commitCompositeWebUiDelivery(input: { response: object; manager: any; taskRunId: string;
|
|
121
|
+
operationRef: string; messageRequestId: string; idempotencyKey: string }): object {
|
|
122
|
+
const response = persistedCapabilities.get(input.response);
|
|
123
|
+
if (!response || !ID.test(input.taskRunId) || !ID.test(input.operationRef) || !ID.test(input.messageRequestId)
|
|
124
|
+
|| !HASH.test(input.idempotencyKey)) throw new Error("composite-delivery-input-invalid");
|
|
125
|
+
const before = sessionSnapshot(response.file, response.cwd, response.sessionId), memory = stableManager(input.manager, before);
|
|
126
|
+
const branch = input.manager.getBranch(), responseIndex = branch.findIndex((entry: any) => entry?.id === response.entryId);
|
|
127
|
+
const matching = branch.map((entry: any, index: number) => ({ entry, index, value: correlation(entry) }))
|
|
128
|
+
.filter(item => item.value?.operationRef === input.operationRef && item.value?.messageRequestId === input.messageRequestId);
|
|
129
|
+
const globalMatches = memory.filter((entry: any) => { const value = correlation(entry); return value?.operationRef === input.operationRef
|
|
130
|
+
&& value?.messageRequestId === input.messageRequestId; });
|
|
131
|
+
if (responseIndex < 0 || matching.length !== 1 || globalMatches.length !== 1
|
|
132
|
+
|| matching[0].index >= responseIndex || branch.slice(matching[0].index + 1, responseIndex)
|
|
133
|
+
.filter((entry: any) => entry?.type === "message" && entry.message?.role === "user").length !== 1)
|
|
134
|
+
throw new Error("composite-delivery-correlation-mismatch");
|
|
135
|
+
const data = { schemaVersion: 1, taskRunId: input.taskRunId, sessionId: response.sessionId,
|
|
136
|
+
responseEntryId: response.entryId, responseDigest: response.digest, responseByteLength: response.byteLength,
|
|
137
|
+
operationRef: input.operationRef, messageRequestId: input.messageRequestId, idempotencyKey: input.idempotencyKey };
|
|
138
|
+
const existing = branch.filter((entry: any) => entry?.type === "custom"
|
|
139
|
+
&& entry.customType === COMPOSITE_DELIVERY_CONFIRMATION_TYPE && entry.data?.idempotencyKey === input.idempotencyKey);
|
|
140
|
+
if (existing.length === 1) {
|
|
141
|
+
const confirmation = existing[0], disk = before.entries.find((entry: any) => entry?.id === confirmation.id);
|
|
142
|
+
if (branch.at(-1) !== confirmation || !isDeepStrictEqual(confirmation.data, data)
|
|
143
|
+
|| !isDeepStrictEqual(confirmation, disk)) throw new Error("composite-delivery-replay-mismatch");
|
|
144
|
+
const observation: DeliveryObservation = { ...response, operationRef: input.operationRef,
|
|
145
|
+
messageRequestId: input.messageRequestId, idempotencyKey: input.idempotencyKey,
|
|
146
|
+
confirmationEntryId: confirmation.id, confirmationDigest: sha(JSON.stringify(confirmation)), fileDigest: before.fileDigest };
|
|
147
|
+
const capability = Object.freeze({ version: "native-webui-delivery-capability-v1",
|
|
148
|
+
confirmationEntryId: confirmation.id, responseEntryId: response.entryId, idempotencyKey: input.idempotencyKey });
|
|
149
|
+
deliveryCapabilities.set(capability, observation); return capability;
|
|
150
|
+
}
|
|
151
|
+
if (existing.length || branch.at(-1)?.id !== response.entryId) throw new Error("composite-delivery-replay-mismatch");
|
|
152
|
+
if (typeof input.manager.appendCustomEntry !== "function") throw new Error("composite-delivery-append-unavailable");
|
|
153
|
+
const confirmationEntryId = input.manager.appendCustomEntry(COMPOSITE_DELIVERY_CONFIRMATION_TYPE, data);
|
|
154
|
+
if (!ID.test(confirmationEntryId)) throw new Error("composite-delivery-entry-invalid");
|
|
155
|
+
const after = sessionSnapshot(response.file, response.cwd, response.sessionId), current = stableManager(input.manager, after);
|
|
156
|
+
const confirmation = current.at(-1), disk = after.entries.at(-1);
|
|
157
|
+
if (input.manager.getLeafId?.() !== confirmationEntryId || confirmation?.id !== confirmationEntryId
|
|
158
|
+
|| confirmation?.type !== "custom" || confirmation.customType !== COMPOSITE_DELIVERY_CONFIRMATION_TYPE
|
|
159
|
+
|| !isDeepStrictEqual(confirmation.data, data) || !isDeepStrictEqual(confirmation, disk)
|
|
160
|
+
|| after.entries.filter((entry: any) => entry?.customType === COMPOSITE_DELIVERY_CONFIRMATION_TYPE
|
|
161
|
+
&& entry.data?.idempotencyKey === input.idempotencyKey).length !== 1)
|
|
162
|
+
throw new Error("composite-delivery-not-persisted");
|
|
163
|
+
const observation: DeliveryObservation = { ...response, operationRef: input.operationRef,
|
|
164
|
+
messageRequestId: input.messageRequestId, idempotencyKey: input.idempotencyKey,
|
|
165
|
+
confirmationEntryId, confirmationDigest: sha(JSON.stringify(confirmation)), fileDigest: after.fileDigest };
|
|
166
|
+
const capability = Object.freeze({ version: "native-webui-delivery-capability-v1", confirmationEntryId,
|
|
167
|
+
responseEntryId: response.entryId, idempotencyKey: input.idempotencyKey });
|
|
168
|
+
deliveryCapabilities.set(capability, observation); return capability;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function webUiDeliveryObservation(capability: object): Readonly<DeliveryObservation> {
|
|
172
|
+
const value = deliveryCapabilities.get(capability);
|
|
173
|
+
if (!value) throw new Error("untrusted-native-delivery-capability");
|
|
174
|
+
return Object.freeze({ ...value, entry: structuredClone(value.entry) });
|
|
175
|
+
}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { createHash, createHmac, KeyObject, randomUUID, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { types } from "node:util";
|
|
5
|
+
|
|
6
|
+
import type { TaskContract } from "../../extensions/guard-types.ts";
|
|
7
|
+
import { durableTaskContractMatches, normalizeTaskContract, taskContractValidationErrors } from "../../extensions/task-state.js";
|
|
8
|
+
import { isCurrentWorkingTreeDigest } from "../../extensions/working-tree-digest.js";
|
|
9
|
+
import { openCompositeAssuranceJournal } from "./runtime-assurance-facts.ts";
|
|
10
|
+
|
|
11
|
+
export const COMPOSITE_TASK_PUBLICATION_VERSION = "composite-task-publication-v1";
|
|
12
|
+
export const COMPOSITE_TERMINAL_TASK_TARGET_VERSION = "composite-terminal-task-target-v1";
|
|
13
|
+
export const COMPOSITE_JOURNAL_PUBLICATION_VERSION = "composite-journal-publication-v1";
|
|
14
|
+
const HASH = /^[a-f0-9]{64}$/;
|
|
15
|
+
const ID = /^[A-Za-z0-9][A-Za-z0-9:._~-]{0,159}$/;
|
|
16
|
+
const MAX_BYTES = 4 * 1024 * 1024;
|
|
17
|
+
const sha = (value: string | Buffer) => createHash("sha256").update(value).digest("hex");
|
|
18
|
+
|
|
19
|
+
function exact(value: any, fields: string[], label: string) {
|
|
20
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || types.isProxy(value)
|
|
21
|
+
|| ![Object.prototype, null].includes(Object.getPrototypeOf(value))
|
|
22
|
+
|| Object.keys(value).length !== fields.length || fields.some(field => !Object.hasOwn(value, field))) {
|
|
23
|
+
throw new Error(`Invalid ${label}`);
|
|
24
|
+
}
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function freeze<T>(value: T): T {
|
|
29
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
30
|
+
for (const child of Object.values(value as object)) freeze(child);
|
|
31
|
+
Object.freeze(value);
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function canonicalTask(value: any, outcome?: "pending" | "completed"): TaskContract {
|
|
37
|
+
const cloned = structuredClone(value), normalized = normalizeTaskContract(cloned);
|
|
38
|
+
if (!normalized || taskContractValidationErrors(normalized).length || outcome && normalized.trace.outcome !== outcome) {
|
|
39
|
+
throw new Error("Composite publication task contract is invalid");
|
|
40
|
+
}
|
|
41
|
+
return normalized as TaskContract;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** updatedAt is storage metadata; every other normalized task byte is publication identity. */
|
|
45
|
+
export function compositeTaskPublicationDigest(value: TaskContract): string {
|
|
46
|
+
const task = canonicalTask(value), { updatedAt: _updatedAt, ...identity } = task;
|
|
47
|
+
return sha(JSON.stringify(identity));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function privateDirectory(directory: string, projectRoot: string) {
|
|
51
|
+
const root = fs.realpathSync.native(projectRoot);
|
|
52
|
+
if (!path.isAbsolute(directory) || fs.realpathSync.native(directory) !== directory) throw new Error("Publication directory is not canonical");
|
|
53
|
+
const relative = path.relative(root, directory), stat = fs.lstatSync(directory);
|
|
54
|
+
if (!relative || (!relative.startsWith(`..${path.sep}`) && relative !== ".." && !path.isAbsolute(relative))
|
|
55
|
+
|| !stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid() || (stat.mode & 0o077) !== 0) {
|
|
56
|
+
throw new Error("Publication directory is not private host state");
|
|
57
|
+
}
|
|
58
|
+
return root;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function key32(key: unknown): asserts key is KeyObject {
|
|
62
|
+
if (!(key instanceof KeyObject) || key.type !== "secret" || key.symmetricKeySize !== 32) throw new TypeError("Expected host 256-bit secret key");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function validateEntry(value: any, terminalTaskDigest: string) {
|
|
66
|
+
exact(value, ["version", "criterionId", "criterionHash", "contextDigest", "journalFile", "preAggregateHead", "aggregate"],
|
|
67
|
+
"composite journal publication");
|
|
68
|
+
exact(value.aggregate, ["idempotencyKey", "assessmentDigest", "taskPublicationDigest"], "composite aggregate publication");
|
|
69
|
+
if (value.version !== COMPOSITE_JOURNAL_PUBLICATION_VERSION || !ID.test(value.criterionId) || !HASH.test(value.criterionHash)
|
|
70
|
+
|| !HASH.test(value.contextDigest) || !/^composite-[a-f0-9]{64}\.jsonl$/.test(value.journalFile)
|
|
71
|
+
|| !HASH.test(value.preAggregateHead) || !HASH.test(value.aggregate.idempotencyKey)
|
|
72
|
+
|| !HASH.test(value.aggregate.assessmentDigest) || value.aggregate.taskPublicationDigest !== terminalTaskDigest) {
|
|
73
|
+
throw new Error("Composite journal publication identity is invalid");
|
|
74
|
+
}
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function validatePayload(value: any, projectRoot: string) {
|
|
79
|
+
exact(value, ["version", "projectId", "taskRunId", "sessionId", "operatorRequestDigest", "pendingTaskDigest",
|
|
80
|
+
"terminalTaskDigest", "workingTreeDigest", "terminalTask", "entries"], "composite task publication");
|
|
81
|
+
const task = canonicalTask(value.terminalTask, "completed");
|
|
82
|
+
if (value.version !== COMPOSITE_TASK_PUBLICATION_VERSION || value.projectId !== sha(fs.realpathSync.native(projectRoot))
|
|
83
|
+
|| value.taskRunId !== task.taskRunId || value.sessionId !== task.sessionId
|
|
84
|
+
|| value.operatorRequestDigest !== task.operatorRequestDigest || !ID.test(value.taskRunId) || !ID.test(value.sessionId)
|
|
85
|
+
|| !/^operator-request-v1:[a-f0-9]{64}$/.test(value.operatorRequestDigest) || !HASH.test(value.pendingTaskDigest)
|
|
86
|
+
|| value.terminalTaskDigest !== compositeTaskPublicationDigest(task) || !isCurrentWorkingTreeDigest(value.workingTreeDigest)
|
|
87
|
+
|| !Array.isArray(value.entries) || value.entries.length < 1 || value.entries.length > 12) {
|
|
88
|
+
throw new Error("Composite task publication target is invalid");
|
|
89
|
+
}
|
|
90
|
+
const ids = new Set<string>();
|
|
91
|
+
for (const entry of value.entries) {
|
|
92
|
+
validateEntry(entry, value.terminalTaskDigest);
|
|
93
|
+
if (ids.has(entry.criterionId)) throw new Error("Duplicate composite publication criterion");
|
|
94
|
+
ids.add(entry.criterionId);
|
|
95
|
+
}
|
|
96
|
+
value.terminalTask = task;
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
type JournalStatus = "pre-aggregate" | "aggregate-settled" | "task-completed";
|
|
101
|
+
|
|
102
|
+
export function openCompositeTaskPublicationStore({ key, directory, projectRoot }: {
|
|
103
|
+
key: KeyObject; directory: string; projectRoot: string }) {
|
|
104
|
+
key32(key); privateDirectory(directory, projectRoot);
|
|
105
|
+
const records = new WeakSet<object>();
|
|
106
|
+
const fileFor = (taskRunId: string, sessionId: string) => path.join(directory,
|
|
107
|
+
`composite-publication-${sha(`${taskRunId}\0${sessionId}`)}.json`);
|
|
108
|
+
const signature = (file: string, text: string) => createHmac("sha256", key)
|
|
109
|
+
.update(`${COMPOSITE_TASK_PUBLICATION_VERSION}\0${file}\0${text}`).digest("hex");
|
|
110
|
+
|
|
111
|
+
function readFile(file: string) {
|
|
112
|
+
if (!fs.existsSync(file)) return null;
|
|
113
|
+
const atPath = fs.lstatSync(file, { bigint: true });
|
|
114
|
+
if (!atPath.isFile() || atPath.isSymbolicLink() || atPath.nlink !== 1n || atPath.uid !== BigInt(process.getuid())
|
|
115
|
+
|| (atPath.mode & 0o077n) !== 0n || atPath.size < 1n || atPath.size > BigInt(MAX_BYTES)) {
|
|
116
|
+
throw new Error("Composite publication file is unsafe");
|
|
117
|
+
}
|
|
118
|
+
const fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
119
|
+
try {
|
|
120
|
+
const before = fs.fstatSync(fd, { bigint: true }), bytes = fs.readFileSync(fd), after = fs.fstatSync(fd, { bigint: true });
|
|
121
|
+
const fields = ["dev", "ino", "mode", "nlink", "uid", "size", "mtimeNs", "ctimeNs"];
|
|
122
|
+
if (bytes.length !== Number(before.size) || fields.some(field => before[field] !== after[field] || after[field] !== atPath[field])) {
|
|
123
|
+
throw new Error("Composite publication changed during read");
|
|
124
|
+
}
|
|
125
|
+
const envelope = exact(JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes)),
|
|
126
|
+
["payload", "signature"], "composite publication envelope");
|
|
127
|
+
if (!Buffer.from(JSON.stringify(envelope)).equals(bytes) || !HASH.test(envelope.signature)) throw new Error("Composite publication is noncanonical");
|
|
128
|
+
const text = JSON.stringify(envelope.payload), expected = signature(file, text);
|
|
129
|
+
if (!timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(envelope.signature, "hex"))) {
|
|
130
|
+
throw new Error("Composite publication signature is invalid");
|
|
131
|
+
}
|
|
132
|
+
const record = freeze(validatePayload(envelope.payload, projectRoot)); records.add(record); return record;
|
|
133
|
+
} finally { fs.closeSync(fd); }
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function read(taskRunId: string, sessionId: string) {
|
|
137
|
+
if (!ID.test(taskRunId) || !ID.test(sessionId)) throw new TypeError("Invalid composite publication task identity");
|
|
138
|
+
return readFile(fileFor(taskRunId, sessionId));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function trusted(record: any) {
|
|
142
|
+
if (!record || !records.has(record)) throw new Error("Untrusted composite task publication");
|
|
143
|
+
const current = readFile(fileFor(record.taskRunId, record.sessionId));
|
|
144
|
+
if (!current || JSON.stringify(current) !== JSON.stringify(record)) throw new Error("Composite task publication changed");
|
|
145
|
+
return current;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function journalStatus(entry: any): JournalStatus {
|
|
149
|
+
const filePath = path.join(directory, entry.journalFile);
|
|
150
|
+
const journal = openCompositeAssuranceJournal({ filePath, projectRoot, key, contextDigest: entry.contextDigest });
|
|
151
|
+
try {
|
|
152
|
+
const head = journal.head(), events = journal.events();
|
|
153
|
+
if (head === entry.preAggregateHead) return "pre-aggregate";
|
|
154
|
+
const first = events.findIndex((event: any) => event.previous === entry.preAggregateHead);
|
|
155
|
+
if (first < 0) throw new Error("Composite publication journal does not extend its prepared head");
|
|
156
|
+
const tail = events.slice(first);
|
|
157
|
+
if (tail.length < 1 || tail.length > 2 || tail[0].kind !== "aggregate-settled"
|
|
158
|
+
|| JSON.stringify(tail[0].data) !== JSON.stringify(entry.aggregate)) {
|
|
159
|
+
throw new Error("Composite publication aggregate journal mismatch");
|
|
160
|
+
}
|
|
161
|
+
if (tail.length === 1) return "aggregate-settled";
|
|
162
|
+
if (tail[1].kind !== "task-completed" || JSON.stringify(tail[1].data) !== JSON.stringify(entry.aggregate)) {
|
|
163
|
+
throw new Error("Composite publication completion journal mismatch");
|
|
164
|
+
}
|
|
165
|
+
return "task-completed";
|
|
166
|
+
} finally { journal.close(); }
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function appendCompletion(entry: any) {
|
|
170
|
+
const filePath = path.join(directory, entry.journalFile);
|
|
171
|
+
const journal = openCompositeAssuranceJournal({ filePath, projectRoot, key, contextDigest: entry.contextDigest });
|
|
172
|
+
try { journal.append("task-completed", entry.aggregate); } finally { journal.close(); }
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function appendAggregate(entry: any) {
|
|
176
|
+
const filePath = path.join(directory, entry.journalFile);
|
|
177
|
+
const journal = openCompositeAssuranceJournal({ filePath, projectRoot, key, contextDigest: entry.contextDigest });
|
|
178
|
+
try {
|
|
179
|
+
if (journal.head() !== entry.preAggregateHead) throw new Error("Composite aggregate recovery head changed");
|
|
180
|
+
journal.append("aggregate-settled", entry.aggregate);
|
|
181
|
+
} finally { journal.close(); }
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function inspect(record: any) {
|
|
185
|
+
const current = trusted(record);
|
|
186
|
+
const statuses = current.entries.map((entry: any) => ({ criterionId: entry.criterionId, status: journalStatus(entry) }));
|
|
187
|
+
return freeze({ statuses, allSettled: statuses.every(item => item.status !== "pre-aggregate"),
|
|
188
|
+
allCompleted: statuses.every(item => item.status === "task-completed") });
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function prepare({ pendingTask, terminalTask, workingTreeDigest, entries }: any) {
|
|
192
|
+
const pending = canonicalTask(pendingTask, "pending"), terminal = canonicalTask(terminalTask, "completed");
|
|
193
|
+
if (pending.taskRunId !== terminal.taskRunId || pending.sessionId !== terminal.sessionId
|
|
194
|
+
|| pending.operatorRequestDigest !== terminal.operatorRequestDigest || !isCurrentWorkingTreeDigest(workingTreeDigest)) {
|
|
195
|
+
throw new Error("Composite publication pending and terminal tasks do not match");
|
|
196
|
+
}
|
|
197
|
+
const payload = validatePayload({ version: COMPOSITE_TASK_PUBLICATION_VERSION,
|
|
198
|
+
projectId: sha(fs.realpathSync.native(projectRoot)), taskRunId: terminal.taskRunId, sessionId: terminal.sessionId,
|
|
199
|
+
operatorRequestDigest: terminal.operatorRequestDigest, pendingTaskDigest: compositeTaskPublicationDigest(pending),
|
|
200
|
+
terminalTaskDigest: compositeTaskPublicationDigest(terminal), workingTreeDigest, terminalTask: terminal,
|
|
201
|
+
entries: structuredClone(entries) }, projectRoot);
|
|
202
|
+
const file = fileFor(payload.taskRunId, payload.sessionId), text = JSON.stringify(payload);
|
|
203
|
+
const envelope = Buffer.from(JSON.stringify({ payload, signature: signature(file, text) }));
|
|
204
|
+
if (envelope.length > MAX_BYTES) throw new Error("Composite publication exceeds byte bound");
|
|
205
|
+
const existing = readFile(file);
|
|
206
|
+
if (existing) {
|
|
207
|
+
if (JSON.stringify(existing) !== JSON.stringify(payload)) throw new Error("Different composite publication already exists");
|
|
208
|
+
return existing;
|
|
209
|
+
}
|
|
210
|
+
for (const entry of payload.entries) if (journalStatus(entry) !== "pre-aggregate") {
|
|
211
|
+
throw new Error("Aggregate exists without its durable task publication intent");
|
|
212
|
+
}
|
|
213
|
+
const temporary = path.join(directory, `.${path.basename(file)}.${process.pid}.${randomUUID()}.tmp`);
|
|
214
|
+
const fd = fs.openSync(temporary, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL
|
|
215
|
+
| fs.constants.O_NOFOLLOW, 0o600);
|
|
216
|
+
try {
|
|
217
|
+
try {
|
|
218
|
+
for (let offset = 0; offset < envelope.length;) {
|
|
219
|
+
const written = fs.writeSync(fd, envelope, offset, envelope.length - offset);
|
|
220
|
+
if (written < 1) throw new Error("Composite publication write was incomplete");
|
|
221
|
+
offset += written;
|
|
222
|
+
}
|
|
223
|
+
fs.fsyncSync(fd);
|
|
224
|
+
} finally { fs.closeSync(fd); }
|
|
225
|
+
fs.renameSync(temporary, file); fs.chmodSync(file, 0o600);
|
|
226
|
+
const parent = fs.openSync(directory, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
227
|
+
try { fs.fsyncSync(parent); } finally { fs.closeSync(parent); }
|
|
228
|
+
} catch (error) { try { fs.unlinkSync(temporary); } catch {} throw error; }
|
|
229
|
+
const observed = readFile(file);
|
|
230
|
+
if (!observed || JSON.stringify(observed) !== JSON.stringify(payload)) throw new Error("Composite publication readback failed");
|
|
231
|
+
return observed;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function settle(record: any) {
|
|
235
|
+
const current = trusted(record);
|
|
236
|
+
for (const entry of current.entries) if (journalStatus(entry) === "pre-aggregate") appendAggregate(entry);
|
|
237
|
+
const result = inspect(current);
|
|
238
|
+
if (!result.allSettled) throw new Error("Composite aggregate settlement recovery is incomplete");
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function complete(record: any) {
|
|
243
|
+
const current = trusted(record);
|
|
244
|
+
const before = inspect(current);
|
|
245
|
+
if (!before.allSettled) throw new Error("Composite task cannot complete before every aggregate");
|
|
246
|
+
for (const entry of current.entries) if (journalStatus(entry) === "aggregate-settled") appendCompletion(entry);
|
|
247
|
+
const result = inspect(current);
|
|
248
|
+
if (!result.allCompleted) throw new Error("Composite task completion recovery is incomplete");
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return Object.freeze({ version: COMPOSITE_TASK_PUBLICATION_VERSION, read, prepare, inspect, settle, complete });
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export function recoverCompositeTaskPublication({ store, record, task, currentWorkingTreeDigest,
|
|
256
|
+
expectedCriteria, cwd, writeTask }: any): TaskContract {
|
|
257
|
+
if (!store || store.version !== COMPOSITE_TASK_PUBLICATION_VERSION || !Array.isArray(expectedCriteria)
|
|
258
|
+
|| typeof writeTask !== "function" || record.operatorRequestDigest !== task.operatorRequestDigest
|
|
259
|
+
|| record.workingTreeDigest !== currentWorkingTreeDigest) throw new Error("Composite publication recovery binding changed");
|
|
260
|
+
const expected = expectedCriteria.map((item: any) => `${item.criterionId}\0${item.criterionHash}`).sort();
|
|
261
|
+
const actual = record.entries.map((item: any) => `${item.criterionId}\0${item.criterionHash}`).sort();
|
|
262
|
+
if (JSON.stringify(expected) !== JSON.stringify(actual)) throw new Error("Composite publication criteria changed");
|
|
263
|
+
let completed = canonicalTask(task);
|
|
264
|
+
if (completed.trace.outcome === "pending") {
|
|
265
|
+
if (compositeTaskPublicationDigest(completed) !== record.pendingTaskDigest) throw new Error("Composite pending task changed before recovery");
|
|
266
|
+
} else if (completed.trace.outcome !== "completed" || compositeTaskPublicationDigest(completed) !== record.terminalTaskDigest) {
|
|
267
|
+
throw new Error("Composite terminal task does not match its publication");
|
|
268
|
+
}
|
|
269
|
+
store.settle(record);
|
|
270
|
+
if (completed.trace.outcome === "pending") completed = writeTask(cwd, record.terminalTask);
|
|
271
|
+
if (!durableTaskContractMatches(cwd, completed)) throw new Error("Recovered terminal task is not durable");
|
|
272
|
+
store.complete(record); return completed;
|
|
273
|
+
}
|
|
@@ -4,11 +4,7 @@ import type { TaskContract } from "../../extensions/guard-types.ts";
|
|
|
4
4
|
import { extractShellCommandInput, normalizeShellCommandForPolicy } from "../../extensions/guard-shell-analysis.ts";
|
|
5
5
|
import { commandMatchesVerifyPlan } from "../../extensions/runtime-evidence.js";
|
|
6
6
|
import { passingVerifyCommandsForDigest } from "../../extensions/task-contract-view.js";
|
|
7
|
-
import {
|
|
8
|
-
workingTreeSnapshot,
|
|
9
|
-
workingTreeSnapshotHasUnavailableEvidence
|
|
10
|
-
} from "../../extensions/task-state.js";
|
|
11
|
-
import { workingTreeEvidenceDigest } from "../../extensions/task-lifecycle.js";
|
|
7
|
+
import { captureWorkspaceVerificationSnapshot } from "../../extensions/workspace-verification-snapshot.js";
|
|
12
8
|
|
|
13
9
|
const SHELL_TOOLS = new Set(["bash", "shell", "exec"]);
|
|
14
10
|
const REUSE_COMMAND = "printf '%s\\n' 'Piagent reused exact verifier evidence for the unchanged working tree; the verifier was not rerun.'";
|
|
@@ -49,6 +45,7 @@ export function evaluateExactVerifierReuse(input: {
|
|
|
49
45
|
toolName: string;
|
|
50
46
|
toolInput: Record<string, unknown>;
|
|
51
47
|
workingTreeDigest: string | null;
|
|
48
|
+
workspaceRevisionDigest?: string | null;
|
|
52
49
|
sessionEntries?: unknown[];
|
|
53
50
|
}): ExactVerifierReuseDecision {
|
|
54
51
|
const no = (reasonCode: string): ExactVerifierReuseDecision => ({ reused: false, reasonCode, commandDigest: null, workingTreeDigest: input.workingTreeDigest });
|
|
@@ -61,7 +58,7 @@ export function evaluateExactVerifierReuse(input: {
|
|
|
61
58
|
if (!extracted.command || extracted.reason) return no("shell-command-unavailable");
|
|
62
59
|
const command = normalizeShellCommandForPolicy(extracted.command);
|
|
63
60
|
if (!commandMatchesVerifyPlan(command, task.verifyCommands)) return no("not-exact-verifier");
|
|
64
|
-
const passing = passingVerifyCommandsForDigest(task, input.workingTreeDigest);
|
|
61
|
+
const passing = passingVerifyCommandsForDigest(task, input.workingTreeDigest, input.workspaceRevisionDigest);
|
|
65
62
|
const exactVerifier = task.verifyCommands.find((candidate) => (
|
|
66
63
|
passing.has(candidate.trim())
|
|
67
64
|
&& commandMatchesVerifyPlan(command, [candidate])
|
|
@@ -84,6 +81,7 @@ export function reuseCurrentTreeExactVerifier(input: {
|
|
|
84
81
|
toolName: string;
|
|
85
82
|
toolInput: Record<string, unknown>;
|
|
86
83
|
sessionEntries?: unknown[];
|
|
84
|
+
getHostProjectVerificationDigest?: (snapshot: ReturnType<typeof captureWorkspaceVerificationSnapshot>, exactCommand: string) => string | null;
|
|
87
85
|
}): ExactVerifierReuseDecision {
|
|
88
86
|
if (!input.task || !SHELL_TOOLS.has(input.toolName)) {
|
|
89
87
|
return { reused: false, reasonCode: "not-applicable", commandDigest: null, workingTreeDigest: null };
|
|
@@ -93,9 +91,11 @@ export function reuseCurrentTreeExactVerifier(input: {
|
|
|
93
91
|
if (!command || !commandMatchesVerifyPlan(command, input.task.verifyCommands)) {
|
|
94
92
|
return { reused: false, reasonCode: "not-exact-verifier", commandDigest: null, workingTreeDigest: null };
|
|
95
93
|
}
|
|
96
|
-
const snapshot =
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
:
|
|
100
|
-
|
|
94
|
+
const snapshot = captureWorkspaceVerificationSnapshot(input.cwd);
|
|
95
|
+
const observedDigest = input.getHostProjectVerificationDigest?.(snapshot, command);
|
|
96
|
+
if (typeof observedDigest !== "string" || !/^[a-f0-9]{64}$/.test(observedDigest)) {
|
|
97
|
+
return { reused: false, reasonCode: "host-project-verifier-observation-missing", commandDigest: null, workingTreeDigest: snapshot.digest };
|
|
98
|
+
}
|
|
99
|
+
return evaluateExactVerifierReuse({ ...input, workingTreeDigest: snapshot.proofCapable ? snapshot.digest : null,
|
|
100
|
+
workspaceRevisionDigest: snapshot.workspaceRevisionDigest });
|
|
101
101
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import type { TaskContract } from "../../extensions/guard-types.ts";
|
|
4
|
+
import { toolResultFingerprint } from "../../extensions/context-engine.js";
|
|
5
|
+
import { claimedExitMatchesObserved, hashEvidenceCommand, observedBashResultFromToolResultEvent } from "../../extensions/runtime-evidence.js";
|
|
6
|
+
import { meaningfulVerificationCommands } from "../../extensions/verification-intelligence.js";
|
|
7
|
+
import { captureWorkspaceVerificationSnapshot } from "../../extensions/workspace-verification-snapshot.js";
|
|
8
|
+
import type { ShellVerificationSnapshots } from "./shell-verification-snapshots.ts";
|
|
9
|
+
|
|
10
|
+
export const HOST_PROJECT_VERIFICATION_VERSION = "host-project-verification-v1";
|
|
11
|
+
type Snapshot = ReturnType<typeof captureWorkspaceVerificationSnapshot>;
|
|
12
|
+
type ToolEvent = { toolCallId?: string; toolName: string; input?: unknown; details?: unknown; isError?: boolean };
|
|
13
|
+
const hash = (value: unknown): string => createHash("sha256").update(JSON.stringify(value)).digest("hex");
|
|
14
|
+
|
|
15
|
+
function taskBinding(task: TaskContract): string {
|
|
16
|
+
return hash([task.taskId, task.taskRunId, task.sessionId, task.operatorRequestDigest ?? null,
|
|
17
|
+
task.verifyCommands, task.acceptanceReceipt?.promptHash ?? null,
|
|
18
|
+
task.acceptanceReceipt?.criteria.map(({ id, hash: criterionHash }) => [id, criterionHash]) ?? []]);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Host-only live observations, never reconstructed from task JSON or stdout. */
|
|
22
|
+
export class HostProjectVerification {
|
|
23
|
+
readonly #invocations: ShellVerificationSnapshots;
|
|
24
|
+
readonly #latest = new Map<string, { taskBinding: string; digest: string; revision: string } | null>();
|
|
25
|
+
constructor(invocations: ShellVerificationSnapshots) { this.#invocations = invocations; }
|
|
26
|
+
#prefix(ctx: ExtensionContext): string { return `${ctx.cwd}\0${ctx.sessionManager.getSessionId()}\0`; }
|
|
27
|
+
#key(ctx: ExtensionContext, task: TaskContract, commandHash: string): string { return `${this.#prefix(ctx)}${task.taskRunId}\0${commandHash}`; }
|
|
28
|
+
|
|
29
|
+
observe(ctx: ExtensionContext, task: TaskContract | undefined, event: ToolEvent, before: Snapshot | undefined, after: Snapshot | undefined): void {
|
|
30
|
+
if (!task || !["pending", "completed"].includes(task.trace.outcome) || task.sessionId !== ctx.sessionManager.getSessionId()) return;
|
|
31
|
+
const observed = observedBashResultFromToolResultEvent(event, ctx.cwd);
|
|
32
|
+
if (!observed?.commandHash || !meaningfulVerificationCommands(task.verifyCommands).some((command) => hashEvidenceCommand(command) === observed.commandHash)) return;
|
|
33
|
+
const callId = event.toolCallId ?? toolResultFingerprint(event.toolName, event.input, []).key;
|
|
34
|
+
const issued = this.#invocations.claimObservation(ctx, event.toolName, event.input, callId, task.taskRunId, before);
|
|
35
|
+
const key = this.#key(ctx, task, observed.commandHash);
|
|
36
|
+
// Every new result replaces the previous result, including unavailable,
|
|
37
|
+
// unmatched, contradictory, or failed observations. No timestamp selection.
|
|
38
|
+
this.#latest.set(key, task.trace.outcome === "pending" && issued && before?.proofCapable && after?.proofCapable
|
|
39
|
+
&& before.digest === after.digest && before.workspaceRevisionDigest === after.workspaceRevisionDigest
|
|
40
|
+
&& claimedExitMatchesObserved(0, { ...observed, isError: event.isError }) && event.isError !== true
|
|
41
|
+
? { taskBinding: taskBinding(task), digest: after.digest, revision: after.workspaceRevisionDigest! } : null);
|
|
42
|
+
while (this.#latest.size > 500) this.#latest.delete(this.#latest.keys().next().value as string);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
currentDigest(ctx: ExtensionContext, task: TaskContract, current: Snapshot, exactCommand?: string, { completedProjection = false } = {}): string | null {
|
|
46
|
+
// A completed task may display an existing live observation, but cannot
|
|
47
|
+
// create one or reserve a new independent execution. New tool results
|
|
48
|
+
// invalidate it even after completion; JSON alone never restores it.
|
|
49
|
+
if ((task.trace.outcome !== "pending" && !(completedProjection && task.trace.outcome === "completed"))
|
|
50
|
+
|| task.sessionId !== ctx.sessionManager.getSessionId() || !current.proofCapable) return null;
|
|
51
|
+
if (this.#invocations.hasPending(ctx, task.taskRunId)) return null;
|
|
52
|
+
const commands = meaningfulVerificationCommands(task.verifyCommands);
|
|
53
|
+
if (commands.length === 0 || commands.length !== task.verifyCommands.length) return null;
|
|
54
|
+
const selected = exactCommand === undefined ? commands : commands.filter((command) => hashEvidenceCommand(command) === hashEvidenceCommand(exactCommand));
|
|
55
|
+
if (selected.length === 0) return null;
|
|
56
|
+
const binding = taskBinding(task), commandHashes = selected.map(hashEvidenceCommand);
|
|
57
|
+
if (commandHashes.some((command) => !command)) return null;
|
|
58
|
+
for (const command of commandHashes) {
|
|
59
|
+
const entry = this.#latest.get(this.#key(ctx, task, command));
|
|
60
|
+
if (!entry || entry.taskBinding !== binding || entry.digest !== current.digest || entry.revision !== current.workspaceRevisionDigest) return null;
|
|
61
|
+
}
|
|
62
|
+
// Equivalent newly observed passing checks can reuse the same independent
|
|
63
|
+
// evidence. Availability comes from live state, not from this public hash.
|
|
64
|
+
return hash([HOST_PROJECT_VERIFICATION_VERSION, ctx.cwd, binding, current.digest, current.workspaceRevisionDigest, commandHashes]);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
clear(ctx: ExtensionContext): void {
|
|
68
|
+
const prefix = this.#prefix(ctx);
|
|
69
|
+
for (const key of this.#latest.keys()) if (key.startsWith(prefix)) this.#latest.delete(key);
|
|
70
|
+
}
|
|
71
|
+
}
|