diff --git a/.bitcode/v40-conversation-terminal-integration.json b/.bitcode/v40-conversation-terminal-integration.json new file mode 100644 index 000000000..854429662 --- /dev/null +++ b/.bitcode/v40-conversation-terminal-integration.json @@ -0,0 +1,816 @@ +{ + "artifactId": "v40-conversation-terminal-integration", + "schemaId": "bitcode.v40.conversationTerminalIntegration.v1", + "version": "V40", + "currentTarget": "V39", + "sourceSafetyVerdict": "source-safe-conversation-terminal-integration-metadata", + "generatedAt": "deterministic", + "artifactRoot": "v40-conversation-terminal-integration:eb67c5f1445232c5d331a090", + "passed": true, + "surfaceIds": [ + "conversation:terminal-handoff-route-contract", + "conversation:stream-events-to-rich-log", + "conversation:route-api-persistence-branch-contracts", + "conversation:writing-source-selector-handoff", + "terminal:reading-state-handoff-readback", + "terminal:pipeline-harness-log-stream", + "terminal:transaction-cockpit-authority-boundary", + "conversation-terminal:rehearsal-docs-and-parity" + ], + "verdictIds": [ + "covered", + "exempt", + "missing", + "blocked" + ], + "rows": [ + { + "integrationSurfaceId": "conversation:terminal-handoff-route-contract", + "integrationKind": "handoff-route-contract", + "sourceRoots": [ + "uapi/app/conversations/conversation-terminal-handoff.ts", + "uapi/app/conversations/components/ConversationTerminalHandoff.tsx", + "uapi/app/terminal/terminal-transaction-query.ts", + "uapi/app/terminal/terminal-routes.ts" + ], + "testPaths": [ + "uapi/tests/conversationTerminalHandoff.test.tsx", + "uapi/tests/conversationTerminalIntegrationCoverage.test.tsx", + "uapi/tests/terminalTransactionQuery.test.ts" + ], + "commandIds": [ + "pnpm --dir uapi exec jest tests/conversationTerminalHandoff.test.tsx tests/conversationTerminalIntegrationCoverage.test.tsx tests/terminalTransactionQuery.test.ts --runInBand" + ], + "requiredSourceMarkers": [ + "buildConversationTerminalHandoffEnvelope", + "readTerminalConversationHandoffContext", + "TERMINAL_ENTERPRISE_READING_STAGE_VALUES", + "terminalRemainsTransactionCockpit" + ], + "requiredTestMarkers": [ + "source-safe Conversation handoff", + "readTerminalConversationHandoffContext", + "source-safe enterprise Reading stages" + ], + "expectedCounts": { + "handoffWorkflowCount": 6, + "readingStageCount": 5 + }, + "coverageTier": "promotion-required", + "closureRequirement": "Conversation handoff envelopes serialize source-safe Terminal route context, read back the five enterprise Reading stages, and never claim ledger or wallet authority.", + "rowRoot": "v40-conversation-terminal-integration-row:d61c1f31aaffac41925fc1ae", + "verdict": "covered", + "sourceSafetyClass": "source_safe_conversation_terminal_integration_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "rawModelResponseWithProtectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false, + "credentialsSerialized": false, + "walletPrivateMaterialVisible": false, + "ledgerAuthorityClaimedByConversation": false, + "valueBearingMainnetRequired": false, + "forbiddenPayloadClasses": [ + "secret-values", + "provider-tokens", + "wallet-private-material", + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "raw-model-responses-with-protected-source", + "unpaid-assetpack-source", + "settlement-private-payloads", + "global-ledger-authority-claim" + ] + }, + { + "integrationSurfaceId": "conversation:stream-events-to-rich-log", + "integrationKind": "stream-to-log-rendering", + "sourceRoots": [ + "packages/api/src/conversations/stream-events.ts", + "uapi/components/base/bitcode/execution/pipeline-execution-log.tsx", + "uapi/components/base/bitcode/execution/pipeline-execution-log-header.tsx", + "uapi/app/conversations/components/ConversationsSidebarLogs.tsx" + ], + "testPaths": [ + "packages/api/src/conversations/__tests__/stream-events.test.ts", + "uapi/tests/conversationStreamPipelineLog.test.tsx", + "uapi/tests/conversationTerminalIntegrationCoverage.test.tsx", + "uapi/tests/pipelineExecutionLogHeader.test.tsx" + ], + "commandIds": [ + "pnpm --filter @bitcode/api exec jest src/conversations/__tests__/stream-events.test.ts --runInBand --forceExit", + "pnpm --dir uapi exec jest tests/conversationStreamPipelineLog.test.tsx tests/conversationTerminalIntegrationCoverage.test.tsx tests/pipelineExecutionLogHeader.test.tsx --runInBand" + ], + "requiredSourceMarkers": [ + "buildConversationStreamEvent", + "buildConversationPipelineLogEvent", + "prompt_template_id_only", + "BitcodeExecutionStreamPanel" + ], + "requiredTestMarkers": [ + "PipelineExecutionLog", + "ConversationStreamEvent:tool_call", + "prompt_template_id_only" + ], + "expectedCounts": { + "conversationStreamEventKindCount": 7, + "richExecutionLogProjectionCount": 2 + }, + "coverageTier": "promotion-required", + "closureRequirement": "Conversation stream events are converted into rich execution-log rows with collapsed status, expandable source-safe metadata, proof roots, telemetry hooks, and prompt/result disclosure posture.", + "rowRoot": "v40-conversation-terminal-integration-row:73c7de3b1cf04b1d565279aa", + "verdict": "covered", + "sourceSafetyClass": "source_safe_conversation_terminal_integration_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "rawModelResponseWithProtectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false, + "credentialsSerialized": false, + "walletPrivateMaterialVisible": false, + "ledgerAuthorityClaimedByConversation": false, + "valueBearingMainnetRequired": false, + "forbiddenPayloadClasses": [ + "secret-values", + "provider-tokens", + "wallet-private-material", + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "raw-model-responses-with-protected-source", + "unpaid-assetpack-source", + "settlement-private-payloads", + "global-ledger-authority-claim" + ] + }, + { + "integrationSurfaceId": "conversation:route-api-persistence-branch-contracts", + "integrationKind": "route-api-contracts", + "sourceRoots": [ + "uapi/app/api/conversations/route.ts", + "uapi/app/api/conversations/[conversationId]/route.ts", + "uapi/app/api/conversations/[conversationId]/stream/route.ts", + "uapi/app/api/conversations/branch/route.ts", + "uapi/app/api/conversations/stream/route.ts", + "packages/api/src/conversations/conversations.ts", + "packages/api/src/conversations/privacy.ts", + "packages/api/src/conversations/telemetry.ts" + ], + "testPaths": [ + "uapi/tests/api/conversationsRoute.test.ts", + "uapi/tests/api/conversationsRouteRead.test.ts", + "uapi/tests/api/chatStreamRoute.test.ts", + "uapi/tests/api/conversationThreadStreamRoute.test.ts", + "uapi/tests/api/conversationBranchRoute.test.ts", + "uapi/tests/api/conversationPersistencePrivacyRedaction.test.ts", + "uapi/tests/api/conversationTelemetryProofHooks.test.ts", + "packages/api/src/conversations/__tests__/branch-conversation.test.ts", + "packages/api/src/conversations/__tests__/privacy.test.ts", + "packages/api/src/conversations/__tests__/telemetry.test.ts" + ], + "commandIds": [ + "pnpm --dir uapi exec jest tests/api/conversationsRoute.test.ts tests/api/conversationBranchRoute.test.ts tests/api/conversationTelemetryProofHooks.test.ts --runInBand", + "pnpm --filter @bitcode/api exec jest src/conversations/__tests__/branch-conversation.test.ts src/conversations/__tests__/privacy.test.ts src/conversations/__tests__/telemetry.test.ts --runInBand --forceExit" + ], + "requiredSourceMarkers": [ + "conversation_id", + "buildConversationTelemetryProofHook", + "redactConversationPersistenceText", + "branch" + ], + "requiredTestMarkers": [ + "conversation", + "privacy", + "telemetry", + "branch" + ], + "expectedCounts": { + "routeFamilyCount": 6, + "persistencePrivacyRequired": true + }, + "coverageTier": "promotion-required", + "closureRequirement": "Conversation routes, persistence readback, branch creation, privacy redaction, and telemetry hooks are integration-covered across UAPI and package API helpers.", + "rowRoot": "v40-conversation-terminal-integration-row:91579fa3a21a904328ab02e5", + "verdict": "covered", + "sourceSafetyClass": "source_safe_conversation_terminal_integration_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "rawModelResponseWithProtectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false, + "credentialsSerialized": false, + "walletPrivateMaterialVisible": false, + "ledgerAuthorityClaimedByConversation": false, + "valueBearingMainnetRequired": false, + "forbiddenPayloadClasses": [ + "secret-values", + "provider-tokens", + "wallet-private-material", + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "raw-model-responses-with-protected-source", + "unpaid-assetpack-source", + "settlement-private-payloads", + "global-ledger-authority-claim" + ] + }, + { + "integrationSurfaceId": "conversation:writing-source-selector-handoff", + "integrationKind": "writing-source-selector-handoff", + "sourceRoots": [ + "uapi/app/conversations/conversation-writing-workspace.ts", + "uapi/app/conversations/components/ConversationWritingWorkspace.tsx", + "uapi/app/conversations/conversation-source-selector.ts", + "uapi/app/conversations/components/ConversationSourceSelector.tsx", + "uapi/app/conversations/components/ConversationsOverlay.tsx" + ], + "testPaths": [ + "uapi/tests/conversationWritingWorkspace.test.tsx", + "uapi/tests/conversationSourceSelector.test.tsx", + "uapi/tests/conversationsOverlayMapping.test.ts", + "uapi/tests/conversationTerminalIntegrationCoverage.test.tsx" + ], + "commandIds": [ + "pnpm --dir uapi exec jest tests/conversationWritingWorkspace.test.tsx tests/conversationSourceSelector.test.tsx tests/conversationsOverlayMapping.test.ts tests/conversationTerminalIntegrationCoverage.test.tsx --runInBand" + ], + "requiredSourceMarkers": [ + "ConversationWritingWorkspace", + "buildConversationWritingWorkspaceHandoff", + "buildConversationSourceSelectorPreview", + "ConversationTerminalHandoff" + ], + "requiredTestMarkers": [ + "source-safe", + "source", + "destination", + "Request Finding Fits for the accepted Read-Need" + ], + "expectedCounts": { + "workspaceModeCount": 4, + "selectorPreviewRequired": true + }, + "coverageTier": "promotion-required", + "closureRequirement": "Conversation writing, source selector, and attachment mapping stay source-safe before they prepare Terminal handoff intent.", + "rowRoot": "v40-conversation-terminal-integration-row:8371dd0cdee6752a1df48791", + "verdict": "covered", + "sourceSafetyClass": "source_safe_conversation_terminal_integration_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "rawModelResponseWithProtectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false, + "credentialsSerialized": false, + "walletPrivateMaterialVisible": false, + "ledgerAuthorityClaimedByConversation": false, + "valueBearingMainnetRequired": false, + "forbiddenPayloadClasses": [ + "secret-values", + "provider-tokens", + "wallet-private-material", + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "raw-model-responses-with-protected-source", + "unpaid-assetpack-source", + "settlement-private-payloads", + "global-ledger-authority-claim" + ] + }, + { + "integrationSurfaceId": "terminal:reading-state-handoff-readback", + "integrationKind": "terminal-reading-state", + "sourceRoots": [ + "uapi/app/terminal/terminal-enterprise-reading-ux-state.ts", + "uapi/app/terminal/TerminalPageClient.tsx", + "uapi/app/terminal/README.md", + "uapi/app/conversations/README.md" + ], + "testPaths": [ + "uapi/tests/terminalEnterpriseReadingUxState.test.ts", + "uapi/tests/conversationTerminalHandoff.test.tsx", + "uapi/tests/conversationTerminalIntegrationCoverage.test.tsx" + ], + "commandIds": [ + "pnpm --dir uapi exec jest tests/terminalEnterpriseReadingUxState.test.ts tests/conversationTerminalHandoff.test.tsx tests/conversationTerminalIntegrationCoverage.test.tsx --runInBand" + ], + "requiredSourceMarkers": [ + "TERMINAL_ENTERPRISE_READING_STEPS", + "request-fit", + "Conversation handoff", + "source-safe" + ], + "requiredTestMarkers": [ + "locks the enterprise Reading UX to five source-safe stages", + "source-safe enterprise Reading stages", + "request-fit" + ], + "expectedCounts": { + "readingStageCount": 5, + "lowDetailDefaultRequired": true + }, + "coverageTier": "promotion-required", + "closureRequirement": "Terminal reads Conversation `readingStage` intent as posture, keeps the five-stage Reading UX source-safe, and blocks protected or unpaid source disclosure.", + "rowRoot": "v40-conversation-terminal-integration-row:2eb2321f069cad982b418333", + "verdict": "covered", + "sourceSafetyClass": "source_safe_conversation_terminal_integration_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "rawModelResponseWithProtectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false, + "credentialsSerialized": false, + "walletPrivateMaterialVisible": false, + "ledgerAuthorityClaimedByConversation": false, + "valueBearingMainnetRequired": false, + "forbiddenPayloadClasses": [ + "secret-values", + "provider-tokens", + "wallet-private-material", + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "raw-model-responses-with-protected-source", + "unpaid-assetpack-source", + "settlement-private-payloads", + "global-ledger-authority-claim" + ] + }, + { + "integrationSurfaceId": "terminal:pipeline-harness-log-stream", + "integrationKind": "terminal-harness-streaming", + "sourceRoots": [ + "uapi/app/terminal/terminal-pipeline-harness-client.ts", + "uapi/app/api/pipeline-harness/asset-pack/route.ts", + "uapi/components/base/bitcode/execution/BitcodeExecutionStreamPanel.tsx", + "uapi/components/base/bitcode/execution/pipeline-execution-log.tsx" + ], + "testPaths": [ + "uapi/tests/terminalPipelineHarnessClient.test.ts", + "uapi/tests/api/pipelineHarnessRoute.test.ts", + "uapi/tests/readingOperationalTelemetryPipelineLog.test.tsx", + "uapi/tests/conversationTerminalIntegrationCoverage.test.tsx" + ], + "commandIds": [ + "pnpm --dir uapi exec jest tests/terminalPipelineHarnessClient.test.ts tests/api/pipelineHarnessRoute.test.ts tests/readingOperationalTelemetryPipelineLog.test.tsx tests/conversationTerminalIntegrationCoverage.test.tsx --runInBand" + ], + "requiredSourceMarkers": [ + "buildTerminalReadFitsFindingSynthesisHarnessStreamSnapshot", + "summarizeTerminalReadFitsFindingSynthesisHarnessEvent", + "readingPipelineTelemetry", + "PipelineExecutionLog" + ], + "requiredTestMarkers": [ + "pipeline ReadFitsFindingSynthesis", + "telemetry 72 lines", + "ThricifiedGeneration" + ], + "expectedCounts": { + "harnessEventProjectionRequired": true, + "inferenceTelemetryReadbackRequired": true + }, + "coverageTier": "promotion-required", + "closureRequirement": "Terminal harness streaming converts live or replayed pipeline events into inspectable rich logs with inference telemetry and no source or secret leakage.", + "rowRoot": "v40-conversation-terminal-integration-row:1e886f1126d199d305d72856", + "verdict": "covered", + "sourceSafetyClass": "source_safe_conversation_terminal_integration_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "rawModelResponseWithProtectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false, + "credentialsSerialized": false, + "walletPrivateMaterialVisible": false, + "ledgerAuthorityClaimedByConversation": false, + "valueBearingMainnetRequired": false, + "forbiddenPayloadClasses": [ + "secret-values", + "provider-tokens", + "wallet-private-material", + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "raw-model-responses-with-protected-source", + "unpaid-assetpack-source", + "settlement-private-payloads", + "global-ledger-authority-claim" + ] + }, + { + "integrationSurfaceId": "terminal:transaction-cockpit-authority-boundary", + "integrationKind": "terminal-authority-boundary", + "sourceRoots": [ + "uapi/app/terminal/terminal-interface-integration-regression.ts", + "uapi/app/terminal/terminal-transaction-read-model.ts", + "uapi/app/terminal/terminal-wallet-btc-operation.ts", + "packages/pipelines/asset-pack/src/reading-interface-product-parity.ts" + ], + "testPaths": [ + "uapi/tests/terminalInterfaceIntegrationRegression.test.ts", + "uapi/tests/terminalTransactionReadModel.test.ts", + "uapi/tests/terminalWalletBtcOperation.test.ts", + "uapi/tests/api/conversationReadingInterfaceParity.test.ts", + "packages/pipelines/asset-pack/src/__tests__/reading-interface-product-parity.test.ts" + ], + "commandIds": [ + "pnpm --dir uapi exec jest tests/terminalInterfaceIntegrationRegression.test.ts tests/terminalTransactionReadModel.test.ts tests/terminalWalletBtcOperation.test.ts tests/api/conversationReadingInterfaceParity.test.ts --runInBand", + "pnpm --filter @bitcode/pipeline-asset-pack exec jest src/__tests__/reading-interface-product-parity.test.ts --runInBand --forceExit" + ], + "requiredSourceMarkers": [ + "terminal-delegated-handoff", + "terminal_handoff", + "PSBT handoff", + "Wallet signer session" + ], + "requiredTestMarkers": [ + "terminal-delegated-handoff", + "signed-psbt" + ], + "expectedCounts": { + "terminalAuthorityRequired": true, + "noConversationWalletAuthority": true + }, + "coverageTier": "promotion-required", + "closureRequirement": "Terminal remains the transaction, wallet, settlement, ledger, and delivery authority while Conversation may only hand off source-safe intent.", + "rowRoot": "v40-conversation-terminal-integration-row:2c3a37c9defaa3d17684bec7", + "verdict": "covered", + "sourceSafetyClass": "source_safe_conversation_terminal_integration_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "rawModelResponseWithProtectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false, + "credentialsSerialized": false, + "walletPrivateMaterialVisible": false, + "ledgerAuthorityClaimedByConversation": false, + "valueBearingMainnetRequired": false, + "forbiddenPayloadClasses": [ + "secret-values", + "provider-tokens", + "wallet-private-material", + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "raw-model-responses-with-protected-source", + "unpaid-assetpack-source", + "settlement-private-payloads", + "global-ledger-authority-claim" + ] + }, + { + "integrationSurfaceId": "conversation-terminal:rehearsal-docs-and-parity", + "integrationKind": "rehearsal-docs-parity", + "sourceRoots": [ + "uapi/app/conversations/conversation-rehearsal.ts", + "uapi/app/conversations/components/ConversationRehearsalPanel.tsx", + "uapi/app/conversations/README.md", + "uapi/app/terminal/README.md", + "packages/protocol/src/canonical/v39-interface-conversation-product-parity.js" + ], + "testPaths": [ + "uapi/tests/api/conversationRehearsal.test.ts", + "uapi/tests/conversationRehearsalPanel.test.tsx", + "packages/protocol/test/v39-interface-conversation-product-parity.test.js", + "uapi/tests/conversationTerminalIntegrationCoverage.test.tsx" + ], + "commandIds": [ + "pnpm --dir uapi exec jest tests/api/conversationRehearsal.test.ts tests/conversationRehearsalPanel.test.tsx tests/conversationTerminalIntegrationCoverage.test.tsx --runInBand", + "pnpm --filter @bitcode/protocol exec node --test --test-force-exit test/v39-interface-conversation-product-parity.test.js" + ], + "requiredSourceMarkers": [ + "terminal_handoff", + "ConversationTerminalHandoff", + "source-safe", + "buildV39InterfaceConversationProductParity" + ], + "requiredTestMarkers": [ + "terminal_handoff", + "source-safe", + "Terminal" + ], + "expectedCounts": { + "rehearsalFlowCovered": true, + "docsParityCovered": true + }, + "coverageTier": "promotion-required", + "closureRequirement": "Conversation and Terminal documentation, rehearsal rows, and interface parity prove the same source-safe authority boundary that the integration tests execute.", + "rowRoot": "v40-conversation-terminal-integration-row:4e272e9e71fdd4f09b6eab73", + "verdict": "covered", + "sourceSafetyClass": "source_safe_conversation_terminal_integration_metadata", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "rawModelResponseWithProtectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false, + "credentialsSerialized": false, + "walletPrivateMaterialVisible": false, + "ledgerAuthorityClaimedByConversation": false, + "valueBearingMainnetRequired": false, + "forbiddenPayloadClasses": [ + "secret-values", + "provider-tokens", + "wallet-private-material", + "protected-source-payloads", + "raw-protected-prompts", + "raw-provider-responses", + "raw-model-responses-with-protected-source", + "unpaid-assetpack-source", + "settlement-private-payloads", + "global-ledger-authority-claim" + ] + } + ], + "rowIds": [ + "conversation:terminal-handoff-route-contract", + "conversation:stream-events-to-rich-log", + "conversation:route-api-persistence-branch-contracts", + "conversation:writing-source-selector-handoff", + "terminal:reading-state-handoff-readback", + "terminal:pipeline-harness-log-stream", + "terminal:transaction-cockpit-authority-boundary", + "conversation-terminal:rehearsal-docs-and-parity" + ], + "predicateResults": [ + { + "id": "package-scripts-include-gate6", + "sourcePath": "package.json", + "passed": true + }, + { + "id": "workflows-run-gate6-check", + "sourcePath": ".github/workflows/bitcode-gate-quality.yml", + "passed": true + }, + { + "id": "gate-quality-runs-conversation-terminal-integration-test", + "sourcePath": ".github/workflows/bitcode-gate-quality.yml", + "passed": true + }, + { + "id": "uapi-jest-includes-conversation-terminal-integration-test", + "sourcePath": "uapi/jest.config.cjs", + "passed": true + }, + { + "id": "protocol-exports-gate6", + "sourcePath": "packages/protocol/src/index.js", + "passed": true + }, + { + "id": "spec-documents-gate6", + "sourcePath": "BITCODE_SPEC_V40.md", + "passed": true + }, + { + "id": "delta-documents-gate6", + "sourcePath": "BITCODE_SPEC_V40_DELTA.md", + "passed": true + }, + { + "id": "notes-document-gate6", + "sourcePath": "BITCODE_SPEC_V40_NOTES.md", + "passed": true + }, + { + "id": "parity-documents-gate6", + "sourcePath": "BITCODE_SPEC_V40_PARITY_MATRIX.md", + "passed": true + }, + { + "id": "roadmap-advanced-through-gate6", + "sourcePath": "SPECIFICATIONS_ROADMAP.md", + "passed": true + }, + { + "id": "readmes-document-gate6", + "sourcePath": "README.md", + "passed": true + }, + { + "id": "roadmap-preserves-v41-prompt-programs", + "sourcePath": "SPECIFICATIONS_ROADMAP.md", + "passed": true + }, + { + "id": "conversation-terminal-handoff-route-contract:source-roots-exist", + "sourcePath": "uapi/app/conversations/conversation-terminal-handoff.ts", + "passed": true + }, + { + "id": "conversation-terminal-handoff-route-contract:test-paths-exist", + "sourcePath": "uapi/tests/conversationTerminalHandoff.test.tsx", + "passed": true + }, + { + "id": "conversation-terminal-handoff-route-contract:source-markers-present", + "sourcePath": "uapi/app/conversations/conversation-terminal-handoff.ts", + "passed": true + }, + { + "id": "conversation-terminal-handoff-route-contract:test-markers-present", + "sourcePath": "uapi/tests/conversationTerminalHandoff.test.tsx", + "passed": true + }, + { + "id": "conversation-stream-events-to-rich-log:source-roots-exist", + "sourcePath": "packages/api/src/conversations/stream-events.ts", + "passed": true + }, + { + "id": "conversation-stream-events-to-rich-log:test-paths-exist", + "sourcePath": "packages/api/src/conversations/__tests__/stream-events.test.ts", + "passed": true + }, + { + "id": "conversation-stream-events-to-rich-log:source-markers-present", + "sourcePath": "packages/api/src/conversations/stream-events.ts", + "passed": true + }, + { + "id": "conversation-stream-events-to-rich-log:test-markers-present", + "sourcePath": "packages/api/src/conversations/__tests__/stream-events.test.ts", + "passed": true + }, + { + "id": "conversation-route-api-persistence-branch-contracts:source-roots-exist", + "sourcePath": "uapi/app/api/conversations/route.ts", + "passed": true + }, + { + "id": "conversation-route-api-persistence-branch-contracts:test-paths-exist", + "sourcePath": "uapi/tests/api/conversationsRoute.test.ts", + "passed": true + }, + { + "id": "conversation-route-api-persistence-branch-contracts:source-markers-present", + "sourcePath": "uapi/app/api/conversations/route.ts", + "passed": true + }, + { + "id": "conversation-route-api-persistence-branch-contracts:test-markers-present", + "sourcePath": "uapi/tests/api/conversationsRoute.test.ts", + "passed": true + }, + { + "id": "conversation-writing-source-selector-handoff:source-roots-exist", + "sourcePath": "uapi/app/conversations/conversation-writing-workspace.ts", + "passed": true + }, + { + "id": "conversation-writing-source-selector-handoff:test-paths-exist", + "sourcePath": "uapi/tests/conversationWritingWorkspace.test.tsx", + "passed": true + }, + { + "id": "conversation-writing-source-selector-handoff:source-markers-present", + "sourcePath": "uapi/app/conversations/conversation-writing-workspace.ts", + "passed": true + }, + { + "id": "conversation-writing-source-selector-handoff:test-markers-present", + "sourcePath": "uapi/tests/conversationWritingWorkspace.test.tsx", + "passed": true + }, + { + "id": "terminal-reading-state-handoff-readback:source-roots-exist", + "sourcePath": "uapi/app/terminal/terminal-enterprise-reading-ux-state.ts", + "passed": true + }, + { + "id": "terminal-reading-state-handoff-readback:test-paths-exist", + "sourcePath": "uapi/tests/terminalEnterpriseReadingUxState.test.ts", + "passed": true + }, + { + "id": "terminal-reading-state-handoff-readback:source-markers-present", + "sourcePath": "uapi/app/terminal/terminal-enterprise-reading-ux-state.ts", + "passed": true + }, + { + "id": "terminal-reading-state-handoff-readback:test-markers-present", + "sourcePath": "uapi/tests/terminalEnterpriseReadingUxState.test.ts", + "passed": true + }, + { + "id": "terminal-pipeline-harness-log-stream:source-roots-exist", + "sourcePath": "uapi/app/terminal/terminal-pipeline-harness-client.ts", + "passed": true + }, + { + "id": "terminal-pipeline-harness-log-stream:test-paths-exist", + "sourcePath": "uapi/tests/terminalPipelineHarnessClient.test.ts", + "passed": true + }, + { + "id": "terminal-pipeline-harness-log-stream:source-markers-present", + "sourcePath": "uapi/app/terminal/terminal-pipeline-harness-client.ts", + "passed": true + }, + { + "id": "terminal-pipeline-harness-log-stream:test-markers-present", + "sourcePath": "uapi/tests/terminalPipelineHarnessClient.test.ts", + "passed": true + }, + { + "id": "terminal-transaction-cockpit-authority-boundary:source-roots-exist", + "sourcePath": "uapi/app/terminal/terminal-interface-integration-regression.ts", + "passed": true + }, + { + "id": "terminal-transaction-cockpit-authority-boundary:test-paths-exist", + "sourcePath": "uapi/tests/terminalInterfaceIntegrationRegression.test.ts", + "passed": true + }, + { + "id": "terminal-transaction-cockpit-authority-boundary:source-markers-present", + "sourcePath": "uapi/app/terminal/terminal-interface-integration-regression.ts", + "passed": true + }, + { + "id": "terminal-transaction-cockpit-authority-boundary:test-markers-present", + "sourcePath": "uapi/tests/terminalInterfaceIntegrationRegression.test.ts", + "passed": true + }, + { + "id": "conversation-terminal-rehearsal-docs-and-parity:source-roots-exist", + "sourcePath": "uapi/app/conversations/conversation-rehearsal.ts", + "passed": true + }, + { + "id": "conversation-terminal-rehearsal-docs-and-parity:test-paths-exist", + "sourcePath": "uapi/tests/api/conversationRehearsal.test.ts", + "passed": true + }, + { + "id": "conversation-terminal-rehearsal-docs-and-parity:source-markers-present", + "sourcePath": "uapi/app/conversations/conversation-rehearsal.ts", + "passed": true + }, + { + "id": "conversation-terminal-rehearsal-docs-and-parity:test-markers-present", + "sourcePath": "uapi/tests/api/conversationRehearsal.test.ts", + "passed": true + } + ], + "coverage": { + "rowCount": 8, + "surfaceCount": 8, + "verdictIds": [ + "covered", + "exempt", + "missing", + "blocked" + ], + "rowsByVerdict": { + "covered": 8 + }, + "rowsByTier": { + "promotion-required": 8 + }, + "expectedTotals": { + "terminalHandoffWorkflowCount": 6, + "terminalReadingStageCount": 5, + "conversationStreamEventKindCount": 7, + "conversationRouteFamilyCount": 6, + "sourceSafeDisclosureBoundaryCount": 8, + "richExecutionLogProjectionCount": 2, + "focusedIntegrationTestCount": 1 + }, + "requiredPredicateCount": 44, + "passedPredicateCount": 44, + "failedPredicateIds": [], + "coveredRowCount": 8, + "missingRowCount": 0, + "blockedRowCount": 0, + "exemptRowCount": 0, + "allCriticalSurfacesClosed": true, + "terminalHandoffRouteCoverageClosed": true, + "conversationStreamLogCoverageClosed": true, + "conversationRouteApiCoverageClosed": true, + "writingSourceSelectorCoverageClosed": true, + "terminalReadingStateCoverageClosed": true, + "terminalHarnessLogStreamCoverageClosed": true, + "terminalAuthorityBoundaryCoverageClosed": true, + "rehearsalDocsParityCoverageClosed": true, + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawProtectedPromptVisible": false, + "rawProviderResponseVisible": false, + "rawModelResponseWithProtectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false, + "credentialsSerialized": false, + "walletPrivateMaterialVisible": false, + "ledgerAuthorityClaimedByConversation": false, + "valueBearingMainnetRequired": false, + "promptContentRewriteDeferredToV41": true + } +} diff --git a/.github/workflows/bitcode-canon-quality.yml b/.github/workflows/bitcode-canon-quality.yml index 350b6da57..ff129c1c3 100644 --- a/.github/workflows/bitcode-canon-quality.yml +++ b/.github/workflows/bitcode-canon-quality.yml @@ -235,6 +235,9 @@ jobs: if [ -f scripts/check-v40-gate5-reading-pipeline-integration.mjs ]; then node scripts/check-v40-gate5-reading-pipeline-integration.mjs --skip-branch-check --skip-integration-tests fi + if [ -f scripts/check-v40-gate6-conversation-terminal-integration.mjs ]; then + node scripts/check-v40-gate6-conversation-terminal-integration.mjs --skip-branch-check --skip-integration-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 9586fc071..c7b5ff3c1 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -364,6 +364,9 @@ jobs: if [ -f scripts/check-v40-gate5-reading-pipeline-integration.mjs ]; then node scripts/check-v40-gate5-reading-pipeline-integration.mjs --skip-branch-check --skip-integration-tests fi + if [ -f scripts/check-v40-gate6-conversation-terminal-integration.mjs ]; then + node scripts/check-v40-gate6-conversation-terminal-integration.mjs --skip-branch-check --skip-integration-tests + fi fi else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 @@ -487,6 +490,9 @@ jobs: if [ -f packages/protocol/test/v39-promotion-readiness.test.js ]; then pnpm --dir packages/protocol exec node --test --test-force-exit test/v39-promotion-readiness.test.js fi + if [ -f packages/protocol/test/v40-conversation-terminal-integration.test.js ]; then + pnpm --dir packages/protocol exec node --test --test-force-exit test/v40-conversation-terminal-integration.test.js + fi pnpm --filter @bitcode/protocol test - name: Test staged Reading route and Terminal harness contracts @@ -503,6 +509,7 @@ jobs: tests/api/conversationSessionRouteHistoryContract.test.ts \ tests/api/conversationStreamEventContract.test.ts \ tests/conversationStreamPipelineLog.test.tsx \ + tests/conversationTerminalIntegrationCoverage.test.tsx \ tests/conversationTerminalHandoff.test.tsx \ tests/api/conversationPersistencePrivacyRedaction.test.ts \ tests/conversationPersistencePrivacyPanel.test.tsx \ diff --git a/BITCODE_SPEC_V40.md b/BITCODE_SPEC_V40.md index faa006ba4..bec84c0b0 100644 --- a/BITCODE_SPEC_V40.md +++ b/BITCODE_SPEC_V40.md @@ -129,6 +129,13 @@ The artifact binds the currently expected Reading topology of two pipelines, fiv The focused integration test runs the deterministic commercial Reading spine from accepted Need synthesis through many-fit Depository search, source-safe AssetPack preview, settlement/right-transfer delivery boundary, and source-safe observability coverage. Gate 5 permits no missing, blocked, or exempt critical Reading integration row; proof rows may include topology, command ids, fixture roots, and coverage flags, but must not include secrets, raw protected prompts, raw provider responses, protected source payloads, or unpaid AssetPack source. +## V40 Gate 6 Conversation And Terminal Integration Coverage + +Gate 6 closes integration coverage for the Conversation-to-Terminal boundary without changing prompt content. +The package-owned `V40ConversationTerminalIntegration` emits `.bitcode/v40-conversation-terminal-integration.json` with eight source-safe rows: Conversation Terminal handoff route contracts, Conversation stream events projected into rich execution logs, Conversation route/API persistence and branch contracts, writing workspace/source selector handoff, Terminal Reading state handoff readback, Terminal pipeline harness log streaming, Terminal transaction-cockpit authority boundaries, and Conversation/Terminal rehearsal/docs/interface parity. +The focused UAPI integration test carries a source-safe Conversation `finding_fits` handoff into Terminal route readback, verifies the five-stage enterprise Reading state at `request-fit`, adapts a Conversation stream tool event into execution-log metadata, and projects that event through the Terminal harness stream snapshot without serializing protected source, raw prompt payload, or unpaid AssetPack source. +Gate 6 permits no missing, blocked, or exempt critical Conversation/Terminal row; proof rows may include route parameters, proof roots, event ids, telemetry posture, command ids, fixture roots, and coverage flags, but must not include secrets, protected source, raw protected prompts, raw model/provider responses, wallet private material, or unpaid AssetPack source. + ## V40 canonical subsystem surfaces ### Depositing and asset supply diff --git a/BITCODE_SPEC_V40_DELTA.md b/BITCODE_SPEC_V40_DELTA.md index 4fd256747..2b64ebae7 100644 --- a/BITCODE_SPEC_V40_DELTA.md +++ b/BITCODE_SPEC_V40_DELTA.md @@ -53,6 +53,7 @@ Gate 5 closes with package-backed `V40ReadingPipelineIntegrationCoverage`, deter ### Gate 6: Conversation And Terminal Integration Coverage Close cross-surface tests for Conversation, Terminal handoff, Reading state, telemetry, and source-safe disclosure. +Gate 6 closes with package-backed `V40ConversationTerminalIntegration`, deterministic `.bitcode/v40-conversation-terminal-integration.json`, protocol exports, a focused Conversation-to-Terminal integration test, source-safe rows for handoff, stream-log projection, route/API contracts, writing/source selector handoff, Terminal Reading state, harness streaming, authority boundaries, docs/rehearsal parity, and `check:v40-gate6`. ### Gate 7: Browser E2E, Accessibility, Responsive, And Visual Proof diff --git a/BITCODE_SPEC_V40_NOTES.md b/BITCODE_SPEC_V40_NOTES.md index 1187a2b33..a0bd0bef0 100644 --- a/BITCODE_SPEC_V40_NOTES.md +++ b/BITCODE_SPEC_V40_NOTES.md @@ -90,3 +90,11 @@ Its generated `.bitcode/v40-reading-pipeline-integration-coverage.json` artifact The focused asset-pack package test runs a deterministic Reading path through accepted Need synthesis, many-fit Depository search, `worthy_fit` runtime evidence, source-safe AssetPack preview, settlement/right-transfer delivery boundary, and source-safe observability coverage. The artifact records expected totals of two Reading pipelines, eleven phases, twelve PTRR agents, forty-eight PTRR steps, one hundred forty-four ThricifiedGeneration records, and four tool surfaces. No missing, blocked, or exempt critical Reading integration row is allowed in the Gate 5 artifact, and prompt content rewriting remains deferred to V41. + +## Gate 6 implementation notes + +Gate 6 is closed by `V40ConversationTerminalIntegration`. +Its generated `.bitcode/v40-conversation-terminal-integration.json` artifact binds Conversation and Terminal integration coverage to eight source-safe rows: Terminal handoff route contracts, Conversation stream events projected into rich execution logs, route/API persistence and branch contracts, writing/source selector handoff, Terminal Reading state readback, Terminal harness log streaming, transaction-cockpit authority boundaries, and rehearsal/docs/interface parity. +The focused UAPI test executes the cross-surface path from a Conversation `finding_fits` handoff into Terminal query parsing, enterprise Reading `request-fit` state, Conversation stream tool-call log metadata, and Terminal harness stream projection. +No missing, blocked, or exempt critical Conversation/Terminal integration row is allowed in the Gate 6 artifact; Conversation may carry source-safe intent only, while Terminal remains the transaction, wallet, ledger, settlement, and delivery cockpit. +Prompt and PromptPart rewriting remains deferred to V41. diff --git a/BITCODE_SPEC_V40_PARITY_MATRIX.md b/BITCODE_SPEC_V40_PARITY_MATRIX.md index fb470038c..153e69349 100644 --- a/BITCODE_SPEC_V40_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V40_PARITY_MATRIX.md @@ -34,6 +34,7 @@ This matrix records the V40 testing surfaces that must become promotion-grade be | Visual proof | Screenshot comparisons are deterministic and reviewable | future V40 artifacts | not yet implemented | | API integration | Route and API contracts are parseable and source-safe | `.bitcode/v40-api-integration-contracts.json` | implemented | | Pipeline integration | Primitive and real Reading pipeline implementations are tested | `.bitcode/v40-reading-pipeline-integration-coverage.json` | implemented | +| Conversation/Terminal integration | Conversation handoff, stream logs, Terminal Reading state, and authority boundaries are tested source-safely | `.bitcode/v40-conversation-terminal-integration.json` | implemented | | Unit coverage | Packages, primitives, isolated implementations, and real implementations have unit coverage | `.bitcode/v40-unit-coverage-inventory.json` | implemented | | Prompt benchmark smoke | Prompt and PromptPart benchmarks run before V41 | future V40 artifacts | not yet implemented | @@ -46,7 +47,7 @@ This matrix records the V40 testing surfaces that must become promotion-grade be | Gate 3 | Unit coverage closure artifact | implemented | | Gate 4 | API/route integration artifact | implemented | | Gate 5 | Reading pipeline integration artifact | implemented | -| Gate 6 | Conversation/Terminal integration artifact | not yet implemented | +| Gate 6 | Conversation/Terminal integration artifact | implemented | | Gate 7 | Browser/visual/accessibility/responsive artifact | not yet implemented | | Gate 8 | Ledger/database/storage/wallet/delivery sync artifact | not yet implemented | | Gate 9 | Local/staging rehearsal artifact | not yet implemented | @@ -57,6 +58,7 @@ Gate 2 implementation evidence: package-backed `V40TestInventoryCoverageMatrix` Gate 3 implementation evidence: package-backed `V40UnitCoverageInventory` emits `.bitcode/v40-unit-coverage-inventory.json` and is wired through `check:v40-gate3`. Gate 4 implementation evidence: package-backed `V40ApiIntegrationContracts` emits `.bitcode/v40-api-integration-contracts.json` and is wired through `check:v40-gate4`. Gate 5 implementation evidence: package-backed `V40ReadingPipelineIntegrationCoverage` emits `.bitcode/v40-reading-pipeline-integration-coverage.json` and is wired through `check:v40-gate5`. +Gate 6 implementation evidence: package-backed `V40ConversationTerminalIntegration` emits `.bitcode/v40-conversation-terminal-integration.json` and is wired through `check:v40-gate6`. ## V40 accepted boundaries diff --git a/README.md b/README.md index 6d8a0dbc9..c315be803 100644 --- a/README.md +++ b/README.md @@ -546,6 +546,13 @@ generated `.bitcode/v40-reading-pipeline-integration-coverage.json`, and Depository search, PTRR agent wiring, AssetPack preview/settlement/delivery, telemetry/readback, Terminal harnesses, pipeline primitives, hosts, and local staging rehearsal linkage. +V40 Gate 6 adds the package-backed `V40ConversationTerminalIntegration`, +generated `.bitcode/v40-conversation-terminal-integration.json`, and +`check:v40-gate6` to close source-safe integration coverage for Conversation +handoff route contracts, Conversation stream-to-rich-log projection, +Conversation route/API persistence and branch contracts, writing/source +selector handoff, Terminal Reading state readback, Terminal harness log +streaming, transaction-cockpit authority boundaries, and rehearsal/docs parity. V38 Gates 1 through 11 are wired through `pnpm run check:v38-gate1`, `pnpm run check:v38-gate2`, `pnpm run check:v38-gate3`, `pnpm run check:v38-gate4`, `pnpm run check:v38-gate5`, diff --git a/SPECIFICATIONS_ROADMAP.md b/SPECIFICATIONS_ROADMAP.md index 7e126bbc3..287e5711c 100644 --- a/SPECIFICATIONS_ROADMAP.md +++ b/SPECIFICATIONS_ROADMAP.md @@ -5,8 +5,8 @@ - Current active canonical pointer: `BITCODE_SPEC.txt` -> `V39` - Current active canon: `BITCODE_SPEC_V39.md` - Current draft target: `BITCODE_SPEC_V40.md`. -- Current working gate: V40 Gate 5 Reading Pipeline Integration Coverage. -- Next queued gate after V40 Gate 5 closure: V40 Gate 6 Conversation And Terminal Integration Coverage. +- Current working gate: V40 Gate 6 Conversation And Terminal Integration Coverage. +- Next queued gate after V40 Gate 6 closure: V40 Gate 7 Browser E2E, Accessibility, Responsive, And Visual Proof. - Latest closed version: V39 Commercial Reading Readiness, which promoted Depository supply indexing, enterprise five-step Reading UX, ReadNeed review/resynthesis, ReadFitsFinding many-candidate runtime, source-safe AssetPack preview and deterministic BTC quote, settlement rights delivery, operational telemetry/repair readback, interface parity, local/staging rehearsal, and V39 promotion readiness. - 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. - V39 Gate 9 closure anchor: commercial Reading readiness now owns package-backed `ReadingInterfaceProductParity`, deterministic `.bitcode/v39-interface-conversation-product-parity.json`, Terminal/Conversation/API/MCP/ChatGPT/package-consumer no-bypass rows, source-safe contract readback, BTD interface root composition, focused package/interface tests, and workflow wiring through `check:v39-gate9`. @@ -17,6 +17,7 @@ - V40 Gate 3 closure anchor: exhaustive testing now owns package-backed `V40UnitCoverageInventory` source, deterministic `.bitcode/v40-unit-coverage-inventory.json`, twelve source-safe covered unit surfaces for protocol report builders, BTD ledger/settlement/right primitives, prompt composition, PTRR agents, registry-backed tools, execution lineage/events/metrics, generic pipeline primitives, Reading AssetPack implementation units, pipeline hosts, isolated interface helpers, utility/security packages, and demonstration boundary coverage, protocol exports, package tests, workflow wiring, and `check:v40-gate3`. - V40 Gate 4 closure anchor: exhaustive testing now owns package-backed `V40ApiIntegrationContracts` source, deterministic `.bitcode/v40-api-integration-contracts.json`, ten source-safe covered API integration surfaces for UAPI Reading/pipeline routes, execution stream routes, Conversation routes, Auxillaries/Orbitals routes, VCS/wallet/webhook routes, public activity/template routes, package API route orchestration, package API Conversation/pipeline routes, MCP execution interface contracts, and ChatGPT App action contracts, protocol exports, package tests, workflow wiring, and `check:v40-gate4`. - V40 Gate 5 closure anchor: exhaustive testing now owns package-backed `V40ReadingPipelineIntegrationCoverage` source, deterministic `.bitcode/v40-reading-pipeline-integration-coverage.json`, nine source-safe Reading integration surfaces for pipeline topology, ReadNeed runtime, ReadFitsFinding search runtime, PTRR agent integration, preview/settlement/delivery boundaries, telemetry/repair readback, Terminal API harness integration, primitive/host integration, and local/staging rehearsal linkage, protocol exports, package tests, workflow wiring, and `check:v40-gate5`. +- V40 Gate 6 closure anchor: exhaustive testing now owns package-backed `V40ConversationTerminalIntegration` source, deterministic `.bitcode/v40-conversation-terminal-integration.json`, eight source-safe Conversation/Terminal integration surfaces for Terminal handoff route contracts, Conversation stream-to-rich-log projection, route/API persistence and branch contracts, writing/source selector handoff, Terminal Reading state readback, Terminal harness log streaming, transaction-cockpit authority boundaries, and rehearsal/docs/interface parity, protocol exports, focused UAPI integration test, package tests, workflow wiring, and `check:v40-gate6`. - Forward planning note: V41 should focus singularly on Prompt and PromptPart implementation quality: prompts as programs. V38's inference correctness hardening and V40's testing/benchmark depth should empower V41 to examine every raw PromptPart, every composed Prompt, every benchmark, every meaningfully benchmarkable semantic part, title, template, interpolation contract, registry binding, inference callsite, and downstream parsed return type; then repartition, retitle, rewrite, catalogue, and validate them across Reading pipelines and conversational interactions. V41 should primarily harden `ReadNeedComprehensionSynthesis` and `ReadFitsFindingSynthesis` prompt surfaces while also covering conversational and other inference prompts with the same catalogue-and-benchmark discipline. - V34 Gate 2 closure anchor: deployment-depth now owns package-backed `DeploymentHostCapabilityCatalog` and `EnvironmentLaneContract` source, deterministic `.bitcode/v34-deployment-host-capability-catalog.json` and `.bitcode/v34-environment-lane-contracts.json`, and visible `value-bearing-mainnet` blocking through `blocked_future_canon_required`. - V34 Gate 3 closure anchor: deployment-depth now owns package-backed `DistributedExecutionRuntimeReceipt` source, deterministic `.bitcode/v34-distributed-execution-runtime-receipts.json`, `request_response_not_required` long-running work posture, and source-safe roots for pipeline, PTRR agent, ThricifiedGeneration, tool, ledger, wallet, proof, object-storage, and repair work. diff --git a/package.json b/package.json index 8b4ea3b7f..320d9c546 100644 --- a/package.json +++ b/package.json @@ -258,6 +258,9 @@ "generate:v40-reading-pipeline-integration": "node scripts/generate-v40-reading-pipeline-integration-coverage.mjs", "check:v40-reading-pipeline-integration": "node scripts/generate-v40-reading-pipeline-integration-coverage.mjs --check", "check:v40-gate5": "node scripts/check-v40-gate5-reading-pipeline-integration.mjs", + "generate:v40-conversation-terminal-integration": "node scripts/generate-v40-conversation-terminal-integration.mjs", + "check:v40-conversation-terminal-integration": "node scripts/generate-v40-conversation-terminal-integration.mjs --check", + "check:v40-gate6": "node scripts/check-v40-gate6-conversation-terminal-integration.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/protocol/README.md b/packages/protocol/README.md index 0d93a6eb9..62f2f0cf8 100644 --- a/packages/protocol/README.md +++ b/packages/protocol/README.md @@ -100,6 +100,16 @@ the real Reading pipeline topology, Need runtime, Finding Fits search runtime, PTRR agents, preview/settlement/delivery boundaries, telemetry/readback, Terminal harness, generic primitives, host harnesses, and local/staging rehearsal linkage. +V40 Gate 6 adds `V40ConversationTerminalIntegration` through +`packages/protocol/src/canonical/v40-conversation-terminal-integration.js`, +`packages/protocol/test/v40-conversation-terminal-integration.test.js`, +`.bitcode/v40-conversation-terminal-integration.json`, and +`check:v40-gate6`. +The artifact is source-safe metadata only and closes integration coverage for +Conversation handoff route contracts, Conversation stream-to-rich-log +projection, route/API persistence and branch contracts, writing/source selector +handoff, Terminal Reading state readback, Terminal harness log streaming, +transaction-cockpit authority boundaries, and rehearsal/docs/interface parity. V39 Gate 1 is wired through `check:v39-gate1` and documents the exact Depository supply, five-step enterprise Reading UX, ReadNeed review, ReadFitsFinding runtime, AssetPack preview, deterministic BTC quote, BTD rights diff --git a/packages/protocol/src/canonical/v40-conversation-terminal-integration.js b/packages/protocol/src/canonical/v40-conversation-terminal-integration.js new file mode 100644 index 000000000..54bd914db --- /dev/null +++ b/packages/protocol/src/canonical/v40-conversation-terminal-integration.js @@ -0,0 +1,555 @@ +// @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 V40_CONVERSATION_TERMINAL_INTEGRATION_ARTIFACT_PATH = + '.bitcode/v40-conversation-terminal-integration.json'; +export const V40_CONVERSATION_TERMINAL_INTEGRATION_SCHEMA_ID = + 'bitcode.v40.conversationTerminalIntegration.v1'; +export const V40_CONVERSATION_TERMINAL_INTEGRATION_VERSION = 'V40'; +export const V40_CONVERSATION_TERMINAL_INTEGRATION_CURRENT_TARGET = 'V39'; +export const V40_CONVERSATION_TERMINAL_INTEGRATION_SOURCE_SAFETY_VERDICT = + 'source-safe-conversation-terminal-integration-metadata'; + +export const V40_CONVERSATION_TERMINAL_SURFACE_IDS = Object.freeze([ + 'conversation:terminal-handoff-route-contract', + 'conversation:stream-events-to-rich-log', + 'conversation:route-api-persistence-branch-contracts', + 'conversation:writing-source-selector-handoff', + 'terminal:reading-state-handoff-readback', + 'terminal:pipeline-harness-log-stream', + 'terminal:transaction-cockpit-authority-boundary', + 'conversation-terminal:rehearsal-docs-and-parity', +]); + +export const V40_CONVERSATION_TERMINAL_VERDICTS = Object.freeze([ + 'covered', + 'exempt', + 'missing', + 'blocked', +]); + +export const V40_CONVERSATION_TERMINAL_EXPECTED_TOTALS = Object.freeze({ + terminalHandoffWorkflowCount: 6, + terminalReadingStageCount: 5, + conversationStreamEventKindCount: 7, + conversationRouteFamilyCount: 6, + sourceSafeDisclosureBoundaryCount: 8, + richExecutionLogProjectionCount: 2, + focusedIntegrationTestCount: 1, +}); + +const FORBIDDEN_PAYLOAD_CLASSES = Object.freeze([ + 'secret-values', + 'provider-tokens', + 'wallet-private-material', + 'protected-source-payloads', + 'raw-protected-prompts', + 'raw-provider-responses', + 'raw-model-responses-with-protected-source', + 'unpaid-assetpack-source', + 'settlement-private-payloads', + 'global-ledger-authority-claim', +]); + +function digest(value) { + return crypto.createHash('sha256').update(value).digest('hex').slice(0, 24); +} + +function rowRoot(id) { + return `v40-conversation-terminal-integration-row:${digest(id)}`; +} + +function readSource(repoRoot, sourcePath) { + const absolutePath = path.join(repoRoot, sourcePath); + return existsSync(absolutePath) ? readFileSync(absolutePath, 'utf8') : ''; +} + +function sourceExists(repoRoot, sourcePath) { + return existsSync(path.join(repoRoot, sourcePath)); +} + +function predicateResult(id, sourcePath, passed) { + return { id, sourcePath, passed: Boolean(passed) }; +} + +function allMarkersPresent(repoRoot, paths, markers) { + const source = paths.map((sourcePath) => readSource(repoRoot, sourcePath)).join('\n'); + return markers.every((marker) => source.includes(marker)); +} + +function row(input) { + return { + ...input, + rowRoot: rowRoot(input.integrationSurfaceId), + verdict: 'covered', + sourceSafetyClass: 'source_safe_conversation_terminal_integration_metadata', + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + rawProtectedPromptVisible: false, + rawProviderResponseVisible: false, + rawModelResponseWithProtectedSourceVisible: false, + unpaidAssetPackSourceVisible: false, + credentialsSerialized: false, + walletPrivateMaterialVisible: false, + ledgerAuthorityClaimedByConversation: false, + valueBearingMainnetRequired: false, + forbiddenPayloadClasses: [...FORBIDDEN_PAYLOAD_CLASSES], + }; +} + +export const V40_CONVERSATION_TERMINAL_INTEGRATION_ROWS = Object.freeze([ + row({ + integrationSurfaceId: 'conversation:terminal-handoff-route-contract', + integrationKind: 'handoff-route-contract', + sourceRoots: [ + 'uapi/app/conversations/conversation-terminal-handoff.ts', + 'uapi/app/conversations/components/ConversationTerminalHandoff.tsx', + 'uapi/app/terminal/terminal-transaction-query.ts', + 'uapi/app/terminal/terminal-routes.ts', + ], + testPaths: [ + 'uapi/tests/conversationTerminalHandoff.test.tsx', + 'uapi/tests/conversationTerminalIntegrationCoverage.test.tsx', + 'uapi/tests/terminalTransactionQuery.test.ts', + ], + commandIds: [ + 'pnpm --dir uapi exec jest tests/conversationTerminalHandoff.test.tsx tests/conversationTerminalIntegrationCoverage.test.tsx tests/terminalTransactionQuery.test.ts --runInBand', + ], + requiredSourceMarkers: [ + 'buildConversationTerminalHandoffEnvelope', + 'readTerminalConversationHandoffContext', + 'TERMINAL_ENTERPRISE_READING_STAGE_VALUES', + 'terminalRemainsTransactionCockpit', + ], + requiredTestMarkers: [ + 'source-safe Conversation handoff', + 'readTerminalConversationHandoffContext', + 'source-safe enterprise Reading stages', + ], + expectedCounts: { + handoffWorkflowCount: 6, + readingStageCount: 5, + }, + coverageTier: 'promotion-required', + closureRequirement: + 'Conversation handoff envelopes serialize source-safe Terminal route context, read back the five enterprise Reading stages, and never claim ledger or wallet authority.', + }), + row({ + integrationSurfaceId: 'conversation:stream-events-to-rich-log', + integrationKind: 'stream-to-log-rendering', + sourceRoots: [ + 'packages/api/src/conversations/stream-events.ts', + 'uapi/components/base/bitcode/execution/pipeline-execution-log.tsx', + 'uapi/components/base/bitcode/execution/pipeline-execution-log-header.tsx', + 'uapi/app/conversations/components/ConversationsSidebarLogs.tsx', + ], + testPaths: [ + 'packages/api/src/conversations/__tests__/stream-events.test.ts', + 'uapi/tests/conversationStreamPipelineLog.test.tsx', + 'uapi/tests/conversationTerminalIntegrationCoverage.test.tsx', + 'uapi/tests/pipelineExecutionLogHeader.test.tsx', + ], + commandIds: [ + 'pnpm --filter @bitcode/api exec jest src/conversations/__tests__/stream-events.test.ts --runInBand --forceExit', + 'pnpm --dir uapi exec jest tests/conversationStreamPipelineLog.test.tsx tests/conversationTerminalIntegrationCoverage.test.tsx tests/pipelineExecutionLogHeader.test.tsx --runInBand', + ], + requiredSourceMarkers: [ + 'buildConversationStreamEvent', + 'buildConversationPipelineLogEvent', + 'prompt_template_id_only', + 'BitcodeExecutionStreamPanel', + ], + requiredTestMarkers: [ + 'PipelineExecutionLog', + 'ConversationStreamEvent:tool_call', + 'prompt_template_id_only', + ], + expectedCounts: { + conversationStreamEventKindCount: 7, + richExecutionLogProjectionCount: 2, + }, + coverageTier: 'promotion-required', + closureRequirement: + 'Conversation stream events are converted into rich execution-log rows with collapsed status, expandable source-safe metadata, proof roots, telemetry hooks, and prompt/result disclosure posture.', + }), + row({ + integrationSurfaceId: 'conversation:route-api-persistence-branch-contracts', + integrationKind: 'route-api-contracts', + sourceRoots: [ + 'uapi/app/api/conversations/route.ts', + 'uapi/app/api/conversations/[conversationId]/route.ts', + 'uapi/app/api/conversations/[conversationId]/stream/route.ts', + 'uapi/app/api/conversations/branch/route.ts', + 'uapi/app/api/conversations/stream/route.ts', + 'packages/api/src/conversations/conversations.ts', + 'packages/api/src/conversations/privacy.ts', + 'packages/api/src/conversations/telemetry.ts', + ], + testPaths: [ + 'uapi/tests/api/conversationsRoute.test.ts', + 'uapi/tests/api/conversationsRouteRead.test.ts', + 'uapi/tests/api/chatStreamRoute.test.ts', + 'uapi/tests/api/conversationThreadStreamRoute.test.ts', + 'uapi/tests/api/conversationBranchRoute.test.ts', + 'uapi/tests/api/conversationPersistencePrivacyRedaction.test.ts', + 'uapi/tests/api/conversationTelemetryProofHooks.test.ts', + 'packages/api/src/conversations/__tests__/branch-conversation.test.ts', + 'packages/api/src/conversations/__tests__/privacy.test.ts', + 'packages/api/src/conversations/__tests__/telemetry.test.ts', + ], + commandIds: [ + 'pnpm --dir uapi exec jest tests/api/conversationsRoute.test.ts tests/api/conversationBranchRoute.test.ts tests/api/conversationTelemetryProofHooks.test.ts --runInBand', + 'pnpm --filter @bitcode/api exec jest src/conversations/__tests__/branch-conversation.test.ts src/conversations/__tests__/privacy.test.ts src/conversations/__tests__/telemetry.test.ts --runInBand --forceExit', + ], + requiredSourceMarkers: [ + 'conversation_id', + 'buildConversationTelemetryProofHook', + 'redactConversationPersistenceText', + 'branch', + ], + requiredTestMarkers: [ + 'conversation', + 'privacy', + 'telemetry', + 'branch', + ], + expectedCounts: { + routeFamilyCount: 6, + persistencePrivacyRequired: true, + }, + coverageTier: 'promotion-required', + closureRequirement: + 'Conversation routes, persistence readback, branch creation, privacy redaction, and telemetry hooks are integration-covered across UAPI and package API helpers.', + }), + row({ + integrationSurfaceId: 'conversation:writing-source-selector-handoff', + integrationKind: 'writing-source-selector-handoff', + sourceRoots: [ + 'uapi/app/conversations/conversation-writing-workspace.ts', + 'uapi/app/conversations/components/ConversationWritingWorkspace.tsx', + 'uapi/app/conversations/conversation-source-selector.ts', + 'uapi/app/conversations/components/ConversationSourceSelector.tsx', + 'uapi/app/conversations/components/ConversationsOverlay.tsx', + ], + testPaths: [ + 'uapi/tests/conversationWritingWorkspace.test.tsx', + 'uapi/tests/conversationSourceSelector.test.tsx', + 'uapi/tests/conversationsOverlayMapping.test.ts', + 'uapi/tests/conversationTerminalIntegrationCoverage.test.tsx', + ], + commandIds: [ + 'pnpm --dir uapi exec jest tests/conversationWritingWorkspace.test.tsx tests/conversationSourceSelector.test.tsx tests/conversationsOverlayMapping.test.ts tests/conversationTerminalIntegrationCoverage.test.tsx --runInBand', + ], + requiredSourceMarkers: [ + 'ConversationWritingWorkspace', + 'buildConversationWritingWorkspaceHandoff', + 'buildConversationSourceSelectorPreview', + 'ConversationTerminalHandoff', + ], + requiredTestMarkers: [ + 'source-safe', + 'source', + 'destination', + 'Request Finding Fits for the accepted Read-Need', + ], + expectedCounts: { + workspaceModeCount: 4, + selectorPreviewRequired: true, + }, + coverageTier: 'promotion-required', + closureRequirement: + 'Conversation writing, source selector, and attachment mapping stay source-safe before they prepare Terminal handoff intent.', + }), + row({ + integrationSurfaceId: 'terminal:reading-state-handoff-readback', + integrationKind: 'terminal-reading-state', + sourceRoots: [ + 'uapi/app/terminal/terminal-enterprise-reading-ux-state.ts', + 'uapi/app/terminal/TerminalPageClient.tsx', + 'uapi/app/terminal/README.md', + 'uapi/app/conversations/README.md', + ], + testPaths: [ + 'uapi/tests/terminalEnterpriseReadingUxState.test.ts', + 'uapi/tests/conversationTerminalHandoff.test.tsx', + 'uapi/tests/conversationTerminalIntegrationCoverage.test.tsx', + ], + commandIds: [ + 'pnpm --dir uapi exec jest tests/terminalEnterpriseReadingUxState.test.ts tests/conversationTerminalHandoff.test.tsx tests/conversationTerminalIntegrationCoverage.test.tsx --runInBand', + ], + requiredSourceMarkers: [ + 'TERMINAL_ENTERPRISE_READING_STEPS', + 'request-fit', + 'Conversation handoff', + 'source-safe', + ], + requiredTestMarkers: [ + 'locks the enterprise Reading UX to five source-safe stages', + 'source-safe enterprise Reading stages', + 'request-fit', + ], + expectedCounts: { + readingStageCount: 5, + lowDetailDefaultRequired: true, + }, + coverageTier: 'promotion-required', + closureRequirement: + 'Terminal reads Conversation `readingStage` intent as posture, keeps the five-stage Reading UX source-safe, and blocks protected or unpaid source disclosure.', + }), + row({ + integrationSurfaceId: 'terminal:pipeline-harness-log-stream', + integrationKind: 'terminal-harness-streaming', + sourceRoots: [ + 'uapi/app/terminal/terminal-pipeline-harness-client.ts', + 'uapi/app/api/pipeline-harness/asset-pack/route.ts', + 'uapi/components/base/bitcode/execution/BitcodeExecutionStreamPanel.tsx', + 'uapi/components/base/bitcode/execution/pipeline-execution-log.tsx', + ], + testPaths: [ + 'uapi/tests/terminalPipelineHarnessClient.test.ts', + 'uapi/tests/api/pipelineHarnessRoute.test.ts', + 'uapi/tests/readingOperationalTelemetryPipelineLog.test.tsx', + 'uapi/tests/conversationTerminalIntegrationCoverage.test.tsx', + ], + commandIds: [ + 'pnpm --dir uapi exec jest tests/terminalPipelineHarnessClient.test.ts tests/api/pipelineHarnessRoute.test.ts tests/readingOperationalTelemetryPipelineLog.test.tsx tests/conversationTerminalIntegrationCoverage.test.tsx --runInBand', + ], + requiredSourceMarkers: [ + 'buildTerminalReadFitsFindingSynthesisHarnessStreamSnapshot', + 'summarizeTerminalReadFitsFindingSynthesisHarnessEvent', + 'readingPipelineTelemetry', + 'PipelineExecutionLog', + ], + requiredTestMarkers: [ + 'pipeline ReadFitsFindingSynthesis', + 'telemetry 72 lines', + 'ThricifiedGeneration', + ], + expectedCounts: { + harnessEventProjectionRequired: true, + inferenceTelemetryReadbackRequired: true, + }, + coverageTier: 'promotion-required', + closureRequirement: + 'Terminal harness streaming converts live or replayed pipeline events into inspectable rich logs with inference telemetry and no source or secret leakage.', + }), + row({ + integrationSurfaceId: 'terminal:transaction-cockpit-authority-boundary', + integrationKind: 'terminal-authority-boundary', + sourceRoots: [ + 'uapi/app/terminal/terminal-interface-integration-regression.ts', + 'uapi/app/terminal/terminal-transaction-read-model.ts', + 'uapi/app/terminal/terminal-wallet-btc-operation.ts', + 'packages/pipelines/asset-pack/src/reading-interface-product-parity.ts', + ], + testPaths: [ + 'uapi/tests/terminalInterfaceIntegrationRegression.test.ts', + 'uapi/tests/terminalTransactionReadModel.test.ts', + 'uapi/tests/terminalWalletBtcOperation.test.ts', + 'uapi/tests/api/conversationReadingInterfaceParity.test.ts', + 'packages/pipelines/asset-pack/src/__tests__/reading-interface-product-parity.test.ts', + ], + commandIds: [ + 'pnpm --dir uapi exec jest tests/terminalInterfaceIntegrationRegression.test.ts tests/terminalTransactionReadModel.test.ts tests/terminalWalletBtcOperation.test.ts tests/api/conversationReadingInterfaceParity.test.ts --runInBand', + 'pnpm --filter @bitcode/pipeline-asset-pack exec jest src/__tests__/reading-interface-product-parity.test.ts --runInBand --forceExit', + ], + requiredSourceMarkers: [ + 'terminal-delegated-handoff', + 'terminal_handoff', + 'PSBT handoff', + 'Wallet signer session', + ], + requiredTestMarkers: [ + 'terminal-delegated-handoff', + 'signed-psbt', + ], + expectedCounts: { + terminalAuthorityRequired: true, + noConversationWalletAuthority: true, + }, + coverageTier: 'promotion-required', + closureRequirement: + 'Terminal remains the transaction, wallet, settlement, ledger, and delivery authority while Conversation may only hand off source-safe intent.', + }), + row({ + integrationSurfaceId: 'conversation-terminal:rehearsal-docs-and-parity', + integrationKind: 'rehearsal-docs-parity', + sourceRoots: [ + 'uapi/app/conversations/conversation-rehearsal.ts', + 'uapi/app/conversations/components/ConversationRehearsalPanel.tsx', + 'uapi/app/conversations/README.md', + 'uapi/app/terminal/README.md', + 'packages/protocol/src/canonical/v39-interface-conversation-product-parity.js', + ], + testPaths: [ + 'uapi/tests/api/conversationRehearsal.test.ts', + 'uapi/tests/conversationRehearsalPanel.test.tsx', + 'packages/protocol/test/v39-interface-conversation-product-parity.test.js', + 'uapi/tests/conversationTerminalIntegrationCoverage.test.tsx', + ], + commandIds: [ + 'pnpm --dir uapi exec jest tests/api/conversationRehearsal.test.ts tests/conversationRehearsalPanel.test.tsx tests/conversationTerminalIntegrationCoverage.test.tsx --runInBand', + 'pnpm --filter @bitcode/protocol exec node --test --test-force-exit test/v39-interface-conversation-product-parity.test.js', + ], + requiredSourceMarkers: [ + 'terminal_handoff', + 'ConversationTerminalHandoff', + 'source-safe', + 'buildV39InterfaceConversationProductParity', + ], + requiredTestMarkers: [ + 'terminal_handoff', + 'source-safe', + 'Terminal', + ], + expectedCounts: { + rehearsalFlowCovered: true, + docsParityCovered: true, + }, + coverageTier: 'promotion-required', + closureRequirement: + 'Conversation and Terminal documentation, rehearsal rows, and interface parity prove the same source-safe authority boundary that the integration tests execute.', + }), +]); + +function buildPredicateResults(repoRoot) { + const packageJson = readSource(repoRoot, 'package.json'); + const gateWorkflow = readSource(repoRoot, '.github/workflows/bitcode-gate-quality.yml'); + const canonWorkflow = readSource(repoRoot, '.github/workflows/bitcode-canon-quality.yml'); + const spec = readSource(repoRoot, 'BITCODE_SPEC_V40.md'); + const delta = readSource(repoRoot, 'BITCODE_SPEC_V40_DELTA.md'); + const notes = readSource(repoRoot, 'BITCODE_SPEC_V40_NOTES.md'); + const parity = readSource(repoRoot, 'BITCODE_SPEC_V40_PARITY_MATRIX.md'); + const roadmap = readSource(repoRoot, 'SPECIFICATIONS_ROADMAP.md'); + const protocolReadme = readSource(repoRoot, 'packages/protocol/README.md'); + const rootReadme = readSource(repoRoot, 'README.md'); + const protocolIndex = readSource(repoRoot, 'packages/protocol/src/index.js'); + const protocolTypes = readSource(repoRoot, 'packages/protocol/src/index.d.ts'); + + const rowPredicates = V40_CONVERSATION_TERMINAL_INTEGRATION_ROWS.flatMap((coverageRow) => { + const safeId = coverageRow.integrationSurfaceId.replace(/[^a-z0-9]+/gu, '-'); + return [ + predicateResult( + `${safeId}:source-roots-exist`, + coverageRow.sourceRoots[0], + coverageRow.sourceRoots.every((sourcePath) => sourceExists(repoRoot, sourcePath)), + ), + predicateResult( + `${safeId}:test-paths-exist`, + coverageRow.testPaths[0], + coverageRow.testPaths.every((testPath) => sourceExists(repoRoot, testPath)), + ), + predicateResult( + `${safeId}:source-markers-present`, + coverageRow.sourceRoots[0], + allMarkersPresent(repoRoot, coverageRow.sourceRoots, coverageRow.requiredSourceMarkers), + ), + predicateResult( + `${safeId}:test-markers-present`, + coverageRow.testPaths[0], + allMarkersPresent(repoRoot, coverageRow.testPaths, coverageRow.requiredTestMarkers), + ), + ]; + }); + + return [ + predicateResult('package-scripts-include-gate6', 'package.json', packageJson.includes('generate:v40-conversation-terminal-integration') && packageJson.includes('check:v40-gate6')), + predicateResult('workflows-run-gate6-check', '.github/workflows/bitcode-gate-quality.yml', gateWorkflow.includes('check-v40-gate6-conversation-terminal-integration.mjs') && canonWorkflow.includes('check-v40-gate6-conversation-terminal-integration.mjs')), + predicateResult('gate-quality-runs-conversation-terminal-integration-test', '.github/workflows/bitcode-gate-quality.yml', gateWorkflow.includes('conversationTerminalIntegrationCoverage.test.tsx')), + predicateResult('uapi-jest-includes-conversation-terminal-integration-test', 'uapi/jest.config.cjs', readSource(repoRoot, 'uapi/jest.config.cjs').includes('conversationTerminalIntegrationCoverage.test.tsx')), + predicateResult('protocol-exports-gate6', 'packages/protocol/src/index.js', protocolIndex.includes('buildV40ConversationTerminalIntegration') && protocolTypes.includes('buildV40ConversationTerminalIntegration')), + predicateResult('spec-documents-gate6', 'BITCODE_SPEC_V40.md', spec.includes('V40 Gate 6 Conversation And Terminal Integration Coverage') && spec.includes(V40_CONVERSATION_TERMINAL_INTEGRATION_ARTIFACT_PATH)), + predicateResult('delta-documents-gate6', 'BITCODE_SPEC_V40_DELTA.md', delta.includes('Gate 6 closes with package-backed `V40ConversationTerminalIntegration`')), + predicateResult('notes-document-gate6', 'BITCODE_SPEC_V40_NOTES.md', notes.includes('Gate 6 implementation notes') && notes.includes('Conversation and Terminal integration coverage')), + predicateResult('parity-documents-gate6', 'BITCODE_SPEC_V40_PARITY_MATRIX.md', parity.includes('v40-conversation-terminal-integration') && parity.includes('| Gate 6 | Conversation/Terminal integration artifact | implemented |')), + predicateResult('roadmap-advanced-through-gate6', 'SPECIFICATIONS_ROADMAP.md', roadmap.includes('Current working gate: V40 Gate 6') && roadmap.includes('V40 Gate 6 closure anchor')), + predicateResult('readmes-document-gate6', 'README.md', rootReadme.includes('V40 Gate 6') && protocolReadme.includes('V40ConversationTerminalIntegration')), + predicateResult('roadmap-preserves-v41-prompt-programs', 'SPECIFICATIONS_ROADMAP.md', roadmap.includes('V41 should focus singularly on Prompt and PromptPart implementation') && roadmap.includes('prompts as programs')), + ...rowPredicates, + ]; +} + +function buildCoverage(rows, predicateResults) { + const failedPredicateIds = predicateResults.filter((predicate) => !predicate.passed).map((predicate) => predicate.id); + const rowsByVerdict = rows.reduce((acc, item) => { + acc[item.verdict] = (acc[item.verdict] || 0) + 1; + return acc; + }, {}); + const rowsByTier = rows.reduce((acc, item) => { + acc[item.coverageTier] = (acc[item.coverageTier] || 0) + 1; + return acc; + }, {}); + + return { + rowCount: rows.length, + surfaceCount: V40_CONVERSATION_TERMINAL_SURFACE_IDS.length, + verdictIds: [...V40_CONVERSATION_TERMINAL_VERDICTS], + rowsByVerdict, + rowsByTier, + expectedTotals: { ...V40_CONVERSATION_TERMINAL_EXPECTED_TOTALS }, + requiredPredicateCount: predicateResults.length, + passedPredicateCount: predicateResults.length - failedPredicateIds.length, + failedPredicateIds, + coveredRowCount: rows.filter((item) => item.verdict === 'covered').length, + missingRowCount: rows.filter((item) => item.verdict === 'missing').length, + blockedRowCount: rows.filter((item) => item.verdict === 'blocked').length, + exemptRowCount: rows.filter((item) => item.verdict === 'exempt').length, + allCriticalSurfacesClosed: failedPredicateIds.length === 0 && rows.every((item) => item.verdict === 'covered'), + terminalHandoffRouteCoverageClosed: rows.some((item) => item.integrationSurfaceId === 'conversation:terminal-handoff-route-contract'), + conversationStreamLogCoverageClosed: rows.some((item) => item.integrationSurfaceId === 'conversation:stream-events-to-rich-log'), + conversationRouteApiCoverageClosed: rows.some((item) => item.integrationSurfaceId === 'conversation:route-api-persistence-branch-contracts'), + writingSourceSelectorCoverageClosed: rows.some((item) => item.integrationSurfaceId === 'conversation:writing-source-selector-handoff'), + terminalReadingStateCoverageClosed: rows.some((item) => item.integrationSurfaceId === 'terminal:reading-state-handoff-readback'), + terminalHarnessLogStreamCoverageClosed: rows.some((item) => item.integrationSurfaceId === 'terminal:pipeline-harness-log-stream'), + terminalAuthorityBoundaryCoverageClosed: rows.some((item) => item.integrationSurfaceId === 'terminal:transaction-cockpit-authority-boundary'), + rehearsalDocsParityCoverageClosed: rows.some((item) => item.integrationSurfaceId === 'conversation-terminal:rehearsal-docs-and-parity'), + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + rawProtectedPromptVisible: false, + rawProviderResponseVisible: false, + rawModelResponseWithProtectedSourceVisible: false, + unpaidAssetPackSourceVisible: false, + credentialsSerialized: false, + walletPrivateMaterialVisible: false, + ledgerAuthorityClaimedByConversation: false, + valueBearingMainnetRequired: false, + promptContentRewriteDeferredToV41: true, + }; +} + +export function buildV40ConversationTerminalIntegration(input = {}) { + const repoRoot = input.repoRoot || DEFAULT_REPO_ROOT; + const rows = [...V40_CONVERSATION_TERMINAL_INTEGRATION_ROWS]; + const predicateResults = buildPredicateResults(repoRoot); + const coverage = buildCoverage(rows, predicateResults); + const artifactRoot = `v40-conversation-terminal-integration:${digest(JSON.stringify({ + rows: rows.map((item) => item.rowRoot), + failedPredicateIds: coverage.failedPredicateIds, + expectedTotals: coverage.expectedTotals, + }))}`; + + return { + artifactId: 'v40-conversation-terminal-integration', + schemaId: V40_CONVERSATION_TERMINAL_INTEGRATION_SCHEMA_ID, + version: V40_CONVERSATION_TERMINAL_INTEGRATION_VERSION, + currentTarget: V40_CONVERSATION_TERMINAL_INTEGRATION_CURRENT_TARGET, + sourceSafetyVerdict: V40_CONVERSATION_TERMINAL_INTEGRATION_SOURCE_SAFETY_VERDICT, + generatedAt: 'deterministic', + artifactRoot, + passed: coverage.failedPredicateIds.length === 0 && coverage.allCriticalSurfacesClosed, + surfaceIds: [...V40_CONVERSATION_TERMINAL_SURFACE_IDS], + verdictIds: [...V40_CONVERSATION_TERMINAL_VERDICTS], + rows, + rowIds: rows.map((item) => item.integrationSurfaceId), + predicateResults, + coverage, + }; +} diff --git a/packages/protocol/src/canonical/v40-reading-pipeline-integration-coverage.js b/packages/protocol/src/canonical/v40-reading-pipeline-integration-coverage.js index 5e9a3d1a3..aab34145f 100644 --- a/packages/protocol/src/canonical/v40-reading-pipeline-integration-coverage.js +++ b/packages/protocol/src/canonical/v40-reading-pipeline-integration-coverage.js @@ -489,7 +489,7 @@ function buildPredicateResults(repoRoot) { predicateResult('delta-documents-gate5', 'BITCODE_SPEC_V40_DELTA.md', delta.includes('Gate 5 closes with package-backed `V40ReadingPipelineIntegrationCoverage`')), predicateResult('notes-document-gate5', 'BITCODE_SPEC_V40_NOTES.md', notes.includes('Gate 5 implementation notes') && notes.includes('Reading pipeline integration coverage')), predicateResult('parity-documents-gate5', 'BITCODE_SPEC_V40_PARITY_MATRIX.md', parity.includes('v40-reading-pipeline-integration-coverage') && parity.includes('| Gate 5 | Reading pipeline integration artifact | implemented |')), - predicateResult('roadmap-advanced-through-gate5', 'SPECIFICATIONS_ROADMAP.md', roadmap.includes('Current working gate: V40 Gate 5') && roadmap.includes('V40 Gate 5 closure anchor')), + predicateResult('roadmap-advanced-through-gate5', 'SPECIFICATIONS_ROADMAP.md', /Current working gate: V40 Gate (?:5|6|7|8|9|10|11)\b/u.test(roadmap) && roadmap.includes('V40 Gate 5 closure anchor')), predicateResult('roadmap-preserves-v41-prompt-programs', 'SPECIFICATIONS_ROADMAP.md', roadmap.includes('V41 should focus singularly on Prompt and PromptPart implementation') && roadmap.includes('prompts as programs')), ...rowPredicates, ]; diff --git a/packages/protocol/src/index.d.ts b/packages/protocol/src/index.d.ts index 0b5e0aba4..6d682cfc1 100644 --- a/packages/protocol/src/index.d.ts +++ b/packages/protocol/src/index.d.ts @@ -375,6 +375,16 @@ export const V40_READING_PIPELINE_INTEGRATION_VERDICTS: readonly string[]; export const V40_READING_PIPELINE_EXPECTED_TOTALS: Readonly>; export const V40_READING_PIPELINE_INTEGRATION_ROWS: readonly Record[]; export function buildV40ReadingPipelineIntegrationCoverage(input?: Record): BitcodeProtocolReport; +export const V40_CONVERSATION_TERMINAL_INTEGRATION_ARTIFACT_PATH: string; +export const V40_CONVERSATION_TERMINAL_INTEGRATION_CURRENT_TARGET: string; +export const V40_CONVERSATION_TERMINAL_INTEGRATION_SCHEMA_ID: string; +export const V40_CONVERSATION_TERMINAL_INTEGRATION_VERSION: string; +export const V40_CONVERSATION_TERMINAL_INTEGRATION_SOURCE_SAFETY_VERDICT: string; +export const V40_CONVERSATION_TERMINAL_SURFACE_IDS: readonly string[]; +export const V40_CONVERSATION_TERMINAL_VERDICTS: readonly string[]; +export const V40_CONVERSATION_TERMINAL_EXPECTED_TOTALS: Readonly>; +export const V40_CONVERSATION_TERMINAL_INTEGRATION_ROWS: readonly Record[]; +export function buildV40ConversationTerminalIntegration(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 2e5618318..606307b9e 100644 --- a/packages/protocol/src/index.js +++ b/packages/protocol/src/index.js @@ -405,6 +405,18 @@ export { V40_READING_PIPELINE_NAMES, buildV40ReadingPipelineIntegrationCoverage } from './canonical/v40-reading-pipeline-integration-coverage.js'; +export { + V40_CONVERSATION_TERMINAL_EXPECTED_TOTALS, + V40_CONVERSATION_TERMINAL_INTEGRATION_ARTIFACT_PATH, + V40_CONVERSATION_TERMINAL_INTEGRATION_CURRENT_TARGET, + V40_CONVERSATION_TERMINAL_INTEGRATION_SCHEMA_ID, + V40_CONVERSATION_TERMINAL_INTEGRATION_SOURCE_SAFETY_VERDICT, + V40_CONVERSATION_TERMINAL_INTEGRATION_VERSION, + V40_CONVERSATION_TERMINAL_INTEGRATION_ROWS, + V40_CONVERSATION_TERMINAL_SURFACE_IDS, + V40_CONVERSATION_TERMINAL_VERDICTS, + buildV40ConversationTerminalIntegration +} from './canonical/v40-conversation-terminal-integration.js'; export { EXCHANGE_INTENT_ACTION_KINDS, EXCHANGE_INTENT_ORDER_CONTRACTS_ARTIFACT_PATH, diff --git a/packages/protocol/test/v40-conversation-terminal-integration.test.js b/packages/protocol/test/v40-conversation-terminal-integration.test.js new file mode 100644 index 000000000..83860e8d5 --- /dev/null +++ b/packages/protocol/test/v40-conversation-terminal-integration.test.js @@ -0,0 +1,75 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { + V40_CONVERSATION_TERMINAL_EXPECTED_TOTALS, + V40_CONVERSATION_TERMINAL_INTEGRATION_ARTIFACT_PATH, + V40_CONVERSATION_TERMINAL_INTEGRATION_ROWS, + V40_CONVERSATION_TERMINAL_INTEGRATION_SCHEMA_ID, + V40_CONVERSATION_TERMINAL_INTEGRATION_SOURCE_SAFETY_VERDICT, + V40_CONVERSATION_TERMINAL_SURFACE_IDS, + V40_CONVERSATION_TERMINAL_VERDICTS, + buildV40ConversationTerminalIntegration, +} from '../src/canonical/v40-conversation-terminal-integration.js'; + +test('V40 Conversation and Terminal integration coverage closes cross-surface handoff and logs', () => { + const report = buildV40ConversationTerminalIntegration(); + + assert.equal( + V40_CONVERSATION_TERMINAL_INTEGRATION_ARTIFACT_PATH, + '.bitcode/v40-conversation-terminal-integration.json', + ); + assert.equal(report.artifactId, 'v40-conversation-terminal-integration'); + assert.equal(report.schemaId, V40_CONVERSATION_TERMINAL_INTEGRATION_SCHEMA_ID); + assert.equal(report.version, 'V40'); + assert.equal(report.currentTarget, 'V39'); + assert.equal(report.sourceSafetyVerdict, V40_CONVERSATION_TERMINAL_INTEGRATION_SOURCE_SAFETY_VERDICT); + assert.equal(report.passed, true); + assert.deepEqual(report.surfaceIds, [...V40_CONVERSATION_TERMINAL_SURFACE_IDS]); + assert.deepEqual(report.verdictIds, [...V40_CONVERSATION_TERMINAL_VERDICTS]); + assert.equal(report.rows.length, V40_CONVERSATION_TERMINAL_INTEGRATION_ROWS.length); + assert.equal(report.coverage.rowCount, 8); + assert.equal(report.coverage.surfaceCount, 8); + assert.equal(report.coverage.coveredRowCount, 8); + assert.equal(report.coverage.missingRowCount, 0); + assert.equal(report.coverage.blockedRowCount, 0); + assert.equal(report.coverage.exemptRowCount, 0); + assert.equal(report.coverage.allCriticalSurfacesClosed, true); + assert.deepEqual(report.coverage.expectedTotals, { ...V40_CONVERSATION_TERMINAL_EXPECTED_TOTALS }); + assert.equal(report.coverage.terminalHandoffRouteCoverageClosed, true); + assert.equal(report.coverage.conversationStreamLogCoverageClosed, true); + assert.equal(report.coverage.conversationRouteApiCoverageClosed, true); + assert.equal(report.coverage.writingSourceSelectorCoverageClosed, true); + assert.equal(report.coverage.terminalReadingStateCoverageClosed, true); + assert.equal(report.coverage.terminalHarnessLogStreamCoverageClosed, true); + assert.equal(report.coverage.terminalAuthorityBoundaryCoverageClosed, true); + assert.equal(report.coverage.rehearsalDocsParityCoverageClosed, true); + assert.equal(report.coverage.promptContentRewriteDeferredToV41, true); + assert.deepEqual(report.coverage.failedPredicateIds, []); + assert.ok(report.artifactRoot.startsWith('v40-conversation-terminal-integration:')); +}); + +test('V40 Conversation and Terminal integration rows remain source-safe metadata only', () => { + for (const row of V40_CONVERSATION_TERMINAL_INTEGRATION_ROWS) { + assert.equal(row.verdict, 'covered'); + assert.ok(row.rowRoot.startsWith('v40-conversation-terminal-integration-row:')); + assert.equal(row.sourceSafetyClass, 'source_safe_conversation_terminal_integration_metadata'); + assert.equal(row.sourceSafeMetadataOnly, true); + assert.equal(row.protectedSourceVisible, false); + assert.equal(row.rawProtectedPromptVisible, false); + assert.equal(row.rawProviderResponseVisible, false); + assert.equal(row.rawModelResponseWithProtectedSourceVisible, false); + assert.equal(row.unpaidAssetPackSourceVisible, false); + assert.equal(row.credentialsSerialized, false); + assert.equal(row.walletPrivateMaterialVisible, false); + assert.equal(row.ledgerAuthorityClaimedByConversation, false); + assert.equal(row.valueBearingMainnetRequired, false); + assert.ok(row.forbiddenPayloadClasses.includes('secret-values')); + assert.ok(row.forbiddenPayloadClasses.includes('unpaid-assetpack-source')); + assert.ok(row.sourceRoots.length > 0); + assert.ok(row.testPaths.length > 0); + assert.ok(row.commandIds.length > 0); + assert.ok(row.requiredSourceMarkers.length > 0); + assert.ok(row.requiredTestMarkers.length > 0); + } +}); diff --git a/scripts/check-v40-gate6-conversation-terminal-integration.mjs b/scripts/check-v40-gate6-conversation-terminal-integration.mjs new file mode 100644 index 000000000..fefcaa463 --- /dev/null +++ b/scripts/check-v40-gate6-conversation-terminal-integration.mjs @@ -0,0 +1,256 @@ +#!/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/v40-conversation-terminal-integration.json'; + +const SECRET_MARKERS = [ + `${['sk', 'proj'].join('-')}-`, + `${['sb', 'secret'].join('_')}__`, + ['service', 'role'].join('_'), + ['eyJhbGciOi', 'JIUzI1Ni'].join(''), + ['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 = { + repoRoot: defaultRepoRoot, + skipBranchCheck: false, + skipIntegrationTests: false, + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--repo-root') args.repoRoot = path.resolve(argv[++index]); + else if (arg === '--skip-branch-check') args.skipBranchCheck = true; + else if (arg === '--skip-integration-tests') args.skipIntegrationTests = true; + 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-v40-gate6-conversation-terminal-integration.mjs [--skip-branch-check] [--skip-integration-tests] [--repo-root ]', + '', + 'Checks V40 Gate 6 Conversation and Terminal integration coverage artifact freshness, source-safe metadata, docs, workflows, and focused integration tests.', + ].join('\n'), + ); + process.stdout.write('\n'); +} + +function runIntegrationSmoke(root, failures) { + const commands = [ + ['pnpm', ['--filter', '@bitcode/protocol', 'exec', 'node', '--test', '--test-force-exit', 'test/v40-conversation-terminal-integration.test.js']], + ['pnpm', ['--filter', '@bitcode/api', 'exec', 'jest', '--config', 'jest.config.cjs', '--runTestsByPath', + 'src/conversations/__tests__/stream-events.test.ts', + 'src/conversations/__tests__/branch-conversation.test.ts', + 'src/conversations/__tests__/privacy.test.ts', + 'src/conversations/__tests__/telemetry.test.ts', + '--runInBand', + '--forceExit', + ]], + ['pnpm', ['--dir', 'uapi', 'exec', 'jest', '--runTestsByPath', + 'tests/conversationTerminalIntegrationCoverage.test.tsx', + 'tests/conversationTerminalHandoff.test.tsx', + 'tests/conversationStreamPipelineLog.test.tsx', + 'tests/conversationWritingWorkspace.test.tsx', + 'tests/conversationSourceSelector.test.tsx', + 'tests/api/conversationsRoute.test.ts', + 'tests/api/conversationBranchRoute.test.ts', + 'tests/api/conversationPersistencePrivacyRedaction.test.ts', + 'tests/api/conversationTelemetryProofHooks.test.ts', + 'tests/terminalEnterpriseReadingUxState.test.ts', + 'tests/terminalPipelineHarnessClient.test.ts', + 'tests/readingOperationalTelemetryPipelineLog.test.tsx', + 'tests/pipelineExecutionLogHeader.test.tsx', + '--runInBand', + ]], + ['pnpm', ['--filter', '@bitcode/pipeline-asset-pack', 'exec', 'jest', '--config', 'jest.config.cjs', '--runTestsByPath', + 'src/__tests__/reading-interface-product-parity.test.ts', + '--runInBand', + '--forceExit', + ]], + ]; + + for (const [command, args] of commands) { + try { + run(root, command, args); + } catch (error) { + failures.push(`Conversation/Terminal integration smoke failed for ${command} ${args.join(' ')}: ${error.stderr || error.message}`); + return; + } + } +} + +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 === 'V39', `BITCODE_SPEC.txt must remain V39 during V40 gate work. Observed ${pointer || 'empty'}.`); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v40' || /^v40\/gate-(?:6|7|8|9|10|11)-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V40 Gate 6+ work must occur on version/v40 or v40/gate-6..11-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + const requiredFiles = [ + ARTIFACT_PATH, + 'packages/protocol/src/canonical/v40-conversation-terminal-integration.js', + 'packages/protocol/test/v40-conversation-terminal-integration.test.js', + 'scripts/generate-v40-conversation-terminal-integration.mjs', + 'scripts/check-v40-gate6-conversation-terminal-integration.mjs', + 'uapi/tests/conversationTerminalIntegrationCoverage.test.tsx', + 'BITCODE_SPEC_V40.md', + 'BITCODE_SPEC_V40_DELTA.md', + 'BITCODE_SPEC_V40_NOTES.md', + 'BITCODE_SPEC_V40_PARITY_MATRIX.md', + 'SPECIFICATIONS_ROADMAP.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 V40 Gate 6 file: ${relativePath}`); + } + + if (failures.length === 0) { + try { + run(root, 'node', ['scripts/generate-v40-conversation-terminal-integration.mjs', '--check']); + } catch (error) { + failures.push(`V40 Conversation/Terminal integration artifact check failed: ${error.stderr || error.message}`); + } + } + + if (failures.length === 0) { + try { + run(root, 'node', [ + '--test', + '--test-force-exit', + 'packages/protocol/test/v40-conversation-terminal-integration.test.js', + ]); + } catch (error) { + failures.push(`V40 Conversation/Terminal integration protocol test failed: ${error.stderr || error.message}`); + } + } + + if (failures.length === 0 && !args.skipIntegrationTests) { + runIntegrationSmoke(root, failures); + } + + const serializedArtifact = fileExists(root, ARTIFACT_PATH) ? read(root, ARTIFACT_PATH) : ''; + for (const marker of SECRET_MARKERS) { + assertCheck(failures, !serializedArtifact.includes(marker), `V40 Gate 6 artifact must not contain secret marker ${marker}.`); + } + + const artifact = serializedArtifact ? JSON.parse(serializedArtifact) : null; + if (artifact) { + assertCheck(failures, artifact.artifactId === 'v40-conversation-terminal-integration', 'Gate 6 artifactId must match.'); + assertCheck(failures, artifact.schemaId === 'bitcode.v40.conversationTerminalIntegration.v1', 'Gate 6 schemaId must match.'); + assertCheck(failures, artifact.version === 'V40' && artifact.currentTarget === 'V39', 'Gate 6 artifact must bind V40 over active V39.'); + assertCheck(failures, artifact.passed === true, 'Gate 6 artifact must pass.'); + assertCheck( + failures, + artifact.sourceSafetyVerdict === 'source-safe-conversation-terminal-integration-metadata', + 'Gate 6 artifact must declare source-safe Conversation/Terminal integration metadata.', + ); + assertCheck(failures, artifact.coverage.rowCount === 8, 'Gate 6 must cover eight Conversation/Terminal integration rows.'); + assertCheck(failures, artifact.coverage.coveredRowCount === 8, 'Gate 6 Conversation/Terminal integration rows must all be covered.'); + assertCheck(failures, artifact.coverage.missingRowCount === 0, 'Gate 6 must not leave missing Conversation/Terminal integration rows.'); + assertCheck(failures, artifact.coverage.blockedRowCount === 0, 'Gate 6 must not leave blocked Conversation/Terminal integration rows.'); + assertCheck(failures, artifact.coverage.exemptRowCount === 0, 'Gate 6 must not rely on Conversation/Terminal integration exemptions.'); + assertCheck(failures, artifact.coverage.expectedTotals.terminalHandoffWorkflowCount === 6, 'Gate 6 must bind six Terminal handoff workflows.'); + assertCheck(failures, artifact.coverage.expectedTotals.terminalReadingStageCount === 5, 'Gate 6 must bind five enterprise Reading stages.'); + assertCheck(failures, artifact.coverage.expectedTotals.conversationStreamEventKindCount === 7, 'Gate 6 must bind seven Conversation stream event kinds.'); + assertCheck(failures, artifact.coverage.allCriticalSurfacesClosed === true, 'Gate 6 must close all critical Conversation/Terminal integration surfaces.'); + for (const field of [ + 'terminalHandoffRouteCoverageClosed', + 'conversationStreamLogCoverageClosed', + 'conversationRouteApiCoverageClosed', + 'writingSourceSelectorCoverageClosed', + 'terminalReadingStateCoverageClosed', + 'terminalHarnessLogStreamCoverageClosed', + 'terminalAuthorityBoundaryCoverageClosed', + 'rehearsalDocsParityCoverageClosed', + ]) { + assertCheck(failures, artifact.coverage[field] === true, `Gate 6 must set ${field}.`); + } + assertCheck(failures, artifact.coverage.promptContentRewriteDeferredToV41 === true, 'Gate 6 must defer prompt rewriting to V41.'); + assertCheck(failures, artifact.coverage.sourceSafeMetadataOnly === true, 'Gate 6 artifact must stay source-safe metadata only.'); + assertCheck(failures, artifact.coverage.protectedSourceVisible === false, 'Gate 6 artifact must not expose protected source.'); + assertCheck(failures, artifact.coverage.unpaidAssetPackSourceVisible === false, 'Gate 6 artifact must not expose unpaid AssetPack source.'); + assertCheck(failures, artifact.coverage.valueBearingMainnetRequired === false, 'Gate 6 must not require value-bearing mainnet.'); + assertCheck(failures, Array.isArray(artifact.coverage.failedPredicateIds) && artifact.coverage.failedPredicateIds.length === 0, 'Gate 6 predicates must all pass.'); + } + + const spec = read(root, 'BITCODE_SPEC_V40.md'); + const delta = read(root, 'BITCODE_SPEC_V40_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V40_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V40_PARITY_MATRIX.md'); + const roadmap = read(root, 'SPECIFICATIONS_ROADMAP.md'); + + assertCheck(failures, spec.includes('V40 Gate 6 Conversation And Terminal Integration Coverage'), 'V40 spec must document Gate 6 Conversation and Terminal integration coverage.'); + assertCheck(failures, delta.includes('Gate 6 closes with package-backed `V40ConversationTerminalIntegration`'), 'V40 delta must document Gate 6 closure.'); + assertCheck(failures, notes.includes('Gate 6 implementation notes'), 'V40 notes must document Gate 6 implementation notes.'); + assertCheck(failures, parity.includes('v40-conversation-terminal-integration'), 'V40 parity must document Gate 6 artifact.'); + assertCheck(failures, roadmap.includes('V40 Gate 6 closure anchor'), 'Roadmap must include V40 Gate 6 closure anchor.'); + + if (failures.length > 0) { + process.stderr.write(`V40 Gate 6 Conversation and Terminal integration check failed:\n- ${failures.join('\n- ')}\n`); + process.exitCode = 1; + return; + } + + process.stdout.write(`V40 Gate 6 Conversation and Terminal integration ok artifact=${artifact.artifactRoot}\n`); +} + +main(); diff --git a/scripts/generate-v40-conversation-terminal-integration.mjs b/scripts/generate-v40-conversation-terminal-integration.mjs new file mode 100644 index 000000000..8252ce838 --- /dev/null +++ b/scripts/generate-v40-conversation-terminal-integration.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 { + V40_CONVERSATION_TERMINAL_INTEGRATION_ARTIFACT_PATH, + buildV40ConversationTerminalIntegration, +} from '../packages/protocol/src/canonical/v40-conversation-terminal-integration.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 = buildV40ConversationTerminalIntegration({ repoRoot }); +const serialized = `${JSON.stringify(artifact, null, 2)}\n`; +const artifactPath = path.join(repoRoot, V40_CONVERSATION_TERMINAL_INTEGRATION_ARTIFACT_PATH); + +if (check) { + const current = readFileSync(artifactPath, 'utf8'); + if (current !== serialized) { + process.stderr.write( + `${V40_CONVERSATION_TERMINAL_INTEGRATION_ARTIFACT_PATH} is stale. Run pnpm run generate:v40-conversation-terminal-integration.\n`, + ); + process.exitCode = 1; + } +} else { + writeFileSync(artifactPath, serialized); + process.stdout.write(`wrote ${V40_CONVERSATION_TERMINAL_INTEGRATION_ARTIFACT_PATH}\n`); +} diff --git a/uapi/jest.config.cjs b/uapi/jest.config.cjs index e222a89fb..c9c0c6aa6 100644 --- a/uapi/jest.config.cjs +++ b/uapi/jest.config.cjs @@ -149,6 +149,7 @@ module.exports = { '/tests/terminalProtocolProjection.test.ts', '/tests/terminalInterfaceIntegrationRegression.test.ts', '/tests/conversationStreamPipelineLog.test.tsx', + '/tests/conversationTerminalIntegrationCoverage.test.tsx', '/tests/readingOperationalTelemetryPipelineLog.test.tsx', '/tests/conversationTerminalHandoff.test.tsx', '/tests/conversationPersistencePrivacyPanel.test.tsx', diff --git a/uapi/tests/conversationTerminalIntegrationCoverage.test.tsx b/uapi/tests/conversationTerminalIntegrationCoverage.test.tsx new file mode 100644 index 000000000..c7a1ec521 --- /dev/null +++ b/uapi/tests/conversationTerminalIntegrationCoverage.test.tsx @@ -0,0 +1,131 @@ +import { + buildConversationStreamEvent, + buildConversationPipelineLogEvent, +} from '@bitcode/api/conversations'; + +import { + buildConversationTerminalHandoffEnvelope, +} from '@/app/conversations/conversation-terminal-handoff'; +import { + assertTerminalEnterpriseReadingUxStateSourceSafe, + buildTerminalEnterpriseReadingUxState, +} from '@/app/terminal/terminal-enterprise-reading-ux-state'; +import { + buildTerminalReadFitsFindingSynthesisHarnessStreamSnapshot, +} from '@/app/terminal/terminal-pipeline-harness-client'; +import { + readTerminalConversationHandoffContext, + readTerminalTransactionDetailSection, +} from '@/app/terminal/terminal-transaction-query'; + +describe('Conversation and Terminal integration coverage', () => { + it('carries a source-safe Conversation handoff into Terminal Reading state and rich logs', () => { + const handoff = buildConversationTerminalHandoffEnvelope({ + conversationId: 'conversation-gate-6', + transactionId: 'transaction-gate-6', + workflow: 'finding_fits', + repositoryAnchor: 'engineeredsoftware/ENGI', + sourceSafeSummary: 'Request Finding Fits for the accepted Read-Need.', + }); + const terminalUrl = new URL(handoff.terminalRoute, 'https://www.bitcode.exchange'); + const terminalContext = readTerminalConversationHandoffContext(terminalUrl.searchParams); + + expect(handoff.metadata.disclosureClass).toBe('source_safe_conversation_terminal_handoff'); + expect(handoff.metadata.protectedSourceVisible).toBe(false); + expect(handoff.metadata.unpaidAssetPackSourceVisible).toBe(false); + expect(handoff.metadata.ledgerAuthorityClaimed).toBe(false); + expect(handoff.metadata.terminalEnterpriseReadingStage).toBe('request-fit'); + expect(readTerminalTransactionDetailSection(terminalUrl.searchParams)).toBe('activity'); + expect(terminalContext).toMatchObject({ + present: true, + conversationId: 'conversation-gate-6', + workflow: 'finding_fits', + policy: 'allowed', + repositoryAnchor: 'engineeredsoftware/ENGI', + readingStage: 'request-fit', + }); + + const readingState = buildTerminalEnterpriseReadingUxState({ + hasRepositorySource: true, + hasReadMeasurement: true, + hasSynthesizedNeed: true, + hasAcceptedNeed: true, + findingFitsRunning: true, + }); + expect(readingState.activeStepId).toBe('request-fit'); + expect(assertTerminalEnterpriseReadingUxStateSourceSafe(readingState)).toEqual({ + admitted: true, + reason: 'source_safe_enterprise_reading_ux_metadata', + }); + + const conversationEvent = buildConversationStreamEvent({ + eventKind: 'tool_call', + legacySseType: 'pipeline_event', + runId: 'run-gate-6', + conversationId: 'conversation-gate-6', + sequence: 4, + collapsedStatus: 'Conversation prepared Terminal Finding Fits handoff', + metadata: { + terminalRoute: handoff.terminalRoute, + readingStage: terminalContext.readingStage, + rawPrompt: 'must not serialize', + sourceContent: 'must not serialize', + }, + }); + const pipelineLogEvent = buildConversationPipelineLogEvent(conversationEvent); + + expect(pipelineLogEvent.status.executionState).toMatchObject({ + pipeline: 'ConversationStream', + phase: 'tooling', + agent: 'ConversationStreamEvent', + step: 'try', + tool: 'conversation-stream-router', + outputSchema: 'ConversationStreamEvent:tool_call', + }); + expect(pipelineLogEvent.status.metadata.redactionPosture).toMatchObject({ + protectedSourceVisible: false, + unpaidAssetPackSourceVisible: false, + rawModelResponseVisible: false, + globalLedgerAuthorityClaimed: false, + }); + expect(JSON.stringify(pipelineLogEvent.status.metadata.expandedMetadata)).not.toContain('must not serialize'); + + const harnessSnapshot = buildTerminalReadFitsFindingSynthesisHarnessStreamSnapshot( + [ + { + event: 'harness-event', + data: { + type: 'telemetry-artifact-event', + lineNumber: 1, + telemetryEvent: { + runId: 'run-gate-6', + namespace: 'conversation.terminal_handoff', + stage: 'request-fit', + streamEventType: 'tool_call', + executionState: pipelineLogEvent.status.executionState, + readingPipelineTelemetry: { + pipelineName: 'ReadFitsFindingSynthesis', + phaseId: 'discovery', + ptrrStepId: 'try', + thricifiedGenerationId: 'conversation-terminal-handoff-tool-call', + outputSchema: 'ConversationStreamEvent:tool_call', + }, + dataKeys: ['eventId', 'proofRoots', 'readingStage'], + }, + }, + }, + ], + 'running', + ); + + expect(harnessSnapshot.output).toContain('pipeline ReadFitsFindingSynthesis'); + expect(harnessSnapshot.output).toContain('PTRR try'); + expect(harnessSnapshot.outputDetails[harnessSnapshot.output]).toBeDefined(); + expect(harnessSnapshot.executionState).toMatchObject({ + pipeline: 'ReadFitsFindingSynthesis', + phase: 'Setup', + agent: 'ConversationStreamEvent', + }); + expect(JSON.stringify(harnessSnapshot)).not.toContain('must not serialize'); + }); +});