create-principles-disciple 1.121.7 → 1.121.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/console/dist/server/config/pd-config-store.d.ts +1 -3
- package/console/dist/server/config/pd-config-store.js +4 -4
- package/console/dist/server/feedback/channels.d.ts +2 -8
- package/console/dist/server/feedback/channels.js +0 -11
- package/console/dist/server/index.js +34 -5
- package/console/dist/server/models/ActivationsConsoleModel.d.ts +28 -1
- package/console/dist/server/models/ActivationsConsoleModel.js +72 -30
- package/console/dist/server/models/GovernanceExperienceCollector.d.ts +28 -0
- package/console/dist/server/models/GovernanceExperienceCollector.js +305 -0
- package/console/dist/server/models/GovernanceProjectionCollector.d.ts +60 -2
- package/console/dist/server/models/GovernanceProjectionCollector.js +323 -285
- package/console/dist/server/models/PrincipleClassifier.d.ts +1 -1
- package/console/dist/server/models/PrincipleClassifier.js +7 -4
- package/console/dist/server/models/PrinciplesConsoleModel.d.ts +2 -1
- package/console/dist/server/models/ReceiptsConsoleModel.d.ts +5 -0
- package/console/dist/server/models/ReceiptsConsoleModel.js +140 -13
- package/console/dist/server/routes/activations.js +1 -1
- package/console/dist/server/routes/failed-tasks.js +28 -11
- package/console/dist/server/routes/governance.d.ts +26 -0
- package/console/dist/server/routes/governance.js +51 -0
- package/console/dist/server/routes/owner-identity.d.ts +31 -0
- package/console/dist/server/routes/owner-identity.js +76 -0
- package/console/dist/server/routes/update-history.d.ts +5 -0
- package/console/dist/server/routes/update-history.js +50 -4
- package/console/dist/server/routes/update.js +186 -32
- package/console/dist/shared/feedback-channel-ids.d.ts +13 -0
- package/console/dist/shared/feedback-channel-ids.js +12 -0
- package/console/dist/shared/feedback-contract.d.ts +46 -0
- package/console/dist/shared/feedback-contract.js +45 -0
- package/console/dist/ui/App.js +1 -1
- package/console/dist/ui/api.d.ts +22 -3
- package/console/dist/ui/api.js +63 -3
- package/console/dist/ui/components/receipts/ReceiptCoverageDisclosure.d.ts +6 -0
- package/console/dist/ui/components/receipts/ReceiptCoverageDisclosure.js +66 -0
- package/console/dist/ui/i18n/en.json +198 -2
- package/console/dist/ui/i18n/zh-CN.json +196 -0
- package/console/dist/ui/pages/activation/ActivationPage.js +14 -2
- package/console/dist/ui/pages/failed-tasks/FailedTasksPage.js +25 -5
- package/console/dist/ui/pages/focus/FocusPage.d.ts +28 -1
- package/console/dist/ui/pages/focus/FocusPage.js +128 -15
- package/console/dist/ui/pages/principles/PrincipleDetailPage.d.ts +30 -0
- package/console/dist/ui/pages/principles/PrincipleDetailPage.js +49 -6
- package/console/dist/ui/pages/settings/SettingsPage.js +67 -2
- package/console/dist/ui/pages/settings/UpdatePage.js +7 -7
- package/console/dist/ui/utils/enum-labels.js +0 -1
- package/console/dist/ui/utils/validators.d.ts +53 -21
- package/console/dist/ui/utils/validators.js +248 -21
- package/console/dist/web/assets/app.css +6 -0
- package/console/dist/web/assets/app.js +2721 -1664
- package/console/package.json +4 -2
- package/core/dist/host/host-adapter.d.ts +1 -1
- package/core/dist/host/host-adapter.d.ts.map +1 -1
- package/core/dist/host/host-adapter.js +1 -0
- package/core/dist/host/host-adapter.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +12 -2
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/attack-e2e-pipeline-smoke.test.js +1 -1
- package/core/dist/runtime-v2/__tests__/attack-e2e-pipeline-smoke.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/governance-experience.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/governance-experience.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/governance-experience.test.js +300 -0
- package/core/dist/runtime-v2/__tests__/governance-experience.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/owner-identity.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/owner-identity.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/owner-identity.test.js +147 -0
- package/core/dist/runtime-v2/__tests__/owner-identity.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/product-telemetry-contract.test.d.ts +18 -0
- package/core/dist/runtime-v2/__tests__/product-telemetry-contract.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/product-telemetry-contract.test.js +303 -0
- package/core/dist/runtime-v2/__tests__/product-telemetry-contract.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/recovery-actions-log.test.js +40 -0
- package/core/dist/runtime-v2/__tests__/recovery-actions-log.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/status-contract.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/status-contract.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/status-contract.test.js +107 -0
- package/core/dist/runtime-v2/__tests__/status-contract.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-evidence-snapshot.test.d.ts +2 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-evidence-snapshot.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-evidence-snapshot.test.js +104 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-evidence-snapshot.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.js +19 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.js +20 -0
- package/core/dist/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.js +40 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/index.d.ts +2 -0
- package/core/dist/runtime-v2/activation/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/index.js +1 -0
- package/core/dist/runtime-v2/activation/index.js.map +1 -1
- package/core/dist/runtime-v2/activation/promotion-evidence-snapshot.d.ts +30 -0
- package/core/dist/runtime-v2/activation/promotion-evidence-snapshot.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/promotion-evidence-snapshot.js +87 -0
- package/core/dist/runtime-v2/activation/promotion-evidence-snapshot.js.map +1 -0
- package/core/dist/runtime-v2/activation/promotion-readiness-evaluator.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/promotion-readiness-evaluator.js +3 -0
- package/core/dist/runtime-v2/activation/promotion-readiness-evaluator.js.map +1 -1
- package/core/dist/runtime-v2/activation/promotion-readiness-reader.d.ts +1 -1
- package/core/dist/runtime-v2/activation/promotion-readiness-reader.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/promotion-readiness-reader.js +2 -2
- package/core/dist/runtime-v2/activation/promotion-readiness-reader.js.map +1 -1
- package/core/dist/runtime-v2/activation/rulecode-owner-decision-service.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/rulecode-owner-decision-service.js +18 -9
- package/core/dist/runtime-v2/activation/rulecode-owner-decision-service.js.map +1 -1
- package/core/dist/runtime-v2/adapter/__tests__/chaos-json-repair.test.js +1 -1
- package/core/dist/runtime-v2/adapter/__tests__/chaos-json-repair.test.js.map +1 -1
- package/core/dist/runtime-v2/adapter/__tests__/json-extractor.test.js +91 -1
- package/core/dist/runtime-v2/adapter/__tests__/json-extractor.test.js.map +1 -1
- package/core/dist/runtime-v2/adapter/__tests__/pi-ai-runtime-adapter.test.js +59 -12
- package/core/dist/runtime-v2/adapter/__tests__/pi-ai-runtime-adapter.test.js.map +1 -1
- package/core/dist/runtime-v2/adapter/__tests__/runtime-config-contract.test.js +10 -9
- package/core/dist/runtime-v2/adapter/__tests__/runtime-config-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/adapter/__tests__/structured-output-repair.test.js +42 -1
- package/core/dist/runtime-v2/adapter/__tests__/structured-output-repair.test.js.map +1 -1
- package/core/dist/runtime-v2/adapter/json-extractor.d.ts +25 -0
- package/core/dist/runtime-v2/adapter/json-extractor.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/json-extractor.js +126 -0
- package/core/dist/runtime-v2/adapter/json-extractor.js.map +1 -1
- package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.d.ts +9 -4
- package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.js +9 -4
- package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.js.map +1 -1
- package/core/dist/runtime-v2/adapter/output-repair-contract.d.ts +5 -1
- package/core/dist/runtime-v2/adapter/output-repair-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/output-repair-contract.js +4 -1
- package/core/dist/runtime-v2/adapter/output-repair-contract.js.map +1 -1
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.d.ts +7 -0
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.d.ts.map +1 -0
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.js +19 -0
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.js.map +1 -0
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts +13 -15
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js +104 -37
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js.map +1 -1
- package/core/dist/runtime-v2/adapter/structured-output-repair.d.ts +16 -1
- package/core/dist/runtime-v2/adapter/structured-output-repair.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/structured-output-repair.js +38 -6
- package/core/dist/runtime-v2/adapter/structured-output-repair.js.map +1 -1
- package/core/dist/runtime-v2/adapter/tools/diagnostician-tool.d.ts +1 -1
- package/core/dist/runtime-v2/adapter/tools/diagnostician-tool.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/pd-config-agent-binding.test.js +8 -9
- package/core/dist/runtime-v2/config/__tests__/pd-config-agent-binding.test.js.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js +27 -3
- package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/pd-config-principles.test.d.ts +11 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-principles.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-principles.test.js +93 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-principles.test.js.map +1 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-workspace.test.js +41 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-workspace.test.js.map +1 -1
- package/core/dist/runtime-v2/config/index.d.ts +2 -2
- package/core/dist/runtime-v2/config/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/index.js +2 -0
- package/core/dist/runtime-v2/config/index.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-agent-binding.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-agent-binding.js +4 -13
- package/core/dist/runtime-v2/config/pd-config-agent-binding.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-effective.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-effective.js +14 -7
- package/core/dist/runtime-v2/config/pd-config-effective.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-feature-flags.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-feature-flags.js +5 -12
- package/core/dist/runtime-v2/config/pd-config-feature-flags.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-types.d.ts +8 -0
- package/core/dist/runtime-v2/config/pd-config-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-types.js +2 -0
- package/core/dist/runtime-v2/config/pd-config-types.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-validate.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-validate.js +48 -3
- package/core/dist/runtime-v2/config/pd-config-validate.js.map +1 -1
- package/core/dist/runtime-v2/core-principles/__tests__/core-axiom-block.test.js +36 -8
- package/core/dist/runtime-v2/core-principles/__tests__/core-axiom-block.test.js.map +1 -1
- package/core/dist/runtime-v2/core-principles/__tests__/core-principle-registry.test.js +36 -12
- package/core/dist/runtime-v2/core-principles/__tests__/core-principle-registry.test.js.map +1 -1
- package/core/dist/runtime-v2/core-principles/core-axiom-block.d.ts +22 -8
- package/core/dist/runtime-v2/core-principles/core-axiom-block.d.ts.map +1 -1
- package/core/dist/runtime-v2/core-principles/core-axiom-block.js +28 -13
- package/core/dist/runtime-v2/core-principles/core-axiom-block.js.map +1 -1
- package/core/dist/runtime-v2/core-principles/core-principle-registry.d.ts +29 -4
- package/core/dist/runtime-v2/core-principles/core-principle-registry.d.ts.map +1 -1
- package/core/dist/runtime-v2/core-principles/core-principle-registry.js +68 -33
- package/core/dist/runtime-v2/core-principles/core-principle-registry.js.map +1 -1
- package/core/dist/runtime-v2/core-principles/index.d.ts +3 -3
- package/core/dist/runtime-v2/core-principles/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/core-principles/index.js +1 -1
- package/core/dist/runtime-v2/core-principles/index.js.map +1 -1
- package/core/dist/runtime-v2/evolution/evolution-types.d.ts +2 -1
- package/core/dist/runtime-v2/evolution/evolution-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/evolution/evolution-types.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/__tests__/anonymous-product-telemetry-flag.test.d.ts +2 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/anonymous-product-telemetry-flag.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/anonymous-product-telemetry-flag.test.js +48 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/anonymous-product-telemetry-flag.test.js.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/codex-conversation-ingestion-flag.test.d.ts +2 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/codex-conversation-ingestion-flag.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/codex-conversation-ingestion-flag.test.js +46 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/codex-conversation-ingestion-flag.test.js.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +86 -31
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-lifecycle.test.d.ts +2 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-lifecycle.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-lifecycle.test.js +83 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-lifecycle.test.js.map +1 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts +19 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js +128 -10
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.d.ts +37 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.d.ts.map +1 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js +304 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js.map +1 -0
- package/core/dist/runtime-v2/feature-flags/index.d.ts +4 -2
- package/core/dist/runtime-v2/feature-flags/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/index.js +3 -1
- package/core/dist/runtime-v2/feature-flags/index.js.map +1 -1
- package/core/dist/runtime-v2/governance-experience-contract.d.ts +468 -0
- package/core/dist/runtime-v2/governance-experience-contract.d.ts.map +1 -0
- package/core/dist/runtime-v2/governance-experience-contract.js +208 -0
- package/core/dist/runtime-v2/governance-experience-contract.js.map +1 -0
- package/core/dist/runtime-v2/governance-experience.d.ts +11 -0
- package/core/dist/runtime-v2/governance-experience.d.ts.map +1 -0
- package/core/dist/runtime-v2/governance-experience.js +276 -0
- package/core/dist/runtime-v2/governance-experience.js.map +1 -0
- package/core/dist/runtime-v2/index.d.ts +20 -8
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +20 -6
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/artificer-output-retry-flag.test.js +29 -10
- package/core/dist/runtime-v2/internalization/__tests__/artificer-output-retry-flag.test.js.map +1 -1
- package/core/dist/runtime-v2/owner-identity.d.ts +69 -0
- package/core/dist/runtime-v2/owner-identity.d.ts.map +1 -0
- package/core/dist/runtime-v2/owner-identity.js +179 -0
- package/core/dist/runtime-v2/owner-identity.js.map +1 -0
- package/core/dist/runtime-v2/pain-signal-runtime-factory.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-signal-runtime-factory.js +2 -3
- package/core/dist/runtime-v2/pain-signal-runtime-factory.js.map +1 -1
- package/core/dist/runtime-v2/product-telemetry/daily-identity.d.ts +70 -0
- package/core/dist/runtime-v2/product-telemetry/daily-identity.d.ts.map +1 -0
- package/core/dist/runtime-v2/product-telemetry/daily-identity.js +89 -0
- package/core/dist/runtime-v2/product-telemetry/daily-identity.js.map +1 -0
- package/core/dist/runtime-v2/product-telemetry/snapshot-contract.d.ts +110 -0
- package/core/dist/runtime-v2/product-telemetry/snapshot-contract.d.ts.map +1 -0
- package/core/dist/runtime-v2/product-telemetry/snapshot-contract.js +250 -0
- package/core/dist/runtime-v2/product-telemetry/snapshot-contract.js.map +1 -0
- package/core/dist/runtime-v2/pruning-read-model.d.ts +2 -1
- package/core/dist/runtime-v2/pruning-read-model.d.ts.map +1 -1
- package/core/dist/runtime-v2/pruning-read-model.js.map +1 -1
- package/core/dist/runtime-v2/receipt-coverage.d.ts +63 -0
- package/core/dist/runtime-v2/receipt-coverage.d.ts.map +1 -0
- package/core/dist/runtime-v2/receipt-coverage.js +19 -0
- package/core/dist/runtime-v2/receipt-coverage.js.map +1 -0
- package/core/dist/runtime-v2/recovery-actions-log.d.ts +7 -0
- package/core/dist/runtime-v2/recovery-actions-log.d.ts.map +1 -1
- package/core/dist/runtime-v2/recovery-actions-log.js +6 -0
- package/core/dist/runtime-v2/recovery-actions-log.js.map +1 -1
- package/core/dist/runtime-v2/runtime-protocol.js +1 -1
- package/core/dist/runtime-v2/runtime-protocol.js.map +1 -1
- package/core/dist/runtime-v2/store/task/__tests__/sqlite-task-store.failed-tasks.test.js +17 -1
- package/core/dist/runtime-v2/store/task/__tests__/sqlite-task-store.failed-tasks.test.js.map +1 -1
- package/core/dist/runtime-v2/store/task/sqlite-task-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/task/sqlite-task-store.js +10 -0
- package/core/dist/runtime-v2/store/task/sqlite-task-store.js.map +1 -1
- package/core/dist/runtime-v2/store/task/task-types.d.ts +2 -0
- package/core/dist/runtime-v2/store/task/task-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/task-status.d.ts +9 -5
- package/core/dist/runtime-v2/task-status.d.ts.map +1 -1
- package/core/dist/runtime-v2/task-status.js +15 -7
- package/core/dist/runtime-v2/task-status.js.map +1 -1
- package/core/dist/runtime-v2/types/event-types.d.ts +4 -0
- package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/event-types.js.map +1 -1
- package/core/dist/runtime-v2/types/index.d.ts +1 -1
- package/core/dist/runtime-v2/types/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/index.js +1 -1
- package/core/dist/runtime-v2/types/index.js.map +1 -1
- package/core/dist/runtime-v2/types/principle-enums.d.ts +3 -2
- package/core/dist/runtime-v2/types/principle-enums.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/principle-enums.js +11 -5
- package/core/dist/runtime-v2/types/principle-enums.js.map +1 -1
- package/core/dist/runtime-v2/types/principle-schema.d.ts +1 -1
- package/core/dist/runtime-v2/types/principle-tree-store.d.ts +1 -1
- package/core/dist/runtime-v2/utils/cli-process-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/utils/cli-process-runner.js +3 -2
- package/core/dist/runtime-v2/utils/cli-process-runner.js.map +1 -1
- package/core/package.json +4 -5
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +4 -2
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +47 -11
- package/dist/index.js.map +1 -1
- package/dist/installer.d.ts +31 -5
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +472 -161
- package/dist/installer.js.map +1 -1
- package/dist/installers/codex-host-installer.d.ts.map +1 -1
- package/dist/installers/codex-host-installer.js +4 -0
- package/dist/installers/codex-host-installer.js.map +1 -1
- package/dist/mvp-config.d.ts +10 -0
- package/dist/mvp-config.d.ts.map +1 -1
- package/dist/mvp-config.js +30 -3
- package/dist/mvp-config.js.map +1 -1
- package/dist/uninstaller.d.ts +9 -1
- package/dist/uninstaller.d.ts.map +1 -1
- package/dist/uninstaller.js +103 -23
- package/dist/uninstaller.js.map +1 -1
- package/dist/update/atomic-file.d.ts +35 -0
- package/dist/update/atomic-file.d.ts.map +1 -0
- package/dist/update/atomic-file.js +120 -0
- package/dist/update/atomic-file.js.map +1 -0
- package/dist/update/bootstrap-protocol.d.ts +55 -0
- package/dist/update/bootstrap-protocol.d.ts.map +1 -0
- package/dist/update/bootstrap-protocol.js +132 -0
- package/dist/update/bootstrap-protocol.js.map +1 -0
- package/dist/update/channel-metadata.d.ts +28 -0
- package/dist/update/channel-metadata.d.ts.map +1 -0
- package/dist/update/channel-metadata.js +90 -0
- package/dist/update/channel-metadata.js.map +1 -0
- package/dist/update/channel-promotion.d.ts +39 -0
- package/dist/update/channel-promotion.d.ts.map +1 -0
- package/dist/update/channel-promotion.js +55 -0
- package/dist/update/channel-promotion.js.map +1 -0
- package/dist/update/data-compatibility.d.ts +35 -0
- package/dist/update/data-compatibility.d.ts.map +1 -0
- package/dist/update/data-compatibility.js +45 -0
- package/dist/update/data-compatibility.js.map +1 -0
- package/dist/update/install-layout.d.ts +59 -0
- package/dist/update/install-layout.d.ts.map +1 -0
- package/dist/update/install-layout.js +127 -0
- package/dist/update/install-layout.js.map +1 -0
- package/dist/update/legacy-migration.d.ts +56 -0
- package/dist/update/legacy-migration.d.ts.map +1 -0
- package/dist/update/legacy-migration.js +254 -0
- package/dist/update/legacy-migration.js.map +1 -0
- package/dist/update/product-identity.d.ts +50 -0
- package/dist/update/product-identity.d.ts.map +1 -0
- package/dist/update/product-identity.js +63 -0
- package/dist/update/product-identity.js.map +1 -0
- package/dist/update/release-asset-manifest.d.ts +31 -0
- package/dist/update/release-asset-manifest.d.ts.map +1 -0
- package/dist/update/release-asset-manifest.js +161 -0
- package/dist/update/release-asset-manifest.js.map +1 -0
- package/dist/update/release-identity.d.ts +33 -0
- package/dist/update/release-identity.d.ts.map +1 -0
- package/dist/update/release-identity.js +108 -0
- package/dist/update/release-identity.js.map +1 -0
- package/dist/update/release-manager.d.ts +96 -0
- package/dist/update/release-manager.d.ts.map +1 -0
- package/dist/update/release-manager.js +253 -0
- package/dist/update/release-manager.js.map +1 -0
- package/dist/update/release-metadata.d.ts +57 -0
- package/dist/update/release-metadata.d.ts.map +1 -0
- package/dist/update/release-metadata.js +200 -0
- package/dist/update/release-metadata.js.map +1 -0
- package/dist/update/release-policy.d.ts +51 -0
- package/dist/update/release-policy.d.ts.map +1 -0
- package/dist/update/release-policy.js +103 -0
- package/dist/update/release-policy.js.map +1 -0
- package/dist/update/rollback-policy.d.ts +56 -0
- package/dist/update/rollback-policy.d.ts.map +1 -0
- package/dist/update/rollback-policy.js +61 -0
- package/dist/update/rollback-policy.js.map +1 -0
- package/dist/update/transaction-journal.d.ts +121 -0
- package/dist/update/transaction-journal.d.ts.map +1 -0
- package/dist/update/transaction-journal.js +333 -0
- package/dist/update/transaction-journal.js.map +1 -0
- package/dist/update/trust-metadata.d.ts +55 -0
- package/dist/update/trust-metadata.d.ts.map +1 -0
- package/dist/update/trust-metadata.js +170 -0
- package/dist/update/trust-metadata.js.map +1 -0
- package/dist/update/update-history.d.ts +46 -0
- package/dist/update/update-history.d.ts.map +1 -0
- package/dist/update/update-history.js +123 -0
- package/dist/update/update-history.js.map +1 -0
- package/dist/utils/env.d.ts +7 -0
- package/dist/utils/env.d.ts.map +1 -1
- package/dist/utils/env.js +134 -44
- package/dist/utils/env.js.map +1 -1
- package/host-runtime/dist/governance-observation-store.d.ts +172 -0
- package/host-runtime/dist/governance-observation-store.js +649 -0
- package/host-runtime/dist/index.d.ts +6 -0
- package/host-runtime/dist/index.js +8 -0
- package/host-runtime/dist/product-telemetry/consent-store.d.ts +107 -0
- package/host-runtime/dist/product-telemetry/consent-store.js +329 -0
- package/host-runtime/dist/product-telemetry/eligibility.d.ts +53 -0
- package/host-runtime/dist/product-telemetry/eligibility.js +69 -0
- package/host-runtime/dist/product-telemetry/exporter.d.ts +46 -0
- package/host-runtime/dist/product-telemetry/exporter.js +71 -0
- package/host-runtime/dist/product-telemetry/milestone-readers.d.ts +61 -0
- package/host-runtime/dist/product-telemetry/milestone-readers.js +234 -0
- package/host-runtime/dist/product-telemetry/service.d.ts +142 -0
- package/host-runtime/dist/product-telemetry/service.js +532 -0
- package/host-runtime/dist/product-telemetry/workspace-scope.d.ts +38 -0
- package/host-runtime/dist/product-telemetry/workspace-scope.js +64 -0
- package/host-runtime/package.json +7 -2
- package/install-layout/dist/index.d.ts +48 -0
- package/install-layout/dist/index.js +81 -0
- package/install-layout/dist/index.test.d.ts +1 -0
- package/install-layout/dist/index.test.js +34 -0
- package/install-layout/package.json +33 -0
- package/package.json +16 -6
- package/pd-cli/dist/commands/__tests__/telemetry-flag-wiring.test.d.ts +9 -0
- package/pd-cli/dist/commands/__tests__/telemetry-flag-wiring.test.d.ts.map +1 -0
- package/pd-cli/dist/commands/__tests__/telemetry-flag-wiring.test.js +76 -0
- package/pd-cli/dist/commands/__tests__/telemetry-flag-wiring.test.js.map +1 -0
- package/pd-cli/dist/commands/__tests__/version.test.d.ts +2 -0
- package/pd-cli/dist/commands/__tests__/version.test.d.ts.map +1 -0
- package/pd-cli/dist/commands/__tests__/version.test.js +134 -0
- package/pd-cli/dist/commands/__tests__/version.test.js.map +1 -0
- package/pd-cli/dist/commands/console.d.ts.map +1 -1
- package/pd-cli/dist/commands/console.js +29 -10
- package/pd-cli/dist/commands/console.js.map +1 -1
- package/pd-cli/dist/commands/pain-record.d.ts.map +1 -1
- package/pd-cli/dist/commands/pain-record.js +6 -15
- package/pd-cli/dist/commands/pain-record.js.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.d.ts +29 -0
- package/pd-cli/dist/commands/runtime-activation.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.js +70 -31
- package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-enqueue-successors.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-enqueue-successors.js +2 -2
- package/pd-cli/dist/commands/runtime-internalization-enqueue-successors.js.map +1 -1
- package/pd-cli/dist/commands/telemetry.d.ts +82 -0
- package/pd-cli/dist/commands/telemetry.d.ts.map +1 -0
- package/pd-cli/dist/commands/telemetry.js +268 -0
- package/pd-cli/dist/commands/telemetry.js.map +1 -0
- package/pd-cli/dist/commands/version.d.ts +11 -0
- package/pd-cli/dist/commands/version.d.ts.map +1 -0
- package/pd-cli/dist/commands/version.js +48 -0
- package/pd-cli/dist/commands/version.js.map +1 -0
- package/pd-cli/dist/index.js +35 -2
- package/pd-cli/dist/index.js.map +1 -1
- package/pd-cli/dist/services/version-report.d.ts +44 -0
- package/pd-cli/dist/services/version-report.d.ts.map +1 -0
- package/pd-cli/dist/services/version-report.js +152 -0
- package/pd-cli/dist/services/version-report.js.map +1 -0
- package/pd-cli/package.json +3 -2
- package/plugin/dist/bundle.js +870 -932
- package/plugin/dist/core/init.d.ts +2 -1
- package/plugin/dist/core/principle-application-ledger.d.ts +10 -0
- package/plugin/dist/core/product-telemetry-trigger.d.ts +14 -0
- package/plugin/dist/core/thinking-os-parser.d.ts +5 -2
- package/plugin/dist/governance-audit.js +386 -0
- package/plugin/dist/hooks/gate-block-helper.d.ts +25 -1
- package/plugin/dist/hooks/gate.d.ts +22 -0
- package/plugin/dist/openclaw.plugin.json +1 -1
- package/plugin/dist/rulehost-evidence.js +832 -0
- package/plugin/dist/templates/langs/en/principles/THINKING_OS.md +53 -45
- package/plugin/dist/templates/langs/en/skills/pd-mentor/SKILL.md +1 -1
- package/plugin/dist/templates/langs/zh/principles/THINKING_OS.md +62 -46
- package/plugin/dist/templates/langs/zh/skills/pd-mentor/SKILL.md +1 -1
- package/plugin/dist/templates/workspace/.principles/THINKING_OS.md +66 -38
- package/plugin/openclaw.plugin.json +1 -1
- package/plugin/package.json +1 -1
- package/plugin/templates/langs/en/principles/THINKING_OS.md +53 -45
- package/plugin/templates/langs/en/skills/pd-mentor/SKILL.md +1 -1
- package/plugin/templates/langs/zh/principles/THINKING_OS.md +62 -46
- package/plugin/templates/langs/zh/skills/pd-mentor/SKILL.md +1 -1
- package/plugin/templates/workspace/.principles/THINKING_OS.md +66 -38
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Governance Observation Store — Codex Governance Closure Slice A (PRI-622).
|
|
3
|
+
*
|
|
4
|
+
* Host-neutral storage seam for bounded Governance Observations, per Codex
|
|
5
|
+
* Governance Closure SPEC rev 2 §6/§7/§10/§11 and the Slice A Implementation
|
|
6
|
+
* SPEC (2026-08-29). The Codex adapter decodes host transcripts and calls
|
|
7
|
+
* {@link ingestGovernanceObservations}; this module owns everything below the
|
|
8
|
+
* seam: sanitization at the persistence boundary, logical/physical identity
|
|
9
|
+
* upsert and convergence, the transcript checkpoint, bounded retention
|
|
10
|
+
* (latest ≤32 visible turns per rollout AND ≤7 days, whichever expires
|
|
11
|
+
* sooner), compaction/rollback tombstones, and the promotion substrate
|
|
12
|
+
* (≤12 preceding turns + trigger + next completed assistant turn with a
|
|
13
|
+
* durable pending tail) that Slice B will drive after pain admission.
|
|
14
|
+
*
|
|
15
|
+
* Slice A creates NO pain identity: promotion accepts a caller-provided
|
|
16
|
+
* pain reference only (SPEC §18).
|
|
17
|
+
*
|
|
18
|
+
* Storage authority: the existing Workspace trajectory store
|
|
19
|
+
* `{workspace}/.state/trajectory.db`. The baseline schema is owned by
|
|
20
|
+
* openclaw-plugin's `applyTrajectorySchema` (mirrored in core's
|
|
21
|
+
* `ensureTrajectorySchema` for the pain tables). The `governance_*` tables
|
|
22
|
+
* below are written and read ONLY by this module, so their DDL lives here —
|
|
23
|
+
* idempotent, versioned by `governance_observation_schema_version`, and
|
|
24
|
+
* additive to any existing trajectory.db (unknown tables are untouched by
|
|
25
|
+
* the other owners). No raw transcript bytes, no second pain authority.
|
|
26
|
+
*/
|
|
27
|
+
import fs from 'node:fs';
|
|
28
|
+
import path from 'node:path';
|
|
29
|
+
import Database from 'better-sqlite3';
|
|
30
|
+
import { sanitizeString, sanitizeValue } from '@principles/core/runtime-v2';
|
|
31
|
+
// ─── Retention policy constants (Owner-approved, SPEC rev 2 §11) ────────────
|
|
32
|
+
export const GOVERNANCE_RETENTION_MAX_TURNS = 32;
|
|
33
|
+
export const GOVERNANCE_RETENTION_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
34
|
+
export const GOVERNANCE_PROMOTION_PRECEDING_TURNS = 12;
|
|
35
|
+
export const GOVERNANCE_PENDING_TAIL_STALE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
36
|
+
const GOVERNANCE_OBSERVATION_SCHEMA_VERSION = 2;
|
|
37
|
+
const MAX_TEXT_BOUND = 200; // matches MAX_EVIDENCE_VALUE_CHARS; guards stored identity fields
|
|
38
|
+
const MAX_JSON_COLUMN = 8_000;
|
|
39
|
+
function isRecord(value) {
|
|
40
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
41
|
+
}
|
|
42
|
+
function own(value, key) {
|
|
43
|
+
return Object.hasOwn(value, key) ? Object.getOwnPropertyDescriptor(value, key)?.value : undefined;
|
|
44
|
+
}
|
|
45
|
+
function boundedString(value, max) {
|
|
46
|
+
if (value === null || value === undefined)
|
|
47
|
+
return null;
|
|
48
|
+
return value.length > max ? value.slice(0, max) : value;
|
|
49
|
+
}
|
|
50
|
+
function safeJson(value) {
|
|
51
|
+
try {
|
|
52
|
+
const text = JSON.stringify(value);
|
|
53
|
+
if (typeof text !== 'string')
|
|
54
|
+
return null;
|
|
55
|
+
if (text.length <= MAX_JSON_COLUMN)
|
|
56
|
+
return text;
|
|
57
|
+
// Truncating a serialized JSON document mid-value yields INVALID JSON.
|
|
58
|
+
// Keep the column bound while staying parseable: store an ESCAPED
|
|
59
|
+
// fragment inside a small wrapper object, shrinking until the wrapper
|
|
60
|
+
// itself fits (escaping can expand the fragment, so verify each round).
|
|
61
|
+
let keep = text.length;
|
|
62
|
+
while (keep > 0) {
|
|
63
|
+
keep = Math.max(0, keep - Math.max(200, Math.floor(keep / 4)));
|
|
64
|
+
const wrapped = JSON.stringify({ truncated: true, preview: text.slice(0, keep) });
|
|
65
|
+
if (wrapped.length <= MAX_JSON_COLUMN)
|
|
66
|
+
return wrapped;
|
|
67
|
+
}
|
|
68
|
+
return '{"truncated":true,"preview":""}';
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const CREATE_STATEMENTS = [
|
|
75
|
+
`CREATE TABLE IF NOT EXISTS governance_observation_schema_version (version INTEGER NOT NULL)`,
|
|
76
|
+
`CREATE TABLE IF NOT EXISTS governance_rollouts (
|
|
77
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
78
|
+
host_kind TEXT NOT NULL,
|
|
79
|
+
rollout_identity TEXT NOT NULL,
|
|
80
|
+
root_session_id TEXT NOT NULL,
|
|
81
|
+
parent_rollout_id TEXT,
|
|
82
|
+
agent_identity TEXT,
|
|
83
|
+
agent_depth INTEGER,
|
|
84
|
+
created_at TEXT NOT NULL,
|
|
85
|
+
updated_at TEXT NOT NULL,
|
|
86
|
+
UNIQUE(host_kind, rollout_identity)
|
|
87
|
+
)`,
|
|
88
|
+
`CREATE TABLE IF NOT EXISTS governance_observations (
|
|
89
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
90
|
+
rollout_row_id INTEGER NOT NULL,
|
|
91
|
+
host_kind TEXT NOT NULL,
|
|
92
|
+
rollout_identity TEXT NOT NULL,
|
|
93
|
+
root_session_id TEXT NOT NULL,
|
|
94
|
+
host_turn_id TEXT NOT NULL,
|
|
95
|
+
kind TEXT NOT NULL,
|
|
96
|
+
logical_key TEXT NOT NULL,
|
|
97
|
+
transcript_record_key TEXT,
|
|
98
|
+
source_order INTEGER,
|
|
99
|
+
source_ordinal INTEGER,
|
|
100
|
+
assistant_item_id TEXT,
|
|
101
|
+
phase TEXT,
|
|
102
|
+
tool_use_id TEXT,
|
|
103
|
+
transcript_tool_call_id TEXT,
|
|
104
|
+
visible_text TEXT,
|
|
105
|
+
sanitized_tool_facts_json TEXT,
|
|
106
|
+
source TEXT NOT NULL,
|
|
107
|
+
completeness TEXT NOT NULL,
|
|
108
|
+
retention_class TEXT NOT NULL DEFAULT 'operational',
|
|
109
|
+
observed_at TEXT NOT NULL,
|
|
110
|
+
promoted_at TEXT,
|
|
111
|
+
promotion_ref TEXT,
|
|
112
|
+
expired_at TEXT,
|
|
113
|
+
UNIQUE(logical_key)
|
|
114
|
+
)`,
|
|
115
|
+
`CREATE INDEX IF NOT EXISTS idx_governance_observations_source_order
|
|
116
|
+
ON governance_observations(rollout_row_id, source_order)`,
|
|
117
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_governance_observations_physical
|
|
118
|
+
ON governance_observations(transcript_record_key) WHERE transcript_record_key IS NOT NULL`,
|
|
119
|
+
`CREATE INDEX IF NOT EXISTS idx_governance_observations_rollout_turn
|
|
120
|
+
ON governance_observations(rollout_row_id, host_turn_id)`,
|
|
121
|
+
`CREATE INDEX IF NOT EXISTS idx_governance_observations_retention
|
|
122
|
+
ON governance_observations(retention_class, observed_at)`,
|
|
123
|
+
`CREATE TABLE IF NOT EXISTS governance_transcript_checkpoints (
|
|
124
|
+
host_kind TEXT NOT NULL,
|
|
125
|
+
rollout_identity TEXT NOT NULL,
|
|
126
|
+
byte_offset INTEGER NOT NULL,
|
|
127
|
+
last_ordinal INTEGER NOT NULL,
|
|
128
|
+
cli_version TEXT,
|
|
129
|
+
root_session_id TEXT NOT NULL,
|
|
130
|
+
incomplete_tail INTEGER NOT NULL DEFAULT 0,
|
|
131
|
+
last_degradation_reason TEXT,
|
|
132
|
+
last_degradation_ordinal INTEGER,
|
|
133
|
+
updated_at TEXT NOT NULL,
|
|
134
|
+
PRIMARY KEY (host_kind, rollout_identity)
|
|
135
|
+
)`,
|
|
136
|
+
`CREATE TABLE IF NOT EXISTS governance_pending_promotion_tails (
|
|
137
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
138
|
+
rollout_row_id INTEGER NOT NULL,
|
|
139
|
+
host_kind TEXT NOT NULL,
|
|
140
|
+
rollout_identity TEXT NOT NULL,
|
|
141
|
+
trigger_logical_key TEXT NOT NULL,
|
|
142
|
+
pain_ref TEXT NOT NULL,
|
|
143
|
+
state TEXT NOT NULL,
|
|
144
|
+
created_at TEXT NOT NULL,
|
|
145
|
+
completed_at TEXT,
|
|
146
|
+
stale_at TEXT,
|
|
147
|
+
UNIQUE(rollout_row_id, trigger_logical_key, pain_ref)
|
|
148
|
+
)`,
|
|
149
|
+
`CREATE INDEX IF NOT EXISTS idx_governance_pending_tails_state
|
|
150
|
+
ON governance_pending_promotion_tails(state, created_at)`,
|
|
151
|
+
];
|
|
152
|
+
/** Column additions after v1 (dev databases created before the source-order fix). */
|
|
153
|
+
const V2_ADDED_COLUMNS = [
|
|
154
|
+
{ table: 'governance_observations', name: 'source_order', type: 'INTEGER' },
|
|
155
|
+
{ table: 'governance_observations', name: 'source_ordinal', type: 'INTEGER' },
|
|
156
|
+
];
|
|
157
|
+
function ensureGovernanceObservationSchema(db) {
|
|
158
|
+
db.transaction(() => {
|
|
159
|
+
for (const statement of CREATE_STATEMENTS)
|
|
160
|
+
db.exec(statement);
|
|
161
|
+
for (const column of V2_ADDED_COLUMNS) {
|
|
162
|
+
try {
|
|
163
|
+
db.exec(`ALTER TABLE ${column.table} ADD COLUMN ${column.name} ${column.type}`);
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
167
|
+
if (!message.includes('duplicate column name'))
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const row = db.prepare('SELECT version FROM governance_observation_schema_version LIMIT 1').get();
|
|
172
|
+
const current = isRecord(row) ? own(row, 'version') : undefined;
|
|
173
|
+
if (typeof current !== 'number') {
|
|
174
|
+
db.prepare('INSERT INTO governance_observation_schema_version (version) VALUES (?)').run(GOVERNANCE_OBSERVATION_SCHEMA_VERSION);
|
|
175
|
+
}
|
|
176
|
+
else if (current < GOVERNANCE_OBSERVATION_SCHEMA_VERSION) {
|
|
177
|
+
db.prepare('UPDATE governance_observation_schema_version SET version = ?').run(GOVERNANCE_OBSERVATION_SCHEMA_VERSION);
|
|
178
|
+
}
|
|
179
|
+
})();
|
|
180
|
+
}
|
|
181
|
+
function openStore(workspaceDir, factory) {
|
|
182
|
+
const dbPath = path.join(workspaceDir, '.state', 'trajectory.db');
|
|
183
|
+
if (!fs.existsSync(dbPath)) {
|
|
184
|
+
return { ok: false, reason: 'trajectory_db_not_found', nextAction: 'initialize the selected PD workspace (pd runtime init) before enabling conversation ingestion' };
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
const db = factory ? factory(dbPath) : new Database(dbPath);
|
|
188
|
+
db.pragma('busy_timeout = 5000');
|
|
189
|
+
db.pragma('journal_mode = WAL');
|
|
190
|
+
ensureGovernanceObservationSchema(db);
|
|
191
|
+
return { db, close: () => { try {
|
|
192
|
+
db.close();
|
|
193
|
+
}
|
|
194
|
+
catch { /* write result already determined */ } } };
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
const detail = error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200);
|
|
198
|
+
return { ok: false, reason: `trajectory_database_unavailable:${detail}`, nextAction: 'inspect or repair the selected PD trajectory database' };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function rowField(row, key) {
|
|
202
|
+
return isRecord(row) ? own(row, key) : undefined;
|
|
203
|
+
}
|
|
204
|
+
function upsertRollout(db, input, now) {
|
|
205
|
+
const existing = db.prepare('SELECT id FROM governance_rollouts WHERE host_kind = ? AND rollout_identity = ?').get(input.hostKind, input.rolloutIdentity);
|
|
206
|
+
const existingId = rowField(existing, 'id');
|
|
207
|
+
if (typeof existingId === 'number') {
|
|
208
|
+
db.prepare('UPDATE governance_rollouts SET root_session_id = ?, parent_rollout_id = COALESCE(?, parent_rollout_id), agent_identity = COALESCE(?, agent_identity), agent_depth = COALESCE(?, agent_depth), updated_at = ? WHERE id = ?')
|
|
209
|
+
.run(input.rootSessionId, input.parentRolloutIdentity ?? null, input.agentIdentity ?? null, input.agentDepth ?? null, now, existingId);
|
|
210
|
+
return existingId;
|
|
211
|
+
}
|
|
212
|
+
const result = db.prepare('INSERT INTO governance_rollouts (host_kind, rollout_identity, root_session_id, parent_rollout_id, agent_identity, agent_depth, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)')
|
|
213
|
+
.run(input.hostKind, input.rolloutIdentity, input.rootSessionId, input.parentRolloutIdentity ?? null, boundedString(input.agentIdentity, MAX_TEXT_BOUND), input.agentDepth ?? null, now, now);
|
|
214
|
+
return Number(result.lastInsertRowid);
|
|
215
|
+
}
|
|
216
|
+
function applyObservation({ db, rolloutRowId, input, workspaceDir }) {
|
|
217
|
+
const existing = db.prepare('SELECT * FROM governance_observations WHERE logical_key = ?').get(input.logicalObservationKey);
|
|
218
|
+
if (!isRecord(existing)) {
|
|
219
|
+
// Physical replay guard: the same transcript record decoded twice (crash
|
|
220
|
+
// before checkpoint, or a re-invoked hook) must not contribute twice.
|
|
221
|
+
if (input.transcriptRecordKey !== undefined) {
|
|
222
|
+
const physical = db.prepare('SELECT id FROM governance_observations WHERE transcript_record_key = ?').get(input.transcriptRecordKey);
|
|
223
|
+
if (isRecord(physical))
|
|
224
|
+
return { disposition: 'duplicate' };
|
|
225
|
+
}
|
|
226
|
+
const sanitizedText = input.visibleText !== undefined ? sanitizeString(input.visibleText, workspaceDir) : null;
|
|
227
|
+
const facts = input.toolFacts !== undefined ? safeJson({ facts: sanitizeValue(input.toolFacts, 0, workspaceDir) }) : null;
|
|
228
|
+
db.prepare(`INSERT INTO governance_observations
|
|
229
|
+
(rollout_row_id, host_kind, rollout_identity, root_session_id, host_turn_id, kind, logical_key, transcript_record_key, source_order, source_ordinal, assistant_item_id, phase, tool_use_id, transcript_tool_call_id, visible_text, sanitized_tool_facts_json, source, completeness, retention_class, observed_at)
|
|
230
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'operational', ?)`)
|
|
231
|
+
.run(rolloutRowId, input.hostKind, input.rolloutIdentity, input.rootSessionId, input.hostTurnId, input.kind, input.logicalObservationKey, input.transcriptRecordKey ?? null, input.recordByteStart ?? null, input.recordOrdinal ?? null, boundedString(input.assistantItemId, MAX_TEXT_BOUND), boundedString(input.phase, MAX_TEXT_BOUND) ?? null, boundedString(input.toolUseId, MAX_TEXT_BOUND), boundedString(input.transcriptToolCallId, MAX_TEXT_BOUND), sanitizedText, facts, input.source, input.completeness, input.observedAt);
|
|
232
|
+
return { disposition: 'inserted' };
|
|
233
|
+
}
|
|
234
|
+
const existingId = rowField(existing, 'id');
|
|
235
|
+
const existingText = rowField(existing, 'visible_text');
|
|
236
|
+
// Source precedence (SPEC §10): user rows created live are enriched by the
|
|
237
|
+
// transcript with identity/ordering; tool rows created live are enriched or
|
|
238
|
+
// no-op'd by tool_use_id; assistant content comes only from the transcript.
|
|
239
|
+
// A user content mismatch for one logical key is a lineage conflict: keep
|
|
240
|
+
// the first committed content, mark partial, and stop checkpoint advance at
|
|
241
|
+
// the conflicting record — never overwrite silently.
|
|
242
|
+
if (input.kind === 'user_turn'
|
|
243
|
+
&& input.source === 'transcript'
|
|
244
|
+
&& input.visibleText !== undefined
|
|
245
|
+
&& typeof existingText === 'string'
|
|
246
|
+
&& sanitizeString(input.visibleText, workspaceDir) !== existingText) {
|
|
247
|
+
db.prepare("UPDATE governance_observations SET completeness = 'partial' WHERE id = ?").run(existingId);
|
|
248
|
+
return { disposition: 'conflict', stopByteStart: input.recordByteStart };
|
|
249
|
+
}
|
|
250
|
+
const updates = [];
|
|
251
|
+
const values = [];
|
|
252
|
+
const fill = (column, value) => {
|
|
253
|
+
const current = rowField(existing, column);
|
|
254
|
+
if ((current === null || current === undefined) && value !== null && value !== undefined) {
|
|
255
|
+
updates.push(`${column} = ?`);
|
|
256
|
+
values.push(value);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
fill('transcript_record_key', input.transcriptRecordKey ?? null);
|
|
260
|
+
// Transcript replay enriches the live row with its real transcript position
|
|
261
|
+
// (PR #1455 review P1): all ordering logic reads source_order, so a live row
|
|
262
|
+
// must gain it the moment the transcript catch-up converges the same event.
|
|
263
|
+
fill('source_order', input.recordByteStart);
|
|
264
|
+
fill('source_ordinal', input.recordOrdinal);
|
|
265
|
+
fill('assistant_item_id', boundedString(input.assistantItemId, MAX_TEXT_BOUND));
|
|
266
|
+
fill('phase', boundedString(input.phase, MAX_TEXT_BOUND));
|
|
267
|
+
fill('tool_use_id', boundedString(input.toolUseId, MAX_TEXT_BOUND));
|
|
268
|
+
fill('transcript_tool_call_id', boundedString(input.transcriptToolCallId, MAX_TEXT_BOUND));
|
|
269
|
+
fill('visible_text', input.visibleText !== undefined ? sanitizeString(input.visibleText, workspaceDir) : null);
|
|
270
|
+
fill('sanitized_tool_facts_json', input.toolFacts !== undefined ? safeJson({ facts: sanitizeValue(input.toolFacts, 0, workspaceDir) }) : null);
|
|
271
|
+
const existingCompleteness = rowField(existing, 'completeness');
|
|
272
|
+
if (existingCompleteness === 'partial' && input.completeness === 'complete') {
|
|
273
|
+
updates.push('completeness = ?');
|
|
274
|
+
values.push('complete');
|
|
275
|
+
}
|
|
276
|
+
if (updates.length === 0)
|
|
277
|
+
return { disposition: 'duplicate' };
|
|
278
|
+
updates.push('source = ?');
|
|
279
|
+
values.push(input.source);
|
|
280
|
+
values.push(existingId);
|
|
281
|
+
db.prepare(`UPDATE governance_observations SET ${updates.join(', ')} WHERE id = ?`).run(...values);
|
|
282
|
+
return { disposition: 'enriched' };
|
|
283
|
+
}
|
|
284
|
+
function expireRows(db, ids, expiry) {
|
|
285
|
+
const { now, klass } = expiry;
|
|
286
|
+
if (ids.length === 0)
|
|
287
|
+
return;
|
|
288
|
+
const chunks = [];
|
|
289
|
+
for (let index = 0; index < ids.length; index += 200)
|
|
290
|
+
chunks.push(ids.slice(index, index + 200));
|
|
291
|
+
for (const chunk of chunks) {
|
|
292
|
+
const placeholders = chunk.map(() => '?').join(',');
|
|
293
|
+
db.prepare(`UPDATE governance_observations SET visible_text = NULL, sanitized_tool_facts_json = NULL, retention_class = ?, expired_at = ? WHERE id IN (${placeholders}) AND retention_class = 'operational'`)
|
|
294
|
+
.run(klass, now, ...chunk);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
function listTurnsInSourceOrder(db, rolloutRowId) {
|
|
298
|
+
const rows = db.prepare(`SELECT host_turn_id, MIN(source_order) AS turn_order, MIN(id) AS arrival
|
|
299
|
+
FROM governance_observations
|
|
300
|
+
WHERE rollout_row_id = ? AND retention_class = 'operational'
|
|
301
|
+
GROUP BY host_turn_id
|
|
302
|
+
ORDER BY (MIN(source_order) IS NULL) ASC, MIN(source_order) ASC, MIN(id) ASC`).all(rolloutRowId);
|
|
303
|
+
return rows.map((row) => ({
|
|
304
|
+
hostTurnId: String(rowField(row, 'host_turn_id')),
|
|
305
|
+
turnOrder: typeof rowField(row, 'turn_order') === 'number' ? rowField(row, 'turn_order') : null,
|
|
306
|
+
}));
|
|
307
|
+
}
|
|
308
|
+
function turnObservationIds(db, rolloutRowId, hostTurnId) {
|
|
309
|
+
const rows = db.prepare("SELECT id FROM governance_observations WHERE rollout_row_id = ? AND host_turn_id = ? AND retention_class = 'operational'")
|
|
310
|
+
.all(rolloutRowId, hostTurnId);
|
|
311
|
+
return rows.map((row) => Number(rowField(row, 'id'))).filter((id) => Number.isInteger(id));
|
|
312
|
+
}
|
|
313
|
+
function pruneRetention(db, rolloutRowId, now) {
|
|
314
|
+
const nowIso = now.toISOString();
|
|
315
|
+
// Age bound: global, bounded single statements over the retention index.
|
|
316
|
+
db.prepare(`UPDATE governance_observations SET visible_text = NULL, sanitized_tool_facts_json = NULL, retention_class = 'expired', expired_at = ?
|
|
317
|
+
WHERE retention_class = 'operational' AND observed_at < ?`)
|
|
318
|
+
.run(nowIso, new Date(now.getTime() - GOVERNANCE_RETENTION_MAX_AGE_MS).toISOString());
|
|
319
|
+
// Turn bound: per ingested rollout, keep the latest N conversational turns
|
|
320
|
+
// in canonical source order (live-only turns count as newest).
|
|
321
|
+
if (rolloutRowId === null)
|
|
322
|
+
return;
|
|
323
|
+
const turns = listTurnsInSourceOrder(db, rolloutRowId);
|
|
324
|
+
if (turns.length <= GOVERNANCE_RETENTION_MAX_TURNS)
|
|
325
|
+
return;
|
|
326
|
+
const expiredIds = [];
|
|
327
|
+
for (const turn of turns.slice(0, turns.length - GOVERNANCE_RETENTION_MAX_TURNS)) {
|
|
328
|
+
expiredIds.push(...turnObservationIds(db, rolloutRowId, turn.hostTurnId));
|
|
329
|
+
}
|
|
330
|
+
expireRows(db, expiredIds, { now: nowIso, klass: 'expired' });
|
|
331
|
+
}
|
|
332
|
+
function completePendingTails(db, rolloutRowId, now) {
|
|
333
|
+
const pending = db.prepare("SELECT * FROM governance_pending_promotion_tails WHERE rollout_row_id = ? AND state = 'pending'").all(rolloutRowId);
|
|
334
|
+
let completed = 0;
|
|
335
|
+
for (const tail of pending) {
|
|
336
|
+
const triggerKey = rowField(tail, 'trigger_logical_key');
|
|
337
|
+
if (typeof triggerKey !== 'string')
|
|
338
|
+
continue;
|
|
339
|
+
const triggerRow = db.prepare('SELECT * FROM governance_observations WHERE logical_key = ?').get(triggerKey);
|
|
340
|
+
if (!isRecord(triggerRow))
|
|
341
|
+
continue;
|
|
342
|
+
const triggerOrder = rowField(triggerRow, 'source_order');
|
|
343
|
+
if (typeof triggerOrder !== 'number')
|
|
344
|
+
continue; // not yet positioned by the transcript replay
|
|
345
|
+
// The next completed assistant turn: the earliest final-answer assistant
|
|
346
|
+
// observation AFTER the trigger in transcript source order.
|
|
347
|
+
const next = db.prepare(`SELECT id FROM governance_observations
|
|
348
|
+
WHERE rollout_row_id = ? AND kind = 'assistant_turn' AND phase = 'final_answer' AND completeness = 'complete' AND source_order > ?
|
|
349
|
+
ORDER BY source_order LIMIT 1`).get(rolloutRowId, triggerOrder);
|
|
350
|
+
const nextId = rowField(next, 'id');
|
|
351
|
+
if (typeof nextId !== 'number')
|
|
352
|
+
continue;
|
|
353
|
+
db.prepare("UPDATE governance_observations SET retention_class = 'promoted', promoted_at = ?, promotion_ref = COALESCE(promotion_ref, ?) WHERE id = ? AND retention_class != 'promoted'")
|
|
354
|
+
.run(now, rowField(tail, 'pain_ref'), nextId);
|
|
355
|
+
db.prepare("UPDATE governance_pending_promotion_tails SET state = 'completed', completed_at = ? WHERE id = ?").run(now, rowField(tail, 'id'));
|
|
356
|
+
completed += 1;
|
|
357
|
+
}
|
|
358
|
+
return completed;
|
|
359
|
+
}
|
|
360
|
+
function expireStalePendingTails(db, now) {
|
|
361
|
+
db.prepare("UPDATE governance_pending_promotion_tails SET state = 'stale', stale_at = ? WHERE state = 'pending' AND created_at < ?")
|
|
362
|
+
.run(now.toISOString(), new Date(now.getTime() - GOVERNANCE_PENDING_TAIL_STALE_MS).toISOString());
|
|
363
|
+
}
|
|
364
|
+
export function ingestGovernanceObservations(input) {
|
|
365
|
+
const opened = openStore(input.workspaceDir, input.databaseFactory);
|
|
366
|
+
if (!('db' in opened))
|
|
367
|
+
return { ok: false, reason: opened.reason, nextAction: opened.nextAction, inserted: 0, enriched: 0, duplicates: 0, checkpointCommitted: false, warnings: [] };
|
|
368
|
+
const { db, close } = opened;
|
|
369
|
+
const now = (input.now ?? new Date()).toISOString();
|
|
370
|
+
const warnings = [];
|
|
371
|
+
try {
|
|
372
|
+
let inserted = 0;
|
|
373
|
+
let enriched = 0;
|
|
374
|
+
let duplicates = 0;
|
|
375
|
+
let conflictStop;
|
|
376
|
+
let conflictKey = '';
|
|
377
|
+
const result = db.transaction(() => {
|
|
378
|
+
let rolloutRowId = null;
|
|
379
|
+
if (input.rollout !== undefined) {
|
|
380
|
+
rolloutRowId = upsertRollout(db, input.rollout, now);
|
|
381
|
+
}
|
|
382
|
+
for (const observation of input.observations) {
|
|
383
|
+
rolloutRowId = upsertRollout(db, observation, now);
|
|
384
|
+
const outcome = applyObservation({ db, rolloutRowId, input: observation, workspaceDir: input.workspaceDir });
|
|
385
|
+
if (outcome.disposition === 'inserted')
|
|
386
|
+
inserted += 1;
|
|
387
|
+
else if (outcome.disposition === 'enriched')
|
|
388
|
+
enriched += 1;
|
|
389
|
+
else if (outcome.disposition === 'duplicate')
|
|
390
|
+
duplicates += 1;
|
|
391
|
+
else if (outcome.disposition === 'conflict') {
|
|
392
|
+
conflictStop = outcome.stopByteStart;
|
|
393
|
+
conflictKey = observation.logicalObservationKey;
|
|
394
|
+
return 'conflict';
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
// Durable checkpoint: advances only in the transaction that commits its
|
|
398
|
+
// decoded observations (SPEC §8) — including deltas that contained only
|
|
399
|
+
// skipped or unknown records. A conflict or malformed record stops the
|
|
400
|
+
// advance at the offending record so it is re-examined, never skipped.
|
|
401
|
+
if (input.checkpoint !== undefined) {
|
|
402
|
+
const degradations = input.degradations ?? [];
|
|
403
|
+
const [firstDegradation] = degradations;
|
|
404
|
+
const stopOffset = conflictStop;
|
|
405
|
+
const byteOffset = stopOffset !== undefined && stopOffset < input.checkpoint.byteOffset ? stopOffset : input.checkpoint.byteOffset;
|
|
406
|
+
const lastDegradation = conflictKey
|
|
407
|
+
? { reason: 'logical_key_content_conflict', ordinal: null }
|
|
408
|
+
: firstDegradation
|
|
409
|
+
? { reason: firstDegradation.reason, ordinal: firstDegradation.ordinal ?? null }
|
|
410
|
+
: null;
|
|
411
|
+
db.prepare(`INSERT INTO governance_transcript_checkpoints
|
|
412
|
+
(host_kind, rollout_identity, byte_offset, last_ordinal, cli_version, root_session_id, incomplete_tail, last_degradation_reason, last_degradation_ordinal, updated_at)
|
|
413
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
414
|
+
ON CONFLICT(host_kind, rollout_identity) DO UPDATE SET
|
|
415
|
+
byte_offset = excluded.byte_offset, last_ordinal = excluded.last_ordinal, cli_version = COALESCE(excluded.cli_version, cli_version),
|
|
416
|
+
root_session_id = excluded.root_session_id, incomplete_tail = excluded.incomplete_tail,
|
|
417
|
+
last_degradation_reason = excluded.last_degradation_reason, last_degradation_ordinal = excluded.last_degradation_ordinal, updated_at = excluded.updated_at`)
|
|
418
|
+
.run(input.checkpoint.hostKind, input.checkpoint.rolloutIdentity, byteOffset, input.checkpoint.lastOrdinal, input.checkpoint.cliVersion ?? null, input.checkpoint.rootSessionId, input.checkpoint.incompleteTail ? 1 : 0, lastDegradation?.reason ?? null, lastDegradation?.ordinal ?? null, now);
|
|
419
|
+
}
|
|
420
|
+
// Marker semantics: compaction replaces logical history (tombstone every
|
|
421
|
+
// unpromoted observation recorded before the marker); rollback truncates
|
|
422
|
+
// the last N logical turns. Physical records remain; bodies must not.
|
|
423
|
+
if (input.compactionTimestamp && rolloutRowId !== null) {
|
|
424
|
+
const stale = db.prepare(`SELECT id FROM governance_observations WHERE rollout_row_id = ? AND retention_class = 'operational' AND observed_at <= ?`)
|
|
425
|
+
.all(rolloutRowId, input.compactionTimestamp);
|
|
426
|
+
expireRows(db, stale.map((row) => Number(rowField(row, 'id'))).filter((id) => Number.isInteger(id)), { now, klass: 'rolled_back' });
|
|
427
|
+
warnings.push('compaction_marker_applied');
|
|
428
|
+
}
|
|
429
|
+
if (Array.isArray(input.rollbackTurns) && input.rollbackTurns.length > 0 && rolloutRowId !== null) {
|
|
430
|
+
let rolledBackTurns = 0;
|
|
431
|
+
for (const markerTurns of input.rollbackTurns) {
|
|
432
|
+
if (typeof markerTurns !== 'number' || markerTurns <= 0)
|
|
433
|
+
continue;
|
|
434
|
+
// The LAST N logical turns in canonical source order (live-only
|
|
435
|
+
// turns are the newest; replayed turns order by transcript bytes).
|
|
436
|
+
const turns = listTurnsInSourceOrder(db, rolloutRowId).slice(-markerTurns);
|
|
437
|
+
const ids = [];
|
|
438
|
+
for (const turn of turns) {
|
|
439
|
+
ids.push(...turnObservationIds(db, rolloutRowId, turn.hostTurnId));
|
|
440
|
+
}
|
|
441
|
+
expireRows(db, ids, { now, klass: 'rolled_back' });
|
|
442
|
+
rolledBackTurns += markerTurns;
|
|
443
|
+
}
|
|
444
|
+
warnings.push(`rollback_marker_applied:${rolledBackTurns}`);
|
|
445
|
+
}
|
|
446
|
+
if (rolloutRowId !== null)
|
|
447
|
+
completePendingTails(db, rolloutRowId, now);
|
|
448
|
+
expireStalePendingTails(db, new Date(now));
|
|
449
|
+
pruneRetention(db, rolloutRowId, new Date(now));
|
|
450
|
+
return 'committed';
|
|
451
|
+
})();
|
|
452
|
+
if (result === 'conflict') {
|
|
453
|
+
return {
|
|
454
|
+
ok: false, reason: 'logical_key_content_conflict', nextAction: 'the first committed content was preserved and the observation is marked partial; run the audited quarantine/recovery command once available (Slice D) or re-ingest from a fresh rollout',
|
|
455
|
+
inserted, enriched, duplicates, checkpointCommitted: false, warnings: [`conflict:${conflictKey}`],
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
return { ok: true, inserted, enriched, duplicates, checkpointCommitted: input.checkpoint !== undefined, warnings };
|
|
459
|
+
}
|
|
460
|
+
catch (error) {
|
|
461
|
+
const detail = error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200);
|
|
462
|
+
return { ok: false, reason: `governance_write_failed:${detail}`, nextAction: 'inspect the workspace trajectory database and retry; nothing was partially committed', inserted: 0, enriched: 0, duplicates: 0, checkpointCommitted: false, warnings: [] };
|
|
463
|
+
}
|
|
464
|
+
finally {
|
|
465
|
+
close();
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
export function readGovernanceCheckpoint(args) {
|
|
469
|
+
const { workspaceDir, hostKind, rolloutIdentity, databaseFactory } = args;
|
|
470
|
+
const opened = openStore(workspaceDir, databaseFactory);
|
|
471
|
+
if (!('db' in opened))
|
|
472
|
+
return opened;
|
|
473
|
+
const { db, close } = opened;
|
|
474
|
+
try {
|
|
475
|
+
const row = db.prepare('SELECT * FROM governance_transcript_checkpoints WHERE host_kind = ? AND rollout_identity = ?').get(hostKind, rolloutIdentity);
|
|
476
|
+
if (!isRecord(row))
|
|
477
|
+
return null;
|
|
478
|
+
return {
|
|
479
|
+
hostKind: String(rowField(row, 'host_kind')),
|
|
480
|
+
rolloutIdentity: String(rowField(row, 'rollout_identity')),
|
|
481
|
+
byteOffset: Number(rowField(row, 'byte_offset')),
|
|
482
|
+
lastOrdinal: Number(rowField(row, 'last_ordinal')),
|
|
483
|
+
cliVersion: typeof rowField(row, 'cli_version') === 'string' ? rowField(row, 'cli_version') : null,
|
|
484
|
+
rootSessionId: String(rowField(row, 'root_session_id')),
|
|
485
|
+
incompleteTail: rowField(row, 'incomplete_tail') === 1,
|
|
486
|
+
lastDegradationReason: typeof rowField(row, 'last_degradation_reason') === 'string' ? rowField(row, 'last_degradation_reason') : null,
|
|
487
|
+
lastDegradationOrdinal: typeof rowField(row, 'last_degradation_ordinal') === 'number' ? rowField(row, 'last_degradation_ordinal') : null,
|
|
488
|
+
updatedAt: String(rowField(row, 'updated_at')),
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
finally {
|
|
492
|
+
close();
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
export function listGovernanceObservations(input) {
|
|
496
|
+
const opened = openStore(input.workspaceDir, input.databaseFactory);
|
|
497
|
+
if (!('db' in opened))
|
|
498
|
+
return opened;
|
|
499
|
+
const { db, close } = opened;
|
|
500
|
+
try {
|
|
501
|
+
const conditions = [];
|
|
502
|
+
const values = [];
|
|
503
|
+
if (input.rolloutIdentity !== undefined) {
|
|
504
|
+
conditions.push('rollout_identity = ?');
|
|
505
|
+
values.push(input.rolloutIdentity);
|
|
506
|
+
}
|
|
507
|
+
if (input.retentionClass !== undefined) {
|
|
508
|
+
conditions.push('retention_class = ?');
|
|
509
|
+
values.push(input.retentionClass);
|
|
510
|
+
}
|
|
511
|
+
const where = conditions.length > 0 ? ` WHERE ${conditions.join(' AND ')}` : '';
|
|
512
|
+
const limit = Math.min(Math.max(input.limit ?? 500, 1), 2000);
|
|
513
|
+
const rows = db.prepare(`SELECT * FROM governance_observations${where} ORDER BY id LIMIT ?`).all(...values, limit);
|
|
514
|
+
const observations = rows.map((row) => ({
|
|
515
|
+
id: Number(rowField(row, 'id')),
|
|
516
|
+
rolloutIdentity: String(rowField(row, 'rollout_identity')),
|
|
517
|
+
rootSessionId: String(rowField(row, 'root_session_id')),
|
|
518
|
+
hostTurnId: String(rowField(row, 'host_turn_id')),
|
|
519
|
+
kind: rowField(row, 'kind'),
|
|
520
|
+
logicalKey: String(rowField(row, 'logical_key')),
|
|
521
|
+
transcriptRecordKey: typeof rowField(row, 'transcript_record_key') === 'string' ? rowField(row, 'transcript_record_key') : null,
|
|
522
|
+
sourceOrder: typeof rowField(row, 'source_order') === 'number' ? rowField(row, 'source_order') : null,
|
|
523
|
+
sourceOrdinal: typeof rowField(row, 'source_ordinal') === 'number' ? rowField(row, 'source_ordinal') : null,
|
|
524
|
+
assistantItemId: typeof rowField(row, 'assistant_item_id') === 'string' ? rowField(row, 'assistant_item_id') : null,
|
|
525
|
+
phase: typeof rowField(row, 'phase') === 'string' ? rowField(row, 'phase') : null,
|
|
526
|
+
toolUseId: typeof rowField(row, 'tool_use_id') === 'string' ? rowField(row, 'tool_use_id') : null,
|
|
527
|
+
transcriptToolCallId: typeof rowField(row, 'transcript_tool_call_id') === 'string' ? rowField(row, 'transcript_tool_call_id') : null,
|
|
528
|
+
visibleText: typeof rowField(row, 'visible_text') === 'string' ? rowField(row, 'visible_text') : null,
|
|
529
|
+
sanitizedToolFactsJson: typeof rowField(row, 'sanitized_tool_facts_json') === 'string' ? rowField(row, 'sanitized_tool_facts_json') : null,
|
|
530
|
+
source: rowField(row, 'source'),
|
|
531
|
+
completeness: rowField(row, 'completeness'),
|
|
532
|
+
retentionClass: rowField(row, 'retention_class'),
|
|
533
|
+
observedAt: String(rowField(row, 'observed_at')),
|
|
534
|
+
promotionRef: typeof rowField(row, 'promotion_ref') === 'string' ? rowField(row, 'promotion_ref') : null,
|
|
535
|
+
}));
|
|
536
|
+
return { ok: true, observations };
|
|
537
|
+
}
|
|
538
|
+
finally {
|
|
539
|
+
close();
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
class PromotionMissingError extends Error {
|
|
543
|
+
reason;
|
|
544
|
+
nextAction;
|
|
545
|
+
constructor(reason, nextAction) {
|
|
546
|
+
super(reason);
|
|
547
|
+
this.reason = reason;
|
|
548
|
+
this.nextAction = nextAction;
|
|
549
|
+
this.name = 'PromotionMissingError';
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
export function promoteGovernanceEvidence(input) {
|
|
553
|
+
const opened = openStore(input.workspaceDir, input.databaseFactory);
|
|
554
|
+
if (!('db' in opened))
|
|
555
|
+
return { ok: false, reason: opened.reason, nextAction: opened.nextAction };
|
|
556
|
+
const { db, close } = opened;
|
|
557
|
+
const now = (input.now ?? new Date()).toISOString();
|
|
558
|
+
const warnings = [];
|
|
559
|
+
try {
|
|
560
|
+
let promoted = 0;
|
|
561
|
+
let tailState = 'pending';
|
|
562
|
+
db.transaction(() => {
|
|
563
|
+
const rollout = db.prepare('SELECT id FROM governance_rollouts WHERE host_kind = ? AND rollout_identity = ?').get(input.hostKind, input.rolloutIdentity);
|
|
564
|
+
const rolloutRowId = rowField(rollout, 'id');
|
|
565
|
+
if (typeof rolloutRowId !== 'number')
|
|
566
|
+
throw new PromotionMissingError('rollout_not_found', 'ingest the rollout before promoting evidence around it');
|
|
567
|
+
// Idempotency: a completed or still-pending tail for the same trigger +
|
|
568
|
+
// pain reference is a no-op replay (crash, restart, duplicate delivery).
|
|
569
|
+
const existingTail = db.prepare('SELECT * FROM governance_pending_promotion_tails WHERE rollout_row_id = ? AND trigger_logical_key = ? AND pain_ref = ?')
|
|
570
|
+
.get(rolloutRowId, input.triggerLogicalKey, input.painRef);
|
|
571
|
+
if (isRecord(existingTail)) {
|
|
572
|
+
const state = rowField(existingTail, 'state');
|
|
573
|
+
if (state === 'completed') {
|
|
574
|
+
tailState = 'completed';
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
if (state === 'pending') {
|
|
578
|
+
// Recovery invariant: the tail may already be satisfiable now.
|
|
579
|
+
const completedNow = completePendingTails(db, rolloutRowId, now);
|
|
580
|
+
if (completedNow > 0)
|
|
581
|
+
tailState = 'completed';
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
// state === 'stale': a diagnosable terminal state — do not silently
|
|
585
|
+
// re-arm; the caller must start a new promotion with a new reference.
|
|
586
|
+
throw new PromotionMissingError('promotion_tail_stale', 'the pending promotion tail expired; create a new promotion with a new pain reference');
|
|
587
|
+
}
|
|
588
|
+
const triggerRow = db.prepare('SELECT * FROM governance_observations WHERE logical_key = ? AND rollout_row_id = ?').get(input.triggerLogicalKey, rolloutRowId);
|
|
589
|
+
if (!isRecord(triggerRow))
|
|
590
|
+
throw new PromotionMissingError('trigger_not_found', 'the triggering observation must be ingested before promotion');
|
|
591
|
+
const triggerId = rowField(triggerRow, 'id');
|
|
592
|
+
const triggerOrder = typeof rowField(triggerRow, 'source_order') === 'number' ? rowField(triggerRow, 'source_order') : null;
|
|
593
|
+
const promoteIds = (ids) => {
|
|
594
|
+
for (const id of ids) {
|
|
595
|
+
db.prepare("UPDATE governance_observations SET retention_class = 'promoted', promoted_at = ?, promotion_ref = COALESCE(promotion_ref, ?) WHERE id = ? AND retention_class != 'promoted'")
|
|
596
|
+
.run(now, input.painRef, id);
|
|
597
|
+
promoted += 1;
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
// ≤12 preceding visible turns: the turns immediately BEFORE the
|
|
601
|
+
// trigger's own turn in canonical source order (transcript byte order;
|
|
602
|
+
// a live trigger not yet replayed positions after everything observed
|
|
603
|
+
// so far, which is exactly its real position — nothing newer exists).
|
|
604
|
+
const turns = listTurnsInSourceOrder(db, rolloutRowId);
|
|
605
|
+
const triggerTurnIndex = turns.findIndex((turn) => {
|
|
606
|
+
const ids = db.prepare('SELECT id FROM governance_observations WHERE rollout_row_id = ? AND host_turn_id = ? AND logical_key = ?')
|
|
607
|
+
.all(rolloutRowId, turn.hostTurnId, input.triggerLogicalKey);
|
|
608
|
+
return ids.length > 0;
|
|
609
|
+
});
|
|
610
|
+
const precedingStart = triggerTurnIndex > 0 ? Math.max(0, triggerTurnIndex - GOVERNANCE_PROMOTION_PRECEDING_TURNS) : -1;
|
|
611
|
+
const preceding = triggerTurnIndex > 0 ? turns.slice(precedingStart, triggerTurnIndex) : [];
|
|
612
|
+
for (const turn of preceding) {
|
|
613
|
+
promoteIds(turnObservationIds(db, rolloutRowId, turn.hostTurnId));
|
|
614
|
+
}
|
|
615
|
+
promoteIds([Number(triggerId)]);
|
|
616
|
+
if (triggerOrder !== null) {
|
|
617
|
+
// Next completed assistant turn: the earliest final-answer assistant
|
|
618
|
+
// AFTER the trigger in transcript source order. When the trigger has
|
|
619
|
+
// no transcript position yet, the durable pending tail below resolves
|
|
620
|
+
// once the replay enriches it (completePendingTails re-checks).
|
|
621
|
+
const next = db.prepare(`SELECT id FROM governance_observations
|
|
622
|
+
WHERE rollout_row_id = ? AND kind = 'assistant_turn' AND phase = 'final_answer' AND completeness = 'complete' AND source_order > ?
|
|
623
|
+
ORDER BY source_order LIMIT 1`).get(rolloutRowId, triggerOrder);
|
|
624
|
+
const nextId = rowField(next, 'id');
|
|
625
|
+
if (typeof nextId === 'number') {
|
|
626
|
+
promoteIds([nextId]);
|
|
627
|
+
tailState = 'completed';
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
if (tailState !== 'completed') {
|
|
631
|
+
db.prepare(`INSERT INTO governance_pending_promotion_tails (rollout_row_id, host_kind, rollout_identity, trigger_logical_key, pain_ref, state, created_at)
|
|
632
|
+
VALUES (?, ?, ?, ?, ?, 'pending', ?)`)
|
|
633
|
+
.run(rolloutRowId, input.hostKind, input.rolloutIdentity, input.triggerLogicalKey, input.painRef, now);
|
|
634
|
+
tailState = 'pending';
|
|
635
|
+
warnings.push('pending_next_assistant_tail');
|
|
636
|
+
}
|
|
637
|
+
})();
|
|
638
|
+
return { ok: true, promoted, tailState, warnings };
|
|
639
|
+
}
|
|
640
|
+
catch (error) {
|
|
641
|
+
if (error instanceof PromotionMissingError)
|
|
642
|
+
return { ok: false, reason: error.reason, nextAction: error.nextAction };
|
|
643
|
+
const detail = error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200);
|
|
644
|
+
return { ok: false, reason: `governance_write_failed:${detail}`, nextAction: 'inspect the workspace trajectory database and retry; nothing was partially committed' };
|
|
645
|
+
}
|
|
646
|
+
finally {
|
|
647
|
+
close();
|
|
648
|
+
}
|
|
649
|
+
}
|
|
@@ -8,7 +8,13 @@ export * from './pd-config.js';
|
|
|
8
8
|
export * from './production-rulehost-gate.js';
|
|
9
9
|
export * from './rule-implementation-runtime.js';
|
|
10
10
|
export * from './production-pain-evidence.js';
|
|
11
|
+
export * from './governance-observation-store.js';
|
|
11
12
|
export * from './host-liveness-contract.js';
|
|
13
|
+
export * from './product-telemetry/consent-store.js';
|
|
14
|
+
export * from './product-telemetry/eligibility.js';
|
|
15
|
+
export * from './product-telemetry/exporter.js';
|
|
16
|
+
export * from './product-telemetry/milestone-readers.js';
|
|
17
|
+
export * from './product-telemetry/service.js';
|
|
12
18
|
export declare const HOST_RUNTIME_ROUTES: readonly ['before_prompt_build', 'before_tool_call', 'after_tool_call'];
|
|
13
19
|
export type HostRuntimeRoute = (typeof HOST_RUNTIME_ROUTES)[number];
|
|
14
20
|
export type HostRuntimePort = (event: HostEvent) => HostEventResult | Promise<HostEventResult>;
|