From 0a624838c306958cda748d5408ae8d9d7bcb6ecf Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 28 May 2026 18:07:23 -0300 Subject: [PATCH] V42 Gate 4: Close ReadNeed review loop Persist source-safe ReadNeed review and resynthesis runtime receipts across synthesize, accept, reject, and resynthesize actions. Expose Terminal runtime/storage/telemetry readbacks, add product closure proof artifact, wire promotion checks, and cover the route/pipeline/protocol contracts with focused tests. --- ...ed-review-resynthesis-product-closure.json | 644 ++++++++++++++++++ .github/workflows/bitcode-canon-quality.yml | 3 + .github/workflows/bitcode-gate-quality.yml | 3 + BITCODE_SPEC_V42.md | 4 +- BITCODE_SPEC_V42_DELTA.md | 1 + BITCODE_SPEC_V42_NOTES.md | 8 + BITCODE_SPEC_V42_PARITY_MATRIX.md | 4 +- README.md | 7 + SPECIFICATIONS_ROADMAP.md | 5 +- package.json | 3 + packages/pipelines/asset-pack/README.md | 8 + .../read-need-review-resynthesis.test.ts | 3 + packages/protocol/README.md | 9 + ...need-review-resynthesis-product-closure.js | 325 +++++++++ packages/protocol/src/index.d.ts | 9 + packages/protocol/src/index.js | 11 + ...review-resynthesis-product-closure.test.js | 73 ++ ...eed-review-resynthesis-product-closure.mjs | 258 +++++++ ...eed-review-resynthesis-product-closure.mjs | 31 + uapi/app/api/read-review/route.ts | 6 + uapi/app/terminal/README.md | 10 + .../terminal/TerminalDepositReadWorkbench.tsx | 130 +++- uapi/tests/api/readReviewRoute.test.ts | 10 + 23 files changed, 1559 insertions(+), 6 deletions(-) create mode 100644 .bitcode/v42-readneed-review-resynthesis-product-closure.json create mode 100644 packages/protocol/src/canonical/v42-readneed-review-resynthesis-product-closure.js create mode 100644 packages/protocol/test/v42-readneed-review-resynthesis-product-closure.test.js create mode 100644 scripts/check-v42-gate4-readneed-review-resynthesis-product-closure.mjs create mode 100644 scripts/generate-v42-readneed-review-resynthesis-product-closure.mjs diff --git a/.bitcode/v42-readneed-review-resynthesis-product-closure.json b/.bitcode/v42-readneed-review-resynthesis-product-closure.json new file mode 100644 index 00000000..2ec7f691 --- /dev/null +++ b/.bitcode/v42-readneed-review-resynthesis-product-closure.json @@ -0,0 +1,644 @@ +{ + "artifactId": "v42-readneed-review-resynthesis-product-closure", + "schemaId": "bitcode.v42.readNeedReviewResynthesisProductClosure.v1", + "version": "V42", + "currentTarget": "V41", + "sourceSafetyVerdict": "source-safe-readneed-review-resynthesis-product-closure-metadata", + "generatedAt": "deterministic", + "artifactRoot": "v42-readneed-review-resynthesis-product-closure:932beb894b734ebe044125ae", + "passed": true, + "rows": [ + { + "rowId": "request:read-request-persistence", + "purpose": "Persist source-safe Read Request data with repository, branch, commit, target artifact kinds, closure criteria, failure modes, feedback, and previous Need lineage.", + "sourceRoots": [ + "packages/pipelines/asset-pack/src/read-need.ts", + "packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts", + "uapi/app/api/read-review/route.ts" + ], + "emittedTypes": [ + "ReadNeedRequest", + "ReadNeedReviewStorageRecord" + ], + "requiredEvidence": [ + "bitcode.read.request", + "read_request", + "previousNeedId" + ], + "rowRoot": "v42-readneed-review-resynthesis-product-closure-row:dd13403f50f233293a797b93", + "sourceSafetyClass": "source_safe_readneed_review_resynthesis_product_closure_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "unpaidAssetPackSourceVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "credentialsSerialized": false, + "forbiddenPayloadClasses": [ + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "unpaid-assetpack-source", + "wallet-private-material", + "settlement-private-payloads", + "secret-values" + ] + }, + { + "rowId": "pipeline:ptrr-failsafe-thricified-need-synthesis", + "purpose": "Keep ReadNeedComprehensionSynthesis product-owned by PTRR agents whose steps carry FailsafeGenerationSequence over ThricifiedGeneration contracts and typed parser output.", + "sourceRoots": [ + "packages/pipelines/asset-pack/src/read-need.ts", + "packages/pipelines/asset-pack/src/reading-pipeline-contract.ts", + "packages/pipelines/asset-pack/src/__tests__/read-need.test.ts" + ], + "emittedTypes": [ + "ReadNeedComprehensionSynthesisInferenceReceipt", + "ReadingPipelineContract" + ], + "requiredEvidence": [ + "ptrrStepIds", + "failsafeSequenceIds", + "thricifiedGenerationIds", + "ReadNeedComprehensionSynthesis.prompt.need-synthesis" + ], + "rowRoot": "v42-readneed-review-resynthesis-product-closure-row:2a7caa01828aa9e731d31be0", + "sourceSafetyClass": "source_safe_readneed_review_resynthesis_product_closure_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "unpaidAssetPackSourceVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "credentialsSerialized": false, + "forbiddenPayloadClasses": [ + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "unpaid-assetpack-source", + "wallet-private-material", + "settlement-private-payloads", + "secret-values" + ] + }, + { + "rowId": "need:synthesized-need-storage", + "purpose": "Persist reviewable synthesized Need output before Finding Fits, including requirements, target artifacts, source constraints, proof expectations, and review state.", + "sourceRoots": [ + "packages/pipelines/asset-pack/src/read-need.ts", + "packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts", + "packages/pipelines/asset-pack/src/__tests__/read-need-review-resynthesis.test.ts" + ], + "emittedTypes": [ + "ReadNeed", + "synthesized_need" + ], + "requiredEvidence": [ + "bitcode.read.need", + "needs_acceptance", + "synthesized_need" + ], + "rowRoot": "v42-readneed-review-resynthesis-product-closure-row:9132dd0681fe996ad9af5add", + "sourceSafetyClass": "source_safe_readneed_review_resynthesis_product_closure_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "unpaidAssetPackSourceVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "credentialsSerialized": false, + "forbiddenPayloadClasses": [ + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "unpaid-assetpack-source", + "wallet-private-material", + "settlement-private-payloads", + "secret-values" + ] + }, + { + "rowId": "feedback:review-resynthesis-lineage", + "purpose": "Preserve user feedback and resynthesis attempts so every new Need stays linked to the prior Need and reviewed feedback.", + "sourceRoots": [ + "packages/pipelines/asset-pack/src/read-need.ts", + "packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts", + "uapi/tests/api/readReviewRoute.test.ts", + "uapi/app/terminal/TerminalDepositReadWorkbench.tsx" + ], + "emittedTypes": [ + "resynthesis_attempt", + "feedbackHistory" + ], + "requiredEvidence": [ + "previousNeedId", + "resynthesize_read_need", + "resynthesis_attempt" + ], + "rowRoot": "v42-readneed-review-resynthesis-product-closure-row:16e048458da7e50ddd1b4f2f", + "sourceSafetyClass": "source_safe_readneed_review_resynthesis_product_closure_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "unpaidAssetPackSourceVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "credentialsSerialized": false, + "forbiddenPayloadClasses": [ + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "unpaid-assetpack-source", + "wallet-private-material", + "settlement-private-payloads", + "secret-values" + ] + }, + { + "rowId": "measurement:need-measurement-storage", + "purpose": "Persist Need measurement roots and pricing measurement inputs that later drive deterministic preview quotes without exposing source.", + "sourceRoots": [ + "packages/pipelines/asset-pack/src/read-need.ts", + "packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts", + "packages/pipelines/asset-pack/src/__tests__/read-need.test.ts" + ], + "emittedTypes": [ + "ReadNeedMeasurementDimension", + "need_measurement" + ], + "requiredEvidence": [ + "measurementRoot", + "pricingMeasurementInputs", + "shareToFeeFormula" + ], + "rowRoot": "v42-readneed-review-resynthesis-product-closure-row:49789e8b9beb3a2d19f60ad7", + "sourceSafetyClass": "source_safe_readneed_review_resynthesis_product_closure_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "unpaidAssetPackSourceVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "credentialsSerialized": false, + "forbiddenPayloadClasses": [ + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "unpaid-assetpack-source", + "wallet-private-material", + "settlement-private-payloads", + "secret-values" + ] + }, + { + "rowId": "admission:accepted-need-gates-finding-fits", + "purpose": "Persist accepted-Need admission as the only source-safe handoff into ReadFitsFindingSynthesis and block Finding Fits without acceptance.", + "sourceRoots": [ + "packages/pipelines/asset-pack/src/read-need.ts", + "packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts", + "uapi/tests/api/readReviewRoute.test.ts", + "uapi/app/terminal/terminal-enterprise-reading-ux-state.ts" + ], + "emittedTypes": [ + "ReadFitsFindingAdmission", + "accepted_need_admission" + ], + "requiredEvidence": [ + "accept_read_need", + "accepted_need_admission", + "accepted_read_need_missing" + ], + "rowRoot": "v42-readneed-review-resynthesis-product-closure-row:db95df08a064d2644a6a86db", + "sourceSafetyClass": "source_safe_readneed_review_resynthesis_product_closure_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "unpaidAssetPackSourceVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "credentialsSerialized": false, + "forbiddenPayloadClasses": [ + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "unpaid-assetpack-source", + "wallet-private-material", + "settlement-private-payloads", + "secret-values" + ] + }, + { + "rowId": "rejection:rejected-need-posture", + "purpose": "Persist rejected-Need posture with rejection root, feedback, blocked Finding Fits stage, and repair/resynthesis next action.", + "sourceRoots": [ + "packages/pipelines/asset-pack/src/read-need.ts", + "packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts", + "uapi/tests/api/readReviewRoute.test.ts", + "uapi/app/terminal/TerminalDepositReadWorkbench.tsx" + ], + "emittedTypes": [ + "RejectedReadNeed", + "rejected_need_posture" + ], + "requiredEvidence": [ + "rejectReadNeed", + "reject_read_need", + "read_need_rejected" + ], + "rowRoot": "v42-readneed-review-resynthesis-product-closure-row:5470af7414fae6fa252d6df8", + "sourceSafetyClass": "source_safe_readneed_review_resynthesis_product_closure_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "unpaidAssetPackSourceVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "credentialsSerialized": false, + "forbiddenPayloadClasses": [ + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "unpaid-assetpack-source", + "wallet-private-material", + "settlement-private-payloads", + "secret-values" + ] + }, + { + "rowId": "telemetry:source-safe-runtime-receipts", + "purpose": "Emit source-safe telemetry receipts containing phase, PTRR step, Failsafe, ThricifiedGeneration, prompt-template, output-schema, and proof-root identities.", + "sourceRoots": [ + "packages/pipelines/asset-pack/src/read-need.ts", + "packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts", + "packages/pipelines/asset-pack/src/reading-pipeline-contract.ts", + "uapi/app/api/read-review/route.ts" + ], + "emittedTypes": [ + "ReadNeedReviewTelemetryReceipt", + "ReadNeedComprehensionSynthesisInferenceReceipt" + ], + "requiredEvidence": [ + "ptrrStepIds", + "failsafeSequenceIds", + "thricifiedGenerationIds", + "promptTemplateIds" + ], + "rowRoot": "v42-readneed-review-resynthesis-product-closure-row:b1707272fafd2df1da82287f", + "sourceSafetyClass": "source_safe_readneed_review_resynthesis_product_closure_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "unpaidAssetPackSourceVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "credentialsSerialized": false, + "forbiddenPayloadClasses": [ + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "unpaid-assetpack-source", + "wallet-private-material", + "settlement-private-payloads", + "secret-values" + ] + }, + { + "rowId": "route:read-review-actions", + "purpose": "Expose synthesize, resynthesize, accept, and reject actions through the Read review route with storage projection, runtime summary, source-safe telemetry, and Finding Fits admission readback.", + "sourceRoots": [ + "uapi/app/api/read-review/route.ts", + "uapi/tests/api/readReviewRoute.test.ts" + ], + "emittedTypes": [ + "readNeedReviewRuntime", + "storageProjection", + "runtimeSummary" + ], + "requiredEvidence": [ + "synthesize_read_need", + "resynthesize_read_need", + "accept_read_need", + "reject_read_need" + ], + "rowRoot": "v42-readneed-review-resynthesis-product-closure-row:6236882a7b982f2c79671dfc", + "sourceSafetyClass": "source_safe_readneed_review_resynthesis_product_closure_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "unpaidAssetPackSourceVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "credentialsSerialized": false, + "forbiddenPayloadClasses": [ + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "unpaid-assetpack-source", + "wallet-private-material", + "settlement-private-payloads", + "secret-values" + ] + }, + { + "rowId": "ui:terminal-need-runtime-readback", + "purpose": "Expose the reviewed Need, feedback loop, rejection path, storage projection, runtime roots, telemetry return type, and Finding Fits blocker/admission state in Terminal without protected source.", + "sourceRoots": [ + "uapi/app/terminal/TerminalDepositReadWorkbench.tsx", + "uapi/app/terminal/README.md" + ], + "emittedTypes": [ + "TerminalReadNeedReviewRuntimeState", + "Need runtime, storage, and telemetry" + ], + "requiredEvidence": [ + "Reject Read-Need", + "readNeedStorageProjection", + "readNeedTelemetry", + "Need runtime, storage, and telemetry" + ], + "rowRoot": "v42-readneed-review-resynthesis-product-closure-row:80bccaab5bdfa287e270838a", + "sourceSafetyClass": "source_safe_readneed_review_resynthesis_product_closure_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "unpaidAssetPackSourceVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "credentialsSerialized": false, + "forbiddenPayloadClasses": [ + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "unpaid-assetpack-source", + "wallet-private-material", + "settlement-private-payloads", + "secret-values" + ] + }, + { + "rowId": "proof:tests-artifact-workflow", + "purpose": "Bind V42 Gate 4 closure to package tests, route tests, protocol artifact tests, docs, scripts, and gate/canon workflow checks.", + "sourceRoots": [ + "packages/pipelines/asset-pack/src/__tests__/read-need-review-resynthesis.test.ts", + "uapi/tests/api/readReviewRoute.test.ts", + ".github/workflows/bitcode-gate-quality.yml", + ".github/workflows/bitcode-canon-quality.yml", + "BITCODE_SPEC_V42.md", + "BITCODE_SPEC_V42_PARITY_MATRIX.md", + "SPECIFICATIONS_ROADMAP.md" + ], + "emittedTypes": [ + "V42ReadNeedReviewResynthesisProductClosure" + ], + "requiredEvidence": [ + "check-v42-gate4-readneed-review-resynthesis-product-closure.mjs", + "v42-readneed-review-resynthesis-product-closure" + ], + "rowRoot": "v42-readneed-review-resynthesis-product-closure-row:b09ae61cf4664f8a3914be8e", + "sourceSafetyClass": "source_safe_readneed_review_resynthesis_product_closure_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "unpaidAssetPackSourceVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "credentialsSerialized": false, + "forbiddenPayloadClasses": [ + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "unpaid-assetpack-source", + "wallet-private-material", + "settlement-private-payloads", + "secret-values" + ] + } + ], + "rowIds": [ + "request:read-request-persistence", + "pipeline:ptrr-failsafe-thricified-need-synthesis", + "need:synthesized-need-storage", + "feedback:review-resynthesis-lineage", + "measurement:need-measurement-storage", + "admission:accepted-need-gates-finding-fits", + "rejection:rejected-need-posture", + "telemetry:source-safe-runtime-receipts", + "route:read-review-actions", + "ui:terminal-need-runtime-readback", + "proof:tests-artifact-workflow" + ], + "predicateResults": [ + { + "id": "read-need-defines-review-states", + "sourcePath": "packages/pipelines/asset-pack/src/read-need.ts", + "passed": true + }, + { + "id": "read-need-accept-and-reject-actions", + "sourcePath": "packages/pipelines/asset-pack/src/read-need.ts", + "passed": true + }, + { + "id": "inference-receipt-covers-ptrr-failsafe-thricified", + "sourcePath": "packages/pipelines/asset-pack/src/read-need.ts", + "passed": true + }, + { + "id": "contract-has-four-phases-and-sixteen-steps", + "sourcePath": "packages/pipelines/asset-pack/src/reading-pipeline-contract.ts", + "passed": true + }, + { + "id": "runtime-defines-storage-records", + "sourcePath": "packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts", + "passed": true + }, + { + "id": "runtime-defines-resynthesis-admission-rejection", + "sourcePath": "packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts", + "passed": true + }, + { + "id": "runtime-source-safety", + "sourcePath": "packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts", + "passed": true + }, + { + "id": "runtime-persists-to-execution-store", + "sourcePath": "packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts", + "passed": true + }, + { + "id": "package-exports-runtime", + "sourcePath": "packages/pipelines/asset-pack/src/index.ts", + "passed": true + }, + { + "id": "package-tests-cover-runtime", + "sourcePath": "packages/pipelines/asset-pack/src/__tests__/read-need-review-resynthesis.test.ts", + "passed": true + }, + { + "id": "read-need-tests-cover-real-inference-receipts", + "sourcePath": "packages/pipelines/asset-pack/src/__tests__/read-need.test.ts", + "passed": true + }, + { + "id": "contract-tests-cover-review-output", + "sourcePath": "packages/pipelines/asset-pack/src/__tests__/reading-pipeline-contract.test.ts", + "passed": true + }, + { + "id": "route-exposes-all-review-actions", + "sourcePath": "uapi/app/api/read-review/route.ts", + "passed": true + }, + { + "id": "route-persists-all-runtime-actions", + "sourcePath": "uapi/app/api/read-review/route.ts", + "passed": true + }, + { + "id": "route-returns-runtime-projection", + "sourcePath": "uapi/app/api/read-review/route.ts", + "passed": true + }, + { + "id": "route-tests-cover-runtime-and-rejection", + "sourcePath": "uapi/tests/api/readReviewRoute.test.ts", + "passed": true + }, + { + "id": "protocol-parity-keeps-finding-fits-blocked", + "sourcePath": "uapi/tests/api/readReviewProtocolParity.test.ts", + "passed": true + }, + { + "id": "terminal-ui-exposes-runtime-readback", + "sourcePath": "uapi/app/terminal/TerminalDepositReadWorkbench.tsx", + "passed": true + }, + { + "id": "terminal-ui-exposes-rejection", + "sourcePath": "uapi/app/terminal/TerminalDepositReadWorkbench.tsx", + "passed": true + }, + { + "id": "terminal-ux-keeps-accepted-need-gate", + "sourcePath": "uapi/app/terminal/terminal-enterprise-reading-ux-state.ts", + "passed": true + }, + { + "id": "spec-gate4-expanded", + "sourcePath": "BITCODE_SPEC_V42.md", + "passed": true + }, + { + "id": "delta-gate4-expanded", + "sourcePath": "BITCODE_SPEC_V42_DELTA.md", + "passed": true + }, + { + "id": "notes-gate4-expanded", + "sourcePath": "BITCODE_SPEC_V42_NOTES.md", + "passed": true + }, + { + "id": "parity-gate4-implemented", + "sourcePath": "BITCODE_SPEC_V42_PARITY_MATRIX.md", + "passed": true + }, + { + "id": "roadmap-advanced-to-gate4", + "sourcePath": "SPECIFICATIONS_ROADMAP.md", + "passed": true + }, + { + "id": "readmes-document-gate4", + "sourcePath": "README.md", + "passed": true + }, + { + "id": "workflows-run-gate4-check", + "sourcePath": ".github/workflows/bitcode-gate-quality.yml", + "passed": true + } + ], + "coverage": { + "rowCount": 11, + "requiredPredicateCount": 27, + "passedPredicateCount": 27, + "failedPredicateIds": [], + "pipelineName": "ReadNeedComprehensionSynthesis", + "nextPipelineName": "ReadFitsFindingSynthesis", + "actions": [ + "synthesize_read_need", + "resynthesize_read_need", + "accept_read_need", + "reject_read_need" + ], + "persistedRecordKinds": [ + "read_request", + "synthesized_need", + "feedback", + "resynthesis_attempt", + "need_measurement", + "accepted_need_admission", + "rejected_need_posture", + "telemetry_receipt" + ], + "phaseCount": 4, + "ptrrStepCount": 16, + "failsafeSequenceCount": 48, + "thricifiedGenerationCount": 48, + "acceptedNeedRequiredForFindingFits": true, + "rejectedNeedBlocksFindingFits": true, + "terminalRuntimeReadbackCovered": true, + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "unpaidAssetPackSourceVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "credentialsSerialized": false, + "legacySourceRoots": false + }, + "sourceRoots": { + "readNeed": "packages/pipelines/asset-pack/src/read-need.ts", + "readNeedRuntime": "packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts", + "readingPipelineContract": "packages/pipelines/asset-pack/src/reading-pipeline-contract.ts", + "packageIndex": "packages/pipelines/asset-pack/src/index.ts", + "packageJson": "packages/pipelines/asset-pack/package.json", + "readNeedTest": "packages/pipelines/asset-pack/src/__tests__/read-need.test.ts", + "runtimeTest": "packages/pipelines/asset-pack/src/__tests__/read-need-review-resynthesis.test.ts", + "readingContractTest": "packages/pipelines/asset-pack/src/__tests__/reading-pipeline-contract.test.ts", + "readReviewRoute": "uapi/app/api/read-review/route.ts", + "readReviewRouteTest": "uapi/tests/api/readReviewRoute.test.ts", + "readReviewProtocolParityTest": "uapi/tests/api/readReviewProtocolParity.test.ts", + "terminalWorkbench": "uapi/app/terminal/TerminalDepositReadWorkbench.tsx", + "terminalUxState": "uapi/app/terminal/terminal-enterprise-reading-ux-state.ts", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml", + "v42Spec": "BITCODE_SPEC_V42.md", + "v42Delta": "BITCODE_SPEC_V42_DELTA.md", + "v42Notes": "BITCODE_SPEC_V42_NOTES.md", + "v42Parity": "BITCODE_SPEC_V42_PARITY_MATRIX.md", + "roadmap": "SPECIFICATIONS_ROADMAP.md", + "rootReadme": "README.md", + "terminalReadme": "uapi/app/terminal/README.md", + "assetPackReadme": "packages/pipelines/asset-pack/README.md", + "protocolReadme": "packages/protocol/README.md" + } +} diff --git a/.github/workflows/bitcode-canon-quality.yml b/.github/workflows/bitcode-canon-quality.yml index dc9f130b..13e5d697 100644 --- a/.github/workflows/bitcode-canon-quality.yml +++ b/.github/workflows/bitcode-canon-quality.yml @@ -301,6 +301,9 @@ jobs: if [ -f scripts/check-v42-gate3-reading-shortest-path-state-machine.mjs ]; then node scripts/check-v42-gate3-reading-shortest-path-state-machine.mjs --skip-branch-check --skip-uapi-tests fi + if [ -f scripts/check-v42-gate4-readneed-review-resynthesis-product-closure.mjs ]; then + node scripts/check-v42-gate4-readneed-review-resynthesis-product-closure.mjs --skip-branch-check --skip-package-tests --skip-uapi-tests + fi fi else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index bf2440ee..82dc5ab8 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -430,6 +430,9 @@ jobs: if [ -f scripts/check-v42-gate3-reading-shortest-path-state-machine.mjs ]; then node scripts/check-v42-gate3-reading-shortest-path-state-machine.mjs --skip-branch-check --skip-uapi-tests fi + if [ -f scripts/check-v42-gate4-readneed-review-resynthesis-product-closure.mjs ]; then + node scripts/check-v42-gate4-readneed-review-resynthesis-product-closure.mjs --skip-branch-check --skip-package-tests --skip-uapi-tests + fi fi else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 diff --git a/BITCODE_SPEC_V42.md b/BITCODE_SPEC_V42.md index 7b85d98f..8c1ce389 100644 --- a/BITCODE_SPEC_V42.md +++ b/BITCODE_SPEC_V42.md @@ -132,6 +132,8 @@ Validating command: `pnpm run check:v42-gate3`. Gate 4 must make `ReadNeedComprehensionSynthesis` product-ready in the MVP flow. The pipeline must synthesize exactly the user's Need from the Read Request, store source-safe Need data, allow user feedback and resynthesis, preserve lineage, and admit Finding Fits only after the Need is accepted. It must cover PTRR agents, FailsafeGenerationSequence, ThricifiedGeneration, prompts, parser return types, telemetry rows, database projection, tests, and UI readback. +Gate 4 is implemented by `.bitcode/v42-readneed-review-resynthesis-product-closure.json`. +The artifact binds `ReadNeedReviewResynthesisRuntime`, all four review actions, source-safe storage projection, rejection posture, accepted-Need admission into `ReadFitsFindingSynthesis`, Terminal runtime/storage/telemetry readback, and the package/API/protocol tests that prove the path. ## V42 Gate 5 ReadFitsFinding AssetPack Preview And Quote Closure @@ -423,7 +425,7 @@ V42 inherits operator-quality expectations for browser proof, accessibility, vis | `.bitcode/v42-canon-posture-drift-report.json` | `check-bitcode-canon-posture-drift` | source-safe metadata | active V41 / draft V42 posture proof | | `.bitcode/v42-depositing-shortest-path.json` | V42 Gate 2 | source-safe metadata | deposit MVP proof | | `.bitcode/v42-reading-shortest-path-state-machine.json` | V42 Gate 3 | source-safe metadata | Reading product state proof | -| `.bitcode/v42-readneed-review-resynthesis.json` | V42 Gate 4 | source-safe metadata | Need review proof | +| `.bitcode/v42-readneed-review-resynthesis-product-closure.json` | V42 Gate 4 | source-safe metadata | Need review proof | | `.bitcode/v42-readfitsfinding-preview-quote.json` | V42 Gate 5 | source-safe metadata | Finding Fits, preview, and quote proof | | `.bitcode/v42-settlement-rights-delivery.json` | V42 Gate 6 | source-safe metadata | settlement/delivery proof | | `.bitcode/v42-ai-reading-demonstration.json` | V42 Gate 7 | source-safe metadata | demonstration value proof | diff --git a/BITCODE_SPEC_V42_DELTA.md b/BITCODE_SPEC_V42_DELTA.md index 33f29a47..36e45942 100644 --- a/BITCODE_SPEC_V42_DELTA.md +++ b/BITCODE_SPEC_V42_DELTA.md @@ -47,6 +47,7 @@ The state machine keeps Terminal guided by default while preserving proof-on-exp ### Gate 4: ReadNeed Review And Resynthesis Product Closure Implement and prove reviewed synthesized Need flow, feedback/resynthesis, accepted-Need admission, storage projection, telemetry, and UI readback. +Gate 4 now binds `ReadNeedReviewResynthesisRuntime` (`readNeedReviewRuntime` route payloads), all four ReadNeed actions, source-safe storage projection, accepted and rejected review states, PTRR/Failsafe/Thricified telemetry receipts, Terminal runtime/storage/telemetry readback, `.bitcode/v42-readneed-review-resynthesis-product-closure.json`, and `check:v42-gate4`. ### Gate 5: ReadFitsFinding AssetPack Preview And Quote Closure diff --git a/BITCODE_SPEC_V42_NOTES.md b/BITCODE_SPEC_V42_NOTES.md index 3ba0c620..098818f0 100644 --- a/BITCODE_SPEC_V42_NOTES.md +++ b/BITCODE_SPEC_V42_NOTES.md @@ -47,6 +47,14 @@ Gate 3 implements the current V42 state-machine layer with `TerminalEnterpriseRe The recoverable route state includes transaction id presence, `readingStage`, active-stage hydration, retry and restart posture, source-safe failure kind, and repair actions. This makes refresh, route handoff, and recovery inspectable without disclosing protected source, protected prompts, raw provider responses, unpaid AssetPack source, wallet private material, private settlement payloads, or ledger authority. +## Gate 4 implementation notes + +Gate 4 closes the ReadNeed product loop. +`ReadNeedComprehensionSynthesis` now has a V42 proof target for source-safe Read Request persistence, synthesized Need storage, feedback and resynthesis lineage, Need measurement roots, accepted Need admission, rejected Need posture, runtime storage projection, and telemetry receipts. +The Terminal readback must show the Need, review state, runtime root, storage root, telemetry root, blockers, PTRR step identity, and storage record roots without exposing protected source, raw protected prompts, raw provider responses, unpaid AssetPack source, wallet private material, or private settlement payloads. +Finding Fits remains blocked until the Need is accepted. +Rejecting a Need must preserve feedback and keep the user on the review/resynthesis step. + ## AssetPack source-safety note V42 must make the preview valuable without leaking the source-bearing AssetPack before settlement. diff --git a/BITCODE_SPEC_V42_PARITY_MATRIX.md b/BITCODE_SPEC_V42_PARITY_MATRIX.md index 86f3f222..b87b9c7c 100644 --- a/BITCODE_SPEC_V42_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V42_PARITY_MATRIX.md @@ -35,7 +35,7 @@ This matrix records the reliable MVP product surfaces that must become promotion | Canon workflow | Canon quality knows active V41 / draft V42 posture and V42 Gate 1 | `.github/workflows/bitcode-canon-quality.yml` | drafted | | Depositing shortest path | Source material can be admitted with Depository proof and compensation visibility | `.bitcode/v42-depositing-shortest-path.json`, `DepositorySupplyCompensationPreview`, `/api/deposits`, Terminal deposit readback | implemented | | Reading state machine | Five-step Reading UX is route-owned, persistent, and source-safe | `.bitcode/v42-reading-shortest-path-state-machine.json`, `TerminalEnterpriseReadingRouteState`, `readingStage`, route/retry/failure tests | implemented | -| ReadNeed product closure | Need synthesis, review, feedback, resynthesis, and accepted-Need admission are product-ready | later V42 Gate 4 artifact | draft-required | +| ReadNeed product closure | Need synthesis, review, feedback, resynthesis, accepted-Need admission, rejected Need blockers, source-safe telemetry, and Terminal runtime readback are product-ready | `.bitcode/v42-readneed-review-resynthesis-product-closure.json`, `ReadNeedReviewResynthesisRuntime`, `/api/read-review`, Terminal Need runtime readback | implemented | | Finding Fits preview and quote | Many-candidate search, selected-fit provenance, source-safe preview, and quote are product-ready | later V42 Gate 5 artifact | draft-required | | Settlement and delivery | BTC/BTD settlement, rights transfer, compensation, and repository PR delivery are synchronized | later V42 Gate 6 artifact | draft-required | | AI-reading demonstration | Standalone demonstration proves AssetPack improves AI beyond public-data-only baseline | later V42 Gate 7 artifact | draft-required | @@ -49,7 +49,7 @@ This matrix records the reliable MVP product surfaces that must become promotion | Gate 1 | Open V42 family, roadmap, docs, workflow posture, package script, and checker | drafted | | Gate 2 | Depositing shortest path and compensation visibility artifact | implemented | | Gate 3 | Reading shortest path state machine artifact | implemented | -| Gate 4 | ReadNeed review and resynthesis product closure artifact | draft-required | +| Gate 4 | ReadNeed review and resynthesis product closure artifact | implemented | | Gate 5 | ReadFitsFinding AssetPack preview and quote closure artifact | draft-required | | Gate 6 | Settlement rights transfer and repository delivery closure artifact | draft-required | | Gate 7 | AI-reading dominant demonstration MVP artifact | draft-required | diff --git a/README.md b/README.md index 3a5b1077..48298c20 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,13 @@ V42 Gate 3 adds the Reading shortest path state machine with accepted-Need blockers, source-safe preview blockers, `.bitcode/v42-reading-shortest-path-state-machine.json`, and `check:v42-gate3`. +V42 Gate 4 adds ReadNeed product closure with +`ReadNeedReviewResynthesisRuntime`, source-safe storage projection, +feedback/resynthesis lineage, accepted-Need Finding Fits admission, +rejected Need blockers, PTRR/Failsafe/Thricified telemetry receipts, +Terminal Need runtime readback, +`.bitcode/v42-readneed-review-resynthesis-product-closure.json`, and +`check:v42-gate4`. V43+ is roadmapped as the later agentic depositing evolution: repository agents synthesize deposit AssetPack options from connected enterprise code, Depository state, and Reading demand; enterprises approve or reject diff --git a/SPECIFICATIONS_ROADMAP.md b/SPECIFICATIONS_ROADMAP.md index f328daae..7bd3c34c 100644 --- a/SPECIFICATIONS_ROADMAP.md +++ b/SPECIFICATIONS_ROADMAP.md @@ -5,12 +5,13 @@ - Current active canonical pointer: `BITCODE_SPEC.txt` -> `V41` - Current active canon: `BITCODE_SPEC_V41.md` - Current draft target: `BITCODE_SPEC_V42.md`. -- Current working gate: V42 Gate 3 Reading Shortest Path State Machine. -- Next queued gate after V42 Gate 3: V42 Gate 4 ReadNeed Review And Resynthesis Product Closure. +- Current working gate: V42 Gate 4 ReadNeed Review And Resynthesis Product Closure. +- Next queued gate after V42 Gate 4: V42 Gate 5 ReadFitsFinding AssetPack Preview And Quote Closure. - Latest closed version: V41 Prompt And PromptPart Excellence, which promoted PromptPart and Prompt inventory, registry interpolation contracts, Reading prompt baselines, ReadNeedComprehensionSynthesis prompt hardening, ReadFitsFindingSynthesis prompt hardening, Conversation/tool/interface prompt rewrite, prompt benchmark telemetry, and V41 promotion readiness. - Recent V42 opening anchor: reliable MVP experience opens over promoted V41 with V42 SPEC, DELTA, NOTES, and PARITY files, `check:v42-gate1`, active V41 / draft V42 posture, and a nine-gate plan for shortest-path Depositing, five-step Reading, ReadNeed product closure, ReadFitsFinding preview and quote closure, settlement and repository delivery, AI-reading demonstration, local/staging rehearsal, and promotion readiness. - V42 Gate 2 closure anchor: reliable MVP experience now owns source-safe Depositing compensation visibility through `DepositorySupplyCompensationPreview`, deposit route `depositoryEvidence.compensationPreview`, deterministic `.bitcode/v42-depositing-shortest-path.json`, route/API readiness checks, source validation, Depository search/vector/storage projection, source-to-shares compensation readback keys, Terminal compensation roots, focused package/protocol tests, workflow wiring, and `check:v42-gate2`. - V42 Gate 3 closure anchor: reliable MVP experience now owns the five-step Reading shortest path state machine through `TerminalEnterpriseReadingUxState`, `TerminalEnterpriseReadingRouteState`, recoverable transaction ids, `readingStage` route hydration, retry/restart posture, source-safe failure repair actions, accepted-Need blockers, source-safe preview blockers, rich Reading pipeline telemetry readback, deterministic `.bitcode/v42-reading-shortest-path-state-machine.json`, focused route/component/protocol tests, workflow wiring, and `check:v42-gate3`. +- V42 Gate 4 closure anchor: reliable MVP experience now owns ReadNeed product closure through `ReadNeedReviewResynthesisRuntime`, source-safe storage projection, reviewed Need feedback/resynthesis lineage, accepted-Need Finding Fits admission, rejected Need blockers, PTRR/Failsafe/Thricified telemetry receipts, Terminal Need runtime/storage/telemetry readback, deterministic `.bitcode/v42-readneed-review-resynthesis-product-closure.json`, focused package/route/protocol tests, workflow wiring, and `check:v42-gate4`. - Recent V41 closure anchor: V41 canonical promotion updated `BITCODE_SPEC.txt` to `V41`, generated `BITCODE_SPEC_V41_PROVEN.md`, preserved active V41 / draft V42 runtime posture, and closed prompt-program excellence canon. - Recent V40 closure anchor: V40 canonical promotion updated `BITCODE_SPEC.txt` to `V40`, generated `BITCODE_SPEC_V40_PROVEN.md`, preserved active V40 / draft V41 runtime posture, and closed exhaustive commercial application testing canon. - Recent V39 closure anchor: V39 canonical promotion updated `BITCODE_SPEC.txt` to `V39`, generated `BITCODE_SPEC_V39_PROVEN.md`, preserved active V39 / draft V40 runtime posture, and closed commercial Reading readiness canon. diff --git a/package.json b/package.json index e2a90f91..4cfaeee3 100644 --- a/package.json +++ b/package.json @@ -310,6 +310,9 @@ "generate:v42-reading-shortest-path-state-machine": "node scripts/generate-v42-reading-shortest-path-state-machine.mjs", "check:v42-reading-shortest-path-state-machine": "node scripts/generate-v42-reading-shortest-path-state-machine.mjs --check", "check:v42-gate3": "node scripts/check-v42-gate3-reading-shortest-path-state-machine.mjs", + "generate:v42-readneed-review-resynthesis-product-closure": "node scripts/generate-v42-readneed-review-resynthesis-product-closure.mjs", + "check:v42-readneed-review-resynthesis-product-closure": "node scripts/generate-v42-readneed-review-resynthesis-product-closure.mjs --check", + "check:v42-gate4": "node scripts/check-v42-gate4-readneed-review-resynthesis-product-closure.mjs", "generate:v38-inference-surface-inventory": "node scripts/generate-v38-inference-surface-inventory.mjs", "check:v38-inference-surface-inventory": "node scripts/generate-v38-inference-surface-inventory.mjs --check", "check:v38-gate2": "node scripts/check-v38-gate2-inference-surface-inventory.mjs", diff --git a/packages/pipelines/asset-pack/README.md b/packages/pipelines/asset-pack/README.md index efcc5d76..051e9e77 100644 --- a/packages/pipelines/asset-pack/README.md +++ b/packages/pipelines/asset-pack/README.md @@ -139,6 +139,14 @@ for resynthesis. The runtime never serializes protected source, raw protected prompts, raw provider responses, unpaid AssetPack source, credentials, wallet private material, or private settlement payloads. +V42 Gate 4 binds this runtime into product closure through +`.bitcode/v42-readneed-review-resynthesis-product-closure.json` and +`check:v42-gate4`. That proof requires all four review actions +(`synthesize_read_need`, `resynthesize_read_need`, `accept_read_need`, +`reject_read_need`), PTRR/Failsafe/Thricified telemetry receipts, source-safe +storage projection, accepted-Need admission, rejected Need blockers, and +Terminal runtime readback before Finding Fits can run. + ## ReadFitsFinding Runtime `ReadFitsFindingRuntime` is the source-safe package primitive that turns diff --git a/packages/pipelines/asset-pack/src/__tests__/read-need-review-resynthesis.test.ts b/packages/pipelines/asset-pack/src/__tests__/read-need-review-resynthesis.test.ts index 9be22ad3..43ce606e 100644 --- a/packages/pipelines/asset-pack/src/__tests__/read-need-review-resynthesis.test.ts +++ b/packages/pipelines/asset-pack/src/__tests__/read-need-review-resynthesis.test.ts @@ -66,6 +66,9 @@ describe('ReadNeed review, resynthesis, and admission runtime', () => { 'need_measurement', 'telemetry_receipt', ]); + expect(runtime.storageProjection.every((record) => record.sourceSafety.protectedSourceVisible === false)).toBe(true); + expect(runtime.storageProjection.every((record) => record.sourceSafety.rawProviderResponseVisible === false)).toBe(true); + expect(runtime.storageProjection.every((record) => record.sourceSafety.unpaidAssetPackSourceVisible === false)).toBe(true); expect(runtime.telemetryReceipts[0]).toMatchObject({ pipelineName: 'ReadNeedComprehensionSynthesis', needId: readNeed.needId, diff --git a/packages/protocol/README.md b/packages/protocol/README.md index 69f9b4ae..a32d34a9 100644 --- a/packages/protocol/README.md +++ b/packages/protocol/README.md @@ -201,6 +201,15 @@ V42 Gate 3 adds the V42 Reading shortest path state machine, route persistence, accepted-Need gating, restart/retry/failure repair, low-detail proof-on-expand UI posture, rich Reading pipeline telemetry readback, activity/workbench readback, and source-safe disclosure boundaries. +V42 Gate 4 adds `V42ReadNeedReviewResynthesisProductClosure` through +`packages/protocol/src/canonical/v42-readneed-review-resynthesis-product-closure.js`, +`packages/protocol/test/v42-readneed-review-resynthesis-product-closure.test.js`, +`.bitcode/v42-readneed-review-resynthesis-product-closure.json`, and +`check:v42-gate4`. It proves ReadNeed review/resynthesis product closure: +source-safe Read Request and Need storage, feedback lineage, Need measurement, +accepted-Need admission, rejected Need blockers, PTRR/Failsafe/Thricified +telemetry receipts, `/api/read-review` action coverage, Terminal runtime +readback, and source-safe disclosure boundaries. V40 Gate 2 adds `V40TestInventoryCoverageMatrix` through `packages/protocol/src/canonical/v40-test-inventory-coverage-matrix.js`, `packages/protocol/test/v40-test-inventory-coverage-matrix.test.js`, diff --git a/packages/protocol/src/canonical/v42-readneed-review-resynthesis-product-closure.js b/packages/protocol/src/canonical/v42-readneed-review-resynthesis-product-closure.js new file mode 100644 index 00000000..895001af --- /dev/null +++ b/packages/protocol/src/canonical/v42-readneed-review-resynthesis-product-closure.js @@ -0,0 +1,325 @@ +// @ts-check + +import crypto from 'node:crypto'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const DEFAULT_REPO_ROOT = path.resolve(__dirname, '..', '..', '..', '..'); + +export const V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ARTIFACT_PATH = + '.bitcode/v42-readneed-review-resynthesis-product-closure.json'; +export const V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_SCHEMA_ID = + 'bitcode.v42.readNeedReviewResynthesisProductClosure.v1'; +export const V42_READNEED_REVIEW_RESYNTHESIS_SCHEMA_ID = + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_SCHEMA_ID; +export const V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_VERSION = 'V42'; +export const V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_CURRENT_TARGET = 'V41'; +export const V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_SOURCE_SAFETY_VERDICT = + 'source-safe-readneed-review-resynthesis-product-closure-metadata'; + +export const V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROW_IDS = Object.freeze([ + 'request:read-request-persistence', + 'pipeline:ptrr-failsafe-thricified-need-synthesis', + 'need:synthesized-need-storage', + 'feedback:review-resynthesis-lineage', + 'measurement:need-measurement-storage', + 'admission:accepted-need-gates-finding-fits', + 'rejection:rejected-need-posture', + 'telemetry:source-safe-runtime-receipts', + 'route:read-review-actions', + 'ui:terminal-need-runtime-readback', + 'proof:tests-artifact-workflow', +]); + +const SOURCE_ROOTS = Object.freeze({ + readNeed: 'packages/pipelines/asset-pack/src/read-need.ts', + readNeedRuntime: 'packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts', + readingPipelineContract: 'packages/pipelines/asset-pack/src/reading-pipeline-contract.ts', + packageIndex: 'packages/pipelines/asset-pack/src/index.ts', + packageJson: 'packages/pipelines/asset-pack/package.json', + readNeedTest: 'packages/pipelines/asset-pack/src/__tests__/read-need.test.ts', + runtimeTest: 'packages/pipelines/asset-pack/src/__tests__/read-need-review-resynthesis.test.ts', + readingContractTest: 'packages/pipelines/asset-pack/src/__tests__/reading-pipeline-contract.test.ts', + readReviewRoute: 'uapi/app/api/read-review/route.ts', + readReviewRouteTest: 'uapi/tests/api/readReviewRoute.test.ts', + readReviewProtocolParityTest: 'uapi/tests/api/readReviewProtocolParity.test.ts', + terminalWorkbench: 'uapi/app/terminal/TerminalDepositReadWorkbench.tsx', + terminalUxState: 'uapi/app/terminal/terminal-enterprise-reading-ux-state.ts', + gateWorkflow: '.github/workflows/bitcode-gate-quality.yml', + canonWorkflow: '.github/workflows/bitcode-canon-quality.yml', + v42Spec: 'BITCODE_SPEC_V42.md', + v42Delta: 'BITCODE_SPEC_V42_DELTA.md', + v42Notes: 'BITCODE_SPEC_V42_NOTES.md', + v42Parity: 'BITCODE_SPEC_V42_PARITY_MATRIX.md', + roadmap: 'SPECIFICATIONS_ROADMAP.md', + rootReadme: 'README.md', + terminalReadme: 'uapi/app/terminal/README.md', + assetPackReadme: 'packages/pipelines/asset-pack/README.md', + protocolReadme: 'packages/protocol/README.md', +}); + +const FORBIDDEN_PAYLOAD_CLASSES = Object.freeze([ + 'protected-source-payloads', + 'raw-protected-prompts', + 'raw-provider-responses', + 'unpaid-assetpack-source', + 'wallet-private-material', + 'settlement-private-payloads', + 'secret-values', +]); + +function digest(value) { + return crypto.createHash('sha256').update(value).digest('hex').slice(0, 24); +} + +function rowRoot(id) { + return `v42-readneed-review-resynthesis-product-closure-row:${digest(id)}`; +} + +function readSource(repoRoot, sourcePath) { + const absolutePath = path.join(repoRoot, sourcePath); + return existsSync(absolutePath) ? readFileSync(absolutePath, 'utf8') : ''; +} + +function predicateResult(id, sourcePath, passed) { + return { id, sourcePath, passed: Boolean(passed) }; +} + +function row(input) { + return { + ...input, + rowRoot: rowRoot(input.rowId), + sourceSafetyClass: 'source_safe_readneed_review_resynthesis_product_closure_metadata', + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + rawProtectedPromptVisible: false, + rawProviderResponseVisible: false, + unpaidAssetPackSourceVisible: false, + walletPrivateMaterialVisible: false, + settlementPrivatePayloadVisible: false, + credentialsSerialized: false, + forbiddenPayloadClasses: [...FORBIDDEN_PAYLOAD_CLASSES], + }; +} + +export const V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROWS = Object.freeze([ + row({ + rowId: 'request:read-request-persistence', + purpose: + 'Persist source-safe Read Request data with repository, branch, commit, target artifact kinds, closure criteria, failure modes, feedback, and previous Need lineage.', + sourceRoots: [SOURCE_ROOTS.readNeed, SOURCE_ROOTS.readNeedRuntime, SOURCE_ROOTS.readReviewRoute], + emittedTypes: ['ReadNeedRequest', 'ReadNeedReviewStorageRecord'], + requiredEvidence: ['bitcode.read.request', 'read_request', 'previousNeedId'], + }), + row({ + rowId: 'pipeline:ptrr-failsafe-thricified-need-synthesis', + purpose: + 'Keep ReadNeedComprehensionSynthesis product-owned by PTRR agents whose steps carry FailsafeGenerationSequence over ThricifiedGeneration contracts and typed parser output.', + sourceRoots: [SOURCE_ROOTS.readNeed, SOURCE_ROOTS.readingPipelineContract, SOURCE_ROOTS.readNeedTest], + emittedTypes: ['ReadNeedComprehensionSynthesisInferenceReceipt', 'ReadingPipelineContract'], + requiredEvidence: ['ptrrStepIds', 'failsafeSequenceIds', 'thricifiedGenerationIds', 'ReadNeedComprehensionSynthesis.prompt.need-synthesis'], + }), + row({ + rowId: 'need:synthesized-need-storage', + purpose: + 'Persist reviewable synthesized Need output before Finding Fits, including requirements, target artifacts, source constraints, proof expectations, and review state.', + sourceRoots: [SOURCE_ROOTS.readNeed, SOURCE_ROOTS.readNeedRuntime, SOURCE_ROOTS.runtimeTest], + emittedTypes: ['ReadNeed', 'synthesized_need'], + requiredEvidence: ['bitcode.read.need', 'needs_acceptance', 'synthesized_need'], + }), + row({ + rowId: 'feedback:review-resynthesis-lineage', + purpose: + 'Preserve user feedback and resynthesis attempts so every new Need stays linked to the prior Need and reviewed feedback.', + sourceRoots: [SOURCE_ROOTS.readNeed, SOURCE_ROOTS.readNeedRuntime, SOURCE_ROOTS.readReviewRouteTest, SOURCE_ROOTS.terminalWorkbench], + emittedTypes: ['resynthesis_attempt', 'feedbackHistory'], + requiredEvidence: ['previousNeedId', 'resynthesize_read_need', 'resynthesis_attempt'], + }), + row({ + rowId: 'measurement:need-measurement-storage', + purpose: + 'Persist Need measurement roots and pricing measurement inputs that later drive deterministic preview quotes without exposing source.', + sourceRoots: [SOURCE_ROOTS.readNeed, SOURCE_ROOTS.readNeedRuntime, SOURCE_ROOTS.readNeedTest], + emittedTypes: ['ReadNeedMeasurementDimension', 'need_measurement'], + requiredEvidence: ['measurementRoot', 'pricingMeasurementInputs', 'shareToFeeFormula'], + }), + row({ + rowId: 'admission:accepted-need-gates-finding-fits', + purpose: + 'Persist accepted-Need admission as the only source-safe handoff into ReadFitsFindingSynthesis and block Finding Fits without acceptance.', + sourceRoots: [SOURCE_ROOTS.readNeed, SOURCE_ROOTS.readNeedRuntime, SOURCE_ROOTS.readReviewRouteTest, SOURCE_ROOTS.terminalUxState], + emittedTypes: ['ReadFitsFindingAdmission', 'accepted_need_admission'], + requiredEvidence: ['accept_read_need', 'accepted_need_admission', 'accepted_read_need_missing'], + }), + row({ + rowId: 'rejection:rejected-need-posture', + purpose: + 'Persist rejected-Need posture with rejection root, feedback, blocked Finding Fits stage, and repair/resynthesis next action.', + sourceRoots: [SOURCE_ROOTS.readNeed, SOURCE_ROOTS.readNeedRuntime, SOURCE_ROOTS.readReviewRouteTest, SOURCE_ROOTS.terminalWorkbench], + emittedTypes: ['RejectedReadNeed', 'rejected_need_posture'], + requiredEvidence: ['rejectReadNeed', 'reject_read_need', 'read_need_rejected'], + }), + row({ + rowId: 'telemetry:source-safe-runtime-receipts', + purpose: + 'Emit source-safe telemetry receipts containing phase, PTRR step, Failsafe, ThricifiedGeneration, prompt-template, output-schema, and proof-root identities.', + sourceRoots: [SOURCE_ROOTS.readNeed, SOURCE_ROOTS.readNeedRuntime, SOURCE_ROOTS.readingPipelineContract, SOURCE_ROOTS.readReviewRoute], + emittedTypes: ['ReadNeedReviewTelemetryReceipt', 'ReadNeedComprehensionSynthesisInferenceReceipt'], + requiredEvidence: ['ptrrStepIds', 'failsafeSequenceIds', 'thricifiedGenerationIds', 'promptTemplateIds'], + }), + row({ + rowId: 'route:read-review-actions', + purpose: + 'Expose synthesize, resynthesize, accept, and reject actions through the Read review route with storage projection, runtime summary, source-safe telemetry, and Finding Fits admission readback.', + sourceRoots: [SOURCE_ROOTS.readReviewRoute, SOURCE_ROOTS.readReviewRouteTest], + emittedTypes: ['readNeedReviewRuntime', 'storageProjection', 'runtimeSummary'], + requiredEvidence: ['synthesize_read_need', 'resynthesize_read_need', 'accept_read_need', 'reject_read_need'], + }), + row({ + rowId: 'ui:terminal-need-runtime-readback', + purpose: + 'Expose the reviewed Need, feedback loop, rejection path, storage projection, runtime roots, telemetry return type, and Finding Fits blocker/admission state in Terminal without protected source.', + sourceRoots: [SOURCE_ROOTS.terminalWorkbench, SOURCE_ROOTS.terminalReadme], + emittedTypes: ['TerminalReadNeedReviewRuntimeState', 'Need runtime, storage, and telemetry'], + requiredEvidence: ['Reject Read-Need', 'readNeedStorageProjection', 'readNeedTelemetry', 'Need runtime, storage, and telemetry'], + }), + row({ + rowId: 'proof:tests-artifact-workflow', + purpose: + 'Bind V42 Gate 4 closure to package tests, route tests, protocol artifact tests, docs, scripts, and gate/canon workflow checks.', + sourceRoots: [ + SOURCE_ROOTS.runtimeTest, + SOURCE_ROOTS.readReviewRouteTest, + SOURCE_ROOTS.gateWorkflow, + SOURCE_ROOTS.canonWorkflow, + SOURCE_ROOTS.v42Spec, + SOURCE_ROOTS.v42Parity, + SOURCE_ROOTS.roadmap, + ], + emittedTypes: ['V42ReadNeedReviewResynthesisProductClosure'], + requiredEvidence: ['check-v42-gate4-readneed-review-resynthesis-product-closure.mjs', 'v42-readneed-review-resynthesis-product-closure'], + }), +]); + +function buildPredicateResults(repoRoot) { + const readNeed = readSource(repoRoot, SOURCE_ROOTS.readNeed); + const runtime = readSource(repoRoot, SOURCE_ROOTS.readNeedRuntime); + const contract = readSource(repoRoot, SOURCE_ROOTS.readingPipelineContract); + const packageIndex = readSource(repoRoot, SOURCE_ROOTS.packageIndex); + const packageJson = readSource(repoRoot, SOURCE_ROOTS.packageJson); + const readNeedTest = readSource(repoRoot, SOURCE_ROOTS.readNeedTest); + const runtimeTest = readSource(repoRoot, SOURCE_ROOTS.runtimeTest); + const contractTest = readSource(repoRoot, SOURCE_ROOTS.readingContractTest); + const route = readSource(repoRoot, SOURCE_ROOTS.readReviewRoute); + const routeTest = readSource(repoRoot, SOURCE_ROOTS.readReviewRouteTest); + const protocolParityTest = readSource(repoRoot, SOURCE_ROOTS.readReviewProtocolParityTest); + const terminalWorkbench = readSource(repoRoot, SOURCE_ROOTS.terminalWorkbench); + const terminalUxState = readSource(repoRoot, SOURCE_ROOTS.terminalUxState); + const gateWorkflow = readSource(repoRoot, SOURCE_ROOTS.gateWorkflow); + const canonWorkflow = readSource(repoRoot, SOURCE_ROOTS.canonWorkflow); + const spec = readSource(repoRoot, SOURCE_ROOTS.v42Spec); + const delta = readSource(repoRoot, SOURCE_ROOTS.v42Delta); + const notes = readSource(repoRoot, SOURCE_ROOTS.v42Notes); + const parity = readSource(repoRoot, SOURCE_ROOTS.v42Parity); + const roadmap = readSource(repoRoot, SOURCE_ROOTS.roadmap); + const rootReadme = readSource(repoRoot, SOURCE_ROOTS.rootReadme); + const terminalReadme = readSource(repoRoot, SOURCE_ROOTS.terminalReadme); + const assetPackReadme = readSource(repoRoot, SOURCE_ROOTS.assetPackReadme); + const protocolReadme = readSource(repoRoot, SOURCE_ROOTS.protocolReadme); + + return [ + predicateResult('read-need-defines-review-states', SOURCE_ROOTS.readNeed, readNeed.includes("'needs_acceptance'") && readNeed.includes("'accepted'") && readNeed.includes("'rejected'")), + predicateResult('read-need-accept-and-reject-actions', SOURCE_ROOTS.readNeed, readNeed.includes('acceptReadNeed') && readNeed.includes('rejectReadNeed') && readNeed.includes('read_need_rejected')), + predicateResult('inference-receipt-covers-ptrr-failsafe-thricified', SOURCE_ROOTS.readNeed, readNeed.includes('ReadNeedComprehensionSynthesisInferenceReceipt') && readNeed.includes('failsafeSequenceIds') && readNeed.includes('thricifiedGenerationIds') && readNeed.includes('promptTemplateIds')), + predicateResult('contract-has-four-phases-and-sixteen-steps', SOURCE_ROOTS.readingPipelineContract, contract.includes('ReadNeedComprehensionSynthesis.request') && contract.includes('ReadNeedComprehensionSynthesis.review') && contract.includes('ptrrStepCount') && contract.includes('thricifiedGenerationCount')), + predicateResult('runtime-defines-storage-records', SOURCE_ROOTS.readNeedRuntime, runtime.includes('ReadNeedReviewStorageRecord') && runtime.includes('read_request') && runtime.includes('synthesized_need') && runtime.includes('need_measurement')), + predicateResult('runtime-defines-resynthesis-admission-rejection', SOURCE_ROOTS.readNeedRuntime, runtime.includes('resynthesis_attempt') && runtime.includes('accepted_need_admission') && runtime.includes('rejected_need_posture')), + predicateResult('runtime-source-safety', SOURCE_ROOTS.readNeedRuntime, runtime.includes('source_safe_read_need_review_resynthesis_metadata') && runtime.includes('protectedSourceVisible: false') && runtime.includes('rawProviderResponseVisible: false') && runtime.includes('unpaidAssetPackSourceVisible: false')), + predicateResult('runtime-persists-to-execution-store', SOURCE_ROOTS.readNeedRuntime, runtime.includes('persistReadNeedReviewResynthesisRuntime') && runtime.includes("execution?.store?.('read-need-review'")), + predicateResult('package-exports-runtime', SOURCE_ROOTS.packageIndex, packageIndex.includes("export * from './read-need-review-resynthesis'") && packageJson.includes('./read-need-review-resynthesis')), + predicateResult('package-tests-cover-runtime', SOURCE_ROOTS.runtimeTest, runtimeTest.includes('ReadNeed review, resynthesis, and admission runtime') && runtimeTest.includes('rejected_need_posture')), + predicateResult('read-need-tests-cover-real-inference-receipts', SOURCE_ROOTS.readNeedTest, readNeedTest.includes('real-inference ReadNeedComprehension') && readNeedTest.includes('thricified-generation') && readNeedTest.includes('accepted_read_need_missing')), + predicateResult('contract-tests-cover-review-output', SOURCE_ROOTS.readingContractTest, contractTest.includes('ReadNeedComprehensionSynthesis') && contractTest.includes('ptrrStepCount: 16')), + predicateResult('route-exposes-all-review-actions', SOURCE_ROOTS.readReviewRoute, route.includes('synthesize_read_need') && route.includes('resynthesize_read_need') && route.includes('accept_read_need') && route.includes('reject_read_need')), + predicateResult('route-persists-all-runtime-actions', SOURCE_ROOTS.readReviewRoute, route.match(/persistReadNeedReviewResynthesisRuntime/g)?.length >= 3), + predicateResult('route-returns-runtime-projection', SOURCE_ROOTS.readReviewRoute, route.includes('readNeedReviewRuntime') && route.includes('storageProjection') && route.includes('runtimeSummary')), + predicateResult('route-tests-cover-runtime-and-rejection', SOURCE_ROOTS.readReviewRouteTest, routeTest.includes('readNeedReviewRuntime') && routeTest.includes('reject_read_need') && routeTest.includes('rejected_need_posture')), + predicateResult('protocol-parity-keeps-finding-fits-blocked', SOURCE_ROOTS.readReviewProtocolParityTest, protocolParityTest.includes('Finding Fits cannot proceed') && protocolParityTest.includes('fitSearchAdmission')), + predicateResult('terminal-ui-exposes-runtime-readback', SOURCE_ROOTS.terminalWorkbench, terminalWorkbench.includes('TerminalReadNeedReviewRuntimeState') && terminalWorkbench.includes('readNeedStorageProjection') && terminalWorkbench.includes('readNeedTelemetry') && terminalWorkbench.includes('Need runtime, storage, and telemetry')), + predicateResult('terminal-ui-exposes-rejection', SOURCE_ROOTS.terminalWorkbench, terminalWorkbench.includes('handleRejectReadNeed') && terminalWorkbench.includes('Reject Read-Need') && terminalWorkbench.includes('reject_read_need')), + predicateResult('terminal-ux-keeps-accepted-need-gate', SOURCE_ROOTS.terminalUxState, terminalUxState.includes('acceptedNeedRequiredBeforeFindingFits') && terminalUxState.includes('sourceSafePreviewBlocked')), + predicateResult('spec-gate4-expanded', SOURCE_ROOTS.v42Spec, spec.includes('V42 Gate 4') && spec.includes('v42-readneed-review-resynthesis-product-closure')), + predicateResult('delta-gate4-expanded', SOURCE_ROOTS.v42Delta, delta.includes('Gate 4') && delta.includes('readNeedReviewRuntime')), + predicateResult('notes-gate4-expanded', SOURCE_ROOTS.v42Notes, notes.includes('Gate 4 implementation notes') && notes.includes('rejected Need posture')), + predicateResult('parity-gate4-implemented', SOURCE_ROOTS.v42Parity, parity.includes('ReadNeed product closure') && parity.includes('implemented')), + predicateResult('roadmap-advanced-to-gate4', SOURCE_ROOTS.roadmap, roadmap.includes('V42 Gate 4 closure anchor') && roadmap.includes('ReadNeedReviewResynthesisRuntime')), + predicateResult('readmes-document-gate4', SOURCE_ROOTS.rootReadme, rootReadme.includes('V42 Gate 4') && terminalReadme.includes('ReadNeedReviewResynthesisRuntime') && assetPackReadme.includes('ReadNeed review') && protocolReadme.includes('V42ReadNeedReviewResynthesisProductClosure')), + predicateResult('workflows-run-gate4-check', SOURCE_ROOTS.gateWorkflow, gateWorkflow.includes('check-v42-gate4-readneed-review-resynthesis-product-closure.mjs') && canonWorkflow.includes('check-v42-gate4-readneed-review-resynthesis-product-closure.mjs')), + ]; +} + +export function buildV42ReadNeedReviewResynthesisProductClosure(options = {}) { + const repoRoot = options.repoRoot || DEFAULT_REPO_ROOT; + const predicateResults = buildPredicateResults(repoRoot); + const failedPredicateIds = predicateResults + .filter((predicate) => !predicate.passed) + .map((predicate) => predicate.id); + const rowRoots = V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROWS.map((item) => item.rowRoot); + const artifactRoot = `v42-readneed-review-resynthesis-product-closure:${digest(JSON.stringify({ + rowRoots, + failedPredicateIds, + }))}`; + + return { + artifactId: 'v42-readneed-review-resynthesis-product-closure', + schemaId: V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_SCHEMA_ID, + version: V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_VERSION, + currentTarget: V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_CURRENT_TARGET, + sourceSafetyVerdict: V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_SOURCE_SAFETY_VERDICT, + generatedAt: 'deterministic', + artifactRoot, + passed: failedPredicateIds.length === 0, + rows: V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROWS, + rowIds: [...V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROW_IDS], + predicateResults, + coverage: { + rowCount: V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROWS.length, + requiredPredicateCount: predicateResults.length, + passedPredicateCount: predicateResults.length - failedPredicateIds.length, + failedPredicateIds, + pipelineName: 'ReadNeedComprehensionSynthesis', + nextPipelineName: 'ReadFitsFindingSynthesis', + actions: ['synthesize_read_need', 'resynthesize_read_need', 'accept_read_need', 'reject_read_need'], + persistedRecordKinds: [ + 'read_request', + 'synthesized_need', + 'feedback', + 'resynthesis_attempt', + 'need_measurement', + 'accepted_need_admission', + 'rejected_need_posture', + 'telemetry_receipt', + ], + phaseCount: 4, + ptrrStepCount: 16, + failsafeSequenceCount: 48, + thricifiedGenerationCount: 48, + acceptedNeedRequiredForFindingFits: true, + rejectedNeedBlocksFindingFits: true, + terminalRuntimeReadbackCovered: true, + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + rawProtectedPromptVisible: false, + rawProviderResponseVisible: false, + unpaidAssetPackSourceVisible: false, + walletPrivateMaterialVisible: false, + settlementPrivatePayloadVisible: false, + credentialsSerialized: false, + legacySourceRoots: Object.values(SOURCE_ROOTS).some((sourcePath) => sourcePath.includes('_legacy/')), + }, + sourceRoots: SOURCE_ROOTS, + }; +} diff --git a/packages/protocol/src/index.d.ts b/packages/protocol/src/index.d.ts index 7bef5cb2..eee3699b 100644 --- a/packages/protocol/src/index.d.ts +++ b/packages/protocol/src/index.d.ts @@ -529,6 +529,15 @@ export const V42_READING_SHORTEST_PATH_STEP_IDS: readonly string[]; export const V42_READING_SHORTEST_PATH_ROW_IDS: readonly string[]; export const V42_READING_SHORTEST_PATH_ROWS: readonly Record[]; export function buildV42ReadingShortestPathStateMachine(input?: Record): BitcodeProtocolReport; +export const V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ARTIFACT_PATH: string; +export const V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_CURRENT_TARGET: string; +export const V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_SCHEMA_ID: string; +export const V42_READNEED_REVIEW_RESYNTHESIS_SCHEMA_ID: string; +export const V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_VERSION: string; +export const V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_SOURCE_SAFETY_VERDICT: string; +export const V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROW_IDS: readonly string[]; +export const V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROWS: readonly Record[]; +export function buildV42ReadNeedReviewResynthesisProductClosure(input?: Record): BitcodeProtocolReport; export const EXCHANGE_INTENT_ORDER_CONTRACTS_ARTIFACT_PATH: string; export const EXCHANGE_INTENT_ORDER_CONTRACTS_CURRENT_TARGET: string; export const EXCHANGE_INTENT_ORDER_CONTRACTS_SCHEMA_ID: string; diff --git a/packages/protocol/src/index.js b/packages/protocol/src/index.js index 7f07b1c9..358610d2 100644 --- a/packages/protocol/src/index.js +++ b/packages/protocol/src/index.js @@ -591,6 +591,17 @@ export { V42_READING_SHORTEST_PATH_STEP_IDS, buildV42ReadingShortestPathStateMachine } from './canonical/v42-reading-shortest-path-state-machine.js'; +export { + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ARTIFACT_PATH, + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_CURRENT_TARGET, + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROW_IDS, + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROWS, + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_SCHEMA_ID, + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_SOURCE_SAFETY_VERDICT, + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_VERSION, + V42_READNEED_REVIEW_RESYNTHESIS_SCHEMA_ID, + buildV42ReadNeedReviewResynthesisProductClosure +} from './canonical/v42-readneed-review-resynthesis-product-closure.js'; export { EXCHANGE_INTENT_ACTION_KINDS, EXCHANGE_INTENT_ORDER_CONTRACTS_ARTIFACT_PATH, diff --git a/packages/protocol/test/v42-readneed-review-resynthesis-product-closure.test.js b/packages/protocol/test/v42-readneed-review-resynthesis-product-closure.test.js new file mode 100644 index 00000000..277ee41c --- /dev/null +++ b/packages/protocol/test/v42-readneed-review-resynthesis-product-closure.test.js @@ -0,0 +1,73 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ARTIFACT_PATH, + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROWS, + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROW_IDS, + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_SCHEMA_ID, + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_SOURCE_SAFETY_VERDICT, + V42_READNEED_REVIEW_RESYNTHESIS_SCHEMA_ID, + buildV42ReadNeedReviewResynthesisProductClosure, +} from '../src/canonical/v42-readneed-review-resynthesis-product-closure.js'; + +test('V42 ReadNeed review and resynthesis product closure binds the accepted Need gate', () => { + const report = buildV42ReadNeedReviewResynthesisProductClosure(); + + assert.equal( + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ARTIFACT_PATH, + '.bitcode/v42-readneed-review-resynthesis-product-closure.json', + ); + assert.equal(report.artifactId, 'v42-readneed-review-resynthesis-product-closure'); + assert.equal(report.schemaId, V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_SCHEMA_ID); + assert.equal(report.schemaId, V42_READNEED_REVIEW_RESYNTHESIS_SCHEMA_ID); + assert.equal(report.version, 'V42'); + assert.equal(report.currentTarget, 'V41'); + assert.equal(report.sourceSafetyVerdict, V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_SOURCE_SAFETY_VERDICT); + assert.equal(report.passed, true); + assert.deepEqual(report.rowIds, [...V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROW_IDS]); + assert.equal(report.rows.length, V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROWS.length); + assert.equal(report.coverage.rowCount, 11); + assert.equal(report.coverage.phaseCount, 4); + assert.equal(report.coverage.ptrrStepCount, 16); + assert.equal(report.coverage.failsafeSequenceCount, 48); + assert.equal(report.coverage.thricifiedGenerationCount, 48); + assert.deepEqual(report.coverage.actions, [ + 'synthesize_read_need', + 'resynthesize_read_need', + 'accept_read_need', + 'reject_read_need', + ]); + assert.equal(report.coverage.acceptedNeedRequiredForFindingFits, true); + assert.equal(report.coverage.rejectedNeedBlocksFindingFits, true); + assert.equal(report.coverage.terminalRuntimeReadbackCovered, true); + assert.equal(report.coverage.sourceSafeMetadataOnly, true); + assert.equal(report.coverage.protectedSourceVisible, false); + assert.equal(report.coverage.rawProtectedPromptVisible, false); + assert.equal(report.coverage.rawProviderResponseVisible, false); + assert.equal(report.coverage.unpaidAssetPackSourceVisible, false); + assert.equal(report.coverage.walletPrivateMaterialVisible, false); + assert.equal(report.coverage.settlementPrivatePayloadVisible, false); + assert.equal(report.coverage.credentialsSerialized, false); + assert.equal(report.coverage.legacySourceRoots, false); + assert.deepEqual(report.coverage.failedPredicateIds, []); + assert.ok(report.artifactRoot.startsWith('v42-readneed-review-resynthesis-product-closure:')); +}); + +test('V42 ReadNeed review rows remain source-safe metadata', () => { + for (const row of V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ROWS) { + assert.ok(row.rowRoot.startsWith('v42-readneed-review-resynthesis-product-closure-row:')); + assert.equal(row.sourceSafetyClass, 'source_safe_readneed_review_resynthesis_product_closure_metadata'); + assert.equal(row.sourceSafeMetadataOnly, true); + assert.equal(row.protectedSourceVisible, false); + assert.equal(row.rawProtectedPromptVisible, false); + assert.equal(row.rawProviderResponseVisible, false); + assert.equal(row.unpaidAssetPackSourceVisible, false); + assert.equal(row.walletPrivateMaterialVisible, false); + assert.equal(row.settlementPrivatePayloadVisible, false); + assert.equal(row.credentialsSerialized, false); + assert.ok(row.forbiddenPayloadClasses.includes('protected-source-payloads')); + assert.ok(row.forbiddenPayloadClasses.includes('raw-provider-responses')); + assert.ok(row.forbiddenPayloadClasses.includes('unpaid-assetpack-source')); + } +}); diff --git a/scripts/check-v42-gate4-readneed-review-resynthesis-product-closure.mjs b/scripts/check-v42-gate4-readneed-review-resynthesis-product-closure.mjs new file mode 100644 index 00000000..d52bc7d3 --- /dev/null +++ b/scripts/check-v42-gate4-readneed-review-resynthesis-product-closure.mjs @@ -0,0 +1,258 @@ +#!/usr/bin/env node + +import { execFileSync } from 'node:child_process'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const defaultRepoRoot = path.resolve(__dirname, '..'); +const ARTIFACT_PATH = '.bitcode/v42-readneed-review-resynthesis-product-closure.json'; + +const SECRET_MARKERS = [ + `${['sk', 'proj'].join('-')}-`, + `${['sb', 'secret'].join('_')}__`, + ['service', 'role'].join('_'), + Buffer.from('{"alg":"HS256","typ":"JWT"}').toString('base64url').slice(0, 18), + ['OPENAI', 'API', 'KEY'].join('_'), + ['SUPABASE', 'SERVICE', 'ROLE'].join('_'), + ['VERCEL', 'TOKEN'].join('_'), + ['VERCEL', 'OIDC', 'TOKEN'].join('_'), + ['PRIVATE', 'KEY'].join('_'), +]; + +function read(root, relativePath) { + return readFileSync(path.join(root, relativePath), 'utf8'); +} + +function fileExists(root, relativePath) { + return existsSync(path.join(root, relativePath)); +} + +function git(root, args) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); +} + +function run(root, command, args) { + return execFileSync(command, args, { + cwd: root, + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'pipe'], + }).trim(); +} + +function assertCheck(failures, condition, message) { + if (!condition) failures.push(message); +} + +function parseArgs(argv) { + const args = { + skipBranchCheck: false, + skipPackageTests: false, + skipUapiTests: false, + repoRoot: defaultRepoRoot, + help: false, + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--skip-branch-check') args.skipBranchCheck = true; + else if (arg === '--skip-package-tests') args.skipPackageTests = true; + else if (arg === '--skip-uapi-tests') args.skipUapiTests = true; + else if (arg === '--repo-root') args.repoRoot = path.resolve(argv[++index]); + else if (arg === '--help' || arg === '-h') args.help = true; + else throw new Error(`Unknown argument ${arg}`); + } + + return args; +} + +function printHelp() { + process.stdout.write( + [ + 'Usage: node scripts/check-v42-gate4-readneed-review-resynthesis-product-closure.mjs [--skip-branch-check] [--skip-package-tests] [--skip-uapi-tests] [--repo-root ]', + '', + 'Checks V42 Gate 4 ReadNeed product closure, review/resynthesis, rejection, accepted-Need admission, source-safe runtime storage, telemetry receipts, Terminal readback, tests, docs, workflow wiring, and proof artifact.', + ].join('\n'), + ); + process.stdout.write('\n'); +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + if (args.help) { + printHelp(); + return; + } + + const root = args.repoRoot; + const failures = []; + const pointer = read(root, 'BITCODE_SPEC.txt').trim(); + + assertCheck( + failures, + pointer === 'V41', + `BITCODE_SPEC.txt must remain V41 during V42 gate work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v42' || /^v42\/gate-(?:4|[5-9]|10)-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V42 Gate 4+ work must occur on version/v42 or v42/gate-4..10-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + const requiredFiles = [ + ARTIFACT_PATH, + 'packages/pipelines/asset-pack/src/read-need.ts', + 'packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts', + 'packages/pipelines/asset-pack/src/reading-pipeline-contract.ts', + 'packages/pipelines/asset-pack/src/__tests__/read-need.test.ts', + 'packages/pipelines/asset-pack/src/__tests__/read-need-review-resynthesis.test.ts', + 'packages/pipelines/asset-pack/src/__tests__/reading-pipeline-contract.test.ts', + 'uapi/app/api/read-review/route.ts', + 'uapi/app/terminal/TerminalDepositReadWorkbench.tsx', + 'uapi/tests/api/readReviewRoute.test.ts', + 'uapi/tests/api/readReviewProtocolParity.test.ts', + 'packages/protocol/src/canonical/v42-readneed-review-resynthesis-product-closure.js', + 'packages/protocol/test/v42-readneed-review-resynthesis-product-closure.test.js', + 'scripts/generate-v42-readneed-review-resynthesis-product-closure.mjs', + 'scripts/check-v42-gate4-readneed-review-resynthesis-product-closure.mjs', + 'BITCODE_SPEC_V42.md', + 'BITCODE_SPEC_V42_DELTA.md', + 'BITCODE_SPEC_V42_NOTES.md', + 'BITCODE_SPEC_V42_PARITY_MATRIX.md', + 'SPECIFICATIONS_ROADMAP.md', + 'README.md', + 'uapi/app/terminal/README.md', + 'packages/pipelines/asset-pack/README.md', + 'packages/protocol/README.md', + 'package.json', + '.github/workflows/bitcode-gate-quality.yml', + '.github/workflows/bitcode-canon-quality.yml', + ]; + + for (const relativePath of requiredFiles) { + assertCheck(failures, fileExists(root, relativePath), `Missing V42 Gate 4 file: ${relativePath}`); + } + + if (failures.length === 0) { + try { + run(root, 'node', ['scripts/generate-v42-readneed-review-resynthesis-product-closure.mjs', '--check']); + } catch (error) { + failures.push(`V42 ReadNeed review/resynthesis artifact check failed: ${error.stderr || error.message}`); + } + } + + if (failures.length === 0) { + try { + run(root, 'node', [ + '--test', + '--test-force-exit', + 'packages/protocol/test/v42-readneed-review-resynthesis-product-closure.test.js', + ]); + } catch (error) { + failures.push(`V42 ReadNeed review/resynthesis protocol test failed: ${error.stderr || error.message}`); + } + } + + if (failures.length === 0 && !args.skipPackageTests) { + try { + run(root, 'pnpm', [ + '--filter', + '@bitcode/pipeline-asset-pack', + 'exec', + 'jest', + '--config', + 'jest.config.cjs', + '--runTestsByPath', + 'src/__tests__/read-need.test.ts', + 'src/__tests__/read-need-review-resynthesis.test.ts', + 'src/__tests__/reading-pipeline-contract.test.ts', + '--runInBand', + '--forceExit', + ]); + } catch (error) { + failures.push(`V42 ReadNeed review/resynthesis package tests failed: ${error.stderr || error.message}`); + } + } + + if (failures.length === 0 && !args.skipUapiTests) { + try { + run(root, 'pnpm', [ + '--dir', + 'uapi', + 'exec', + 'jest', + '--runTestsByPath', + 'tests/api/readReviewRoute.test.ts', + 'tests/api/readReviewProtocolParity.test.ts', + 'tests/terminalDepositReadWorkbench.test.ts', + 'tests/terminalEnterpriseReadingUxState.test.ts', + '--runInBand', + ]); + } catch (error) { + failures.push(`V42 ReadNeed review/resynthesis UAPI tests failed: ${error.stderr || error.message}`); + } + } + + const serializedArtifact = fileExists(root, ARTIFACT_PATH) ? read(root, ARTIFACT_PATH) : ''; + for (const marker of SECRET_MARKERS) { + assertCheck(failures, !serializedArtifact.includes(marker), `V42 Gate 4 artifact must not contain secret marker ${marker}.`); + } + + const artifact = serializedArtifact ? JSON.parse(serializedArtifact) : null; + if (artifact) { + assertCheck(failures, artifact.artifactId === 'v42-readneed-review-resynthesis-product-closure', 'Gate 4 artifactId must match.'); + assertCheck( + failures, + artifact.schemaId === 'bitcode.v42.readNeedReviewResynthesisProductClosure.v1', + 'Gate 4 schemaId must match.', + ); + assertCheck(failures, artifact.version === 'V42' && artifact.currentTarget === 'V41', 'Gate 4 artifact must bind V42 over active V41.'); + assertCheck(failures, artifact.passed === true, 'Gate 4 artifact must pass.'); + assertCheck( + failures, + artifact.sourceSafetyVerdict === 'source-safe-readneed-review-resynthesis-product-closure-metadata', + 'Gate 4 artifact must declare source-safe ReadNeed review/resynthesis product closure metadata.', + ); + assertCheck(failures, artifact.coverage.rowCount === 11, 'Gate 4 must cover eleven ReadNeed product closure rows.'); + assertCheck(failures, artifact.coverage.phaseCount === 4, 'Gate 4 must cover four ReadNeedComprehensionSynthesis phases.'); + assertCheck(failures, artifact.coverage.ptrrStepCount === 16, 'Gate 4 must cover sixteen PTRR steps.'); + assertCheck(failures, artifact.coverage.failsafeSequenceCount === 48, 'Gate 4 must cover forty-eight Failsafe sequences.'); + assertCheck(failures, artifact.coverage.thricifiedGenerationCount === 48, 'Gate 4 must cover forty-eight ThricifiedGeneration receipts.'); + assertCheck(failures, artifact.coverage.acceptedNeedRequiredForFindingFits === true, 'Gate 4 must require accepted Need before Finding Fits.'); + assertCheck(failures, artifact.coverage.rejectedNeedBlocksFindingFits === true, 'Gate 4 must block Finding Fits after rejected Need.'); + assertCheck(failures, artifact.coverage.terminalRuntimeReadbackCovered === true, 'Gate 4 must cover Terminal runtime readback.'); + assertCheck(failures, artifact.coverage.sourceSafeMetadataOnly === true, 'Gate 4 must remain source-safe metadata only.'); + assertCheck(failures, artifact.coverage.protectedSourceVisible === false, 'Gate 4 artifact must not expose protected source.'); + assertCheck(failures, artifact.coverage.rawProtectedPromptVisible === false, 'Gate 4 artifact must not expose protected prompts.'); + assertCheck(failures, artifact.coverage.rawProviderResponseVisible === false, 'Gate 4 artifact must not expose raw provider responses.'); + assertCheck(failures, artifact.coverage.unpaidAssetPackSourceVisible === false, 'Gate 4 artifact must not expose unpaid AssetPack source.'); + assertCheck(failures, artifact.coverage.walletPrivateMaterialVisible === false, 'Gate 4 artifact must not expose wallet private material.'); + assertCheck(failures, artifact.coverage.settlementPrivatePayloadVisible === false, 'Gate 4 artifact must not expose settlement private payloads.'); + assertCheck(failures, artifact.coverage.credentialsSerialized === false, 'Gate 4 artifact must not serialize credentials.'); + assertCheck(failures, artifact.coverage.legacySourceRoots === false, 'Gate 4 must not rely on legacy source roots.'); + assertCheck(failures, Array.isArray(artifact.coverage.failedPredicateIds) && artifact.coverage.failedPredicateIds.length === 0, 'Gate 4 predicates must all pass.'); + } + + const spec = read(root, 'BITCODE_SPEC_V42.md'); + const parity = read(root, 'BITCODE_SPEC_V42_PARITY_MATRIX.md'); + const terminalReadme = read(root, 'uapi/app/terminal/README.md'); + assertCheck(failures, spec.includes('V42 Gate 4') && spec.includes('v42-readneed-review-resynthesis-product-closure'), 'V42 spec must expand Gate 4 ReadNeed product closure.'); + assertCheck(failures, parity.includes('ReadNeed product closure') && parity.includes('implemented'), 'V42 parity matrix must mark ReadNeed product closure implemented.'); + assertCheck(failures, terminalReadme.includes('V42 Gate 4') && terminalReadme.includes('ReadNeedReviewResynthesisRuntime'), 'Terminal README must document Gate 4 ReadNeed runtime readback.'); + + if (failures.length > 0) { + process.stderr.write(`V42 Gate 4 ReadNeed product closure check failed:\n- ${failures.join('\n- ')}\n`); + process.exitCode = 1; + return; + } + + process.stdout.write(`V42 Gate 4 ReadNeed product closure ok artifact=${artifact.artifactRoot}\n`); +} + +main(); diff --git a/scripts/generate-v42-readneed-review-resynthesis-product-closure.mjs b/scripts/generate-v42-readneed-review-resynthesis-product-closure.mjs new file mode 100644 index 00000000..cb05c4a3 --- /dev/null +++ b/scripts/generate-v42-readneed-review-resynthesis-product-closure.mjs @@ -0,0 +1,31 @@ +#!/usr/bin/env node + +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { + V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ARTIFACT_PATH, + buildV42ReadNeedReviewResynthesisProductClosure, +} from '../packages/protocol/src/canonical/v42-readneed-review-resynthesis-product-closure.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); + +const check = process.argv.includes('--check'); +const artifact = buildV42ReadNeedReviewResynthesisProductClosure({ repoRoot }); +const serialized = `${JSON.stringify(artifact, null, 2)}\n`; +const artifactPath = path.join(repoRoot, V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ARTIFACT_PATH); + +if (check) { + const current = readFileSync(artifactPath, 'utf8'); + if (current !== serialized) { + process.stderr.write( + `${V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ARTIFACT_PATH} is stale. Run pnpm run generate:v42-readneed-review-resynthesis-product-closure.\n`, + ); + process.exitCode = 1; + } +} else { + writeFileSync(artifactPath, serialized); + process.stdout.write(`wrote ${V42_READNEED_REVIEW_RESYNTHESIS_PRODUCT_CLOSURE_ARTIFACT_PATH}\n`); +} diff --git a/uapi/app/api/read-review/route.ts b/uapi/app/api/read-review/route.ts index f7a2d304..7966a42c 100644 --- a/uapi/app/api/read-review/route.ts +++ b/uapi/app/api/read-review/route.ts @@ -126,6 +126,7 @@ export async function POST(request: Request) { const { acceptReadNeed, admitReadFitsFinding } = await import('@bitcode/pipeline-asset-pack/read-need'); const { buildReadNeedReviewResynthesisRuntime, + persistReadNeedReviewResynthesisRuntime, summarizeReadNeedReviewResynthesisRuntime, } = await import('@bitcode/pipeline-asset-pack/read-need-review-resynthesis'); const { @@ -145,10 +146,12 @@ export async function POST(request: Request) { acceptedReadNeed, requireAcceptedReadNeed: true, }); + const inferenceCapture = createRouteInferenceCapture(); const reviewRuntime = buildReadNeedReviewResynthesisRuntime({ action, readNeed: acceptedReadNeed, }); + persistReadNeedReviewResynthesisRuntime(inferenceCapture.execution, reviewRuntime); const acceptanceStep = READ_NEED_COMPREHENSION_SYNTHESIS_CONTRACT.phases .flatMap((phase) => phase.agents) @@ -197,6 +200,7 @@ export async function POST(request: Request) { const { rejectReadNeed, admitReadFitsFinding } = await import('@bitcode/pipeline-asset-pack/read-need'); const { buildReadNeedReviewResynthesisRuntime, + persistReadNeedReviewResynthesisRuntime, summarizeReadNeedReviewResynthesisRuntime, } = await import('@bitcode/pipeline-asset-pack/read-need-review-resynthesis'); const { @@ -219,11 +223,13 @@ export async function POST(request: Request) { readNeed: rejectedReadNeed, requireAcceptedReadNeed: true, }); + const inferenceCapture = createRouteInferenceCapture(); const reviewRuntime = buildReadNeedReviewResynthesisRuntime({ action, readNeed: rejectedReadNeed, feedback: stringArray(body.feedback || body.readNeedFeedback), }); + persistReadNeedReviewResynthesisRuntime(inferenceCapture.execution, reviewRuntime); const reviewStep = READ_NEED_COMPREHENSION_SYNTHESIS_CONTRACT.phases .flatMap((phase) => phase.agents) diff --git a/uapi/app/terminal/README.md b/uapi/app/terminal/README.md index 176bc0a0..a5803f85 100644 --- a/uapi/app/terminal/README.md +++ b/uapi/app/terminal/README.md @@ -115,6 +115,16 @@ settlement, and settlement readback gates delivery. The source-safe proof artifact is `.bitcode/v42-reading-shortest-path-state-machine.json`, checked by `pnpm run check:v42-gate3`. +V42 Gate 4 closes the Terminal ReadNeed review loop. The staged Reading +surface now keeps `ReadNeedReviewResynthesisRuntime`, storage projection rows, +telemetry return type, runtime root, storage root, telemetry root, admission +blockers, and rejected Need posture visible in expandable source-safe detail. +Terminal exposes synthesize, resynthesize, accept, and reject actions before +Finding Fits; accepting the Need is the only admission handoff to +`ReadFitsFindingSynthesis`. The source-safe proof artifact is +`.bitcode/v42-readneed-review-resynthesis-product-closure.json`, checked by +`pnpm run check:v42-gate4`. + ## Live staging-testnet QA Terminal Deposit/Read QA starts only after Wallet and Externals prerequisites are diff --git a/uapi/app/terminal/TerminalDepositReadWorkbench.tsx b/uapi/app/terminal/TerminalDepositReadWorkbench.tsx index 4d4e1453..599e8117 100644 --- a/uapi/app/terminal/TerminalDepositReadWorkbench.tsx +++ b/uapi/app/terminal/TerminalDepositReadWorkbench.tsx @@ -104,6 +104,24 @@ type TerminalReadNeedState = Record & { }; }; +type TerminalReadNeedReviewRuntimeState = Record & { + schema?: 'bitcode.read-need-review-resynthesis-runtime'; + runtimeId?: string; + action?: string; + reviewState?: string; + findingFitsAdmission?: { + admitted?: boolean; + blockers?: string[]; + }; + reviewLoop?: Record; + proofRoots?: { + runtimeRoot?: string; + storageRoot?: string; + telemetryRoot?: string; + readRequestRoot?: string; + }; +}; + interface TerminalDepositReadWorkbenchProps { repositoryContext?: TerminalRepositoryContextState | null; depositedSourceRevision?: TerminalDepositedSourceRevision | null; @@ -134,9 +152,12 @@ export default function TerminalDepositReadWorkbench({ const [harnessUserHasScrolled, setHarnessUserHasScrolled] = useState(false); const [readNeed, setReadNeed] = useState(null); const [acceptedReadNeed, setAcceptedReadNeed] = useState(null); + const [readNeedReviewRuntime, setReadNeedReviewRuntime] = useState(null); + const [readNeedStorageProjection, setReadNeedStorageProjection] = useState>>([]); + const [readNeedTelemetry, setReadNeedTelemetry] = useState | null>(null); const [readNeedFeedback, setReadNeedFeedback] = useState(''); const [readNeedMessage, setReadNeedMessage] = useState(null); - const [readNeedAction, setReadNeedAction] = useState<'synthesize' | 'accept' | 'resynthesize' | null>(null); + const [readNeedAction, setReadNeedAction] = useState<'synthesize' | 'accept' | 'reject' | 'resynthesize' | null>(null); const [readNeedSynthesisCount, setReadNeedSynthesisCount] = useState(0); const workbenchSnapshot = useMemo(() => { const liveWorkbenchSnapshot = buildLiveTerminalDepositReadWorkbenchSnapshot(repositoryContext, depositedSourceRevision); @@ -157,6 +178,9 @@ export default function TerminalDepositReadWorkbench({ setHarnessEvents([]); setReadNeed(null); setAcceptedReadNeed(null); + setReadNeedReviewRuntime(null); + setReadNeedStorageProjection([]); + setReadNeedTelemetry(null); setReadNeedFeedback(''); setReadNeedMessage(null); setReadNeedAction(null); @@ -410,6 +434,23 @@ export default function TerminalDepositReadWorkbench({ { label: 'Previous Need', value: shortIdentifier(currentReadNeed.request?.previousNeedId) || currentReadNeed.request?.previousNeedId || 'none' }, ]; }, [currentReadNeed]); + const readNeedRuntimeRows = useMemo(() => { + if (!readNeedReviewRuntime && !readNeedTelemetry && readNeedStorageProjection.length === 0) return []; + const admission = objectValue(readNeedReviewRuntime?.findingFitsAdmission); + const proofRoots = objectValue(readNeedReviewRuntime?.proofRoots); + return [ + { label: 'Runtime', value: shortIdentifier(readNeedReviewRuntime?.runtimeId) || textValue(readNeedReviewRuntime?.runtimeId) || 'pending' }, + { label: 'Action', value: textValue(readNeedReviewRuntime?.action) || 'pending' }, + { label: 'Admission', value: admission?.admitted === true ? 'admitted' : 'blocked' }, + { label: 'Blockers', value: stringList(admission?.blockers).join(', ') || 'none' }, + { label: 'Storage records', value: String(readNeedStorageProjection.length || 'pending') }, + { label: 'Runtime root', value: shortIdentifier(proofRoots?.runtimeRoot) || 'pending' }, + { label: 'Storage root', value: shortIdentifier(proofRoots?.storageRoot) || 'pending' }, + { label: 'Telemetry root', value: shortIdentifier(proofRoots?.telemetryRoot || readNeedTelemetry?.telemetryRoot) || 'pending' }, + { label: 'PTRR step', value: shortIdentifier(readNeedTelemetry?.ptrrStepId) || textValue(readNeedTelemetry?.ptrrStepId) || 'pending' }, + { label: 'Return type', value: textValue(readNeedTelemetry?.returnType) || 'pending' }, + ]; + }, [readNeedReviewRuntime, readNeedStorageProjection, readNeedTelemetry]); const stageCards = enterpriseReadingState.steps; const canRunLiveFit = !showDemonstrationWorkbench && @@ -531,6 +572,9 @@ export default function TerminalDepositReadWorkbench({ if (!nextNeed) throw new Error('Read-Need synthesis did not return a typed Need.'); setReadNeed(nextNeed); setAcceptedReadNeed(null); + setReadNeedReviewRuntime(objectValue(payload?.readNeedReviewRuntime) as TerminalReadNeedReviewRuntimeState | null); + setReadNeedStorageProjection(Array.isArray(payload?.storageProjection) ? payload.storageProjection as Array> : []); + setReadNeedTelemetry(objectValue(payload?.telemetry)); setReadNeedSynthesisCount((count) => count + 1); setReadNeedMessage( action === 'synthesize_read_need' @@ -573,6 +617,9 @@ export default function TerminalDepositReadWorkbench({ } setAcceptedReadNeed(accepted); setReadNeed(accepted); + setReadNeedReviewRuntime(objectValue(payload?.readNeedReviewRuntime) as TerminalReadNeedReviewRuntimeState | null); + setReadNeedStorageProjection(Array.isArray(payload?.storageProjection) ? payload.storageProjection as Array> : []); + setReadNeedTelemetry(objectValue(payload?.telemetry)); setReadNeedMessage('Read-Need accepted. Finding Fits can now run against deposited source.'); await onRecordActivity?.({ type: 'agentic-execution:read-measurement', @@ -604,6 +651,47 @@ export default function TerminalDepositReadWorkbench({ } }, [onRecordActivity, readNeed]); + const handleRejectReadNeed = useCallback(async () => { + if (!readNeed) return; + + setReadNeedAction('reject'); + setReadNeedMessage(null); + + try { + const response = await fetch('/api/read-review', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + action: 'reject_read_need', + readNeed, + feedback: readNeedFeedback.trim() ? [readNeedFeedback.trim()] : [], + }), + }); + + if (!response.ok) { + throw new Error(await readTerminalRouteError(response, 'Unable to reject the Read-Need.')); + } + + const payload = objectValue(await response.json()); + const rejected = terminalReadNeed(payload?.rejectedReadNeed || payload?.readNeed); + if (!rejected || rejected.reviewState !== 'rejected') { + throw new Error('Read-Need rejection did not return a rejected Need.'); + } + setReadNeed(rejected); + setAcceptedReadNeed(null); + setReadNeedReviewRuntime(objectValue(payload?.readNeedReviewRuntime) as TerminalReadNeedReviewRuntimeState | null); + setReadNeedStorageProjection(Array.isArray(payload?.storageProjection) ? payload.storageProjection as Array> : []); + setReadNeedTelemetry(objectValue(payload?.telemetry)); + setReadNeedMessage('Read-Need rejected. Finding Fits remains blocked until a resynthesized Need is accepted.'); + } catch (error) { + setReadNeedMessage(error instanceof Error ? error.message : 'Unable to reject the Read-Need.'); + } finally { + setReadNeedAction(null); + } + }, [readNeed, readNeedFeedback]); + const handleRunLiveFit = useCallback(async () => { if (!harnessRequestState.ready) { setHarnessState('failed'); @@ -850,6 +938,16 @@ export default function TerminalDepositReadWorkbench({ > {readNeedAction === 'accept' ? 'Accepting…' : 'Accept Read-Need'} +