create-principles-disciple 1.144.27 → 1.145.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_release/product-identity.json +2 -2
- package/codex-adapter/dist/index.d.ts +2 -2
- package/codex-adapter/dist/index.js +1 -1
- package/codex-adapter/dist/ingestion/admission.js +16 -0
- package/codex-adapter/dist/ingestion/codex-version.d.ts +10 -4
- package/codex-adapter/dist/ingestion/codex-version.js +10 -4
- package/codex-adapter/dist/ingestion/explicit-owner-statement.d.ts +48 -0
- package/codex-adapter/dist/ingestion/explicit-owner-statement.js +123 -0
- package/codex-adapter/dist/ingestion/ingestion.js +50 -1
- package/codex-adapter/dist/pd-hook.js +66 -3
- package/codex-adapter/dist/worker/workspace-worker.d.ts +14 -0
- package/codex-adapter/dist/worker/workspace-worker.js +194 -11
- package/codex-adapter/package.json +2 -2
- package/console/dist/server/models/ApprovalsConsoleModel.d.ts +2 -2
- package/console/dist/server/models/ApprovalsConsoleModel.js +1 -1
- package/console/dist/server/models/ApprovalsGroupedConsoleModel.js +1 -1
- package/console/dist/server/models/PrinciplesConsoleModel.d.ts +26 -1
- package/console/dist/server/models/PrinciplesConsoleModel.js +18 -1
- package/console/dist/server/routes/activations.js +4 -4
- package/console/dist/server/routes/approvals.js +2 -2
- package/console/dist/server/routes/failed-tasks.d.ts +9 -0
- package/console/dist/server/routes/failed-tasks.js +116 -7
- package/console/dist/server/routes/principles.js +73 -1
- package/console/dist/shared/prompt-injection-contract.d.ts +1 -1
- package/console/dist/ui/api.d.ts +5 -5
- package/console/dist/ui/i18n/en.json +13 -2
- package/console/dist/ui/i18n/zh-CN.json +13 -2
- package/console/dist/ui/pages/activation/ActivationPage.js +2 -1
- package/console/dist/ui/pages/failed-tasks/FailedTasksPage.js +42 -4
- package/console/dist/ui/pages/focus/FocusPage.js +3 -3
- package/console/dist/ui/pages/principles/PrinciplesPage.js +7 -2
- package/console/dist/ui/utils/validators.d.ts +6 -2
- package/console/dist/ui/utils/validators.js +19 -4
- package/console/dist/web/assets/app.css +26 -0
- package/console/dist/web/assets/app.js +24 -24
- package/console/package.json +4 -4
- package/core/dist/host/host-installer.d.ts +3 -1
- package/core/dist/host/host-installer.d.ts.map +1 -1
- package/core/dist/host/host-installer.js.map +1 -1
- package/core/dist/runtime-v2/admission-gate.d.ts +8 -0
- package/core/dist/runtime-v2/admission-gate.d.ts.map +1 -1
- package/core/dist/runtime-v2/admission-gate.js +3 -2
- package/core/dist/runtime-v2/admission-gate.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-defaults.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-defaults.js +16 -1
- package/core/dist/runtime-v2/config/pd-config-defaults.js.map +1 -1
- package/core/dist/runtime-v2/context-payload.d.ts +43 -3
- package/core/dist/runtime-v2/context-payload.d.ts.map +1 -1
- package/core/dist/runtime-v2/context-payload.js +15 -1
- package/core/dist/runtime-v2/context-payload.js.map +1 -1
- package/core/dist/runtime-v2/evidence-guards.d.ts +6 -0
- package/core/dist/runtime-v2/evidence-guards.d.ts.map +1 -1
- package/core/dist/runtime-v2/evidence-guards.js +11 -0
- package/core/dist/runtime-v2/evidence-guards.js.map +1 -1
- package/core/dist/runtime-v2/evolution/evolution-types.d.ts +4 -4
- package/core/dist/runtime-v2/evolution/evolution-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/evolution/evolution-types.js +1 -1
- package/core/dist/runtime-v2/evolution/evolution-types.js.map +1 -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 +6 -0
- 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.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js +8 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +5 -2
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +3 -1
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-output.d.ts +11 -0
- package/core/dist/runtime-v2/internalization/evaluator-output.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-output.js +10 -0
- package/core/dist/runtime-v2/internalization/evaluator-output.js.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.d.ts +3 -3
- package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.js +49 -5
- package/core/dist/runtime-v2/internalization/evaluator-prompt-builder.js.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.js +13 -16
- package/core/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/owner-decision-review.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/owner-decision-review.js +5 -1
- package/core/dist/runtime-v2/internalization/owner-decision-review.js.map +1 -1
- package/core/dist/runtime-v2/internalization/owner-review.d.ts +2 -2
- package/core/dist/runtime-v2/internalization/owner-review.js +2 -2
- package/core/dist/runtime-v2/internalization/scribe-output.d.ts +12 -0
- package/core/dist/runtime-v2/internalization/scribe-output.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/scribe-output.js +20 -0
- package/core/dist/runtime-v2/internalization/scribe-output.js.map +1 -1
- package/core/dist/runtime-v2/internalization/scribe-prompt-builder.d.ts +32 -1
- package/core/dist/runtime-v2/internalization/scribe-prompt-builder.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/scribe-prompt-builder.js +38 -1
- package/core/dist/runtime-v2/internalization/scribe-prompt-builder.js.map +1 -1
- package/core/dist/runtime-v2/internalization-queue-read-model.d.ts +6 -0
- package/core/dist/runtime-v2/internalization-queue-read-model.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization-queue-read-model.js +8 -1
- package/core/dist/runtime-v2/internalization-queue-read-model.js.map +1 -1
- package/core/dist/runtime-v2/intervention-evidence-normalizer.d.ts.map +1 -1
- package/core/dist/runtime-v2/intervention-evidence-normalizer.js +10 -3
- package/core/dist/runtime-v2/intervention-evidence-normalizer.js.map +1 -1
- package/core/dist/runtime-v2/pain-ingress.d.ts +1 -1
- package/core/dist/runtime-v2/pain-ingress.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-signal-bridge.d.ts +68 -2
- package/core/dist/runtime-v2/pain-signal-bridge.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-signal-bridge.js +541 -18
- package/core/dist/runtime-v2/pain-signal-bridge.js.map +1 -1
- package/core/dist/runtime-v2/pain-signal-runtime-factory.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-signal-runtime-factory.js +4 -0
- package/core/dist/runtime-v2/pain-signal-runtime-factory.js.map +1 -1
- package/core/dist/runtime-v2/product-telemetry/snapshot-contract.d.ts +2 -2
- package/core/dist/runtime-v2/product-telemetry/snapshot-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/product-telemetry/snapshot-contract.js +2 -2
- package/core/dist/runtime-v2/product-telemetry/snapshot-contract.js.map +1 -1
- package/core/dist/runtime-v2/store/candidate/admission-document.d.ts +90 -0
- package/core/dist/runtime-v2/store/candidate/admission-document.d.ts.map +1 -0
- package/core/dist/runtime-v2/store/candidate/admission-document.js +142 -0
- package/core/dist/runtime-v2/store/candidate/admission-document.js.map +1 -0
- package/core/dist/runtime-v2/store/candidate/candidate-store.d.ts +53 -0
- package/core/dist/runtime-v2/store/candidate/candidate-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/candidate/memory-candidate-store.d.ts +35 -0
- package/core/dist/runtime-v2/store/candidate/memory-candidate-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/candidate/memory-candidate-store.js +48 -0
- package/core/dist/runtime-v2/store/candidate/memory-candidate-store.js.map +1 -1
- package/core/dist/runtime-v2/store/candidate/sqlite-candidate-store.d.ts +44 -0
- package/core/dist/runtime-v2/store/candidate/sqlite-candidate-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/candidate/sqlite-candidate-store.js +136 -0
- package/core/dist/runtime-v2/store/candidate/sqlite-candidate-store.js.map +1 -1
- package/core/dist/runtime-v2/store/context/sqlite-context-assembler.js.map +1 -1
- package/core/dist/runtime-v2/store/intervention-evidence-schema.js +1 -1
- package/core/dist/runtime-v2/store/runtime-state-manager.d.ts +65 -0
- package/core/dist/runtime-v2/store/runtime-state-manager.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/runtime-state-manager.js +46 -0
- package/core/dist/runtime-v2/store/runtime-state-manager.js.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection.js +42 -0
- package/core/dist/runtime-v2/store/sqlite-connection.js.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-intervention-evidence-store.d.ts +1 -1
- package/core/dist/runtime-v2/store/sqlite-intervention-evidence-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-intervention-evidence-store.js.map +1 -1
- package/core/dist/runtime-v2/store/task/sqlite-family-reopen.d.ts +19 -0
- package/core/dist/runtime-v2/store/task/sqlite-family-reopen.d.ts.map +1 -0
- package/core/dist/runtime-v2/store/task/sqlite-family-reopen.js +36 -0
- package/core/dist/runtime-v2/store/task/sqlite-family-reopen.js.map +1 -0
- package/core/dist/runtime-v2/store/task/sqlite-task-store.d.ts +23 -0
- 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 +50 -0
- package/core/dist/runtime-v2/store/task/sqlite-task-store.js.map +1 -1
- package/core/dist/runtime-v2/task-status.d.ts +3 -1
- package/core/dist/runtime-v2/task-status.d.ts.map +1 -1
- package/core/dist/runtime-v2/task-status.js +1 -1
- package/core/dist/runtime-v2/task-status.js.map +1 -1
- package/core/dist/runtime-v2/trajectory-schema.d.ts.map +1 -1
- package/core/dist/runtime-v2/trajectory-schema.js +11 -0
- package/core/dist/runtime-v2/trajectory-schema.js.map +1 -1
- package/core/dist/runtime-v2/types/event-types.d.ts +2 -2
- package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/event-types.js +1 -1
- package/core/dist/runtime-v2/types/event-types.js.map +1 -1
- package/core/dist/runtime-v2/types/evidence-chain-contract.d.ts +1 -1
- package/core/dist/runtime-v2/types/evidence-chain-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/evidence-chain-contract.js +2 -2
- package/core/dist/runtime-v2/types/evidence-chain-contract.js.map +1 -1
- package/core/dist/runtime-v2/types/intervention-evidence-contract.d.ts +3 -3
- package/core/dist/runtime-v2/types/intervention-evidence-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/intervention-evidence-contract.js +1 -0
- package/core/dist/runtime-v2/types/intervention-evidence-contract.js.map +1 -1
- package/core/dist/telemetry-event.d.ts +2 -2
- package/core/dist/telemetry-event.d.ts.map +1 -1
- package/core/dist/telemetry-event.js +4 -0
- package/core/dist/telemetry-event.js.map +1 -1
- package/core/dist/trajectory-types.d.ts +2 -2
- package/core/dist/trajectory-types.d.ts.map +1 -1
- package/core/package.json +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +84 -8
- package/dist/index.js.map +1 -1
- package/dist/installer.d.ts +42 -11
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +140 -36
- package/dist/installer.js.map +1 -1
- package/dist/installers/index.d.ts +18 -7
- package/dist/installers/index.d.ts.map +1 -1
- package/dist/installers/index.js +13 -4
- package/dist/installers/index.js.map +1 -1
- package/dist/installers/workbuddy-host-installer.d.ts +246 -0
- package/dist/installers/workbuddy-host-installer.d.ts.map +1 -0
- package/dist/installers/workbuddy-host-installer.js +1419 -0
- package/dist/installers/workbuddy-host-installer.js.map +1 -0
- package/dist/mvp-config.d.ts +24 -0
- package/dist/mvp-config.d.ts.map +1 -1
- package/dist/mvp-config.js +36 -0
- package/dist/mvp-config.js.map +1 -1
- package/dist/prompts.d.ts +13 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +45 -8
- package/dist/prompts.js.map +1 -1
- package/dist/uninstaller.d.ts +1 -1
- package/dist/uninstaller.d.ts.map +1 -1
- package/dist/uninstaller.js +29 -4
- package/dist/uninstaller.js.map +1 -1
- package/host-runtime/dist/governance-signal-admission.d.ts +63 -0
- package/host-runtime/dist/governance-signal-admission.js +322 -53
- package/host-runtime/dist/host-liveness-contract.js +7 -1
- package/host-runtime/dist/index.d.ts +1 -0
- package/host-runtime/dist/index.js +5 -1
- package/host-runtime/dist/internalization-consumer-cycle.d.ts +12 -0
- package/host-runtime/dist/internalization-consumer-cycle.js +43 -1
- package/host-runtime/dist/intervention-evidence-ingress.d.ts +1 -1
- package/host-runtime/dist/product-telemetry/service.js +1 -1
- package/host-runtime/dist/production-pain-evidence.d.ts +59 -1
- package/host-runtime/dist/production-pain-evidence.js +200 -17
- package/host-runtime/dist/prompt-activation-deliverability.js +5 -4
- package/host-runtime/dist/prompt-injection-event-evidence.d.ts +1 -1
- package/host-runtime/dist/prompt-injection-event-evidence.js +5 -1
- package/host-runtime/dist/prompt-injection-projection.d.ts +14 -5
- package/host-runtime/dist/prompt-injection-projection.js +30 -16
- package/host-runtime/dist/workbuddy-worker-status.d.ts +24 -0
- package/host-runtime/dist/workbuddy-worker-status.js +52 -0
- package/host-runtime/package.json +3 -3
- package/install-layout/dist/index.d.ts +18 -1
- package/install-layout/dist/index.js +15 -2
- package/install-layout/package.json +1 -1
- package/package.json +6 -5
- package/pd-cli/dist/commands/candidate.d.ts.map +1 -1
- package/pd-cli/dist/commands/candidate.js +44 -4
- package/pd-cli/dist/commands/candidate.js.map +1 -1
- package/pd-cli/dist/commands/codex-worker.d.ts.map +1 -1
- package/pd-cli/dist/commands/codex-worker.js +30 -1
- package/pd-cli/dist/commands/codex-worker.js.map +1 -1
- package/pd-cli/dist/commands/config-doctor.d.ts.map +1 -1
- package/pd-cli/dist/commands/config-doctor.js +19 -4
- package/pd-cli/dist/commands/config-doctor.js.map +1 -1
- package/pd-cli/dist/commands/diagnose.d.ts.map +1 -1
- package/pd-cli/dist/commands/diagnose.js +4 -1
- package/pd-cli/dist/commands/diagnose.js.map +1 -1
- package/pd-cli/dist/commands/health-codex-install.d.ts +85 -0
- package/pd-cli/dist/commands/health-codex-install.d.ts.map +1 -0
- package/pd-cli/dist/commands/health-codex-install.js +207 -0
- package/pd-cli/dist/commands/health-codex-install.js.map +1 -0
- package/pd-cli/dist/commands/health-codex.d.ts.map +1 -1
- package/pd-cli/dist/commands/health-codex.js +78 -0
- package/pd-cli/dist/commands/health-codex.js.map +1 -1
- package/pd-cli/dist/commands/pain-list.d.ts +3 -2
- package/pd-cli/dist/commands/pain-list.d.ts.map +1 -1
- package/pd-cli/dist/commands/pain-list.js +10 -10
- package/pd-cli/dist/commands/pain-list.js.map +1 -1
- package/pd-cli/dist/commands/pain-record.d.ts +2 -0
- package/pd-cli/dist/commands/pain-record.d.ts.map +1 -1
- package/pd-cli/dist/commands/pain-record.js +36 -0
- package/pd-cli/dist/commands/pain-record.js.map +1 -1
- package/pd-cli/dist/commands/pain-retry.d.ts +6 -0
- package/pd-cli/dist/commands/pain-retry.d.ts.map +1 -1
- package/pd-cli/dist/commands/pain-retry.js +152 -5
- package/pd-cli/dist/commands/pain-retry.js.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.d.ts +1 -1
- package/pd-cli/dist/commands/runtime-activation.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.js +3 -3
- package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
- package/pd-cli/dist/commands/workbuddy-worker.d.ts +19 -0
- package/pd-cli/dist/commands/workbuddy-worker.d.ts.map +1 -0
- package/pd-cli/dist/commands/workbuddy-worker.js +168 -0
- package/pd-cli/dist/commands/workbuddy-worker.js.map +1 -0
- package/pd-cli/dist/index.js +29 -1
- package/pd-cli/dist/index.js.map +1 -1
- package/pd-cli/dist/resolve-workspace.d.ts +14 -2
- package/pd-cli/dist/resolve-workspace.d.ts.map +1 -1
- package/pd-cli/dist/resolve-workspace.js +88 -21
- package/pd-cli/dist/resolve-workspace.js.map +1 -1
- package/pd-cli/dist/services/admission-write-gate.d.ts +24 -0
- package/pd-cli/dist/services/admission-write-gate.d.ts.map +1 -0
- package/pd-cli/dist/services/admission-write-gate.js +41 -0
- package/pd-cli/dist/services/admission-write-gate.js.map +1 -0
- package/pd-cli/dist/services/pd-config-loader.d.ts +39 -7
- package/pd-cli/dist/services/pd-config-loader.d.ts.map +1 -1
- package/pd-cli/dist/services/pd-config-loader.js +111 -18
- package/pd-cli/dist/services/pd-config-loader.js.map +1 -1
- package/pd-cli/dist/services/rulehost-pipeline-runner.d.ts +10 -0
- package/pd-cli/dist/services/rulehost-pipeline-runner.d.ts.map +1 -1
- package/pd-cli/dist/services/rulehost-pipeline-runner.js +59 -4
- package/pd-cli/dist/services/rulehost-pipeline-runner.js.map +1 -1
- package/pd-cli/package.json +4 -3
- package/plugin/dist/bundle.js +564 -509
- package/plugin/dist/governance-audit.js +1 -1
- package/plugin/dist/openclaw.plugin.json +1 -1
- package/plugin/dist/rulehost-evidence.js +1 -1
- package/plugin/openclaw.plugin.json +1 -1
- package/plugin/package.json +3 -3
- package/release-manager/dist/index.d.ts.map +1 -1
- package/release-manager/dist/index.js +84 -8
- package/release-manager/dist/index.js.map +1 -1
- package/release-manager/dist/installer.d.ts +42 -11
- package/release-manager/dist/installer.d.ts.map +1 -1
- package/release-manager/dist/installer.js +140 -36
- package/release-manager/dist/installer.js.map +1 -1
- package/release-manager/dist/installers/index.d.ts +18 -7
- package/release-manager/dist/installers/index.d.ts.map +1 -1
- package/release-manager/dist/installers/index.js +13 -4
- package/release-manager/dist/installers/index.js.map +1 -1
- package/release-manager/dist/installers/workbuddy-host-installer.d.ts +246 -0
- package/release-manager/dist/installers/workbuddy-host-installer.d.ts.map +1 -0
- package/release-manager/dist/installers/workbuddy-host-installer.js +1419 -0
- package/release-manager/dist/installers/workbuddy-host-installer.js.map +1 -0
- package/release-manager/dist/mvp-config.d.ts +24 -0
- package/release-manager/dist/mvp-config.d.ts.map +1 -1
- package/release-manager/dist/mvp-config.js +36 -0
- package/release-manager/dist/mvp-config.js.map +1 -1
- package/release-manager/dist/prompts.d.ts +13 -0
- package/release-manager/dist/prompts.d.ts.map +1 -1
- package/release-manager/dist/prompts.js +45 -8
- package/release-manager/dist/prompts.js.map +1 -1
- package/release-manager/dist/uninstaller.d.ts +1 -1
- package/release-manager/dist/uninstaller.d.ts.map +1 -1
- package/release-manager/dist/uninstaller.js +29 -4
- package/release-manager/dist/uninstaller.js.map +1 -1
- package/release-manager/package.json +5 -4
- package/workbuddy-adapter/dist/codec/index.d.ts +2 -0
- package/workbuddy-adapter/dist/codec/index.js +2 -0
- package/workbuddy-adapter/dist/codec/input-decoder.d.ts +30 -0
- package/workbuddy-adapter/dist/codec/input-decoder.js +232 -0
- package/workbuddy-adapter/dist/codec/output-encoder.d.ts +62 -0
- package/workbuddy-adapter/dist/codec/output-encoder.js +75 -0
- package/workbuddy-adapter/dist/host-adapter.d.ts +33 -0
- package/workbuddy-adapter/dist/host-adapter.js +23 -0
- package/workbuddy-adapter/dist/index.d.ts +16 -0
- package/workbuddy-adapter/dist/index.js +16 -0
- package/workbuddy-adapter/dist/pd-hook.d.ts +17 -0
- package/workbuddy-adapter/dist/pd-hook.js +505 -0
- package/workbuddy-adapter/dist/tool-semantics.d.ts +22 -0
- package/workbuddy-adapter/dist/tool-semantics.js +33 -0
- package/workbuddy-adapter/dist/workbuddy-evidence-recorder.d.ts +50 -0
- package/workbuddy-adapter/dist/workbuddy-evidence-recorder.js +238 -0
- package/workbuddy-adapter/dist/worker/workspace-worker.d.ts +41 -0
- package/workbuddy-adapter/dist/worker/workspace-worker.js +219 -0
- package/workbuddy-adapter/dist/workspace-resolution.d.ts +15 -0
- package/workbuddy-adapter/dist/workspace-resolution.js +53 -0
- package/workbuddy-adapter/package.json +62 -0
- package/workbuddy-adapter/plugin/.codebuddy-plugin/plugin.json +6 -0
- package/workbuddy-adapter/plugin/hooks/hooks.json +62 -0
- package/workbuddy-adapter/plugin/scripts/wrapper.cjs +79 -0
|
@@ -40,6 +40,8 @@ import { promoteGovernanceEvidence, ensureGovernanceSchema } from './governance-
|
|
|
40
40
|
import { loadPdConfigForPlugin } from './pd-config.js';
|
|
41
41
|
// ─── Shared detector constants (one truth for both hosts) ───────────────────
|
|
42
42
|
export const GOVERNANCE_STRONG_PAIN_SCORE = 70;
|
|
43
|
+
/** CR-07: rate-limit bucket key for explicit Owner statements (no keyword rule version). */
|
|
44
|
+
const EXPLICIT_OWNER_STATEMENT_RULE_VERSION = 9001;
|
|
43
45
|
export const GOVERNANCE_STRONG_RATE_LIMIT_PER_HOUR = 5;
|
|
44
46
|
export const GOVERNANCE_RATE_LIMIT_WINDOW_MS = 60 * 60 * 1000;
|
|
45
47
|
/** Sync-only detection config: ambiguous candidates are NOT signals here (§12). */
|
|
@@ -292,6 +294,23 @@ function ensureGovernanceAdmissionSchema(db) {
|
|
|
292
294
|
db.transaction(() => {
|
|
293
295
|
for (const statement of ADMISSION_CREATE_STATEMENTS)
|
|
294
296
|
db.exec(statement);
|
|
297
|
+
// SPEC-CODEX-PAIN-CLOSURE-001 CR-01: this store also writes tool_calls
|
|
298
|
+
// (admitToolFailure); make sure the host tool-use-id join column exists on
|
|
299
|
+
// workspaces whose base schema predates it (idempotent additive ALTER —
|
|
300
|
+
// only when the table itself exists: governance-only databases without a
|
|
301
|
+
// tool_calls table are a valid pre-existing state, not an error).
|
|
302
|
+
const hasToolCalls = db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'tool_calls'").get() !== undefined;
|
|
303
|
+
if (hasToolCalls) {
|
|
304
|
+
try {
|
|
305
|
+
db.exec('ALTER TABLE tool_calls ADD COLUMN tool_use_id TEXT');
|
|
306
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_tool_calls_session_tool_use_id ON tool_calls(session_id, tool_use_id)');
|
|
307
|
+
}
|
|
308
|
+
catch (err) {
|
|
309
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
310
|
+
if (!message.includes('duplicate column name'))
|
|
311
|
+
throw err;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
295
314
|
})();
|
|
296
315
|
}
|
|
297
316
|
function openAdmissionStore(workspaceDir, factory) {
|
|
@@ -299,8 +318,9 @@ function openAdmissionStore(workspaceDir, factory) {
|
|
|
299
318
|
if (!fs.existsSync(dbPath)) {
|
|
300
319
|
return { ok: false, reason: 'trajectory_db_not_found', nextAction: 'initialize the selected PD workspace (pd runtime init) before enabling conversation ingestion' };
|
|
301
320
|
}
|
|
321
|
+
let db;
|
|
302
322
|
try {
|
|
303
|
-
|
|
323
|
+
db = factory ? factory(dbPath) : new Database(dbPath);
|
|
304
324
|
db.pragma('busy_timeout = 5000');
|
|
305
325
|
db.pragma('journal_mode = WAL');
|
|
306
326
|
ensureGovernanceAdmissionSchema(db);
|
|
@@ -308,11 +328,19 @@ function openAdmissionStore(workspaceDir, factory) {
|
|
|
308
328
|
// tails): one open makes the whole governance schema ready.
|
|
309
329
|
ensureGovernanceSchema(db);
|
|
310
330
|
return { db, close: () => { try {
|
|
311
|
-
db
|
|
331
|
+
db?.close();
|
|
312
332
|
}
|
|
313
333
|
catch { /* write result already determined */ } } };
|
|
314
334
|
}
|
|
315
335
|
catch (error) {
|
|
336
|
+
// PRI-624 discipline: a half-opened handle (e.g. a corrupt/non-SQLite
|
|
337
|
+
// file that passes the lazy open but fails the first pragma) must be
|
|
338
|
+
// closed here — the worker retries every cycle, so a leaked handle would
|
|
339
|
+
// pin the workspace trajectory.db (and its temp dir) forever.
|
|
340
|
+
try {
|
|
341
|
+
db?.close();
|
|
342
|
+
}
|
|
343
|
+
catch { /* best-effort cleanup of an unusable handle */ }
|
|
316
344
|
const detail = error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200);
|
|
317
345
|
return { ok: false, reason: `trajectory_database_unavailable:${detail}`, nextAction: 'inspect or repair the selected PD trajectory database' };
|
|
318
346
|
}
|
|
@@ -356,9 +384,11 @@ function tryConsumeRateLimit({ db, rootSessionId, ruleVersion, now }) {
|
|
|
356
384
|
return true;
|
|
357
385
|
}
|
|
358
386
|
function insertCorrectionPain({ db, candidate, workspaceDir, painId, detection, nowIso }) {
|
|
359
|
-
const reason =
|
|
360
|
-
?
|
|
361
|
-
:
|
|
387
|
+
const reason = candidate.explicitOwnerStatement === true
|
|
388
|
+
? 'Codex explicit owner statement (PD记录痛苦 prefix)'
|
|
389
|
+
: detection !== undefined && detection.matchedTerms.length > 0
|
|
390
|
+
? `User correction detected: ${detection.matchedTerms.join(', ')}`
|
|
391
|
+
: 'User correction detected';
|
|
362
392
|
// P1-1 privacy (review round 2): the FULL raw text must pass through the
|
|
363
393
|
// sanitizer BEFORE any truncation — sanitizeString's own contract is
|
|
364
394
|
// redact → path-replace → bound. Slicing first would split a token that
|
|
@@ -372,12 +402,32 @@ function insertCorrectionPain({ db, candidate, workspaceDir, painId, detection,
|
|
|
372
402
|
.run(candidate.rootSessionId, 'user_correction', GOVERNANCE_STRONG_PAIN_SCORE, reason.slice(0, MAX_REASON_BOUND), 'severe', 'system_infer', null, excerpt, painId, null, candidate.hostKind, nowIso);
|
|
373
403
|
return reason;
|
|
374
404
|
}
|
|
375
|
-
|
|
405
|
+
/**
|
|
406
|
+
* ONE builder for the tool_failure task payload shape — the Codex inline
|
|
407
|
+
* admission path and the WorkBuddy bare-pain sweep must produce the SAME
|
|
408
|
+
* shape, differing only in the attributed host and the pain facts.
|
|
409
|
+
*/
|
|
410
|
+
function toolFailureTaskPayload(fields) {
|
|
376
411
|
// P1-1 privacy (review round 2): sanitize the FULL text before any
|
|
377
412
|
// truncation — a token crossing the 200-char boundary must be redacted, not
|
|
378
413
|
// split into a fragment that survives verbatim. sanitizeString bounds itself.
|
|
379
|
-
const payload =
|
|
380
|
-
|
|
414
|
+
const payload = {
|
|
415
|
+
painType: 'tool_failure',
|
|
416
|
+
source: fields.toolName,
|
|
417
|
+
reason: fields.reason || `tool=${fields.toolName}`,
|
|
418
|
+
score: fields.score,
|
|
419
|
+
sessionId: fields.sessionId,
|
|
420
|
+
hostKind: fields.hostKind,
|
|
421
|
+
evidence: [{ sourceRef: `governance_observation:${fields.logicalObservationKey}`, note: sanitizeString(fields.reason || fields.toolName, fields.workspaceDir) }],
|
|
422
|
+
};
|
|
423
|
+
return JSON.stringify(payload);
|
|
424
|
+
}
|
|
425
|
+
function taskSubmissionPayload(candidate, workspaceDir, reason) {
|
|
426
|
+
if (candidate.kind === 'user_correction') {
|
|
427
|
+
// P1-1 privacy (review round 2): sanitize the FULL text before any
|
|
428
|
+
// truncation — a token crossing the 200-char boundary must be redacted, not
|
|
429
|
+
// split into a fragment that survives verbatim. sanitizeString bounds itself.
|
|
430
|
+
const payload = {
|
|
381
431
|
painType: 'user_frustration',
|
|
382
432
|
source: 'user_correction',
|
|
383
433
|
reason: reason || 'User correction detected',
|
|
@@ -385,39 +435,56 @@ function taskSubmissionPayload(candidate, workspaceDir, reason) {
|
|
|
385
435
|
sessionId: candidate.rootSessionId,
|
|
386
436
|
hostKind: 'codex',
|
|
387
437
|
evidence: [{ sourceRef: `governance_observation:${candidate.logicalObservationKey}`, note: sanitizeString(candidate.text, workspaceDir) }],
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
sessionId: candidate.rootSessionId,
|
|
395
|
-
hostKind: 'codex',
|
|
396
|
-
evidence: [{ sourceRef: `governance_observation:${candidate.logicalObservationKey}`, note: sanitizeString(reason || candidate.toolName, workspaceDir) }],
|
|
438
|
+
// SPEC-CODEX-PAIN-CLOSURE-001 CR-02 (merged from main): an explicit
|
|
439
|
+
// Owner statement rides as classified correction evidence — never
|
|
440
|
+
// summarized by an AI, never inside evidence[] pseudo-trace entries.
|
|
441
|
+
...(candidate.explicitOwnerStatement === true
|
|
442
|
+
? { correctionEvidence: { text: sanitizeString(candidate.text, workspaceDir), classification: 'owner_statement', channel: 'codex_explicit_prefix' } }
|
|
443
|
+
: {}),
|
|
397
444
|
};
|
|
398
|
-
|
|
445
|
+
return JSON.stringify(payload);
|
|
446
|
+
}
|
|
447
|
+
return toolFailureTaskPayload({
|
|
448
|
+
hostKind: candidate.hostKind,
|
|
449
|
+
logicalObservationKey: candidate.logicalObservationKey,
|
|
450
|
+
sessionId: candidate.rootSessionId,
|
|
451
|
+
toolName: candidate.toolName,
|
|
452
|
+
reason,
|
|
453
|
+
score: 70,
|
|
454
|
+
workspaceDir,
|
|
455
|
+
});
|
|
399
456
|
}
|
|
400
|
-
function insertAdmissionMarker({ db,
|
|
401
|
-
const payload = taskSubmissionPayload(candidate, workspaceDir, reason);
|
|
457
|
+
function insertAdmissionMarker({ db, identity, canonicalPainId, ruleVersion, reason, payloadJson, nowIso }) {
|
|
402
458
|
db.prepare(`INSERT INTO governance_signal_admissions
|
|
403
459
|
(host_kind, logical_observation_key, rollout_identity, root_session_id, signal_kind, decision, canonical_pain_id, diagnostician_task_id, rule_version, reason, task_payload_json, created_at, updated_at)
|
|
404
460
|
VALUES (?, ?, ?, ?, ?, 'admitted', ?, NULL, ?, ?, ?, ?, ?)`)
|
|
405
|
-
.run(
|
|
461
|
+
.run(identity.hostKind, identity.logicalObservationKey, identity.rolloutIdentity, identity.rootSessionId, identity.signalKind, canonicalPainId, ruleVersion, reason.slice(0, MAX_REASON_BOUND) || null, payloadJson, nowIso, nowIso);
|
|
406
462
|
}
|
|
407
463
|
function admitCorrection({ db, candidate, workspaceDir, now, nowIso, keywordStore, onDegradation }) {
|
|
464
|
+
// SPEC-CODEX-PAIN-CLOSURE-001 CR-07: an EXPLICIT Owner statement
|
|
465
|
+
// (`PD记录痛苦:<text>` in the current Codex message) does not pass through
|
|
466
|
+
// keyword detection at all — the explicit request IS the signal. Ordinary
|
|
467
|
+
// conversation keeps the STRONG+high-precision gate unchanged.
|
|
468
|
+
const isExplicit = candidate.explicitOwnerStatement === true;
|
|
408
469
|
// Detection runs OUTSIDE the write transaction (pure scan of the shared
|
|
409
|
-
// keyword store); its outcome feeds the transaction below.
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
470
|
+
// keyword store); its outcome feeds the transaction below. An EXPLICIT
|
|
471
|
+
// statement skips detection entirely — the Owner's explicit request is the
|
|
472
|
+
// signal (CR-07), so there is no detection result and no rule version.
|
|
473
|
+
const detection = isExplicit
|
|
474
|
+
? undefined
|
|
475
|
+
: evaluateCorrectionSignal({
|
|
476
|
+
workspaceDir,
|
|
477
|
+
text: candidate.text,
|
|
478
|
+
sessionId: candidate.rootSessionId,
|
|
479
|
+
detectedAt: nowIso,
|
|
480
|
+
...(keywordStore ? { store: keywordStore } : {}),
|
|
481
|
+
...(onDegradation ? { onDegradation } : {}),
|
|
482
|
+
});
|
|
483
|
+
const isStrongHighPrecision = isExplicit
|
|
484
|
+
|| (detection !== undefined
|
|
485
|
+
&& detection.output.isSignal
|
|
486
|
+
&& detection.output.strength === 'STRONG'
|
|
487
|
+
&& detection.output.matchedPrecision === 'high');
|
|
421
488
|
if (!isStrongHighPrecision) {
|
|
422
489
|
// Ordinary conversation / weak negation / ambiguous candidates: no pain,
|
|
423
490
|
// no task, no quota, and no marker (SPEC §18 scenario 6 — silence).
|
|
@@ -445,12 +512,25 @@ function admitCorrection({ db, candidate, workspaceDir, now, nowIso, keywordStor
|
|
|
445
512
|
db.prepare('UPDATE pain_events SET host_kind = ? WHERE canonical_pain_id = ? AND host_kind IS NULL').run(candidate.hostKind, painId);
|
|
446
513
|
}
|
|
447
514
|
else {
|
|
448
|
-
|
|
515
|
+
// CR-07: explicit submissions carry their own rate-limit bucket
|
|
516
|
+
// (detection never ran — no keyword rule version exists for them).
|
|
517
|
+
const rateLimitRuleVersion = isExplicit ? EXPLICIT_OWNER_STATEMENT_RULE_VERSION : (detection?.ruleVersion ?? EXPLICIT_OWNER_STATEMENT_RULE_VERSION);
|
|
518
|
+
if (!tryConsumeRateLimit({ db, rootSessionId: candidate.rootSessionId, ruleVersion: rateLimitRuleVersion, now })) {
|
|
449
519
|
throw new RateLimitedSignal();
|
|
450
520
|
}
|
|
451
|
-
reason = insertCorrectionPain({ db, candidate, workspaceDir, painId, detection: detection
|
|
521
|
+
reason = insertCorrectionPain({ db, candidate, workspaceDir, painId, detection: detection?.output, nowIso });
|
|
452
522
|
}
|
|
453
|
-
insertAdmissionMarker({
|
|
523
|
+
insertAdmissionMarker({
|
|
524
|
+
db,
|
|
525
|
+
identity: { hostKind: candidate.hostKind, logicalObservationKey: candidate.logicalObservationKey, rolloutIdentity: candidate.rolloutIdentity, rootSessionId: candidate.rootSessionId, signalKind: candidate.kind },
|
|
526
|
+
canonicalPainId: painId,
|
|
527
|
+
// Merged from main (CR-07): explicit owner statements never ran keyword
|
|
528
|
+
// detection, so `detection` is optional — no ruleVersion exists for them.
|
|
529
|
+
ruleVersion: detection?.ruleVersion ?? null,
|
|
530
|
+
reason,
|
|
531
|
+
payloadJson: taskSubmissionPayload(candidate, workspaceDir, reason),
|
|
532
|
+
nowIso,
|
|
533
|
+
});
|
|
454
534
|
})();
|
|
455
535
|
}
|
|
456
536
|
catch (error) {
|
|
@@ -459,7 +539,7 @@ function admitCorrection({ db, candidate, workspaceDir, now, nowIso, keywordStor
|
|
|
459
539
|
}
|
|
460
540
|
throw error;
|
|
461
541
|
}
|
|
462
|
-
return { disposition: 'admitted', kind: 'user_correction', logicalObservationKey: candidate.logicalObservationKey, canonicalPainId: painId, duplicate, ruleVersion: detection
|
|
542
|
+
return { disposition: 'admitted', kind: 'user_correction', logicalObservationKey: candidate.logicalObservationKey, canonicalPainId: painId, duplicate, ruleVersion: detection?.ruleVersion ?? null };
|
|
463
543
|
}
|
|
464
544
|
function admitToolFailure({ db, candidate, workspaceDir, nowIso }) {
|
|
465
545
|
const identity = deriveProductionToolPainIdentity({
|
|
@@ -468,6 +548,9 @@ function admitToolFailure({ db, candidate, workspaceDir, nowIso }) {
|
|
|
468
548
|
turnId: candidate.hostTurnId,
|
|
469
549
|
toolName: candidate.toolName,
|
|
470
550
|
source: candidate.source,
|
|
551
|
+
// I1 identity parity: same call id the live handler derived from (the
|
|
552
|
+
// candidate builder forwards the host `tool_use_id`).
|
|
553
|
+
...(candidate.toolCallId !== undefined ? { toolCallId: candidate.toolCallId } : {}),
|
|
471
554
|
...(candidate.toolInput !== undefined ? { toolInput: candidate.toolInput } : {}),
|
|
472
555
|
...(candidate.toolOutput !== undefined ? { toolOutput: candidate.toolOutput } : {}),
|
|
473
556
|
});
|
|
@@ -475,7 +558,7 @@ function admitToolFailure({ db, candidate, workspaceDir, nowIso }) {
|
|
|
475
558
|
// Admission gate — identical semantics to the live production handler on a
|
|
476
559
|
// fresh process (ADR-0020 accepts cold in-memory cooldowns for Codex;
|
|
477
560
|
// canonical idempotency is the guard).
|
|
478
|
-
const sourceObservation = buildToolFailureObservation({ toolName: candidate.toolName, error: outcome.error, exitCode: outcome.exitCode });
|
|
561
|
+
const sourceObservation = buildToolFailureObservation({ toolName: candidate.toolName, error: outcome.error, exitCode: outcome.exitCode ?? undefined });
|
|
479
562
|
const sourceKind = resolveSourceKind({
|
|
480
563
|
observedAt: nowIso,
|
|
481
564
|
workspaceId: workspaceDir,
|
|
@@ -483,7 +566,7 @@ function admitToolFailure({ db, candidate, workspaceDir, nowIso }) {
|
|
|
483
566
|
toolName: candidate.toolName,
|
|
484
567
|
failureSource: sourceObservation.failureSource,
|
|
485
568
|
toolNotFound: sourceObservation.toolNotFound,
|
|
486
|
-
nonZeroExit: outcome.exitCode !== 0,
|
|
569
|
+
nonZeroExit: outcome.exitCode !== null && outcome.exitCode !== 0,
|
|
487
570
|
});
|
|
488
571
|
// Risk evaluation mirrors the production handler: it reads the RAW params
|
|
489
572
|
// (sanitized params replace paths with placeholders and would lose the
|
|
@@ -491,7 +574,7 @@ function admitToolFailure({ db, candidate, workspaceDir, nowIso }) {
|
|
|
491
574
|
const rawFile = isRecord(outcome.params) ? (own(outcome.params, 'file_path') ?? own(outcome.params, 'path')) : undefined;
|
|
492
575
|
const relativePath = String(rawFile ?? 'unknown').slice(0, 500);
|
|
493
576
|
const isRisky = path.isAbsolute(relativePath) && !path.resolve(relativePath).startsWith(`${workspaceDir}${path.sep}`);
|
|
494
|
-
const painScore = Math.min(100, (outcome.
|
|
577
|
+
const painScore = Math.min(100, (outcome.failure ? 70 : 0) + (isRisky ? 20 : 0));
|
|
495
578
|
const triage = evaluateTriage({ sourceKind, score: painScore, isRisky });
|
|
496
579
|
const trigger = evaluateTriggerController({ triageResult: triage, isOwnerManual: false, isCooldownActive: false, isValid: true, score: painScore, sessionId: candidate.rootSessionId });
|
|
497
580
|
const gateAdmitted = outcome.failure && PRODUCTION_WRITE_TOOLS.has(candidate.toolName) && trigger.shouldCreateDiagnosticTask;
|
|
@@ -503,18 +586,24 @@ function admitToolFailure({ db, candidate, workspaceDir, nowIso }) {
|
|
|
503
586
|
let duplicateWithoutPain = false;
|
|
504
587
|
let reason = '';
|
|
505
588
|
db.transaction(() => {
|
|
506
|
-
// Same duplicate
|
|
507
|
-
//
|
|
508
|
-
|
|
509
|
-
|
|
589
|
+
// Same duplicate probes as the production handler: the host tool-call id
|
|
590
|
+
// (CR-01) is the stable join key; the content-shape probe stays the
|
|
591
|
+
// fallback for hosts/candidates without ids.
|
|
592
|
+
if (candidate.toolUseId !== undefined
|
|
593
|
+
&& db.prepare('SELECT 1 FROM tool_calls WHERE session_id = ? AND tool_use_id = ?').get(candidate.rootSessionId, candidate.toolUseId) !== undefined) {
|
|
594
|
+
duplicate = true;
|
|
595
|
+
duplicateWithoutPain = db.prepare('SELECT 1 FROM pain_events WHERE canonical_pain_id = ?').get(painId) === undefined;
|
|
596
|
+
}
|
|
597
|
+
else if (db.prepare('SELECT 1 FROM tool_calls WHERE session_id = ? AND tool_name = ? AND params_json = ? AND outcome = ? AND exit_code IS ? AND error_message IS ? AND result_preview IS ?')
|
|
598
|
+
.get(candidate.rootSessionId, candidate.toolName, paramsJson, outcome.outcome, outcome.exitCode, outcome.error ?? null, resultPreview) !== undefined) {
|
|
510
599
|
duplicate = true;
|
|
511
600
|
duplicateWithoutPain = db.prepare('SELECT 1 FROM pain_events WHERE canonical_pain_id = ?').get(painId) === undefined;
|
|
512
601
|
}
|
|
513
602
|
else {
|
|
514
603
|
db.prepare(`INSERT INTO sessions (session_id, started_at, updated_at) VALUES (?, ?, ?) ON CONFLICT(session_id) DO UPDATE SET updated_at = excluded.updated_at`)
|
|
515
604
|
.run(candidate.rootSessionId, nowIso, nowIso);
|
|
516
|
-
db.prepare(`INSERT INTO tool_calls (session_id, tool_name, outcome, duration_ms, exit_code, error_type, error_message, gfi_before, gfi_after, params_json, result_preview, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
517
|
-
.run(candidate.rootSessionId, candidate.toolName, outcome.
|
|
605
|
+
db.prepare(`INSERT INTO tool_calls (session_id, tool_name, outcome, duration_ms, exit_code, error_type, error_message, gfi_before, gfi_after, params_json, result_preview, created_at, tool_use_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
606
|
+
.run(candidate.rootSessionId, candidate.toolName, outcome.outcome, outcome.durationMs ?? null, outcome.exitCode, outcome.error ? outcome.error.split(/[\s:]/, 1)[0] : null, outcome.error ?? null, null, null, paramsJson, resultPreview, nowIso, candidate.toolUseId ?? null);
|
|
518
607
|
reason = `tool=${candidate.toolName}; error=${outcome.error ?? `exit=${outcome.exitCode}`}; path=${relativePath}`;
|
|
519
608
|
db.prepare(`INSERT INTO pain_events (session_id, source, score, reason, severity, origin, confidence, text, canonical_pain_id, runtime_task_id, host_kind, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
520
609
|
.run(candidate.rootSessionId, sourceObservation.failureSource ?? 'tool_failure', painScore, reason, painScore >= 70 ? 'severe' : painScore >= 40 ? 'moderate' : 'mild', 'system_infer', null, null, painId, null, candidate.hostKind, nowIso);
|
|
@@ -523,7 +612,15 @@ function admitToolFailure({ db, candidate, workspaceDir, nowIso }) {
|
|
|
523
612
|
// pain row; the IS NULL guard keeps any durable attribution.
|
|
524
613
|
db.prepare('UPDATE pain_events SET host_kind = ? WHERE canonical_pain_id = ? AND host_kind IS NULL').run(candidate.hostKind, painId);
|
|
525
614
|
if (!duplicateWithoutPain) {
|
|
526
|
-
insertAdmissionMarker({
|
|
615
|
+
insertAdmissionMarker({
|
|
616
|
+
db,
|
|
617
|
+
identity: { hostKind: candidate.hostKind, logicalObservationKey: candidate.logicalObservationKey, rolloutIdentity: candidate.rolloutIdentity, rootSessionId: candidate.rootSessionId, signalKind: candidate.kind },
|
|
618
|
+
canonicalPainId: painId,
|
|
619
|
+
ruleVersion: null,
|
|
620
|
+
reason: sanitizeString(reason, workspaceDir),
|
|
621
|
+
payloadJson: taskSubmissionPayload(candidate, workspaceDir, reason),
|
|
622
|
+
nowIso,
|
|
623
|
+
});
|
|
527
624
|
}
|
|
528
625
|
// A duplicate call row without an admitted pain mirrors the production
|
|
529
626
|
// handler (no pain insert on duplicates) and records no marker, so a later
|
|
@@ -601,10 +698,25 @@ function isGovernanceTaskPayload(value) {
|
|
|
601
698
|
}
|
|
602
699
|
if (typeof own(value, 'score') !== 'number')
|
|
603
700
|
return false;
|
|
604
|
-
|
|
701
|
+
// The admitting host is part of the frozen payload contract; the Diagnostician
|
|
702
|
+
// attribution must be one of the governed hosts (never free text).
|
|
703
|
+
const hostKind = own(value, 'hostKind');
|
|
704
|
+
if (hostKind !== 'openclaw' && hostKind !== 'codex' && hostKind !== 'workbuddy')
|
|
705
|
+
return false;
|
|
706
|
+
// CR-02 (merged from main): a validated explicit Owner statement is a
|
|
707
|
+
// first-class input basis — the evidence array may legitimately be empty for
|
|
708
|
+
// such submissions (the statement itself satisfies the empty-input-evidence
|
|
709
|
+
// admission condition).
|
|
710
|
+
const correctionEvidence = own(value, 'correctionEvidence');
|
|
711
|
+
const hasOwnerStatement = isRecord(correctionEvidence)
|
|
712
|
+
&& own(correctionEvidence, 'classification') === 'owner_statement'
|
|
713
|
+
&& own(correctionEvidence, 'channel') === 'codex_explicit_prefix'
|
|
714
|
+
&& typeof own(correctionEvidence, 'text') === 'string'
|
|
715
|
+
&& own(correctionEvidence, 'text').length > 0;
|
|
716
|
+
if (correctionEvidence !== undefined && !hasOwnerStatement)
|
|
605
717
|
return false;
|
|
606
718
|
const evidence = own(value, 'evidence');
|
|
607
|
-
if (!Array.isArray(evidence) || evidence.length === 0 || evidence.length > 8)
|
|
719
|
+
if (!Array.isArray(evidence) || (evidence.length === 0 && !hasOwnerStatement) || evidence.length > 8)
|
|
608
720
|
return false;
|
|
609
721
|
for (const entry of evidence) {
|
|
610
722
|
if (!isRecord(entry))
|
|
@@ -693,8 +805,16 @@ export async function ensureGovernanceDiagnosticianTask(input) {
|
|
|
693
805
|
score: payloadParsed.score,
|
|
694
806
|
sessionId: payloadParsed.sessionId,
|
|
695
807
|
provenance: 'host_context_bound',
|
|
696
|
-
|
|
808
|
+
// The admitting host comes from the marker's own payload — the ONE
|
|
809
|
+
// durable attribution fact (existing codex markers keep 'codex',
|
|
810
|
+
// workbuddy markers attribute 'workbuddy').
|
|
811
|
+
hostKind: payloadParsed.hostKind,
|
|
697
812
|
evidence: [...payloadParsed.evidence],
|
|
813
|
+
// CR-02: replay the explicit Owner statement verbatim (classified,
|
|
814
|
+
// channel-disclosed) so re-created tasks keep the same input basis.
|
|
815
|
+
...(payloadParsed.correctionEvidence !== undefined
|
|
816
|
+
? { correctionEvidence: { ...payloadParsed.correctionEvidence, sessionId: payloadParsed.sessionId } }
|
|
817
|
+
: {}),
|
|
698
818
|
recordObservability: true,
|
|
699
819
|
});
|
|
700
820
|
// recordPain (async) leaves a cached bridge holding open SQLite
|
|
@@ -791,6 +911,129 @@ export async function ensureGovernanceContinuation(input) {
|
|
|
791
911
|
close();
|
|
792
912
|
}
|
|
793
913
|
}
|
|
914
|
+
/**
|
|
915
|
+
* Admit bare host pains — failure rows the shared production pain handler
|
|
916
|
+
* already persisted (host_kind set, canonical_pain_id set, runtime_task_id
|
|
917
|
+
* NULL) but that no inline admission exists for. The WorkBuddy hook is the
|
|
918
|
+
* only evidence producer on that host (SPEC workbuddy-host-adapter §1: no
|
|
919
|
+
* transcript reads), so these rows would otherwise stay stranded as
|
|
920
|
+
* evidence-only forever: reconcile only continues ADMITTED markers, and no
|
|
921
|
+
* WorkBuddy admission step existed (review R2/P1).
|
|
922
|
+
*
|
|
923
|
+
* Policy: only failures scoring at/above the Codex tool_failure admission
|
|
924
|
+
* floor (GOVERNANCE_STRONG_PAIN_SCORE = 70) are queued for diagnosis — that
|
|
925
|
+
* floor is the existing signal-quality boundary for write-tool failures, and
|
|
926
|
+
* lower-scored failures stay evidence-only in pain_events/tool_calls rather
|
|
927
|
+
* than diluting the diagnostician queue. Idempotency reuses the ONE existing
|
|
928
|
+
* authorities: the unique admission marker (canonical_pain_id probe +
|
|
929
|
+
* UNIQUE logical key) and the deterministic task id, so repeated sweeps and
|
|
930
|
+
* crash restarts never mint a second task. Task creation reuses
|
|
931
|
+
* `ensureGovernanceDiagnosticianTask` unchanged (including its Case-B link
|
|
932
|
+
* repair). Evidence promotion is deliberately NOT attempted here: the
|
|
933
|
+
* promotion substrate (governance_rollouts/observations) is fed by transcript
|
|
934
|
+
* ingestion, which the WorkBuddy MVP excludes.
|
|
935
|
+
*/
|
|
936
|
+
export async function admitBareHostPains(input) {
|
|
937
|
+
const opened = openAdmissionStore(input.workspaceDir, input.databaseFactory);
|
|
938
|
+
if (!('db' in opened)) {
|
|
939
|
+
return { ok: false, reason: opened.reason, nextAction: opened.nextAction, admitted: 0, ensured: 0, skippedLowScore: 0, skippedInvalid: 0, degradations: [opened.reason] };
|
|
940
|
+
}
|
|
941
|
+
const { db, close } = opened;
|
|
942
|
+
if (!hasProductionPainSchema(db)) {
|
|
943
|
+
close();
|
|
944
|
+
return { ok: false, reason: 'trajectory_schema_invalid', nextAction: 'run the supported PD workspace migration before enabling the worker', admitted: 0, ensured: 0, skippedLowScore: 0, skippedInvalid: 0, degradations: ['trajectory_schema_invalid'] };
|
|
945
|
+
}
|
|
946
|
+
const nowIso = (input.now ?? new Date()).toISOString();
|
|
947
|
+
const workspaceDir = path.resolve(input.workspaceDir);
|
|
948
|
+
const limit = Math.min(Math.max(input.limit ?? 5, 1), 50);
|
|
949
|
+
// Bare pains of this host that no admission marker covers yet. A marker is
|
|
950
|
+
// the durable "already handled" fact; runtime_task_id additionally excludes
|
|
951
|
+
// pains that reached a task through another path.
|
|
952
|
+
const barePainPredicate = `
|
|
953
|
+
FROM pain_events p
|
|
954
|
+
WHERE p.host_kind = ?
|
|
955
|
+
AND p.runtime_task_id IS NULL
|
|
956
|
+
AND p.canonical_pain_id IS NOT NULL
|
|
957
|
+
AND NOT EXISTS (SELECT 1 FROM governance_signal_admissions a WHERE a.canonical_pain_id = p.canonical_pain_id)`;
|
|
958
|
+
try {
|
|
959
|
+
const lowScoreRow = db.prepare(`SELECT COUNT(*) AS n ${barePainPredicate} AND p.score < ?`).get(input.hostKind, GOVERNANCE_STRONG_PAIN_SCORE);
|
|
960
|
+
const skippedLowScore = typeof rowField(lowScoreRow, 'n') === 'number' ? rowField(lowScoreRow, 'n') : 0;
|
|
961
|
+
const rows = db.prepare(`SELECT p.canonical_pain_id, p.session_id, p.source, p.score, p.reason ${barePainPredicate} AND p.score >= ? ORDER BY p.id LIMIT ?`)
|
|
962
|
+
.all(input.hostKind, GOVERNANCE_STRONG_PAIN_SCORE, limit);
|
|
963
|
+
let admitted = 0;
|
|
964
|
+
let ensured = 0;
|
|
965
|
+
let skippedInvalid = 0;
|
|
966
|
+
const degradations = [];
|
|
967
|
+
const freshMarkers = [];
|
|
968
|
+
for (const row of rows) {
|
|
969
|
+
const painId = rowField(row, 'canonical_pain_id');
|
|
970
|
+
const sessionId = rowField(row, 'session_id');
|
|
971
|
+
const score = rowField(row, 'score');
|
|
972
|
+
if (typeof painId !== 'string' || painId.length === 0 || typeof sessionId !== 'string' || sessionId.length === 0
|
|
973
|
+
|| typeof score !== 'number' || !Number.isFinite(score)) {
|
|
974
|
+
skippedInvalid += 1;
|
|
975
|
+
continue;
|
|
976
|
+
}
|
|
977
|
+
const logicalObservationKey = `${input.hostKind}|${sessionId}|${painId}`;
|
|
978
|
+
const reason = typeof rowField(row, 'reason') === 'string' ? rowField(row, 'reason') : '';
|
|
979
|
+
const source = typeof rowField(row, 'source') === 'string' ? rowField(row, 'source') : 'tool_failure';
|
|
980
|
+
// The pain row carries the tool name only inside its reason prefix
|
|
981
|
+
// (`tool=<name>; ...` — the production writer's format); the row's
|
|
982
|
+
// source column is the failure class, used as the fallback.
|
|
983
|
+
const toolName = /^tool=([^;]{1,120});/.exec(reason)?.[1] ?? source;
|
|
984
|
+
const inserted = db.transaction(() => {
|
|
985
|
+
// Re-probe inside the transaction: a concurrent sweep or live admission
|
|
986
|
+
// may have marked this pain between the scan and this write.
|
|
987
|
+
if (db.prepare('SELECT 1 FROM governance_signal_admissions WHERE canonical_pain_id = ?').get(painId) !== undefined)
|
|
988
|
+
return false;
|
|
989
|
+
insertAdmissionMarker({
|
|
990
|
+
db,
|
|
991
|
+
identity: { hostKind: input.hostKind, logicalObservationKey, rolloutIdentity: sessionId, rootSessionId: sessionId, signalKind: 'tool_failure' },
|
|
992
|
+
canonicalPainId: painId,
|
|
993
|
+
ruleVersion: null,
|
|
994
|
+
reason,
|
|
995
|
+
payloadJson: toolFailureTaskPayload({ hostKind: input.hostKind, logicalObservationKey, sessionId, toolName, reason, score, workspaceDir }),
|
|
996
|
+
nowIso,
|
|
997
|
+
});
|
|
998
|
+
return true;
|
|
999
|
+
})();
|
|
1000
|
+
if (inserted) {
|
|
1001
|
+
admitted += 1;
|
|
1002
|
+
freshMarkers.push({ logicalObservationKey, canonicalPainId: painId });
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
// Reuse the crash-safe ensure semantics unchanged: deterministic task id,
|
|
1006
|
+
// task-store PK idempotency, Case-B link repair.
|
|
1007
|
+
for (const marker of freshMarkers) {
|
|
1008
|
+
const continuation = await ensureGovernanceDiagnosticianTask({
|
|
1009
|
+
workspaceDir,
|
|
1010
|
+
logicalObservationKey: marker.logicalObservationKey,
|
|
1011
|
+
canonicalPainId: marker.canonicalPainId,
|
|
1012
|
+
...(input.databaseFactory ? { databaseFactory: input.databaseFactory } : {}),
|
|
1013
|
+
});
|
|
1014
|
+
if (continuation.ok) {
|
|
1015
|
+
if (continuation.created)
|
|
1016
|
+
ensured += 1;
|
|
1017
|
+
}
|
|
1018
|
+
else {
|
|
1019
|
+
degradations.push(`${marker.logicalObservationKey}:${continuation.reason}`);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
return {
|
|
1023
|
+
ok: degradations.length === 0,
|
|
1024
|
+
...(degradations.length > 0 ? { reason: 'bare_pain_admission_degradations', nextAction: 'inspect the per-item degradations; the admitted pains and markers remain durable and reconcile retries task creation' } : {}),
|
|
1025
|
+
admitted, ensured, skippedLowScore, skippedInvalid,
|
|
1026
|
+
degradations: degradations.slice(0, 10),
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
catch (error) {
|
|
1030
|
+
const detail = error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200);
|
|
1031
|
+
return { ok: false, reason: `bare_pain_admission_failed:${detail}`, nextAction: 'inspect the workspace trajectory database and retry; committed markers remain durable', admitted: 0, ensured: 0, skippedLowScore: 0, skippedInvalid: 0, degradations: [`bare_pain_admission_failed:${detail}`] };
|
|
1032
|
+
}
|
|
1033
|
+
finally {
|
|
1034
|
+
close();
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
794
1037
|
/**
|
|
795
1038
|
* Narrow idempotent reconciliation between the trajectory admission markers
|
|
796
1039
|
* and the Runtime V2 task store (separate SQLite databases — no cross-store
|
|
@@ -826,6 +1069,14 @@ export async function reconcileGovernanceContinuation(input) {
|
|
|
826
1069
|
// Case A/B: task link missing (crash before task, or before the link write)
|
|
827
1070
|
// Case C: promotion never started (no observation carries this painRef)
|
|
828
1071
|
//
|
|
1072
|
+
// Case C/D (promotion recovery) is scoped to the hosts whose evidence
|
|
1073
|
+
// substrate it exists for: the promotion rows come from transcript
|
|
1074
|
+
// ingestion (governance_rollouts/observations), which only Codex feeds.
|
|
1075
|
+
// A WorkBuddy marker is COMPLETE with task+link — its hook is the only
|
|
1076
|
+
// evidence producer and the MVP excludes transcript reads, so demanding a
|
|
1077
|
+
// promotion row would degrade reconciliation with rollout_not_found
|
|
1078
|
+
// forever (review R2/P1).
|
|
1079
|
+
//
|
|
829
1080
|
// A pending tail (promotion started, waiting for the next assistant turn)
|
|
830
1081
|
// is NOT a recovery need — it's a forward-looking state resolved by future
|
|
831
1082
|
// evidence. The live already_admitted redelivery path (ensureContinuation
|
|
@@ -833,13 +1084,14 @@ export async function reconcileGovernanceContinuation(input) {
|
|
|
833
1084
|
// not retry pending tails, so pending-tail markers do not block later
|
|
834
1085
|
// markers. Stale tails are NOT auto-recoverable (substrate refuses to
|
|
835
1086
|
// re-arm them): they are counted separately below and reported.
|
|
836
|
-
const markers = db.prepare(`SELECT a.logical_observation_key, a.canonical_pain_id
|
|
1087
|
+
const markers = db.prepare(`SELECT a.logical_observation_key, a.canonical_pain_id, a.host_kind
|
|
837
1088
|
FROM governance_signal_admissions a
|
|
838
1089
|
WHERE a.decision = 'admitted'
|
|
839
1090
|
AND (
|
|
840
1091
|
a.diagnostician_task_id IS NULL
|
|
841
|
-
OR
|
|
842
|
-
|
|
1092
|
+
OR (a.host_kind = 'codex'
|
|
1093
|
+
AND NOT EXISTS (SELECT 1 FROM governance_observations o
|
|
1094
|
+
WHERE o.promotion_ref = a.canonical_pain_id))
|
|
843
1095
|
)
|
|
844
1096
|
ORDER BY a.id LIMIT ?`).all(limit);
|
|
845
1097
|
for (const row of markers) {
|
|
@@ -847,6 +1099,23 @@ export async function reconcileGovernanceContinuation(input) {
|
|
|
847
1099
|
const painId = rowField(row, 'canonical_pain_id');
|
|
848
1100
|
if (typeof key !== 'string' || typeof painId !== 'string')
|
|
849
1101
|
continue;
|
|
1102
|
+
// WorkBuddy (and any future no-transcript host) markers continue through
|
|
1103
|
+
// the task-ensure seam ONLY: there is no promotion substrate to recover,
|
|
1104
|
+
// and routing them through ensureGovernanceContinuation would report a
|
|
1105
|
+
// permanent rollout_not_found degradation despite a healthy task link.
|
|
1106
|
+
if (rowField(row, 'host_kind') !== 'codex') {
|
|
1107
|
+
const ensured = await ensureGovernanceDiagnosticianTask({ workspaceDir, logicalObservationKey: key, canonicalPainId: painId });
|
|
1108
|
+
if (ensured.ok) {
|
|
1109
|
+
if (ensured.created)
|
|
1110
|
+
tasksEnsured += 1;
|
|
1111
|
+
if (ensured.linkRepaired)
|
|
1112
|
+
linksRepaired += 1;
|
|
1113
|
+
}
|
|
1114
|
+
else {
|
|
1115
|
+
degradations.push(`${key}:${ensured.reason}`);
|
|
1116
|
+
}
|
|
1117
|
+
continue;
|
|
1118
|
+
}
|
|
850
1119
|
const cont = await ensureGovernanceContinuation({ workspaceDir, logicalObservationKey: key, canonicalPainId: painId });
|
|
851
1120
|
if (cont.ok) {
|
|
852
1121
|
// Only count REAL actions: a task actually created, a link actually
|
|
@@ -96,7 +96,13 @@ export function readWorkspaceHostKindFacts(workspaceDir) {
|
|
|
96
96
|
nextAction: provenance.nextAction,
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
|
-
|
|
99
|
+
// Known-host filter — must stay in lockstep with PROMPT_INJECTION_TARGET_HOSTS
|
|
100
|
+
// (prompt-injection-projection.ts, the roster SSoT). Importing that roster here
|
|
101
|
+
// would create a module cycle (the projection reads host facts from THIS
|
|
102
|
+
// module), so the set is restated with this sync note. Review R1: a two-host
|
|
103
|
+
// filter silently dropped WorkBuddy pain evidence, so a WorkBuddy-only
|
|
104
|
+
// workspace could never confirm its shared route from persisted facts.
|
|
105
|
+
const evidenceKinds = provenance.kinds.filter((kind) => kind === 'openclaw' || kind === 'codex' || kind === 'workbuddy');
|
|
100
106
|
const effectiveKinds = [...new Set([...declaredKinds, ...evidenceKinds])].sort();
|
|
101
107
|
return { ok: true, declaredKinds, evidenceKinds, effectiveKinds };
|
|
102
108
|
}
|
|
@@ -31,6 +31,7 @@ export * from './product-telemetry/service.js';
|
|
|
31
31
|
export * from './codex-disclosure.js';
|
|
32
32
|
export * from './codex-ingestion-consent.js';
|
|
33
33
|
export * from './codex-worker-status.js';
|
|
34
|
+
export * from './workbuddy-worker-status.js';
|
|
34
35
|
export * from './codex-legacy-registration.js';
|
|
35
36
|
export * from './codex-transcript-locate.js';
|
|
36
37
|
export * from './intervention-evidence-ingress.js';
|
|
@@ -53,6 +53,10 @@ export * from './codex-ingestion-consent.js';
|
|
|
53
53
|
// PRI-625 Slice D: ONE §15 worker-mode authority, moved from codex-adapter so
|
|
54
54
|
// the CLI, the Console, and the worker share the same semantics.
|
|
55
55
|
export * from './codex-worker-status.js';
|
|
56
|
+
// WorkBuddy third host (SPEC workbuddy-host-adapter §5): the §15 worker-mode
|
|
57
|
+
// authority for the WorkBuddy governance workspace — same one-semantics
|
|
58
|
+
// placement as the Codex evaluation above, no ingestion step to gate.
|
|
59
|
+
export * from './workbuddy-worker-status.js';
|
|
56
60
|
// PRI-625 Slice D: ONE legacy-registration predicate (installer refusal,
|
|
57
61
|
// health dualRegistration, and future setup flows all read the same fact).
|
|
58
62
|
export * from './codex-legacy-registration.js';
|
|
@@ -226,7 +230,7 @@ export function createProductionHostRuntime(options = {}) {
|
|
|
226
230
|
skippedWarnings: prompt.warnings,
|
|
227
231
|
injectedCharCount: prompt.additionalContext.length,
|
|
228
232
|
budget: RUNTIME_V2_PRINCIPLE_BUDGET,
|
|
229
|
-
...(options.hostKind === 'openclaw' || options.hostKind === 'codex' ? { hostKind: options.hostKind } : {}),
|
|
233
|
+
...(options.hostKind === 'openclaw' || options.hostKind === 'codex' || options.hostKind === 'workbuddy' ? { hostKind: options.hostKind } : {}),
|
|
230
234
|
eventId: randomUUID(),
|
|
231
235
|
...(prompt.truncated !== undefined ? { v2Truncated: prompt.truncated } : {}),
|
|
232
236
|
...(event.context.turnId !== undefined ? { runId: event.context.turnId } : {}),
|
|
@@ -71,6 +71,18 @@ export interface InternalizationConsumerCycleOutcome {
|
|
|
71
71
|
readonly taskKind?: string;
|
|
72
72
|
readonly runStatus?: 'succeeded' | 'failed' | 'retried';
|
|
73
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* PRI-954 (F10) oldest-ready-stage-first ordering. Returns the configured
|
|
76
|
+
* runner kinds reordered to start at the stage that owns the globally oldest
|
|
77
|
+
* ready task (by `createdAt`); later stages keep their relative priority
|
|
78
|
+
* order, so dependency order inside one stage scan is untouched. Tasks
|
|
79
|
+
* without a readable createdAt sort last for ordering purposes (their stage
|
|
80
|
+
* keeps the default position) — unknown age never jumps the queue.
|
|
81
|
+
*/
|
|
82
|
+
export declare function orderKindsByOldestReadyStage<T extends string>(runnerKinds: readonly T[], readyTasks: readonly {
|
|
83
|
+
taskKind: T;
|
|
84
|
+
createdAt?: string;
|
|
85
|
+
}[]): T[];
|
|
74
86
|
/**
|
|
75
87
|
* Run ONE bounded consumer cycle for a workspace. At most one downstream task
|
|
76
88
|
* is leased and executed per cycle (DEFAULT_CONSUMER_MAX_TASKS_PER_CYCLE=1);
|