@piagent/platform 1.6.1 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +71 -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/model-options.md +20 -15
- 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 +3 -0
- package/docs/quality-benchmark.md +128 -8
- package/docs/quickstart-vietnamese.md +2 -2
- package/docs/release-install-policy.md +38 -11
- 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 +23 -0
- package/docs-site/content/runtime.html +2 -2
- package/docs-site/content/whats-new.html +23 -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 +24 -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 +24 -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/model-route-policy.ts +33 -13
- package/packages/piagent-core/runtime/model/model-route-types.ts +10 -6
- 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-DMU7Xe_O.js} +1 -1
- package/packages/piagent-webui/dist/client/assets/index-Cui9AAV_.js +176 -0
- package/packages/piagent-webui/dist/client/assets/{index-BV-_03yl.css → index-DVahUVWy.css} +1 -1
- 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 +14 -6
- 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/configure-model-scope.sh +6 -2
- package/scripts/fs4-readiness-evaluation.mjs +7 -1
- package/scripts/install-global.sh +2 -2
- package/scripts/model-route-evaluation-core.ts +1 -0
- package/scripts/phase-tools-evaluation.mjs +1 -0
- package/scripts/pi-auto.sh +7 -1
- package/scripts/pi-model-route.mjs +1 -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/setup.sh +2 -2
- package/scripts/typescript-loader.mjs +135 -1
- package/scripts/update-global.mjs +6 -7
- package/scripts/verify-local.sh +37 -56
- package/scripts/verify-release-identity.mjs +5 -3
- package/templates/global/settings.json +5 -1
- package/packages/piagent-webui/dist/client/assets/index-CgOEyRPG.js +0 -176
|
@@ -0,0 +1,756 @@
|
|
|
1
|
+
import { parse, parseExpression } from "@babel/parser";
|
|
2
|
+
import { flatRecordFactories, flatRecordValue } from "./acceptance-literal-dataflow.js";
|
|
3
|
+
import { literalArrayIterationEnvironmentIsStable } from "./acceptance-executable-evidence.js";
|
|
4
|
+
import { integerAssertionArguments, integerTestInputsStable } from "./acceptance-integer-domains.js";
|
|
5
|
+
|
|
6
|
+
/** A closed rejection clause declares its input domain. Test literals may
|
|
7
|
+
* witness that domain, but cannot add requirements for incidental arguments.
|
|
8
|
+
* Other prose remains with the existing engines; never consume a substring
|
|
9
|
+
* and silently discard an additional constraint.
|
|
10
|
+
*/
|
|
11
|
+
export function rejectedIntegerParameter(text, contextText) {
|
|
12
|
+
const clause = String(text ?? "").replace(/\s+/g, " ").trim();
|
|
13
|
+
const match = /^`?([A-Za-z_$][\w$]*)`?\s+must\s+reject\s+(?:a\s+)?non-integer\s+`?([A-Za-z_$][\w$]*)`?\s+with\s+`?(TypeError|RangeError|Error)`?[.;]?$/i.exec(clause);
|
|
14
|
+
if (match) return { target: match[1], parameter: match[2], errorClass: match[3] };
|
|
15
|
+
const plain = clause.replaceAll("`", "");
|
|
16
|
+
if (!/^Reject\s+negative(?:\/|\s+or\s+)non-integer\b/i.test(plain)) return null;
|
|
17
|
+
const compound = /^Reject\s+negative(?:\/|\s+or\s+)non-integer\s+([A-Za-z_$][\w$]*(?:\s+(?:or|and)\s+[A-Za-z_$][\w$]*)*)\s+inputs?\s+with\s+(TypeError|RangeError|Error)[.;]?$/i.exec(plain);
|
|
18
|
+
const parameters = compound ? compound[1].split(/\s+(?:or|and)\s+/i) : [];
|
|
19
|
+
const contract = { target: null, parameters, errorClass: compound?.[2] ?? null, partitions: ["negative", "fractional"] };
|
|
20
|
+
const fields = recordIntegerContext(contract, contextText);
|
|
21
|
+
return fields ? { ...contract, recordFields: fields } : contract;
|
|
22
|
+
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const memberName = node => node?.type === "Identifier" ? node.name
|
|
26
|
+
: node?.type === "MemberExpression" && !node.computed
|
|
27
|
+
? `${memberName(node.object)}.${node.property.name}` : null;
|
|
28
|
+
|
|
29
|
+
function hasFractionalWitness(assertions, binding, index) {
|
|
30
|
+
return assertions.some(assertion => {
|
|
31
|
+
if (!binding.testNames.some(name => assertion.targets.includes(name))) return false;
|
|
32
|
+
try {
|
|
33
|
+
const operation = parseExpression(assertion.operation);
|
|
34
|
+
const body = operation.body?.type === "BlockStatement" && operation.body.body.length === 1
|
|
35
|
+
? operation.body.body[0]?.argument : operation.body;
|
|
36
|
+
if (body?.type !== "CallExpression" || body.arguments.some(argument => argument.type === "SpreadElement")
|
|
37
|
+
|| !binding.testNames.includes(memberName(body.callee))) return false;
|
|
38
|
+
const argument = body.arguments[index];
|
|
39
|
+
const value = argument?.type === "NumericLiteral" ? argument.value
|
|
40
|
+
: argument?.type === "UnaryExpression" && argument.operator === "-" && argument.argument.type === "NumericLiteral"
|
|
41
|
+
? -argument.argument.value : undefined;
|
|
42
|
+
return typeof value === "number" && Number.isFinite(value) && !Number.isInteger(value);
|
|
43
|
+
} catch { return false; }
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// This additional domain proof is deliberately exact: an unshadowed intrinsic
|
|
48
|
+
// predicate, before any effect or early return, immediately throws the declared
|
|
49
|
+
// intrinsic error. Existing import, source-origin, verifier and tree gates are
|
|
50
|
+
// still mandatory. More complex guards need their own supported proof.
|
|
51
|
+
function directIntegerGuard(sourceEntries, binding, contract, parameterIndex) {
|
|
52
|
+
let selected;
|
|
53
|
+
try {
|
|
54
|
+
for (const entry of sourceEntries) {
|
|
55
|
+
if (entry.text.length > 64_000) return false;
|
|
56
|
+
const ast = parse(entry.text, { sourceType: "unambiguous", plugins: /\.[cm]?tsx?$/.test(entry.path) ? ["typescript"] : ["jsx"] });
|
|
57
|
+
let safe = true, count = 0;
|
|
58
|
+
const visit = (node, parent, grandparent, depth = 0) => {
|
|
59
|
+
if (!node || typeof node.type !== "string") return;
|
|
60
|
+
if (++count > 12_000 || depth > 128) throw new Error("parameter-proof-budget");
|
|
61
|
+
if (node.type === "Identifier" && node.name === "Number") {
|
|
62
|
+
if (!(parent?.type === "MemberExpression" && parent.object === node && !parent.computed
|
|
63
|
+
&& ["isInteger", "isSafeInteger", "isFinite"].includes(parent.property.name)
|
|
64
|
+
&& grandparent?.type === "CallExpression" && grandparent.callee === parent)) safe = false;
|
|
65
|
+
}
|
|
66
|
+
for (const [key, value] of Object.entries(node)) {
|
|
67
|
+
if (["loc", "extra", "comments", "tokens", "errors"].includes(key)) continue;
|
|
68
|
+
if (Array.isArray(value)) value.forEach(item => visit(item, node, parent, depth + 1));
|
|
69
|
+
else if (value && typeof value === "object") visit(value, node, parent, depth + 1);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
visit(ast);
|
|
73
|
+
if (!safe) return false;
|
|
74
|
+
if (entry.path !== binding.sourcePath) continue;
|
|
75
|
+
for (const statement of ast.program.body) {
|
|
76
|
+
const node = statement.declaration ?? statement;
|
|
77
|
+
if (node.type === "FunctionDeclaration" && node.id?.name.toLowerCase() === binding.sourceName) selected = node;
|
|
78
|
+
if (node.type === "VariableDeclaration") for (const item of node.declarations) {
|
|
79
|
+
if (item.id.name?.toLowerCase() === binding.sourceName && ["ArrowFunctionExpression", "FunctionExpression"].includes(item.init?.type)) selected = item.init;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (!selected?.params.every(parameter => parameter.type === "Identifier")
|
|
84
|
+
|| selected.params[parameterIndex].name !== (contract.parameter ?? contract.parameters[parameterIndex]) || selected.async || selected.generator) return false;
|
|
85
|
+
const candidates = contract.parameters ? selected.body?.body?.slice(0, contract.parameters.length) : [selected.body?.body?.[0]];
|
|
86
|
+
const parameterFor = statement => {
|
|
87
|
+
const condition = statement?.test, predicate = condition?.type === "LogicalExpression" && condition.operator === "||" ? condition.left : null;
|
|
88
|
+
const lower = condition?.right, name = predicate?.argument?.arguments?.[0]?.name;
|
|
89
|
+
return statement?.type === "IfStatement" && !statement.alternate && predicate?.type === "UnaryExpression" && predicate.operator === "!"
|
|
90
|
+
&& predicate.argument.type === "CallExpression" && memberName(predicate.argument.callee) === "Number.isInteger"
|
|
91
|
+
&& predicate.argument.arguments.length === 1 && predicate.argument.arguments[0].type === "Identifier"
|
|
92
|
+
&& lower?.type === "BinaryExpression" && lower.operator === "<" && lower.left.type === "Identifier" && lower.left.name === name
|
|
93
|
+
&& lower.right.type === "NumericLiteral" && lower.right.value === 0 ? name : null;
|
|
94
|
+
};
|
|
95
|
+
if (contract.parameters && (candidates?.length !== contract.parameters.length
|
|
96
|
+
|| new Set(candidates.map(parameterFor)).size !== contract.parameters.length
|
|
97
|
+
|| candidates.some(statement => !contract.parameters.includes(parameterFor(statement))))) return false;
|
|
98
|
+
const first = contract.parameters ? candidates.find(statement => parameterFor(statement) === contract.parameter) : candidates[0];
|
|
99
|
+
const condition = contract.parameters ? first?.test?.left : first?.test;
|
|
100
|
+
if (first?.type !== "IfStatement" || condition?.type !== "UnaryExpression" || condition.operator !== "!"
|
|
101
|
+
|| condition.argument?.type !== "CallExpression" || memberName(condition.argument.callee) !== "Number.isInteger"
|
|
102
|
+
|| condition.argument.arguments.length !== 1 || condition.argument.arguments[0].type !== "Identifier"
|
|
103
|
+
|| condition.argument.arguments[0].name !== contract.parameter) return false;
|
|
104
|
+
const consequent = first.consequent.type === "BlockStatement" && first.consequent.body.length === 1
|
|
105
|
+
? first.consequent.body[0] : first.consequent;
|
|
106
|
+
const error = consequent?.argument;
|
|
107
|
+
return consequent?.type === "ThrowStatement" && error?.type === "NewExpression"
|
|
108
|
+
&& error.callee.type === "Identifier" && error.callee.name === contract.errorClass
|
|
109
|
+
&& error.arguments.every(argument => ["StringLiteral", "NumericLiteral", "BooleanLiteral", "NullLiteral"].includes(argument.type));
|
|
110
|
+
} catch { return false; }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function integerParameterBindingEvidence({ contract, binding, parameters, assertions, sourceEntries, testEntries = [] }) {
|
|
114
|
+
if (contract?.recordFields) return recordWitnesses({ contract, binding, assertions, sourceEntries, testEntries });
|
|
115
|
+
if (!contract) return null;
|
|
116
|
+
if (contract.parameters) {
|
|
117
|
+
const unique = new Set(contract.parameters.map(name => name.toLowerCase()));
|
|
118
|
+
const indices = contract.parameters.map(name => parameters.indexOf(name.toLowerCase()));
|
|
119
|
+
const bound = indices.length > 0 && indices.length <= 8 && unique.size === indices.length && indices.every(index => index >= 0);
|
|
120
|
+
const invocations = assertions.flatMap(assertion => binding.testNames.flatMap(name => integerAssertionArguments(assertion, name)));
|
|
121
|
+
const valid = value => value?.kind === "number" && Number.isInteger(value.value) && value.value >= 0;
|
|
122
|
+
return {
|
|
123
|
+
sourceOk: bound && indices.every((index, order) => directIntegerGuard(sourceEntries, binding, { ...contract, parameter: contract.parameters[order] }, index)),
|
|
124
|
+
testOk: bound && indices.every(index => contract.partitions.every(partition => invocations.some(args =>
|
|
125
|
+
args[index]?.kind === "number" && indices.every(other => other === index || valid(args[other]))
|
|
126
|
+
&& (partition === "negative" ? args[index].value < 0 : Number.isFinite(args[index].value) && !Number.isInteger(args[index].value))))),
|
|
127
|
+
inputs: bound ? indices.map(index => ({ name: parameters[index], partitions: contract.partitions })) : []
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const index = parameters.findIndex(name => name === contract.parameter.toLowerCase());
|
|
131
|
+
const bound = binding.target === contract.target.toLowerCase() && index >= 0;
|
|
132
|
+
return {
|
|
133
|
+
sourceOk: bound && directIntegerGuard(sourceEntries, binding, contract, index),
|
|
134
|
+
testOk: bound && hasFractionalWitness(assertions, binding, index),
|
|
135
|
+
inputs: bound ? [{ name: parameters[index], partitions: ["fractional"] }] : []
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Related task prose can bind a monetary input to a per-record field. This
|
|
140
|
+
// projection supplies names only; it cannot replace source guards or witnesses.
|
|
141
|
+
function recordIntegerContext(contract, contextText) {
|
|
142
|
+
if (!contract?.parameters || contract.parameters.length !== 2 || !contract.parameters.includes("money")
|
|
143
|
+
|| typeof contextText !== "string" || contextText.length > 16_000) return null;
|
|
144
|
+
const context = contextText.replace(/\s+/g, " ");
|
|
145
|
+
if (!/\bAll values are integer cents or basis points\./i.test(context)) return null;
|
|
146
|
+
const matches = [...context.matchAll(/\bFor each [a-z]+, multiply `([A-Za-z_$][\w$]*)` by the positive integer `([A-Za-z_$][\w$]*)` \(default ([1-9]\d*)\)/g)];
|
|
147
|
+
const tuples = [...new Set(matches.map(match => JSON.stringify(match.slice(1))))].map(value => JSON.parse(value));
|
|
148
|
+
if (tuples.length !== 1) return null;
|
|
149
|
+
const [money, quantity, defaultValue] = tuples[0];
|
|
150
|
+
if (money === quantity || !contract.parameters.includes(quantity) || !Number.isSafeInteger(Number(defaultValue))) return null;
|
|
151
|
+
return [{ name: money, minimum: 0 }, { name: quantity, minimum: 1, defaultValue: Number(defaultValue) }];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const recordFail = () => { throw new Error("unsupported-record-integer-proof"); };
|
|
155
|
+
const recordNumber = node => node?.type === "NumericLiteral" && Number.isFinite(node.value) ? node.value
|
|
156
|
+
: memberName(node) === "Number.MAX_SAFE_INTEGER" ? Number.MAX_SAFE_INTEGER : undefined;
|
|
157
|
+
const recordParameter = node => node?.type === "Identifier" ? node.name
|
|
158
|
+
: node?.type === "AssignmentPattern" && node.left.type === "Identifier" && recordNumber(node.right) !== undefined ? node.left.name : null;
|
|
159
|
+
function recordSourceFunctions(entries, sourcePath) {
|
|
160
|
+
let selected;
|
|
161
|
+
for (const entry of entries) {
|
|
162
|
+
if (entry.text.length > 64_000) recordFail();
|
|
163
|
+
const ast = parse(entry.text, { sourceType: "module", errorRecovery: false });
|
|
164
|
+
const functions = new Map(), protectedNames = new Set(["Number", "Math", "Array", "TypeError", "RangeError", "Error"]);
|
|
165
|
+
for (const statement of ast.program.body) {
|
|
166
|
+
const fn = statement.type === "ExportNamedDeclaration" && !statement.source ? statement.declaration : statement;
|
|
167
|
+
if (fn?.type !== "FunctionDeclaration" || fn.async || fn.generator || !fn.id || functions.has(fn.id.name)
|
|
168
|
+
|| protectedNames.has(fn.id.name)) recordFail();
|
|
169
|
+
functions.set(fn.id.name, fn);
|
|
170
|
+
}
|
|
171
|
+
for (const name of functions.keys()) protectedNames.add(name);
|
|
172
|
+
let count = 0;
|
|
173
|
+
const visit = (node, parent, depth = 0) => {
|
|
174
|
+
if (!node || typeof node.type !== "string") return;
|
|
175
|
+
if (++count > 12_000 || depth > 128) recordFail();
|
|
176
|
+
if (["AssignmentExpression", "UpdateExpression", "AwaitExpression", "YieldExpression", "ThisExpression"].includes(node.type)) recordFail();
|
|
177
|
+
if (node.type === "CallExpression" && !functions.has(node.callee.name)
|
|
178
|
+
&& !["Number.isInteger", "Number.isSafeInteger", "Number.isFinite", "Math.round", "Math.floor", "Math.ceil", "Array.isArray"].includes(memberName(node.callee))
|
|
179
|
+
&& !(node.callee.type === "MemberExpression" && !node.callee.computed && ["reduce", "every"].includes(node.callee.property.name))) recordFail();
|
|
180
|
+
if (node.type === "Identifier" && ["Number", "Math", "Array"].includes(node.name)
|
|
181
|
+
&& !(parent?.type === "MemberExpression" && parent.object === node && !parent.computed)) recordFail();
|
|
182
|
+
if (node.type === "VariableDeclarator" && (node.id.type !== "Identifier" || protectedNames.has(node.id.name))) recordFail();
|
|
183
|
+
if (/Function/.test(node.type) && node.params) {
|
|
184
|
+
const names = node.params.map(recordParameter);
|
|
185
|
+
if (names.some(name => !name || protectedNames.has(name)) || new Set(names).size !== names.length) recordFail();
|
|
186
|
+
}
|
|
187
|
+
for (const [key, value] of Object.entries(node)) {
|
|
188
|
+
if (["loc", "extra", "comments", "tokens", "errors"].includes(key)) continue;
|
|
189
|
+
if (Array.isArray(value)) value.forEach(item => visit(item, node, depth + 1));
|
|
190
|
+
else if (value && typeof value === "object") visit(value, node, depth + 1);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
visit(ast);
|
|
194
|
+
if (entry.path === sourcePath) selected = functions;
|
|
195
|
+
}
|
|
196
|
+
return selected ?? recordFail();
|
|
197
|
+
}
|
|
198
|
+
function recordError(statement, errorClass) {
|
|
199
|
+
const body = statement?.type === "BlockStatement" && statement.body.length === 1 ? statement.body[0] : statement;
|
|
200
|
+
return body?.type === "ThrowStatement" && body.argument?.type === "NewExpression"
|
|
201
|
+
&& body.argument.callee.type === "Identifier" && body.argument.callee.name === errorClass
|
|
202
|
+
&& body.argument.arguments.every(node => ["StringLiteral", "NumericLiteral", "NullLiteral", "BooleanLiteral"].includes(node.type));
|
|
203
|
+
}
|
|
204
|
+
function recordGuard(call, functions, errorClass) {
|
|
205
|
+
const helper = call?.type === "CallExpression" && call.callee.type === "Identifier" ? functions.get(call.callee.name) : null;
|
|
206
|
+
if (!helper || call.arguments.length < 2 || call.arguments.length > helper.params.length || helper.params.length > 3
|
|
207
|
+
|| helper.body.body.length !== 2 || helper.body.body[1].type !== "ReturnStatement"
|
|
208
|
+
|| helper.body.body[1].argument?.name !== recordParameter(helper.params[0])) return null;
|
|
209
|
+
const names = helper.params.map(recordParameter), constants = new Map();
|
|
210
|
+
for (let index = 1; index < names.length; index++) {
|
|
211
|
+
const value = recordNumber(call.arguments[index] ?? helper.params[index]?.right);
|
|
212
|
+
if (!Number.isSafeInteger(value)) return null;
|
|
213
|
+
constants.set(names[index], value);
|
|
214
|
+
}
|
|
215
|
+
const guard = helper.body.body[0], terms = [];
|
|
216
|
+
const flatten = node => node?.type === "LogicalExpression" && node.operator === "||"
|
|
217
|
+
? (flatten(node.left), flatten(node.right)) : terms.push(node);
|
|
218
|
+
flatten(guard?.test);
|
|
219
|
+
const predicate = terms[0]?.argument;
|
|
220
|
+
if (guard?.type !== "IfStatement" || guard.alternate || !recordError(guard.consequent, errorClass)
|
|
221
|
+
|| terms.length < 2 || terms.length > 3 || terms[0].type !== "UnaryExpression" || terms[0].operator !== "!"
|
|
222
|
+
|| predicate?.type !== "CallExpression" || !["Number.isInteger", "Number.isSafeInteger"].includes(memberName(predicate.callee))
|
|
223
|
+
|| predicate.arguments.length !== 1 || predicate.arguments[0].type !== "Identifier" || predicate.arguments[0].name !== names[0]) return null;
|
|
224
|
+
const bound = (term, operator) => term?.type === "BinaryExpression" && term.operator === operator
|
|
225
|
+
&& term.left.type === "Identifier" && term.left.name === names[0]
|
|
226
|
+
? recordNumber(term.right) ?? constants.get(term.right.name) : undefined;
|
|
227
|
+
const minimum = bound(terms[1], "<"), maximum = terms.length === 3 ? bound(terms[2], ">") : Infinity;
|
|
228
|
+
if (!Number.isSafeInteger(minimum) || !(maximum >= minimum)) return null;
|
|
229
|
+
return { minimum, maximum, safe: memberName(predicate.callee) === "Number.isSafeInteger" };
|
|
230
|
+
}
|
|
231
|
+
function recordPureNumber(node, names) {
|
|
232
|
+
if (node?.type === "Identifier") return names.has(node.name);
|
|
233
|
+
if (node?.type === "NumericLiteral") return Number.isFinite(node.value);
|
|
234
|
+
if (node?.type === "UnaryExpression" && ["+", "-"].includes(node.operator)) return recordPureNumber(node.argument, names);
|
|
235
|
+
if (node?.type === "BinaryExpression" && ["+", "-", "*", "/", "%", "**"].includes(node.operator)) return recordPureNumber(node.left, names) && recordPureNumber(node.right, names);
|
|
236
|
+
return node?.type === "CallExpression" && ["Math.round", "Math.floor", "Math.ceil"].includes(memberName(node.callee))
|
|
237
|
+
&& node.arguments.length === 1 && recordPureNumber(node.arguments[0], names);
|
|
238
|
+
}
|
|
239
|
+
function recordSourceProfile({ contract, binding, sourceEntries }) {
|
|
240
|
+
try {
|
|
241
|
+
const functions = recordSourceFunctions(sourceEntries, binding.sourcePath);
|
|
242
|
+
const candidates = [...functions.values()].filter(fn => fn.id.name.toLowerCase() === binding.sourceName);
|
|
243
|
+
if (candidates.length !== 1) return null;
|
|
244
|
+
const fn = candidates[0], params = fn.params.map(recordParameter), statements = fn.body.body;
|
|
245
|
+
const guard = statements[0], array = guard?.test?.argument;
|
|
246
|
+
if (guard?.type !== "IfStatement" || guard.alternate || guard.test.type !== "UnaryExpression" || guard.test.operator !== "!"
|
|
247
|
+
|| array?.type !== "CallExpression" || memberName(array.callee) !== "Array.isArray" || array.arguments.length !== 1
|
|
248
|
+
|| array.arguments[0].type !== "Identifier" || !params.includes(array.arguments[0].name)
|
|
249
|
+
|| !recordError(guard.consequent, contract.errorClass)) return null;
|
|
250
|
+
const arrayName = array.arguments[0].name, arrayIndex = params.indexOf(arrayName), scalars = new Map(), numbers = new Set();
|
|
251
|
+
const allNames = new Set([...params, ...functions.keys(), "Number", "Array", "Math"]);
|
|
252
|
+
let fields;
|
|
253
|
+
for (const statement of statements.slice(1, -1)) {
|
|
254
|
+
if (statement.type === "ExpressionStatement") {
|
|
255
|
+
const call = statement.expression, domain = recordGuard(call, functions, contract.errorClass), name = call.arguments?.[0]?.name;
|
|
256
|
+
if (fields || !domain || !params.includes(name) || name === arrayName || scalars.has(name)) return null;
|
|
257
|
+
scalars.set(name, domain); numbers.add(name); continue;
|
|
258
|
+
}
|
|
259
|
+
if (statement.type !== "VariableDeclaration" || statement.kind !== "const" || statement.declarations.length !== 1 || fields) return null;
|
|
260
|
+
const declaration = statement.declarations[0], call = declaration.init, callback = call?.arguments?.[0];
|
|
261
|
+
if (declaration.id.type !== "Identifier" || allNames.has(declaration.id.name) || call?.type !== "CallExpression"
|
|
262
|
+
|| memberName(call.callee) !== `${arrayName}.reduce` || call.arguments.length !== 2 || recordNumber(call.arguments[1]) === undefined
|
|
263
|
+
|| callback?.type !== "ArrowFunctionExpression" || callback.async || callback.params.length !== 2
|
|
264
|
+
|| callback.params.some(param => param.type !== "Identifier" || allNames.has(param.name))
|
|
265
|
+
|| callback.body.type !== "BlockStatement") return null;
|
|
266
|
+
const [accumulator, element] = callback.params.map(param => param.name), locals = new Set([accumulator]), seen = new Set(allNames);
|
|
267
|
+
seen.add(accumulator); seen.add(element); fields = new Map();
|
|
268
|
+
for (const step of callback.body.body.slice(0, -1)) {
|
|
269
|
+
if (step.type !== "VariableDeclaration" || step.kind !== "const" || step.declarations.length !== 1) return null;
|
|
270
|
+
const local = step.declarations[0], invocation = local.init, domain = recordGuard(invocation, functions, contract.errorClass);
|
|
271
|
+
let property = invocation?.arguments?.[0], defaultValue;
|
|
272
|
+
if (property?.type === "LogicalExpression" && property.operator === "??") { defaultValue = recordNumber(property.right); property = property.left; if (defaultValue === undefined) return null; }
|
|
273
|
+
if (local.id.type !== "Identifier" || seen.has(local.id.name) || !domain
|
|
274
|
+
|| !["OptionalMemberExpression", "MemberExpression"].includes(property?.type) || property.computed
|
|
275
|
+
|| property.object.type !== "Identifier" || property.object.name !== element || fields.has(property.property.name)) return null;
|
|
276
|
+
fields.set(property.property.name, { ...domain, defaultValue }); seen.add(local.id.name); locals.add(local.id.name);
|
|
277
|
+
}
|
|
278
|
+
const last = callback.body.body.at(-1);
|
|
279
|
+
if (last?.type !== "ReturnStatement" || !recordPureNumber(last.argument, locals)) return null;
|
|
280
|
+
numbers.add(declaration.id.name);
|
|
281
|
+
}
|
|
282
|
+
if (!fields || scalars.size !== params.length - 1 || statements.at(-1)?.type !== "ReturnStatement"
|
|
283
|
+
|| !recordPureNumber(statements.at(-1).argument, numbers)) return null;
|
|
284
|
+
if (!contract.recordFields.every(field => fields.has(field.name) && fields.get(field.name).minimum === field.minimum
|
|
285
|
+
&& fields.get(field.name).defaultValue === field.defaultValue)) return null;
|
|
286
|
+
return { arrayIndex, fields, scalars: params.map(name => scalars.get(name)), defaults: fn.params.map(param => param.type === "AssignmentPattern" ? recordNumber(param.right) : undefined) };
|
|
287
|
+
} catch { return null; }
|
|
288
|
+
}
|
|
289
|
+
function recordLiteral(node, bindings = new Map(), depth = 0) {
|
|
290
|
+
if (!node || depth > 4) return null;
|
|
291
|
+
if (node.type === "Identifier" && bindings.has(node.name)) return bindings.get(node.name);
|
|
292
|
+
if (node.type === "ArrayExpression" && node.elements.length <= 16) {
|
|
293
|
+
const values = node.elements.map(item => recordLiteral(item, bindings, depth + 1));
|
|
294
|
+
return values.every(Boolean) ? { kind: "array", values } : null;
|
|
295
|
+
}
|
|
296
|
+
if (node.type === "ObjectExpression" && node.properties.length <= 16) {
|
|
297
|
+
const values = new Map();
|
|
298
|
+
for (const property of node.properties) {
|
|
299
|
+
if (property.type !== "ObjectProperty" || property.computed || property.method || property.key.type !== "Identifier"
|
|
300
|
+
|| ["__proto__", "constructor", "prototype"].includes(property.key.name) || values.has(property.key.name)) return null;
|
|
301
|
+
const value = recordLiteral(property.value, bindings, depth + 1); if (!value) return null;
|
|
302
|
+
values.set(property.key.name, value);
|
|
303
|
+
}
|
|
304
|
+
return { kind: "record", values };
|
|
305
|
+
}
|
|
306
|
+
if (node.type === "NumericLiteral") return { kind: "number", value: node.value };
|
|
307
|
+
if (node.type === "UnaryExpression" && ["+", "-"].includes(node.operator)) { const value = recordLiteral(node.argument, bindings, depth + 1); return value?.kind === "number" ? { kind: "number", value: node.operator === "-" ? -value.value : value.value } : null; }
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
function recordWitnesses({ contract, binding, assertions, sourceEntries, testEntries }) {
|
|
311
|
+
const profile = recordSourceProfile({ contract, binding, sourceEntries });
|
|
312
|
+
if (!profile) return { sourceOk: false, testOk: false, inputs: [], recordSourceOk: false };
|
|
313
|
+
const valid = (value, domain) => value?.kind === "number" && Number.isInteger(value.value)
|
|
314
|
+
&& (!domain.safe || Number.isSafeInteger(value.value)) && value.value >= domain.minimum && value.value <= domain.maximum;
|
|
315
|
+
let stable = testEntries.length > 0 && testEntries.every(entry => integerTestInputsStable(entry.text)
|
|
316
|
+
&& literalArrayIterationEnvironmentIsStable(entry.text));
|
|
317
|
+
for (const entry of testEntries) {
|
|
318
|
+
try {
|
|
319
|
+
const ast = parse(entry.text, { sourceType: "module" });
|
|
320
|
+
const inspect = (node, parent, grandparent) => {
|
|
321
|
+
if (!node || typeof node.type !== "string") return;
|
|
322
|
+
if (node.type === "Identifier" && node.name === "Array" && !(parent?.type === "MemberExpression"
|
|
323
|
+
&& parent.object === node && !parent.computed && ["isArray", "from", "of"].includes(parent.property.name)
|
|
324
|
+
&& grandparent?.type === "CallExpression" && grandparent.callee === parent)) stable = false;
|
|
325
|
+
if (node.type === "ObjectProperty" && node.key.type === "Identifier" && !node.computed
|
|
326
|
+
&& [...profile.fields.keys()].some(name => name.toLowerCase() === node.key.name.toLowerCase() && name !== node.key.name)) stable = false;
|
|
327
|
+
for (const [key, value] of Object.entries(node)) { if (["loc", "extra", "comments", "tokens", "errors"].includes(key)) continue; if (Array.isArray(value)) value.forEach(item => inspect(item, node, parent)); else if (value && typeof value === "object") inspect(value, node, parent); }
|
|
328
|
+
};
|
|
329
|
+
inspect(ast);
|
|
330
|
+
} catch { stable = false; }
|
|
331
|
+
}
|
|
332
|
+
const invocations = assertions.flatMap(assertion => binding.testNames.flatMap(name => integerAssertionArguments(assertion, name, recordLiteral)));
|
|
333
|
+
const testOk = stable && contract.recordFields.every(field => contract.partitions.every(partition => invocations.some(args => {
|
|
334
|
+
const array = args[profile.arrayIndex];
|
|
335
|
+
if (array?.kind !== "array" || array.values.length !== 1 || array.values[0].kind !== "record"
|
|
336
|
+
|| args.length > profile.scalars.length || profile.scalars.some((domain, index) => domain && !valid(args[index] ?? { kind: "number", value: profile.defaults[index] }, domain))) return false;
|
|
337
|
+
const record = array.values[0].values, candidate = record.get(field.name.toLowerCase());
|
|
338
|
+
if (candidate?.kind !== "number" || !(partition === "negative" ? candidate.value < 0 : Number.isFinite(candidate.value) && !Number.isInteger(candidate.value))) return false;
|
|
339
|
+
return [...profile.fields].every(([name, domain]) => name === field.name
|
|
340
|
+
|| valid(record.get(name.toLowerCase()) ?? { kind: "number", value: domain.defaultValue }, domain));
|
|
341
|
+
})));
|
|
342
|
+
return { sourceOk: true, testOk, inputs: [], recordSourceOk: true };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export { recordSourceFunctions as closedNumericValidationFunctions, recordError as closedLiteralError };
|
|
346
|
+
|
|
347
|
+
// A bounded record-transition contract keeps identifier rejection and applied
|
|
348
|
+
// order together. Names come from the declared signature and field clause.
|
|
349
|
+
function orderedRecordContract(text, contextText) {
|
|
350
|
+
let clause=String(text??'').replace(/\s+/g,' ').trim();
|
|
351
|
+
if(!/Preserve applied-event order and reject malformed state or event shapes/i.test(clause))return null;
|
|
352
|
+
const result={supported:false},context=String(contextText??'');if(context.length>16000)return result;
|
|
353
|
+
const declarations=[...new Set([...context.matchAll(/Each event has a unique non-empty string `[\w$]+`, a non-empty string `[\w$]+`, an integer `[\w$]+`, and `[\w$]+`\./g)].map(item=>item[0]))];
|
|
354
|
+
if(declarations.length>1)return result;
|
|
355
|
+
if(/^Preserve applied-event order and reject malformed state or event shapes, including empty IDs, with `?TypeError`?[.;]?$/i.test(clause)&&declarations.length===1)clause=declarations[0]+' '+clause;
|
|
356
|
+
const match=/^Each event has a unique non-empty string `([\w$]+)`, a non-empty string `([\w$]+)`, an integer `([\w$]+)`, and `([\w$]+)`\. Preserve applied-event order and reject malformed state or event shapes, including empty IDs, with `?(TypeError)`?[.;]?$/i.exec(clause);
|
|
357
|
+
if(!match)return result;
|
|
358
|
+
const signatures=[...new Set([...context.matchAll(/`([A-Za-z_$][\w$]*)\(\s*([A-Za-z_$][\w$]*)\s*,\s*([A-Za-z_$][\w$]*)\s*\)`/g)].map(item=>JSON.stringify(item.slice(1))))].map(value=>JSON.parse(value));
|
|
359
|
+
if(signatures.length!==1||new Set(match.slice(1,5)).size!==4||signatures[0][1]===signatures[0][2])return result;
|
|
360
|
+
return {supported:true,target:signatures[0][0],parameters:signatures[0].slice(1),id:match[1],owner:match[2],revision:match[3],payload:match[4],errorClass:match[5]};
|
|
361
|
+
}
|
|
362
|
+
const orderedTerms=(node,operator)=>node?.type==='LogicalExpression'&&node.operator===operator?[...orderedTerms(node.left,operator),...orderedTerms(node.right,operator)]:[node];
|
|
363
|
+
const orderedIdentifier=(node,name)=>node?.type==='Identifier'&&node.name===name;
|
|
364
|
+
const orderedMember=(node,root,field)=>memberName(node)===`${root}.${field}`;
|
|
365
|
+
const orderedCall=(node,name,args)=>node?.type==='CallExpression'&&memberName(node.callee)===name&&node.arguments.length===args.length&&args.every((check,index)=>check(node.arguments[index]));
|
|
366
|
+
const orderedNot=(node,check)=>node?.type==='UnaryExpression'&&node.operator==='!'&&check(node.argument);
|
|
367
|
+
const orderedNumber=(node,value)=>node?.type==='NumericLiteral'&&node.value===value;
|
|
368
|
+
const orderedConst=node=>node?.type==='VariableDeclaration'&&node.kind==='const'&&node.declarations.length===1&&node.declarations[0].id.type==='Identifier'?node.declarations[0]:null;
|
|
369
|
+
function orderedWalk(node,visit,parent=null,depth=0,budget={count:0}) {
|
|
370
|
+
if(!node||typeof node.type!=='string')return;
|
|
371
|
+
if(++budget.count>12000||depth>128)throw new Error('ordered-record-budget');visit(node,parent);
|
|
372
|
+
for(const [key,value]of Object.entries(node)){
|
|
373
|
+
if(['loc','extra','comments','tokens','errors'].includes(key))continue;
|
|
374
|
+
if(Array.isArray(value))value.forEach(item=>orderedWalk(item,visit,node,depth+1,budget));
|
|
375
|
+
else if(value&&typeof value==='object')orderedWalk(value,visit,node,depth+1,budget);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
function orderedPredicate(fn,kind) {
|
|
379
|
+
if(!fn||fn.async||fn.generator||fn.params.length!==1||fn.params[0].type!=='Identifier'||fn.body.body.length!==1||fn.body.body[0].type!=='ReturnStatement')return false;
|
|
380
|
+
const name=fn.params[0].name,terms=orderedTerms(fn.body.body[0].argument,'&&');
|
|
381
|
+
const type=(node,wanted)=>node?.type==='BinaryExpression'&&node.operator==='==='&&node.left.type==='UnaryExpression'&&node.left.operator==='typeof'
|
|
382
|
+
&&orderedIdentifier(node.left.argument,name)&&node.right.type==='StringLiteral'&&node.right.value===wanted;
|
|
383
|
+
return kind==='record'?terms.length===3&&orderedIdentifier(terms[0],name)&&type(terms[1],'object')
|
|
384
|
+
&&orderedNot(terms[2],node=>orderedCall(node,'Array.isArray',[arg=>orderedIdentifier(arg,name)]))
|
|
385
|
+
:terms.length===2&&type(terms[0],'string')&&terms[1].type==='BinaryExpression'&&terms[1].operator==='>'
|
|
386
|
+
&&orderedMember(terms[1].left,name,'length')&&orderedNumber(terms[1].right,0);
|
|
387
|
+
}
|
|
388
|
+
function orderedRecordSource(contract,binding,sourceEntries) {
|
|
389
|
+
if(!contract.supported||binding.sourceName.toLowerCase()!==contract.target.toLowerCase()||sourceEntries.length!==1||sourceEntries[0].path!==binding.sourcePath)return null;
|
|
390
|
+
try {
|
|
391
|
+
const entry=sourceEntries[0];if(entry.text.length>64000)return null;
|
|
392
|
+
const ast=parse(entry.text,{sourceType:'module'}),functions=new Map(),exports=[];
|
|
393
|
+
for(const statement of ast.program.body){
|
|
394
|
+
const fn=statement.type==='ExportNamedDeclaration'&&!statement.source?statement.declaration:statement;
|
|
395
|
+
if(fn?.type!=='FunctionDeclaration'||fn.async||fn.generator||!fn.id||functions.has(fn.id.name))return null;
|
|
396
|
+
functions.set(fn.id.name,fn);if(statement.type==='ExportNamedDeclaration')exports.push(fn.id.name);
|
|
397
|
+
}
|
|
398
|
+
if(functions.size!==3||exports.length!==1||exports[0]!==contract.target)return null;
|
|
399
|
+
const fn=functions.get(contract.target);if(fn.params.length!==2||fn.params.some((node,index)=>!orderedIdentifier(node,contract.parameters[index]))||fn.body.body.length!==5)return null;
|
|
400
|
+
const [initial,events]=contract.parameters,[guard,copyDeclaration,setDeclaration,loop,returned]=fn.body.body,parts=orderedTerms(guard?.test,'||');
|
|
401
|
+
const recordName=parts[0]?.argument?.callee?.name,stringName=parts[3]?.arguments?.[0]?.body?.argument?.callee?.name;
|
|
402
|
+
if(recordName===stringName||recordName===contract.target||stringName===contract.target||!orderedPredicate(functions.get(recordName),'record')||!orderedPredicate(functions.get(stringName),'string'))return null;
|
|
403
|
+
const safeField=name=>typeof name==='string'&&/^[A-Za-z_$][\w$]*$/.test(name)&&!['constructor','prototype','__proto__'].includes(name);
|
|
404
|
+
const dictionary=parts[1]?.argument?.arguments?.[0]?.property?.name,appliedField=parts[2]?.argument?.arguments?.[0]?.property?.name;
|
|
405
|
+
if(!safeField(dictionary)||!safeField(appliedField)||dictionary===appliedField)return null;
|
|
406
|
+
const record=(node,check)=>orderedNot(node,call=>orderedCall(call,recordName,[check]));
|
|
407
|
+
const string=(node,check)=>orderedNot(node,call=>orderedCall(call,stringName,[check]));
|
|
408
|
+
const integer=(node,check)=>orderedNot(node,call=>orderedCall(call,'Number.isInteger',[check]));
|
|
409
|
+
const negative=(node,check)=>node?.type==='BinaryExpression'&&node.operator==='<'&&check(node.left)&&orderedNumber(node.right,0);
|
|
410
|
+
const callback=parts[3]?.arguments?.[0];
|
|
411
|
+
if(guard.type!=='IfStatement'||guard.alternate||!recordError(guard.consequent,contract.errorClass)||parts.length!==5
|
|
412
|
+
||!record(parts[0],arg=>orderedIdentifier(arg,initial))||!record(parts[1],arg=>orderedMember(arg,initial,dictionary))
|
|
413
|
+
||!orderedNot(parts[2],call=>orderedCall(call,'Array.isArray',[arg=>orderedMember(arg,initial,appliedField)]))
|
|
414
|
+
||!orderedCall(parts[3],`${initial}.${appliedField}.some`,[arg=>arg===callback])||callback.type!=='ArrowFunctionExpression'||callback.async||callback.params.length!==1||callback.params[0].type!=='Identifier'
|
|
415
|
+
||!string(callback.body,arg=>orderedIdentifier(arg,callback.params[0].name))||!orderedNot(parts[4],call=>orderedCall(call,'Array.isArray',[arg=>orderedIdentifier(arg,events)])))return null;
|
|
416
|
+
const copy=orderedConst(copyDeclaration),set=orderedConst(setDeclaration),output=copy?.id.name,seen=set?.id.name;
|
|
417
|
+
if(!copy||!set||!orderedCall(copy.init,'structuredClone',[arg=>orderedIdentifier(arg,initial)])||set.init?.type!=='NewExpression'||!orderedIdentifier(set.init.callee,'Set')
|
|
418
|
+
||set.init.arguments.length!==1||!orderedMember(set.init.arguments[0],output,appliedField))return null;
|
|
419
|
+
const iterator=loop.type==='ForOfStatement'&&!loop.await&&loop.left.type==='VariableDeclaration'&&loop.left.kind==='const'&&loop.left.declarations.length===1?loop.left.declarations[0].id:null;
|
|
420
|
+
const item=iterator?.name;
|
|
421
|
+
if(iterator?.type!=='Identifier'||!orderedIdentifier(loop.right,events)||loop.body.type!=='BlockStatement'||loop.body.body.length!==9||returned.type!=='ReturnStatement'||!orderedIdentifier(returned.argument,output))return null;
|
|
422
|
+
const [itemGuard,duplicate,currentDeclaration,currentGuard,versionDeclaration,conflict,store,append,mark]=loop.body.body;
|
|
423
|
+
const itemParts=orderedTerms(itemGuard.test,'||'),field=name=>node=>orderedMember(node,item,name);
|
|
424
|
+
if(itemGuard.type!=='IfStatement'||itemGuard.alternate||!recordError(itemGuard.consequent,contract.errorClass)||itemParts.length!==5
|
|
425
|
+
||!record(itemParts[0],arg=>orderedIdentifier(arg,item))||!string(itemParts[1],field(contract.id))||!string(itemParts[2],field(contract.owner))
|
|
426
|
+
||!integer(itemParts[3],field(contract.revision))||!negative(itemParts[4],field(contract.revision)))return null;
|
|
427
|
+
if(duplicate.type!=='IfStatement'||duplicate.alternate||!orderedCall(duplicate.test,`${seen}.has`,[field(contract.id)])||duplicate.consequent.type!=='ContinueStatement'||duplicate.consequent.label)return null;
|
|
428
|
+
const current=orderedConst(currentDeclaration),version=orderedConst(versionDeclaration),currentName=current?.id.name,versionName=version?.id.name;
|
|
429
|
+
if(!current||!version||current.init?.type!=='MemberExpression'||!current.init.computed||!orderedMember(current.init.object,output,dictionary)||!field(contract.owner)(current.init.property))return null;
|
|
430
|
+
const currentParts=orderedTerms(currentGuard.test?.right,'||'),versionField=currentParts[1]?.argument?.arguments?.[0]?.property?.name;
|
|
431
|
+
if(!safeField(versionField)||currentGuard.type!=='IfStatement'||currentGuard.alternate||currentGuard.test?.type!=='LogicalExpression'||currentGuard.test.operator!=='&&'
|
|
432
|
+
||currentGuard.test.left.type!=='BinaryExpression'||currentGuard.test.left.operator!=='!=='||!orderedIdentifier(currentGuard.test.left.left,currentName)||!orderedIdentifier(currentGuard.test.left.right,'undefined')
|
|
433
|
+
||currentParts.length!==3||!record(currentParts[0],arg=>orderedIdentifier(arg,currentName))||!integer(currentParts[1],arg=>orderedMember(arg,currentName,versionField))
|
|
434
|
+
||!negative(currentParts[2],arg=>orderedMember(arg,currentName,versionField))||!recordError(currentGuard.consequent,contract.errorClass))return null;
|
|
435
|
+
const readVersion=version.init?.left;
|
|
436
|
+
if(version.init?.type!=='LogicalExpression'||version.init.operator!=='??'||readVersion?.type!=='OptionalMemberExpression'||!readVersion.optional||readVersion.computed
|
|
437
|
+
||!orderedIdentifier(readVersion.object,currentName)||readVersion.property.name!==versionField||!orderedNumber(version.init.right,0))return null;
|
|
438
|
+
if(conflict.type!=='IfStatement'||conflict.alternate||conflict.test?.type!=='BinaryExpression'||conflict.test.operator!=='!=='||!orderedIdentifier(conflict.test.left,versionName)
|
|
439
|
+
||!field(contract.revision)(conflict.test.right)||!recordError(conflict.consequent,'Error'))return null;
|
|
440
|
+
const assignment=store.type==='ExpressionStatement'?store.expression:null,properties=assignment?.right?.properties;
|
|
441
|
+
if(assignment?.type!=='AssignmentExpression'||assignment.operator!=='='||assignment.left.type!=='MemberExpression'||!assignment.left.computed
|
|
442
|
+
||!orderedMember(assignment.left.object,output,dictionary)||!field(contract.owner)(assignment.left.property)||assignment.right.type!=='ObjectExpression'||properties.length!==2
|
|
443
|
+
||properties.some(property=>property.type!=='ObjectProperty'||property.computed||property.method||!safeField(property.key.name))||properties[0].key.name!==versionField
|
|
444
|
+
||properties[0].value.type!=='BinaryExpression'||properties[0].value.operator!=='+'||!orderedIdentifier(properties[0].value.left,versionName)||!orderedNumber(properties[0].value.right,1)
|
|
445
|
+
||properties[1].key.name===versionField||!orderedCall(properties[1].value,'structuredClone',[field(contract.payload)]))return null;
|
|
446
|
+
if(append.type!=='ExpressionStatement'||!orderedCall(append.expression,`${output}.${appliedField}.push`,[field(contract.id)])
|
|
447
|
+
||mark.type!=='ExpressionStatement'||!orderedCall(mark.expression,`${seen}.add`,[field(contract.id)]))return null;
|
|
448
|
+
const locals=[...contract.parameters,output,seen,item,currentName,versionName],protectedNames=new Set(['Array','Number','Set','structuredClone','TypeError','Error','undefined',...functions.keys()]);
|
|
449
|
+
if(new Set(locals).size!==locals.length||locals.some(name=>protectedNames.has(name)))return null;
|
|
450
|
+
orderedWalk(ast,(node,parent)=>{
|
|
451
|
+
if(node.type==='Identifier'&&['Array','Number'].includes(node.name)&&!(parent?.type==='MemberExpression'&&parent.object===node&&!parent.computed))throw new Error('ordered-native');
|
|
452
|
+
if(node.type==='Identifier'&&node.name==='structuredClone'&&!(parent?.type==='CallExpression'&&parent.callee===node))throw new Error('ordered-native');
|
|
453
|
+
if(node.type==='Identifier'&&node.name==='Set'&&!(parent?.type==='NewExpression'&&parent.callee===node))throw new Error('ordered-native');
|
|
454
|
+
if(/Function/.test(node.type)&&node.params.some(parameter=>parameter.type!=='Identifier'||protectedNames.has(parameter.name)))throw new Error('ordered-shadow');
|
|
455
|
+
if(node.type==='VariableDeclarator'&&(node.id.type!=='Identifier'||protectedNames.has(node.id.name)))throw new Error('ordered-shadow');
|
|
456
|
+
});
|
|
457
|
+
return {dictionary,appliedField,versionField};
|
|
458
|
+
} catch{return null;}
|
|
459
|
+
}
|
|
460
|
+
function orderedRecordTests(contract,profile,binding,testEntries) {
|
|
461
|
+
if(!profile)return {testOk:false};
|
|
462
|
+
const observed=new Set();let order=false,calls=0;
|
|
463
|
+
const isRecord=value=>value?.kind==='record',isArray=value=>value?.kind==='array',primitive=value=>value?.kind==='primitive',field=(value,name)=>value?.fields?.get(name);
|
|
464
|
+
const validId=value=>primitive(value)&&typeof value.value==='string'&&value.value.length>0;
|
|
465
|
+
const validInteger=value=>primitive(value)&&Number.isInteger(value.value)&&value.value>=0;
|
|
466
|
+
const validState=value=>isRecord(value)&&isRecord(field(value,profile.dictionary))&&isArray(field(value,profile.appliedField))&&field(value,profile.appliedField).elements.every(validId);
|
|
467
|
+
const validEvent=value=>isRecord(value)&&validId(field(value,contract.id))&&validId(field(value,contract.owner))&&validInteger(field(value,contract.revision));
|
|
468
|
+
const examine=args=>{
|
|
469
|
+
if(args.length!==2||!args.every(Boolean))return;calls++;
|
|
470
|
+
const [state,events]=args;
|
|
471
|
+
if(isArray(events)&&events.elements.length===0){
|
|
472
|
+
if(primitive(state)&&state.value===null)observed.add('state:null');
|
|
473
|
+
if(isArray(state))observed.add('state:array');
|
|
474
|
+
if(isRecord(state)&&state.fields.size===0)observed.add('state:missing');
|
|
475
|
+
if(isRecord(state)&&isArray(field(state,profile.appliedField))&&field(state,profile.appliedField).elements.every(validId)&&primitive(field(state,profile.dictionary))&&field(state,profile.dictionary).value===null)observed.add('state:dictionary');
|
|
476
|
+
if(isRecord(state)&&isRecord(field(state,profile.dictionary))){
|
|
477
|
+
if(primitive(field(state,profile.appliedField)))observed.add('state:applied-array');
|
|
478
|
+
if(isArray(field(state,profile.appliedField))&&field(state,profile.appliedField).elements.some(value=>primitive(value)&&value.value===''))observed.add('state:applied-id');
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if(!validState(state)||!isArray(events)||events.elements.length!==1)return;
|
|
482
|
+
const value=events.elements[0];
|
|
483
|
+
if(primitive(value)&&value.value===null)observed.add('event:null');
|
|
484
|
+
if(isArray(value))observed.add('event:array');
|
|
485
|
+
if(isRecord(value)&&value.fields.size===0)observed.add('event:missing');
|
|
486
|
+
for(const name of [contract.id,contract.owner]){
|
|
487
|
+
const other=name===contract.id?contract.owner:contract.id,candidate=field(value,name);
|
|
488
|
+
if(!isRecord(value)||!validId(field(value,other))||!validInteger(field(value,contract.revision))||!primitive(candidate))continue;
|
|
489
|
+
if(candidate.value==='')observed.add(name+':empty');
|
|
490
|
+
if(typeof candidate.value!=='string')observed.add(name+':type');
|
|
491
|
+
}
|
|
492
|
+
const revision=field(value,contract.revision);
|
|
493
|
+
if(isRecord(value)&&[contract.id,contract.owner].every(name=>validId(field(value,name)))&&primitive(revision)){
|
|
494
|
+
if(typeof revision.value==='number'&&Number.isFinite(revision.value)&&!Number.isInteger(revision.value))observed.add('revision:fractional');
|
|
495
|
+
if(typeof revision.value!=='number')observed.add('revision:type');
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
for(const link of binding.testBindings??[{testPath:binding.testPath,testName:binding.testName}]){
|
|
499
|
+
const entry=testEntries.find(item=>item.path===link.testPath);if(!entry||entry.text.length>64000)continue;
|
|
500
|
+
try {
|
|
501
|
+
const ast=parse(entry.text,{sourceType:'module'}),factories=flatRecordFactories(ast,true),imports=ast.program.body.filter(node=>node.type==='ImportDeclaration');
|
|
502
|
+
const imported=module=>imports.filter(node=>node.source.value===module).flatMap(node=>node.specifiers.filter(item=>item.type==='ImportDefaultSpecifier').map(item=>item.local.name));
|
|
503
|
+
const asserts=[...imported('node:assert/strict'),...imported('node:assert')],runners=imported('node:test');
|
|
504
|
+
if(imports.length!==3||asserts.length!==1||runners.length!==1||[...factories.values()].some(value=>!value))continue;
|
|
505
|
+
const assertName=asserts[0],testName=runners[0],sourceImport=imports.find(node=>!node.source.value.startsWith('node:'));
|
|
506
|
+
if(sourceImport?.specifiers.length!==1||sourceImport.specifiers[0].type!=='ImportSpecifier'||sourceImport.specifiers[0].local.name.toLowerCase()!==link.testName||sourceImport.specifiers[0].imported.name!==contract.target)continue;
|
|
507
|
+
const target=sourceImport.specifiers[0].local.name,protectedNames=new Set([assertName,testName,target,'structuredClone','TypeError',...factories.keys()]);
|
|
508
|
+
const methods=['throws','doesNotThrow','deepEqual','deepStrictEqual','equal','strictEqual','notStrictEqual'];
|
|
509
|
+
orderedWalk(ast,(node,parent)=>{
|
|
510
|
+
if(node.type==='ImportDeclaration'||parent?.type==='ImportSpecifier'||parent?.type==='ImportDefaultSpecifier')return;
|
|
511
|
+
if(node.type==='Identifier'&&['Array','Number','Object','Set','Reflect','Proxy','Function','eval','globalThis','global','process','Symbol'].includes(node.name))throw new Error('ordered-test-native');
|
|
512
|
+
if(node.type==='MemberExpression'&&(node.computed||['constructor','prototype','__proto__'].includes(node.property.name)))throw new Error('ordered-test-reflection');
|
|
513
|
+
if(node.type==='Identifier'&&['undefined','nan','infinity'].includes(node.name.toLowerCase())&&(!['undefined','NaN','Infinity'].includes(node.name)||!(parent?.type==='ObjectProperty'&&parent.value===node||parent?.type==='ArrayExpression'||parent?.type==='CallExpression'&&parent.arguments.includes(node)||parent?.type==='UnaryExpression'&&parent.argument===node)))throw new Error('ordered-test-literal-shadow');
|
|
514
|
+
if(node.type==='CallExpression'&&![target,testName,'structuredClone',...factories.keys(),...methods.map(name=>`${assertName}.${name}`)].includes(memberName(node.callee)))throw new Error('ordered-test-call');
|
|
515
|
+
if(node.type==='Identifier'&&protectedNames.has(node.name)){
|
|
516
|
+
const factory=factories.get(node.name),declaration=factory?.declaration;
|
|
517
|
+
if(!(parent?.type==='CallExpression'&&parent.callee===node||parent?.type==='VariableDeclarator'&&parent===declaration&&parent.id===node
|
|
518
|
+
||node.name===assertName&&parent?.type==='MemberExpression'&&parent.object===node||node.name==='TypeError'&&parent?.type==='CallExpression'&&memberName(parent.callee)===`${assertName}.throws`&&parent.arguments[1]===node))throw new Error('ordered-test-binding');
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
let expansion=0;
|
|
522
|
+
const actualCall=node=>node?.type==='CallExpression'&&orderedIdentifier(node.callee,target)&&node.arguments.length===2&&!node.arguments.some(arg=>arg.type==='SpreadElement');
|
|
523
|
+
const rejection=node=>{
|
|
524
|
+
const call=node?.type==='ExpressionStatement'?node.expression:null,callback=call?.arguments?.[0];
|
|
525
|
+
return orderedCall(call,`${assertName}.throws`,[arg=>arg===callback,arg=>orderedIdentifier(arg,contract.errorClass)])&&callback.type==='ArrowFunctionExpression'&&!callback.async&&callback.params.length===0&&actualCall(callback.body)?callback.body:null;
|
|
526
|
+
};
|
|
527
|
+
const collect=(node,values,before,depth=0)=>{
|
|
528
|
+
if(++expansion>512||depth>2)throw new Error('ordered-test-budget');
|
|
529
|
+
const call=rejection(node);if(call){examine(call.arguments.map(arg=>flatRecordValue(arg,values,factories,before,0,true)));return true;}
|
|
530
|
+
if(node.type==='BlockStatement')return node.body.length>0&&node.body.every(item=>collect(item,values,before,depth));
|
|
531
|
+
if(node.type!=='ForOfStatement'||node.await||node.left.type!=='VariableDeclaration'||node.left.kind!=='const'||node.left.declarations.length!==1||node.left.declarations[0].id.type!=='Identifier'
|
|
532
|
+
||node.right.type!=='ArrayExpression'||!node.right.elements.length||node.right.elements.length>32)return false;
|
|
533
|
+
const variable=node.left.declarations[0].id.name;if(protectedNames.has(variable)||values.has(variable))return false;
|
|
534
|
+
const rows=node.right.elements.map(arg=>flatRecordValue(arg,values,factories,before,0,true));if(!rows.every(Boolean))return false;
|
|
535
|
+
return rows.every(value=>collect(node.body,new Map([...values,[variable,value]]),before,depth+1));
|
|
536
|
+
};
|
|
537
|
+
for(const statement of ast.program.body){
|
|
538
|
+
if(statement.type==='ImportDeclaration')continue;
|
|
539
|
+
if(statement.type==='VariableDeclaration'&&statement.kind==='const'&&statement.declarations.every(item=>factories.get(item.id.name)?.declaration===item))continue;
|
|
540
|
+
const registration=statement.type==='ExpressionStatement'?statement.expression:null,callback=registration?.arguments?.[1];
|
|
541
|
+
if(!orderedCall(registration,testName,[node=>node.type==='StringLiteral',node=>node===callback])||callback.type!=='ArrowFunctionExpression'||callback.async||callback.params.length!==0||callback.body.type!=='BlockStatement')throw new Error('ordered-test-registration');
|
|
542
|
+
for(const item of callback.body.body)if(!collect(item,new Map(),registration.start))break;
|
|
543
|
+
const values=new Map();let pending=null;
|
|
544
|
+
orderPrefix: for(const item of callback.body.body){
|
|
545
|
+
if(item.type==='VariableDeclaration'&&item.kind==='const'){
|
|
546
|
+
for(const declaration of item.declarations){
|
|
547
|
+
if(declaration.id.type!=='Identifier'||protectedNames.has(declaration.id.name)||values.has(declaration.id.name))throw new Error('ordered-order-binding');
|
|
548
|
+
if(actualCall(declaration.init))pending={name:declaration.id.name,args:declaration.init.arguments.map(arg=>flatRecordValue(arg,values,factories,registration.start,0,true))};
|
|
549
|
+
const value=flatRecordValue(declaration.init,values,factories,registration.start,0,true);if(value)values.set(declaration.id.name,value);else if(!actualCall(declaration.init)&&!orderedCall(declaration.init,'structuredClone',[node=>Boolean(flatRecordValue(node,values,factories,registration.start,0,true))]))break orderPrefix;
|
|
550
|
+
}
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
const call=item.type==='ExpressionStatement'?item.expression:null;
|
|
554
|
+
if(pending&&call?.type==='CallExpression'&&[`${assertName}.deepEqual`,`${assertName}.deepStrictEqual`].includes(memberName(call.callee))&&call.arguments.length===2&&orderedIdentifier(call.arguments[0],pending.name)){
|
|
555
|
+
const expected=flatRecordValue(call.arguments[1],values,factories,registration.start,0,true),[state,events]=pending.args;
|
|
556
|
+
if(validState(state)&&isArray(events)&&events.elements.every(validEvent)&&isRecord(expected)&&isArray(field(expected,profile.appliedField))){
|
|
557
|
+
const ids=field(state,profile.appliedField).elements.map(value=>value.value),newIds=[];
|
|
558
|
+
for(const event of events.elements){const id=field(event,contract.id).value;if(!ids.includes(id)){ids.push(id);newIds.push(id);}}
|
|
559
|
+
const actual=field(expected,profile.appliedField).elements;
|
|
560
|
+
if(newIds.length>=2&&actual.length===ids.length&&actual.every((value,index)=>validId(value)&&value.value===ids[index]))order=true;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
break;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
} catch{return {testOk:false,observed:[...observed],order,calls};}
|
|
567
|
+
}
|
|
568
|
+
const required=['state:null','state:array','state:missing','state:dictionary','state:applied-array','state:applied-id','event:null','event:array','event:missing','revision:fractional','revision:type',...[contract.id,contract.owner].flatMap(name=>[name+':empty',name+':type'])];
|
|
569
|
+
return {testOk:order&&required.every(name=>observed.has(name)),observed:[...observed],missing:required.filter(name=>!observed.has(name)),order,calls};
|
|
570
|
+
}
|
|
571
|
+
export function orderedRecordRejectionEvidence({taskText,contextText,bindings,sourceEntries,testEntries}) {
|
|
572
|
+
const contract=orderedRecordContract(taskText,contextText);if(!contract)return null;
|
|
573
|
+
const results=bindings.map(binding=>{const profile=orderedRecordSource(contract,binding,sourceEntries);return {sourceOk:Boolean(profile),...orderedRecordTests(contract,profile,binding,testEntries)};});
|
|
574
|
+
return {sourceOk:contract.supported&&results.length>0&&results.every(result=>result.sourceOk),testOk:contract.supported&&results.length>0&&results.every(result=>result.testOk),results};
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// Only fresh local visitation maps and result arrays may be written. The
|
|
578
|
+
// recursive edge walk and both visitation states remain part of the proof.
|
|
579
|
+
function dependencyGraphSource(entries,binding) {
|
|
580
|
+
try {
|
|
581
|
+
const selected=entries.filter(entry=>entry.path===binding.sourcePath);
|
|
582
|
+
if(entries.length!==1||selected.length!==1||selected[0].text.length>64000)return null;
|
|
583
|
+
const ast=parse(selected[0].text,{sourceType:'module'}),exported=ast.program.body[0],fn=exported?.declaration;
|
|
584
|
+
if(ast.program.body.length!==1||exported.type!=='ExportNamedDeclaration'||fn?.type!=='FunctionDeclaration'||fn.async||fn.generator
|
|
585
|
+
||fn.id.name.toLowerCase()!==binding.sourceName.toLowerCase()||fn.params.length!==1||fn.params[0].type!=='Identifier'||fn.body.body.length!==6)return null;
|
|
586
|
+
const input=fn.params[0].name,[indexNode,stateNode,resultNode,visit,outer,returned]=fn.body.body;
|
|
587
|
+
const index=orderedConst(indexNode),state=orderedConst(stateNode),result=orderedConst(resultNode);
|
|
588
|
+
if(!index||!state||!result)return null;
|
|
589
|
+
const indexName=index.id.name,stateName=state.id.name,resultName=result.id.name;
|
|
590
|
+
const nativeMap=node=>node?.type==='NewExpression'&&orderedIdentifier(node.callee,'Map');
|
|
591
|
+
if(!nativeMap(index.init)||index.init.arguments.length!==1||!nativeMap(state.init)||state.init.arguments.length!==0||result.init?.type!=='ArrayExpression'||result.init.elements.length)return null;
|
|
592
|
+
const mapping=index.init.arguments[0],callback=mapping?.arguments?.[0];
|
|
593
|
+
if(!orderedCall(mapping,`${input}.map`,[node=>node===callback])||callback?.type!=='ArrowFunctionExpression'||callback.async||callback.params.length!==1||callback.params[0].type!=='Identifier'
|
|
594
|
+
||callback.body.type!=='ArrayExpression'||callback.body.elements.length!==2)return null;
|
|
595
|
+
const item=callback.params[0].name,[key,value]=callback.body.elements,keyField=key?.property?.name;
|
|
596
|
+
const safeField=name=>typeof name==='string'&&/^[A-Za-z_$][\w$]*$/.test(name)&&!['constructor','prototype','__proto__'].includes(name);
|
|
597
|
+
if(!safeField(keyField)||!orderedMember(key,item,keyField)||!orderedIdentifier(value,item))return null;
|
|
598
|
+
if(visit.type!=='FunctionDeclaration'||visit.async||visit.generator||visit.params.length!==1||visit.params[0].type!=='Identifier'||visit.body.body.length!==6)return null;
|
|
599
|
+
const visitName=visit.id.name,name=visit.params[0].name,[active,done,markActive,edges,markDone,append]=visit.body.body;
|
|
600
|
+
const stateValue=(node,value)=>node?.type==='BinaryExpression'&&node.operator==='==='&&orderedCall(node.left,`${stateName}.get`,[arg=>orderedIdentifier(arg,name)])&&orderedNumber(node.right,value);
|
|
601
|
+
const thrown=active.consequent?.type==='ThrowStatement'?active.consequent.argument:null;
|
|
602
|
+
if(active.type!=='IfStatement'||active.alternate||!stateValue(active.test,1)||thrown?.type!=='NewExpression'||!orderedIdentifier(thrown.callee,'Error')||thrown.arguments.length!==1||thrown.arguments[0].type!=='StringLiteral')return null;
|
|
603
|
+
if(done.type!=='IfStatement'||done.alternate||!stateValue(done.test,2)||done.consequent.type!=='ReturnStatement'||done.consequent.argument)return null;
|
|
604
|
+
const setState=(node,value)=>node?.type==='ExpressionStatement'&&orderedCall(node.expression,`${stateName}.set`,[arg=>orderedIdentifier(arg,name),arg=>orderedNumber(arg,value)]);
|
|
605
|
+
if(!setState(markActive,1)||!setState(markDone,2)||append.type!=='ExpressionStatement'||!orderedCall(append.expression,`${resultName}.push`,[arg=>orderedIdentifier(arg,name)]))return null;
|
|
606
|
+
const iterator=node=>node?.type==='ForOfStatement'&&!node.await&&node.left.type==='VariableDeclaration'&&node.left.kind==='const'&&node.left.declarations.length===1&&node.left.declarations[0].id.type==='Identifier'&&!node.left.declarations[0].init?node.left.declarations[0].id.name:null;
|
|
607
|
+
const dependency=iterator(edges),outerItem=iterator(outer),lookup=edges.right?.left,edgeField=lookup?.property?.name;
|
|
608
|
+
if(!dependency||!outerItem||!safeField(edgeField)||edgeField===keyField||edges.right?.type!=='LogicalExpression'||edges.right.operator!=='??'||edges.right.right.type!=='ArrayExpression'||edges.right.right.elements.length
|
|
609
|
+
||lookup?.type!=='OptionalMemberExpression'||!lookup.optional||lookup.computed||!orderedCall(lookup.object,`${indexName}.get`,[arg=>orderedIdentifier(arg,name)]))return null;
|
|
610
|
+
const guard=edges.body;
|
|
611
|
+
if(guard.type!=='IfStatement'||guard.alternate||!orderedCall(guard.test,`${indexName}.has`,[arg=>orderedIdentifier(arg,dependency)])||guard.consequent.type!=='ExpressionStatement'
|
|
612
|
+
||!orderedCall(guard.consequent.expression,visitName,[arg=>orderedIdentifier(arg,dependency)]))return null;
|
|
613
|
+
if(!orderedIdentifier(outer.right,input)||outer.body.type!=='ExpressionStatement'||!orderedCall(outer.body.expression,visitName,[arg=>orderedMember(arg,outerItem,keyField)])
|
|
614
|
+
||returned.type!=='ReturnStatement'||!orderedIdentifier(returned.argument,resultName))return null;
|
|
615
|
+
const roles=[fn.id.name,input,indexName,stateName,resultName,visitName,name,dependency],native=new Set(['Map','Error','Array','Object','undefined']);
|
|
616
|
+
if(new Set(roles).size!==roles.length||roles.some(role=>native.has(role))||[item,outerItem].some(role=>native.has(role)||roles.includes(role)))return null;
|
|
617
|
+
orderedWalk(ast,(node,parent)=>{
|
|
618
|
+
if(node.type==='Identifier'&&native.has(node.name)&&!(parent?.type==='NewExpression'&&parent.callee===node&&['Map','Error'].includes(node.name)))throw new Error('graph-native-binding');
|
|
619
|
+
if(node.type==='Identifier'&&node.name===visitName&&!(parent===visit&&parent.id===node||parent?.type==='CallExpression'&&parent.callee===node))throw new Error('graph-recursion-alias');
|
|
620
|
+
});
|
|
621
|
+
return {sourceName:fn.id.name,keyField,edgeField,message:thrown.arguments[0].value};
|
|
622
|
+
} catch {return null;}
|
|
623
|
+
}
|
|
624
|
+
function literalDependencyGraph(value,source) {
|
|
625
|
+
if(value?.kind!=='array'||value.elements.length>32)return null;
|
|
626
|
+
const byKey=new Map();
|
|
627
|
+
for(const item of value.elements){
|
|
628
|
+
const key=item?.fields?.get(source.keyField),edges=item?.fields?.get(source.edgeField);
|
|
629
|
+
if(item?.kind!=='record'||key?.kind!=='primitive'||typeof key.value!=='string'||!key.value||byKey.has(key.value)
|
|
630
|
+
||edges!==undefined&&(edges.kind!=='array'||edges.elements.some(edge=>edge?.kind!=='primitive'||typeof edge.value!=='string')))return null;
|
|
631
|
+
byKey.set(key.value,edges?.elements.map(edge=>edge.value)??[]);
|
|
632
|
+
}
|
|
633
|
+
const state=new Map(),order=[],stack=[];let direct=false,indirect=false;
|
|
634
|
+
const visit=key=>{
|
|
635
|
+
if(state.get(key)===1){if(stack.at(-1)===key)direct=true;else indirect=true;return;}
|
|
636
|
+
if(state.get(key)===2)return;state.set(key,1);stack.push(key);
|
|
637
|
+
for(const edge of byKey.get(key))if(byKey.has(edge))visit(edge);
|
|
638
|
+
stack.pop();state.set(key,2);order.push(key);
|
|
639
|
+
};
|
|
640
|
+
for(const key of byKey.keys())visit(key);
|
|
641
|
+
return {direct,indirect,order,hasEdge:[...byKey].some(([key,edges])=>edges.some(edge=>edge!==key&&byKey.has(edge)))};
|
|
642
|
+
}
|
|
643
|
+
function dependencyGraphTests(text,target,source) {
|
|
644
|
+
const evidence={direct:false,indirect:false,mutableSuccess:false,snapshot:false};
|
|
645
|
+
try {
|
|
646
|
+
if(text.length>64000)return evidence;
|
|
647
|
+
const ast=parse(text,{sourceType:'module'}),imports=ast.program.body.filter(node=>node.type==='ImportDeclaration');
|
|
648
|
+
const local=module=>imports.filter(node=>node.source.value===module).flatMap(node=>node.specifiers.filter(item=>item.type==='ImportDefaultSpecifier').map(item=>item.local.name));
|
|
649
|
+
const asserts=[...local('node:assert/strict'),...local('node:assert')],runners=local('node:test');
|
|
650
|
+
if(imports.length!==3||asserts.length!==1||runners.length!==1)return evidence;
|
|
651
|
+
const assertName=asserts[0],testName=runners[0],imported=imports.find(node=>!node.source.value.startsWith('node:'));
|
|
652
|
+
if(imported?.specifiers.length!==1||imported.specifiers[0].type!=='ImportSpecifier'||imported.specifiers[0].imported.name!==source.sourceName||imported.specifiers[0].local.name.toLowerCase()!==target.toLowerCase())return evidence;
|
|
653
|
+
target=imported.specifiers[0].local.name;
|
|
654
|
+
const protectedNames=new Set([assertName,testName,target,'Error','Object','Set','structuredClone']);
|
|
655
|
+
orderedWalk(ast,(node,parent)=>{
|
|
656
|
+
if(parent?.type==='ImportSpecifier'||parent?.type==='ImportDefaultSpecifier')return;
|
|
657
|
+
if(['AssignmentExpression','UpdateExpression','AwaitExpression','ThisExpression','NewExpression'].includes(node.type)&&!(node.type==='NewExpression'&&orderedIdentifier(node.callee,'Set')&&node.arguments.length===1&&node.arguments[0].type==='Identifier'))throw new Error('graph-test-effect');
|
|
658
|
+
if(node.type==='UnaryExpression'&&node.operator==='delete'||node.type==='MemberExpression'&&(node.computed||['constructor','prototype','__proto__'].includes(node.property.name)))throw new Error('graph-test-reflection');
|
|
659
|
+
if(node.type==='Identifier'&&['global','globalThis','process','Reflect','Proxy','Function','eval','Symbol','Array','Map'].includes(node.name))throw new Error('graph-test-global');
|
|
660
|
+
if(node.type==='Identifier'&&protectedNames.has(node.name)){
|
|
661
|
+
const allowed=parent?.type==='CallExpression'&&parent.callee===node&&[target,testName,'structuredClone'].includes(node.name)
|
|
662
|
+
||parent?.type==='MemberExpression'&&parent.object===node&&(node.name===assertName||node.name==='Object'&&parent.property.name==='freeze')
|
|
663
|
+
||node.name==='Error'&&parent?.type==='BinaryExpression'&&parent.operator==='instanceof'&&parent.right===node
|
|
664
|
+
||node.name==='Set'&&parent?.type==='NewExpression'&&parent.callee===node;
|
|
665
|
+
if(!allowed)throw new Error('graph-test-binding');
|
|
666
|
+
}
|
|
667
|
+
if(node.type==='CallExpression'&&![target,testName,'structuredClone','Object.freeze',...['throws','deepEqual','deepStrictEqual','equal','strictEqual'].map(method=>`${assertName}.${method}`)].includes(memberName(node.callee))
|
|
668
|
+
&&!(node.callee.type==='MemberExpression'&&!node.callee.computed&&node.callee.property.name==='includes'&&node.callee.object.type==='MemberExpression'&&node.callee.object.property.name==='message'))throw new Error('graph-test-call');
|
|
669
|
+
});
|
|
670
|
+
let expansion=0;
|
|
671
|
+
const facts=(node,values)=>{
|
|
672
|
+
if(orderedCall(node,'Object.freeze',[arg=>Boolean(arg)])){const value=facts(node.arguments[0],values);if(value)value.frozen=true;return value??null;}
|
|
673
|
+
if(node?.type==='ArrayExpression'){const elements=node.elements.map(item=>facts(item,values));return elements.every(Boolean)?{kind:'array',elements}:null;}
|
|
674
|
+
if(node?.type==='ObjectExpression'){
|
|
675
|
+
const fields=new Map();for(const property of node.properties){if(property.type!=='ObjectProperty'||property.computed||property.method||!['Identifier','StringLiteral'].includes(property.key.type))return null;
|
|
676
|
+
const key=property.key.name??property.key.value,value=facts(property.value,values);if(!value||fields.has(key)||['constructor','prototype','__proto__'].includes(key))return null;fields.set(key,value);}
|
|
677
|
+
return {kind:'record',fields};
|
|
678
|
+
}
|
|
679
|
+
return flatRecordValue(node,values,new Map(),Infinity,0,true);
|
|
680
|
+
};
|
|
681
|
+
const mutable=value=>value?.kind==='array'&&!value.frozen&&value.elements.every(item=>!item.frozen&&(!item.fields.get(source.edgeField)||!item.fields.get(source.edgeField).frozen));
|
|
682
|
+
const actual=node=>node?.type==='CallExpression'&&orderedIdentifier(node.callee,target)&&node.arguments.length===1&&node.arguments[0].type!=='SpreadElement';
|
|
683
|
+
const expectedMessage=callback=>{
|
|
684
|
+
if(callback?.type!=='ArrowFunctionExpression'||callback.async||callback.params.length!==1||callback.params[0].type!=='Identifier')return null;
|
|
685
|
+
const name=callback.params[0].name,body=callback.body;
|
|
686
|
+
return !protectedNames.has(name)&&body.type==='LogicalExpression'&&body.operator==='&&'&&body.left.type==='BinaryExpression'&&body.left.operator==='instanceof'&&orderedIdentifier(body.left.left,name)&&orderedIdentifier(body.left.right,'Error')
|
|
687
|
+
&&orderedCall(body.right,`${name}.message.includes`,[arg=>arg.type==='StringLiteral'])?body.right.arguments[0].value:null;
|
|
688
|
+
};
|
|
689
|
+
const read=(nodes,values=new Map(),depth=0)=>{
|
|
690
|
+
if(depth>2)throw new Error('graph-test-depth');const snapshots=new Map(),results=new Map(),called=new Set();
|
|
691
|
+
const observe=call=>{if(!actual(call))return null;const value=facts(call.arguments[0],values),graph=literalDependencyGraph(value,source);if(!graph)return null;
|
|
692
|
+
if(call.arguments[0].type==='Identifier')called.add(call.arguments[0].name);return {graph,mutable:mutable(value)};};
|
|
693
|
+
const order=(observation,expected)=>{
|
|
694
|
+
if(!observation||observation.graph.direct||observation.graph.indirect||expected?.kind!=='array')return;
|
|
695
|
+
if(observation.mutable&&observation.graph.hasEdge&&expected.elements.length===observation.graph.order.length&&expected.elements.every((value,index)=>value.kind==='primitive'&&value.value===observation.graph.order[index]))evidence.mutableSuccess=true;
|
|
696
|
+
};
|
|
697
|
+
for(const statement of nodes){
|
|
698
|
+
if(++expansion>512)throw new Error('graph-test-budget');
|
|
699
|
+
if(statement.type==='VariableDeclaration'&&statement.kind==='const'){
|
|
700
|
+
for(const declaration of statement.declarations){
|
|
701
|
+
if(declaration.id.type!=='Identifier'||protectedNames.has(declaration.id.name)||values.has(declaration.id.name)||snapshots.has(declaration.id.name)||results.has(declaration.id.name))throw new Error('graph-test-local');
|
|
702
|
+
const name=declaration.id.name,value=facts(declaration.init,values);if(declaration.init?.type==='Identifier')return;if(value){values.set(name,value);continue;}
|
|
703
|
+
if(orderedCall(declaration.init,'structuredClone',[arg=>arg.type==='Identifier'&&values.has(arg.name)])){if(called.has(declaration.init.arguments[0].name))return;snapshots.set(name,declaration.init.arguments[0].name);continue;}
|
|
704
|
+
const observed=observe(declaration.init);if(observed){results.set(name,observed);continue;}
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
if(statement.type==='ForOfStatement'&&!statement.await&&statement.left.type==='VariableDeclaration'&&statement.left.kind==='const'&&statement.left.declarations.length===1&&statement.left.declarations[0].id.type==='Identifier'){
|
|
710
|
+
const name=statement.left.declarations[0].id.name,rows=facts(statement.right,values);
|
|
711
|
+
if(protectedNames.has(name)||values.has(name)||rows?.kind!=='array'||rows.elements.length>32)return;
|
|
712
|
+
for(const row of rows.elements)read(statement.body.type==='BlockStatement'?statement.body.body:[statement.body],new Map([...values,[name,row]]),depth+1);continue;
|
|
713
|
+
}
|
|
714
|
+
const call=statement.type==='ExpressionStatement'?statement.expression:null;
|
|
715
|
+
if(call?.type!=='CallExpression')return;
|
|
716
|
+
if(memberName(call.callee)===`${assertName}.throws`&&call.arguments.length===2){
|
|
717
|
+
const callback=call.arguments[0],message=expectedMessage(call.arguments[1]);
|
|
718
|
+
if(callback?.type!=='ArrowFunctionExpression'||callback.async||callback.params.length||!message||!source.message.includes(message))return;
|
|
719
|
+
const observed=observe(callback.body);if(!observed)return;
|
|
720
|
+
if(message.includes('cycle')){evidence.direct ||= observed.graph.direct;evidence.indirect ||= observed.graph.indirect;}
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
if([`${assertName}.deepEqual`,`${assertName}.deepStrictEqual`].includes(memberName(call.callee))&&call.arguments.length===2){
|
|
724
|
+
const [left,right]=call.arguments;
|
|
725
|
+
if(left.type==='Identifier'&&right.type==='Identifier'&&snapshots.get(right.name)===left.name&&called.has(left.name)&&mutable(values.get(left.name)))evidence.snapshot=true;
|
|
726
|
+
order(left.type==='Identifier'?results.get(left.name):observe(left),facts(right,values));continue;
|
|
727
|
+
}
|
|
728
|
+
if([`${assertName}.equal`,`${assertName}.strictEqual`].includes(memberName(call.callee))&&call.arguments.length===2)continue;
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
for(const statement of ast.program.body){
|
|
733
|
+
if(statement.type==='ImportDeclaration')continue;
|
|
734
|
+
const call=statement.type==='ExpressionStatement'?statement.expression:null,callback=call?.arguments?.[1];
|
|
735
|
+
if(!orderedCall(call,testName,[node=>node.type==='StringLiteral',node=>node===callback])||callback?.type!=='ArrowFunctionExpression'||callback.async||callback.params.length||callback.body.type!=='BlockStatement')throw new Error('graph-test-registration');
|
|
736
|
+
read(callback.body.body);
|
|
737
|
+
}
|
|
738
|
+
return evidence;
|
|
739
|
+
} catch {return {direct:false,indirect:false,mutableSuccess:false,snapshot:false};}
|
|
740
|
+
}
|
|
741
|
+
export function dependencyCycleEvidence({taskText,bindings,sourceEntries,testEntries}) {
|
|
742
|
+
const clause=String(taskText??'').replace(/\s+/g,' ').trim();
|
|
743
|
+
if(!/\bcycle\b/i.test(clause)||!/^Throw an? `?Error`? containing/i.test(clause))return null;
|
|
744
|
+
const supported=/^Throw an `Error` containing `cycle` when an in-repository cycle exists[.;]?$/i.test(clause);
|
|
745
|
+
const results=bindings.map(binding=>{
|
|
746
|
+
const source=supported&&dependencyGraphSource(sourceEntries,binding),links=binding.testBindings??[{testPath:binding.testPath,testName:binding.testName}];
|
|
747
|
+
const evidence=source?links.map(link=>{const entry=testEntries.find(entry=>entry.path===link.testPath);return entry?dependencyGraphTests(entry.text,link.testName,source):{};}):[];
|
|
748
|
+
return {sourceOk:Boolean(source&&source.message.includes('cycle')),testOk:evidence.some(item=>item.direct&&item.indirect),evidence,links};
|
|
749
|
+
});
|
|
750
|
+
return {sourceOk:supported&&results.length>0&&results.every(item=>item.sourceOk),testOk:supported&&results.length>0&&results.every(item=>item.testOk),results};
|
|
751
|
+
}
|
|
752
|
+
export function dependencyGraphNonMutationEvidence({rawCriterion,profiles,sourceEntries}) {
|
|
753
|
+
if(!/^Do not mutate input[.;]?$/i.test(String(rawCriterion).replace(/\s+/g,' ').trim()))return false;
|
|
754
|
+
return profiles.some(profile=>(profile.bindings??[]).some(binding=>{const source=dependencyGraphSource(sourceEntries,binding);if(!source)return false;
|
|
755
|
+
const evidence=dependencyGraphTests(profile.raw,binding.testName,source);return evidence.mutableSuccess&&evidence.snapshot;}));
|
|
756
|
+
}
|