openclaw-hybrid-memory 2026.5.310 → 2026.6.10
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/api/plugin-runtime.ts +2 -0
- package/backends/facts-db/contradictions.ts +1 -1
- package/cli/cmd-extract-directives.ts +225 -11
- package/cli/cmd-extract-proposals.ts +5 -6
- package/cli/cmd-extract-reinforcement.ts +71 -0
- package/cli/cmd-feedback.ts +15 -9
- package/cli/commands/manage/register-reflection-pipeline.ts +247 -13
- package/cli/commands/manage/register-storage-maintenance.ts +224 -15
- package/cli/commands/manage/storage-stats-helpers.ts +13 -2
- package/cli/context.ts +9 -19
- package/cli/distill.ts +31 -1
- package/cli/register.ts +28 -38
- package/dist/api/plugin-runtime.js.map +1 -1
- package/dist/backends/agent-health-store.js.map +1 -1
- package/dist/backends/apitap-store.js.map +1 -1
- package/dist/backends/audit-store.js.map +1 -1
- package/dist/backends/base-sqlite-store.js.map +1 -1
- package/dist/backends/cost-tracker.js.map +1 -1
- package/dist/backends/credentials-db.js +2 -3
- package/dist/backends/credentials-db.js.map +1 -1
- package/dist/backends/crystallization-store.js.map +1 -1
- package/dist/backends/edict-store.js.map +1 -1
- package/dist/backends/event-bus.js.map +1 -1
- package/dist/backends/event-log.js.map +1 -1
- package/dist/backends/facts-db/cache-manager.js.map +1 -1
- package/dist/backends/facts-db/clusters.js.map +1 -1
- package/dist/backends/facts-db/contradictions.js +1 -1
- package/dist/backends/facts-db/contradictions.js.map +1 -1
- package/dist/backends/facts-db/crud.js.map +1 -1
- package/dist/backends/facts-db/db-connection.js.map +1 -1
- package/dist/backends/facts-db/entity-autolink.js.map +1 -1
- package/dist/backends/facts-db/entity-layer.js.map +1 -1
- package/dist/backends/facts-db/episodes.js.map +1 -1
- package/dist/backends/facts-db/fact-queries.js.map +1 -1
- package/dist/backends/facts-db/fact-read-queries.js.map +1 -1
- package/dist/backends/facts-db/facts-db-layer1.js.map +1 -1
- package/dist/backends/facts-db/facts-db-layer2.js.map +1 -1
- package/dist/backends/facts-db/facts-db-layer3.js.map +1 -1
- package/dist/backends/facts-db/fts-text.js.map +1 -1
- package/dist/backends/facts-db/generated-skills/policy.js.map +1 -1
- package/dist/backends/facts-db/generated-skills.js.map +1 -1
- package/dist/backends/facts-db/housekeeping.js.map +1 -1
- package/dist/backends/facts-db/links.js.map +1 -1
- package/dist/backends/facts-db/maintenance.js.map +1 -1
- package/dist/backends/facts-db/procedures/crud.js.map +1 -1
- package/dist/backends/facts-db/procedures/internal.js.map +1 -1
- package/dist/backends/facts-db/procedures/promotion.js.map +1 -1
- package/dist/backends/facts-db/procedures/search.js.map +1 -1
- package/dist/backends/facts-db/procedures/stats.js.map +1 -1
- package/dist/backends/facts-db/reinforcement.js.map +1 -1
- package/dist/backends/facts-db/row-mapper.js.map +1 -1
- package/dist/backends/facts-db/scan-cursors.js.map +1 -1
- package/dist/backends/facts-db/schema-bootstrap.js.map +1 -1
- package/dist/backends/facts-db/scope-sql.js.map +1 -1
- package/dist/backends/facts-db/search.js.map +1 -1
- package/dist/backends/facts-db/stats.js.map +1 -1
- package/dist/backends/facts-db/types.js.map +1 -1
- package/dist/backends/facts-db/variants.js.map +1 -1
- package/dist/backends/identity-reflection-store.js.map +1 -1
- package/dist/backends/issue-store.js.map +1 -1
- package/dist/backends/learnings-db.js.map +1 -1
- package/dist/backends/migrations/facts-migrations.js.map +1 -1
- package/dist/backends/migrations/procedures.js.map +1 -1
- package/dist/backends/narratives-db.js.map +1 -1
- package/dist/backends/persona-state-store.js.map +1 -1
- package/dist/backends/proposals-db.js.map +1 -1
- package/dist/backends/scope-filter-sql.js.map +1 -1
- package/dist/backends/sqlite-schema-meta.js.map +1 -1
- package/dist/backends/tool-proposal-store.js.map +1 -1
- package/dist/backends/vector-db/constants.js.map +1 -1
- package/dist/backends/vector-db/path-utils.js.map +1 -1
- package/dist/backends/vector-db/runtime-locks.js.map +1 -1
- package/dist/backends/vector-db/vector-db-class.js.map +1 -1
- package/dist/backends/wal.js.map +1 -1
- package/dist/backends/workflow-store.js.map +1 -1
- package/dist/benchmark/shadow-eval.js.map +1 -1
- package/dist/cli/active-tasks.js.map +1 -1
- package/dist/cli/backup.js.map +1 -1
- package/dist/cli/benchmark.js.map +1 -1
- package/dist/cli/cmd-backfill.js.map +1 -1
- package/dist/cli/cmd-config.js.map +1 -1
- package/dist/cli/cmd-credentials.js.map +1 -1
- package/dist/cli/cmd-demo.js.map +1 -1
- package/dist/cli/cmd-distill.js.map +1 -1
- package/dist/cli/cmd-doctor.js.map +1 -1
- package/dist/cli/cmd-examples.js.map +1 -1
- package/dist/cli/cmd-extract-daily.js.map +1 -1
- package/dist/cli/cmd-extract-directives.js +141 -10
- package/dist/cli/cmd-extract-directives.js.map +1 -1
- package/dist/cli/cmd-extract-procedures.js.map +1 -1
- package/dist/cli/cmd-extract-proposals.js +3 -2
- package/dist/cli/cmd-extract-proposals.js.map +1 -1
- package/dist/cli/cmd-extract-reinforcement.js +39 -0
- package/dist/cli/cmd-extract-reinforcement.js.map +1 -1
- package/dist/cli/cmd-extract-sessions.js.map +1 -1
- package/dist/cli/cmd-feedback.js +9 -4
- package/dist/cli/cmd-feedback.js.map +1 -1
- package/dist/cli/cmd-health.js.map +1 -1
- package/dist/cli/cmd-providers.js.map +1 -1
- package/dist/cli/cmd-selfcorrection.js.map +1 -1
- package/dist/cli/cmd-setup.js.map +1 -1
- package/dist/cli/cmd-status.js.map +1 -1
- package/dist/cli/cmd-store.js.map +1 -1
- package/dist/cli/cmd-user-friendly.js.map +1 -1
- package/dist/cli/cmd-verify.js.map +1 -1
- package/dist/cli/commands/manage/bindings.js.map +1 -1
- package/dist/cli/commands/manage/dream-cycle-followup.js.map +1 -1
- package/dist/cli/commands/manage/maintenance-heartbeat.js.map +1 -1
- package/dist/cli/commands/manage/register-agents-audit-runall.js.map +1 -1
- package/dist/cli/commands/manage/register-analyze-maintenance-logs.js.map +1 -1
- package/dist/cli/commands/manage/register-budget-proposals.js.map +1 -1
- package/dist/cli/commands/manage/register-config-cli.js.map +1 -1
- package/dist/cli/commands/manage/register-corrections-and-pipeline.js.map +1 -1
- package/dist/cli/commands/manage/register-corrections.js.map +1 -1
- package/dist/cli/commands/manage/register-council.js.map +1 -1
- package/dist/cli/commands/manage/register-credentials-scope.js.map +1 -1
- package/dist/cli/commands/manage/register-digest.js.map +1 -1
- package/dist/cli/commands/manage/register-lifecycle.js.map +1 -1
- package/dist/cli/commands/manage/register-procedure-lifecycle.js.map +1 -1
- package/dist/cli/commands/manage/register-reconcile-cron-ledgers.js.map +1 -1
- package/dist/cli/commands/manage/register-reflection-pipeline.js +144 -7
- package/dist/cli/commands/manage/register-reflection-pipeline.js.map +1 -1
- package/dist/cli/commands/manage/register-self-correction-feedback.js.map +1 -1
- package/dist/cli/commands/manage/register-storage-and-stats.js.map +1 -1
- package/dist/cli/commands/manage/register-storage-entities-decay.js.map +1 -1
- package/dist/cli/commands/manage/register-storage-graph-audit.js.map +1 -1
- package/dist/cli/commands/manage/register-storage-maintenance.js +152 -9
- package/dist/cli/commands/manage/register-storage-maintenance.js.map +1 -1
- package/dist/cli/commands/manage/register-validate-cron-exit.js.map +1 -1
- package/dist/cli/commands/manage/storage-stats-helpers.js +10 -3
- package/dist/cli/commands/manage/storage-stats-helpers.js.map +1 -1
- package/dist/cli/commands/register-manage-commands.js.map +1 -1
- package/dist/cli/config-feature-summaries.js.map +1 -1
- package/dist/cli/config-output-sink.js.map +1 -1
- package/dist/cli/distill-session-jsonl.js.map +1 -1
- package/dist/cli/distill.js +10 -1
- package/dist/cli/distill.js.map +1 -1
- package/dist/cli/global-verbose.js.map +1 -1
- package/dist/cli/goals.js.map +1 -1
- package/dist/cli/hybrid-mem-commander-utils.js.map +1 -1
- package/dist/cli/install/config-merge.js.map +1 -1
- package/dist/cli/install/cron-jobs.js.map +1 -1
- package/dist/cli/install/embedding-detect.js.map +1 -1
- package/dist/cli/install/run-install.js.map +1 -1
- package/dist/cli/install/workspace.js.map +1 -1
- package/dist/cli/proposals.js.map +1 -1
- package/dist/cli/register.js.map +1 -1
- package/dist/cli/shared.js.map +1 -1
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/task-queue-status.js.map +1 -1
- package/dist/cli/verified.js.map +1 -1
- package/dist/cli/verify/fact-count.js.map +1 -1
- package/dist/cli/verify/openclaw-config.js.map +1 -1
- package/dist/cli/verify/plugin-config-credentials.js.map +1 -1
- package/dist/cli/verify/sections/config-cron.js.map +1 -1
- package/dist/cli/verify/sections/embeddings.js.map +1 -1
- package/dist/cli/verify/sections/infrastructure.js.map +1 -1
- package/dist/cli/verify/sections/llm-models.js.map +1 -1
- package/dist/cli/verify/sections/reconcile.js.map +1 -1
- package/dist/cli/verify/verify-run-state.js.map +1 -1
- package/dist/cli/verify-llm-azure-auth.js.map +1 -1
- package/dist/cli/verify.js.map +1 -1
- package/dist/config/hybrid-schema.js.map +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/maintenance-fallback-policy.js.map +1 -1
- package/dist/config/parsers/capture.js.map +1 -1
- package/dist/config/parsers/core.js.map +1 -1
- package/dist/config/parsers/features.js.map +1 -1
- package/dist/config/parsers/index.js.map +1 -1
- package/dist/config/parsers/maintenance.js.map +1 -1
- package/dist/config/parsers/retrieval.js.map +1 -1
- package/dist/config/parsers/sensors.js.map +1 -1
- package/dist/config/skill-sections.js.map +1 -1
- package/dist/config/skill-size-limits.js.map +1 -1
- package/dist/config/types/agents.js.map +1 -1
- package/dist/config/types/bootstrap.js.map +1 -1
- package/dist/config/types/core.js.map +1 -1
- package/dist/config/types/index.js.map +1 -1
- package/dist/config/utils.js.map +1 -1
- package/dist/index-help.js.map +1 -1
- package/dist/index-testing-exports.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/lifecycle/hook-resolution-api.js.map +1 -1
- package/dist/lifecycle/hooks.js +0 -1
- package/dist/lifecycle/hooks.js.map +1 -1
- package/dist/lifecycle/resolve-agent-id.js.map +1 -1
- package/dist/lifecycle/session-state.js.map +1 -1
- package/dist/lifecycle/stage-active-task.js.map +1 -1
- package/dist/lifecycle/stage-auth-failure.js.map +1 -1
- package/dist/lifecycle/stage-capture/run-capture.js.map +1 -1
- package/dist/lifecycle/stage-capture.js.map +1 -1
- package/dist/lifecycle/stage-cleanup.js.map +1 -1
- package/dist/lifecycle/stage-credential-hint.js.map +1 -1
- package/dist/lifecycle/stage-frustration.js.map +1 -1
- package/dist/lifecycle/stage-goal-stewardship.js.map +1 -1
- package/dist/lifecycle/stage-goal-subagent.js.map +1 -1
- package/dist/lifecycle/stage-injection.js +1 -1
- package/dist/lifecycle/stage-injection.js.map +1 -1
- package/dist/lifecycle/stage-recall/run-recall.js.map +1 -1
- package/dist/lifecycle/stage-recall.js.map +1 -1
- package/dist/lifecycle/stage-setup.js.map +1 -1
- package/dist/routes/dashboard/collectors.js.map +1 -1
- package/dist/routes/dashboard/html.js.map +1 -1
- package/dist/routes/dashboard/server.js.map +1 -1
- package/dist/routes/dashboard-graph.js.map +1 -1
- package/dist/routes/graphql-resolvers.js.map +1 -1
- package/dist/routes/graphql-server.js.map +1 -1
- package/dist/services/active-task-checkpoint.js.map +1 -1
- package/dist/services/active-task-injection.js.map +1 -1
- package/dist/services/active-task.js.map +1 -1
- package/dist/services/adaptive-catch-up-pacing.js +25 -0
- package/dist/services/adaptive-catch-up-pacing.js.map +1 -0
- package/dist/services/adaptive-maintenance-llm.js.map +1 -1
- package/dist/services/adaptive-model-limits.js.map +1 -1
- package/dist/services/ambient-retrieval.js.map +1 -1
- package/dist/services/apitap-service.js.map +1 -1
- package/dist/services/audit-health-exit-info.js.map +1 -1
- package/dist/services/audit-health-json.js.map +1 -1
- package/dist/services/auth-failure-detect.js.map +1 -1
- package/dist/services/auto-capture.js.map +1 -1
- package/dist/services/auto-classifier.js.map +1 -1
- package/dist/services/auto-skills-audit.js.map +1 -1
- package/dist/services/bootstrap-optional.js.map +1 -1
- package/dist/services/bootstrap-priority.js.map +1 -1
- package/dist/services/bootstrap.js.map +1 -1
- package/dist/services/capture-provenance.js.map +1 -1
- package/dist/services/capture-utils.js.map +1 -1
- package/dist/services/chat.js +22 -3
- package/dist/services/chat.js.map +1 -1
- package/dist/services/classification-scope.js.map +1 -1
- package/dist/services/classification.js.map +1 -1
- package/dist/services/cli-sql-dump.js.map +1 -1
- package/dist/services/consolidation.js.map +1 -1
- package/dist/services/context-audit.js +1 -1
- package/dist/services/context-audit.js.map +1 -1
- package/dist/services/context-budget.js.map +1 -1
- package/dist/services/context-engine.js.map +1 -1
- package/dist/services/contextual-variants.js.map +1 -1
- package/dist/services/continuous-verifier.js.map +1 -1
- package/dist/services/contradiction-adjudicator.js.map +1 -1
- package/dist/services/cost-context.js.map +1 -1
- package/dist/services/cost-feature-labels.js.map +1 -1
- package/dist/services/credential-migration.js.map +1 -1
- package/dist/services/credential-scanner.js.map +1 -1
- package/dist/services/credential-validation.js.map +1 -1
- package/dist/services/cron-exit-validator.js.map +1 -1
- package/dist/services/cron-guard.js.map +1 -1
- package/dist/services/cron-job-bash-harness.js +52 -5
- package/dist/services/cron-job-bash-harness.js.map +1 -1
- package/dist/services/cron-maintenance-reconciler.js +1 -3
- package/dist/services/cron-maintenance-reconciler.js.map +1 -1
- package/dist/services/cross-agent-learning.js.map +1 -1
- package/dist/services/crystallization-proposer.js.map +1 -1
- package/dist/services/dedupe-policy.js.map +1 -1
- package/dist/services/deprecated-cron-commands.js.map +1 -1
- package/dist/services/directive-extract.js.map +1 -1
- package/dist/services/document-chunker.js.map +1 -1
- package/dist/services/document-grader.js.map +1 -1
- package/dist/services/dream-cycle.js.map +1 -1
- package/dist/services/embedding-migration.js.map +1 -1
- package/dist/services/embedding-registry.js.map +1 -1
- package/dist/services/embeddings/chain-provider.js.map +1 -1
- package/dist/services/embeddings/factory.js.map +1 -1
- package/dist/services/embeddings/fallback-provider.js.map +1 -1
- package/dist/services/embeddings/ollama-provider.js.map +1 -1
- package/dist/services/embeddings/onnx-provider.js.map +1 -1
- package/dist/services/embeddings/openai-provider.js.map +1 -1
- package/dist/services/embeddings/shared.js +3 -3
- package/dist/services/embeddings/shared.js.map +1 -1
- package/dist/services/embeddings/types.js.map +1 -1
- package/dist/services/entity-enrichment-adaptive.js +128 -0
- package/dist/services/entity-enrichment-adaptive.js.map +1 -0
- package/dist/services/entity-enrichment-cli.js +389 -42
- package/dist/services/entity-enrichment-cli.js.map +1 -1
- package/dist/services/entity-enrichment.js +31 -5
- package/dist/services/entity-enrichment.js.map +1 -1
- package/dist/services/error-reporter/noisy-errors.js.map +1 -1
- package/dist/services/error-reporter/sanitize.js.map +1 -1
- package/dist/services/error-reporter.js.map +1 -1
- package/dist/services/event-hub-repair.js.map +1 -1
- package/dist/services/export-memory.js.map +1 -1
- package/dist/services/fact-extraction.js.map +1 -1
- package/dist/services/feedback-effectiveness.js.map +1 -1
- package/dist/services/find-duplicates.js.map +1 -1
- package/dist/services/frustration-detector.js.map +1 -1
- package/dist/services/fts-search.js.map +1 -1
- package/dist/services/gap-detector.js.map +1 -1
- package/dist/services/generated-skill-lifecycle.js.map +1 -1
- package/dist/services/generated-skill-validation.js.map +1 -1
- package/dist/services/goal-active-task-mirror.js.map +1 -1
- package/dist/services/goal-circuit-breaker.js.map +1 -1
- package/dist/services/goal-health.js.map +1 -1
- package/dist/services/goal-registry.js.map +1 -1
- package/dist/services/goal-stewardship-heartbeat.js.map +1 -1
- package/dist/services/goal-stewardship-llm-triage.js.map +1 -1
- package/dist/services/goal-stewardship-verify-cron.js.map +1 -1
- package/dist/services/goal-stewardship.js.map +1 -1
- package/dist/services/goal-subagent.js.map +1 -1
- package/dist/services/graph-retrieval.js.map +1 -1
- package/dist/services/humanizer-score.js.map +1 -1
- package/dist/services/hybrid-mem-cron-default-job-steps.js.map +1 -1
- package/dist/services/hyde-helper.js.map +1 -1
- package/dist/services/identity-reflection.js.map +1 -1
- package/dist/services/implicit-feedback-extract.js.map +1 -1
- package/dist/services/index.js.map +1 -1
- package/dist/services/ingest-utils.js.map +1 -1
- package/dist/services/intent-template.js.map +1 -1
- package/dist/services/json-array-parser.js.map +1 -1
- package/dist/services/knowledge-gaps.js.map +1 -1
- package/dist/services/language-keywords-build.js.map +1 -1
- package/dist/services/lifecycle/github-adapter.js.map +1 -1
- package/dist/services/llm-rate-limit-headers.js +1 -2
- package/dist/services/llm-rate-limit-headers.js.map +1 -1
- package/dist/services/maintenance-auto-fix.js.map +1 -1
- package/dist/services/maintenance-log-analyzer.js +7 -1
- package/dist/services/maintenance-log-analyzer.js.map +1 -1
- package/dist/services/maintenance-timestamp.js.map +1 -1
- package/dist/services/memory-diagnostics.js.map +1 -1
- package/dist/services/memory-index.js.map +1 -1
- package/dist/services/merge-results.js.map +1 -1
- package/dist/services/model-capabilities.js.map +1 -1
- package/dist/services/model-pricing.js.map +1 -1
- package/dist/services/narrative-recall.js.map +1 -1
- package/dist/services/openclaw-session-artifact.js.map +1 -1
- package/dist/services/passive-observer.js.map +1 -1
- package/dist/services/pattern-detector-hash.js.map +1 -1
- package/dist/services/pattern-detector.js.map +1 -1
- package/dist/services/pending-autopilot/foundation.js.map +1 -1
- package/dist/services/pending-autopilot/redaction.js.map +1 -1
- package/dist/services/pending-autopilot/store.js.map +1 -1
- package/dist/services/pending-autopilot/types.js.map +1 -1
- package/dist/services/pending-digest-autopilot-cron.js.map +1 -1
- package/dist/services/pending-digest-autopilot.js.map +1 -1
- package/dist/services/pending-review-digest.js.map +1 -1
- package/dist/services/persona-proposal-triage.js.map +1 -1
- package/dist/services/persona-state-promotion.js.map +1 -1
- package/dist/services/post-compaction-recall.js.map +1 -1
- package/dist/services/pre-consolidation-flush.js.map +1 -1
- package/dist/services/pre-finalization-guard.js.map +1 -1
- package/dist/services/procedure-cluster.js.map +1 -1
- package/dist/services/procedure-extractor.js.map +1 -1
- package/dist/services/procedure-promotion/duplicate-skill-cache.js.map +1 -1
- package/dist/services/procedure-promotion-policy.js.map +1 -1
- package/dist/services/procedure-selection-metrics.js.map +1 -1
- package/dist/services/procedure-skill-eval.js.map +1 -1
- package/dist/services/procedure-skill-generator.js.map +1 -1
- package/dist/services/procedure-skill-recipe.js.map +1 -1
- package/dist/services/procedure-skill-shrink.js.map +1 -1
- package/dist/services/procedure-skill-workflow.js.map +1 -1
- package/dist/services/provenance.js.map +1 -1
- package/dist/services/public-export-bundle.js.map +1 -1
- package/dist/services/python-bridge.js.map +1 -1
- package/dist/services/query-expander.js.map +1 -1
- package/dist/services/query-validator.js.map +1 -1
- package/dist/services/recall-pipeline.js.map +1 -1
- package/dist/services/recall-timing.js.map +1 -1
- package/dist/services/recent-http-attempts.js.map +1 -1
- package/dist/services/reflection/shared.js.map +1 -1
- package/dist/services/reflection.js.map +1 -1
- package/dist/services/reinforcement-extract.js.map +1 -1
- package/dist/services/reranker.js.map +1 -1
- package/dist/services/responses-adapter.js.map +1 -1
- package/dist/services/retrieval-aliases.js.map +1 -1
- package/dist/services/retrieval-mode-policy.js.map +1 -1
- package/dist/services/retrieval-orchestrator/packing.js.map +1 -1
- package/dist/services/retrieval-orchestrator.d.ts +2 -3
- package/dist/services/retrieval-orchestrator.js.map +1 -1
- package/dist/services/rrf-fusion.js.map +1 -1
- package/dist/services/self-correction-extract.js.map +1 -1
- package/dist/services/session-observability.js.map +1 -1
- package/dist/services/session-pre-filter.js.map +1 -1
- package/dist/services/shortest-path.js.map +1 -1
- package/dist/services/skill-allowed-tools.js.map +1 -1
- package/dist/services/skill-creator-validator.js.map +1 -1
- package/dist/services/skill-crystallizer-helpers.js.map +1 -1
- package/dist/services/skill-crystallizer.js.map +1 -1
- package/dist/services/skill-description-builder.js.map +1 -1
- package/dist/services/skill-eval-synthesizer.js.map +1 -1
- package/dist/services/skill-examples-builder.js.map +1 -1
- package/dist/services/skill-frontmatter.js.map +1 -1
- package/dist/services/skill-name-validator.js.map +1 -1
- package/dist/services/skill-prompt-injection.js.map +1 -1
- package/dist/services/skill-reference-sidecar.js.map +1 -1
- package/dist/services/skill-script-bundler.js.map +1 -1
- package/dist/services/skill-validator.js.map +1 -1
- package/dist/services/startup-memory-attribution.js.map +1 -1
- package/dist/services/task-hygiene.js.map +1 -1
- package/dist/services/task-ledger/canonical.js.map +1 -1
- package/dist/services/task-ledger-facts.js.map +1 -1
- package/dist/services/task-queue-leases.js.map +1 -1
- package/dist/services/task-queue-watchdog.js.map +1 -1
- package/dist/services/tool-effectiveness.js.map +1 -1
- package/dist/services/tool-proposer.js.map +1 -1
- package/dist/services/tools-md-section.js.map +1 -1
- package/dist/services/topic-clusters.js.map +1 -1
- package/dist/services/trajectory-tracker.js.map +1 -1
- package/dist/services/vector-backend-observability.js.map +1 -1
- package/dist/services/vector-lifecycle-audit.js.map +1 -1
- package/dist/services/vector-maintenance.js.map +1 -1
- package/dist/services/vector-search.js.map +1 -1
- package/dist/services/verification-store.js.map +1 -1
- package/dist/services/verified-fact-triage.js.map +1 -1
- package/dist/services/wal-helpers.js.map +1 -1
- package/dist/services/workflow-tracker.js.map +1 -1
- package/dist/setup/bootstrap-databases.js.map +1 -1
- package/dist/setup/cli-context/cli-services.js.map +1 -1
- package/dist/setup/cli-context/help-text.js.map +1 -1
- package/dist/setup/cli-context/metadata.js.map +1 -1
- package/dist/setup/cli-context/register-cli-with-help.js.map +1 -1
- package/dist/setup/cli-context/register-full.js.map +1 -1
- package/dist/setup/cli-context/register-help.js.map +1 -1
- package/dist/setup/cost-instrumentation.js.map +1 -1
- package/dist/setup/hybrid-memory-generation-state.js.map +1 -1
- package/dist/setup/hybrid-memory-reload-coordinator.js +13 -13
- package/dist/setup/hybrid-memory-reload-coordinator.js.map +1 -1
- package/dist/setup/plugin-service.js.map +1 -1
- package/dist/setup/provider-router.js.map +1 -1
- package/dist/setup/register-context-engine.js.map +1 -1
- package/dist/setup/register-hooks.js.map +1 -1
- package/dist/setup/register-plugin.js +25 -21
- package/dist/setup/register-plugin.js.map +1 -1
- package/dist/setup/register-tools.js.map +1 -1
- package/dist/setup/reregister-policy.js +2 -2
- package/dist/setup/reregister-policy.js.map +1 -1
- package/dist/setup/tool-installers.js.map +1 -1
- package/dist/setup/workspace-bootstrap.js.map +1 -1
- package/dist/src/worker/narratives.js.map +1 -1
- package/dist/tools/apitap-tools.js.map +1 -1
- package/dist/tools/credential-tools.js.map +1 -1
- package/dist/tools/crystallization-tools.js.map +1 -1
- package/dist/tools/dashboard-routes.js.map +1 -1
- package/dist/tools/document-tools.js.map +1 -1
- package/dist/tools/goal-tools.js.map +1 -1
- package/dist/tools/graph-tools.js.map +1 -1
- package/dist/tools/issue-tools.js.map +1 -1
- package/dist/tools/memory/build-runtime.js.map +1 -1
- package/dist/tools/memory/helpers.js.map +1 -1
- package/dist/tools/memory/register-checkpoint-tools.js.map +1 -1
- package/dist/tools/memory/register-directory-tools.js.map +1 -1
- package/dist/tools/memory/register-edict-tools.js.map +1 -1
- package/dist/tools/memory/register-episode-tools.js.map +1 -1
- package/dist/tools/memory/register-recall-tools.js.map +1 -1
- package/dist/tools/memory/register-store-tools.js.map +1 -1
- package/dist/tools/memory-tools.js.map +1 -1
- package/dist/tools/persona-tools.js.map +1 -1
- package/dist/tools/provenance-tools.js.map +1 -1
- package/dist/tools/public-api-routes.js.map +1 -1
- package/dist/tools/safe-register-http-route.js.map +1 -1
- package/dist/tools/self-extension-tools.js.map +1 -1
- package/dist/tools/task-hygiene-tools.js.map +1 -1
- package/dist/tools/utility-tools.js.map +1 -1
- package/dist/tools/verification-tools.js.map +1 -1
- package/dist/tools/workflow-tools.js.map +1 -1
- package/dist/types/issue-types.js.map +1 -1
- package/dist/types/learnings-types.js.map +1 -1
- package/dist/types/memory.js.map +1 -1
- package/dist/utils/apim-gateway-fetch.js.map +1 -1
- package/dist/utils/atomic-write.js.map +1 -1
- package/dist/utils/auth-failover.js.map +1 -1
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/compaction-model-watchdog.js.map +1 -1
- package/dist/utils/consolidation-controls.js.map +1 -1
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/date-detector.js.map +1 -1
- package/dist/utils/dates.js.map +1 -1
- package/dist/utils/decay.js.map +1 -1
- package/dist/utils/duration.js.map +1 -1
- package/dist/utils/embed-call.js.map +1 -1
- package/dist/utils/entity-lookup-resolve.js.map +1 -1
- package/dist/utils/entity-mention-quality.js.map +1 -1
- package/dist/utils/entity-stopwords.js.map +1 -1
- package/dist/utils/env-manager.js.map +1 -1
- package/dist/utils/error-tracking.js.map +1 -1
- package/dist/utils/event-loop-yield.js.map +1 -1
- package/dist/utils/extract-last-user-message.js.map +1 -1
- package/dist/utils/extraction-from-template.js.map +1 -1
- package/dist/utils/fact-embeddings.js.map +1 -1
- package/dist/utils/file-snapshot.js.map +1 -1
- package/dist/utils/format.js.map +1 -1
- package/dist/utils/fs.js.map +1 -1
- package/dist/utils/gh-repo-arg.js.map +1 -1
- package/dist/utils/hybrid-mem-json-cli.js.map +1 -1
- package/dist/utils/language-keywords.js.map +1 -1
- package/dist/utils/lifecycle-generation.js.map +1 -1
- package/dist/utils/llm-json-array.js.map +1 -1
- package/dist/utils/llm-selection.js.map +1 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/model-provider-family.js.map +1 -1
- package/dist/utils/model-tier.js.map +1 -1
- package/dist/utils/openclaw-agent-defaults.js.map +1 -1
- package/dist/utils/path.js.map +1 -1
- package/dist/utils/plugin-root.js.map +1 -1
- package/dist/utils/plugin-update-check.js.map +1 -1
- package/dist/utils/procedure-risk.js.map +1 -1
- package/dist/utils/progress-indicators.js.map +1 -1
- package/dist/utils/prompt-loader.js.map +1 -1
- package/dist/utils/provenance.js.map +1 -1
- package/dist/utils/provider-detection.js.map +1 -1
- package/dist/utils/registration-superseded.js.map +1 -1
- package/dist/utils/salience.js.map +1 -1
- package/dist/utils/sanitize-messages.js.map +1 -1
- package/dist/utils/scope-filter.js.map +1 -1
- package/dist/utils/skill-discovery.js.map +1 -1
- package/dist/utils/sqlite-file-perms.js.map +1 -1
- package/dist/utils/sqlite-outcome-compat.js.map +1 -1
- package/dist/utils/sqlite-transaction.js.map +1 -1
- package/dist/utils/stable-stringify.js.map +1 -1
- package/dist/utils/subagent-ended-utils.js.map +1 -1
- package/dist/utils/tags.js.map +1 -1
- package/dist/utils/text.js.map +1 -1
- package/dist/utils/timeout.js.map +1 -1
- package/dist/utils/typebox.js.map +1 -1
- package/dist/utils/version-check.js.map +1 -1
- package/dist/utils/wal-replay.js.map +1 -1
- package/dist/versionInfo.js.map +1 -1
- package/index.ts +2 -2
- package/lifecycle/hooks.ts +0 -1
- package/npm-shrinkwrap.json +487 -186
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -2
- package/services/adaptive-catch-up-pacing.ts +28 -0
- package/services/chat.ts +34 -1
- package/services/cron-job-bash-harness.ts +52 -5
- package/services/embeddings/shared.ts +5 -2
- package/services/entity-enrichment-adaptive.ts +245 -0
- package/services/entity-enrichment-cli.ts +553 -47
- package/services/entity-enrichment.ts +43 -2
- package/services/llm-rate-limit-headers.ts +1 -4
- package/services/maintenance-log-analyzer.ts +13 -9
- package/services/reinforcement-extract.ts +19 -0
- package/setup/hybrid-memory-reload-coordinator.ts +26 -0
- package/setup/register-plugin.ts +62 -32
- package/setup/reregister-policy.ts +10 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-backend-observability.js","names":[],"sources":["../../services/vector-backend-observability.ts"],"sourcesContent":["import { existsSync, lstatSync, readdirSync, readFileSync, readlinkSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport type { VectorDB } from \"../backends/vector-db.js\";\n\ntype ProcStatusSnapshot = {\n vmRssKb: number | null;\n vmHwmKb: number | null;\n rssAnonKb: number | null;\n rssFileKb: number | null;\n rssShmemKb: number | null;\n vmSwapKb: number | null;\n};\n\ntype FdGroup = \"lancedb\" | \"sqlite\" | \"wal\" | \"shm\" | \"socket\" | \"pipe\" | \"anon\" | \"other\";\n\ntype FdStats = {\n total: number;\n byGroup: Record<FdGroup, number>;\n sampleTargets: Record<FdGroup, string[]>;\n lancedbPaths: string[];\n};\n\ntype SizeSummary = {\n bytes: number | null;\n scannedEntries: number;\n truncated: boolean;\n};\n\ntype LanceTableStats = {\n name: \"memories\" | \"semantic_query_cache\";\n path: string;\n exists: boolean;\n sizeBytes: number | null;\n sizeScanTruncated: boolean;\n rowCount: number | null;\n};\n\nexport type VectorBackendObservability = {\n capturedAt: string;\n memory: {\n rssBytes: number;\n heapTotalBytes: number;\n heapUsedBytes: number;\n externalBytes: number;\n arrayBuffersBytes: number;\n nativeRssEstimateBytes: number;\n procStatus: ProcStatusSnapshot | null;\n };\n fileDescriptors: FdStats | null;\n vectorDb: {\n path: string | null;\n initialized: boolean | null;\n lanceAvailable: boolean | null;\n degraded: { active: boolean; reason: string | null; sinceEpochMs: number | null } | null;\n openReaders: number | null;\n optimizing: boolean | null;\n search: {\n active: number;\n peak: number;\n total: number;\n lastRequestedLimit: number;\n lastEffectiveLimit: number;\n lastResultCount: number;\n lastCompletedAtEpochMs: number | null;\n } | null;\n cache: {\n rows: number | null;\n maxRowsPerFilterKey: number;\n candidateLimitMax: number;\n lastFilterKey: string | null;\n lastRemovedRows: number;\n lastPrunedAtEpochMs: number | null;\n } | null;\n lastOptimize: {\n ranAtEpochMs: number | null;\n compacted: number;\n removedFragments: number;\n freedBytes: number;\n } | null;\n bounds: {\n vectorSearchMaxResults: number;\n semanticCacheMaxRowsPerFilterKey: number;\n semanticCacheCandidateLimitMax: number;\n } | null;\n };\n lancedb: {\n basePath: string | null;\n totalSizeBytes: number | null;\n tables: LanceTableStats[];\n };\n};\n\nfunction readProcStatusMemory(): ProcStatusSnapshot | null {\n const statusPath = \"/proc/self/status\";\n if (!existsSync(statusPath)) return null;\n try {\n const raw = readFileSync(statusPath, \"utf-8\");\n const parseKb = (key: string): number | null => {\n const match = raw.match(new RegExp(`^${key}:\\\\s+(\\\\d+)\\\\s+kB$`, \"m\"));\n if (!match) return null;\n const parsed = Number.parseInt(match[1], 10);\n return Number.isFinite(parsed) ? parsed : null;\n };\n return {\n vmRssKb: parseKb(\"VmRSS\"),\n vmHwmKb: parseKb(\"VmHWM\"),\n rssAnonKb: parseKb(\"RssAnon\"),\n rssFileKb: parseKb(\"RssFile\"),\n rssShmemKb: parseKb(\"RssShmem\"),\n vmSwapKb: parseKb(\"VmSwap\"),\n };\n } catch {\n return null;\n }\n}\n\nfunction classifyFdTarget(target: string): FdGroup {\n const lowered = target.toLowerCase();\n if (lowered.startsWith(\"socket:\")) return \"socket\";\n if (lowered.startsWith(\"pipe:\")) return \"pipe\";\n if (lowered.startsWith(\"anon_inode:\")) return \"anon\";\n if (lowered.endsWith(\"-wal\")) return \"wal\";\n if (lowered.endsWith(\"-shm\")) return \"shm\";\n if (lowered.endsWith(\".db\") || lowered.includes(\".db?\")) return \"sqlite\";\n if (lowered.includes(\".lance\") || lowered.includes(\"/lancedb/\")) return \"lancedb\";\n return \"other\";\n}\n\nfunction collectFdStats(sampleLimit = 5): FdStats | null {\n const fdRoot = \"/proc/self/fd\";\n if (!existsSync(fdRoot)) return null;\n const byGroup: Record<FdGroup, number> = {\n lancedb: 0,\n sqlite: 0,\n wal: 0,\n shm: 0,\n socket: 0,\n pipe: 0,\n anon: 0,\n other: 0,\n };\n const sampleTargets: Record<FdGroup, string[]> = {\n lancedb: [],\n sqlite: [],\n wal: [],\n shm: [],\n socket: [],\n pipe: [],\n anon: [],\n other: [],\n };\n const lanceSet = new Set<string>();\n let total = 0;\n try {\n const entries = readdirSync(fdRoot);\n for (const fd of entries) {\n const fdPath = join(fdRoot, fd);\n let target = \"\";\n try {\n target = readlinkSync(fdPath);\n } catch {\n continue;\n }\n total += 1;\n const group = classifyFdTarget(target);\n byGroup[group] += 1;\n if (sampleTargets[group].length < sampleLimit) {\n sampleTargets[group].push(target);\n }\n if (group === \"lancedb\") {\n const cleaned = target.replace(/\\s+\\(deleted\\)$/, \"\");\n lanceSet.add(cleaned);\n }\n }\n } catch {\n return null;\n }\n return {\n total,\n byGroup,\n sampleTargets,\n lancedbPaths: [...lanceSet].sort(),\n };\n}\n\nfunction measurePathBytes(path: string, maxEntries = 50_000): SizeSummary {\n const out: SizeSummary = { bytes: 0, scannedEntries: 0, truncated: false };\n if (!existsSync(path)) return { bytes: null, scannedEntries: 0, truncated: false };\n const queue = [path];\n while (queue.length > 0) {\n const current = queue.pop();\n if (!current) continue;\n let st: ReturnType<typeof lstatSync>;\n try {\n st = lstatSync(current);\n } catch {\n // Transient ENOENT/EACCES — skip this entry and continue the scan\n continue;\n }\n out.scannedEntries += 1;\n if (out.scannedEntries > maxEntries) {\n out.truncated = true;\n return out;\n }\n if (st.isDirectory()) {\n let children: string[];\n try {\n children = readdirSync(current).map((name) => join(current, name));\n } catch {\n // Directory became unreadable (e.g. concurrent Lance compaction) — skip\n continue;\n }\n queue.push(...children);\n } else if (st.isFile()) {\n if (out.bytes != null) out.bytes += st.size;\n }\n }\n return out;\n}\n\nexport async function collectVectorBackendObservability(opts: {\n vectorDb: VectorDB;\n resolvedLancePath?: string;\n lanceBytes?: number | null;\n fdSampleLimit?: number;\n}): Promise<VectorBackendObservability> {\n const usage = process.memoryUsage();\n const nativeRssEstimateBytes = Math.max(0, usage.rss - usage.heapTotal - usage.external);\n const procStatus = readProcStatusMemory();\n const fdStats = collectFdStats(opts.fdSampleLimit ?? 5);\n\n const vectorDbWithObs = opts.vectorDb as unknown as {\n getPath?: () => string;\n isInitialized?: () => boolean;\n isLanceDbAvailable?: () => boolean;\n getDegradedState?: () => { active: boolean; reason: string | null; sinceEpochMs: number | null };\n getOpenReaderCount?: () => number;\n isOptimizing?: () => boolean;\n getSearchTelemetry?: () => {\n active: number;\n peak: number;\n total: number;\n lastRequestedLimit: number;\n lastEffectiveLimit: number;\n lastResultCount: number;\n lastCompletedAtEpochMs: number | null;\n };\n getSemanticQueryCacheTelemetry?: () => {\n maxRowsPerFilterKey: number;\n candidateLimitMax: number;\n lastFilterKey: string | null;\n lastRemovedRows: number;\n lastPrunedAtEpochMs: number | null;\n };\n getLastOptimizeTelemetry?: () => {\n ranAtEpochMs: number | null;\n compacted: number;\n removedFragments: number;\n freedBytes: number;\n };\n getRuntimeBounds?: () => {\n vectorSearchMaxResults: number;\n semanticCacheMaxRowsPerFilterKey: number;\n semanticCacheCandidateLimitMax: number;\n };\n countSemanticQueryCacheRows?: () => Promise<number>;\n count?: () => Promise<number>;\n };\n\n const basePathRaw = vectorDbWithObs.getPath?.() ?? opts.resolvedLancePath ?? null;\n const basePath = basePathRaw ? resolve(basePathRaw) : null;\n\n const memoriesPath = basePath ? join(basePath, \"memories.lance\") : \"\";\n const cachePath = basePath ? join(basePath, \"semantic_query_cache.lance\") : \"\";\n const [memoriesCount, cacheCount] = await Promise.all([\n typeof vectorDbWithObs.count === \"function\" ? vectorDbWithObs.count().catch(() => null) : Promise.resolve(null),\n typeof vectorDbWithObs.countSemanticQueryCacheRows === \"function\"\n ? vectorDbWithObs.countSemanticQueryCacheRows().catch(() => null)\n : Promise.resolve(null),\n ]);\n\n const memoriesSize = basePath ? measurePathBytes(memoriesPath) : { bytes: null, scannedEntries: 0, truncated: false };\n const cacheSize = basePath ? measurePathBytes(cachePath) : { bytes: null, scannedEntries: 0, truncated: false };\n const totalSizeBytes = opts.lanceBytes ?? null;\n const cacheTelemetry = vectorDbWithObs.getSemanticQueryCacheTelemetry?.() ?? null;\n\n return {\n capturedAt: new Date().toISOString(),\n memory: {\n rssBytes: usage.rss,\n heapTotalBytes: usage.heapTotal,\n heapUsedBytes: usage.heapUsed,\n externalBytes: usage.external,\n arrayBuffersBytes: usage.arrayBuffers,\n nativeRssEstimateBytes,\n procStatus,\n },\n fileDescriptors: fdStats,\n vectorDb: {\n path: basePath,\n initialized: vectorDbWithObs.isInitialized?.() ?? null,\n lanceAvailable: vectorDbWithObs.isLanceDbAvailable?.() ?? null,\n degraded: vectorDbWithObs.getDegradedState?.() ?? null,\n openReaders: vectorDbWithObs.getOpenReaderCount?.() ?? null,\n optimizing: vectorDbWithObs.isOptimizing?.() ?? null,\n search: vectorDbWithObs.getSearchTelemetry?.() ?? null,\n cache:\n cacheTelemetry == null\n ? null\n : {\n rows: cacheCount,\n maxRowsPerFilterKey: cacheTelemetry.maxRowsPerFilterKey,\n candidateLimitMax: cacheTelemetry.candidateLimitMax,\n lastFilterKey: cacheTelemetry.lastFilterKey,\n lastRemovedRows: cacheTelemetry.lastRemovedRows,\n lastPrunedAtEpochMs: cacheTelemetry.lastPrunedAtEpochMs,\n },\n lastOptimize: vectorDbWithObs.getLastOptimizeTelemetry?.() ?? null,\n bounds: vectorDbWithObs.getRuntimeBounds?.() ?? null,\n },\n lancedb: {\n basePath,\n totalSizeBytes,\n tables: basePath\n ? [\n {\n name: \"memories\",\n path: memoriesPath,\n exists: existsSync(memoriesPath),\n sizeBytes: memoriesSize.bytes,\n sizeScanTruncated: memoriesSize.truncated,\n rowCount: memoriesCount,\n },\n {\n name: \"semantic_query_cache\",\n path: cachePath,\n exists: existsSync(cachePath),\n sizeBytes: cacheSize.bytes,\n sizeScanTruncated: cacheSize.truncated,\n rowCount: cacheCount,\n },\n ]\n : [],\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"vector-backend-observability.js","names":[],"sources":["../../services/vector-backend-observability.ts"],"sourcesContent":["import { existsSync, lstatSync, readdirSync, readFileSync, readlinkSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport type { VectorDB } from \"../backends/vector-db.js\";\n\ntype ProcStatusSnapshot = {\n vmRssKb: number | null;\n vmHwmKb: number | null;\n rssAnonKb: number | null;\n rssFileKb: number | null;\n rssShmemKb: number | null;\n vmSwapKb: number | null;\n};\n\ntype FdGroup = \"lancedb\" | \"sqlite\" | \"wal\" | \"shm\" | \"socket\" | \"pipe\" | \"anon\" | \"other\";\n\ntype FdStats = {\n total: number;\n byGroup: Record<FdGroup, number>;\n sampleTargets: Record<FdGroup, string[]>;\n lancedbPaths: string[];\n};\n\ntype SizeSummary = {\n bytes: number | null;\n scannedEntries: number;\n truncated: boolean;\n};\n\ntype LanceTableStats = {\n name: \"memories\" | \"semantic_query_cache\";\n path: string;\n exists: boolean;\n sizeBytes: number | null;\n sizeScanTruncated: boolean;\n rowCount: number | null;\n};\n\nexport type VectorBackendObservability = {\n capturedAt: string;\n memory: {\n rssBytes: number;\n heapTotalBytes: number;\n heapUsedBytes: number;\n externalBytes: number;\n arrayBuffersBytes: number;\n nativeRssEstimateBytes: number;\n procStatus: ProcStatusSnapshot | null;\n };\n fileDescriptors: FdStats | null;\n vectorDb: {\n path: string | null;\n initialized: boolean | null;\n lanceAvailable: boolean | null;\n degraded: { active: boolean; reason: string | null; sinceEpochMs: number | null } | null;\n openReaders: number | null;\n optimizing: boolean | null;\n search: {\n active: number;\n peak: number;\n total: number;\n lastRequestedLimit: number;\n lastEffectiveLimit: number;\n lastResultCount: number;\n lastCompletedAtEpochMs: number | null;\n } | null;\n cache: {\n rows: number | null;\n maxRowsPerFilterKey: number;\n candidateLimitMax: number;\n lastFilterKey: string | null;\n lastRemovedRows: number;\n lastPrunedAtEpochMs: number | null;\n } | null;\n lastOptimize: {\n ranAtEpochMs: number | null;\n compacted: number;\n removedFragments: number;\n freedBytes: number;\n } | null;\n bounds: {\n vectorSearchMaxResults: number;\n semanticCacheMaxRowsPerFilterKey: number;\n semanticCacheCandidateLimitMax: number;\n } | null;\n };\n lancedb: {\n basePath: string | null;\n totalSizeBytes: number | null;\n tables: LanceTableStats[];\n };\n};\n\nfunction readProcStatusMemory(): ProcStatusSnapshot | null {\n const statusPath = \"/proc/self/status\";\n if (!existsSync(statusPath)) return null;\n try {\n const raw = readFileSync(statusPath, \"utf-8\");\n const parseKb = (key: string): number | null => {\n const match = raw.match(new RegExp(`^${key}:\\\\s+(\\\\d+)\\\\s+kB$`, \"m\"));\n if (!match) return null;\n const parsed = Number.parseInt(match[1], 10);\n return Number.isFinite(parsed) ? parsed : null;\n };\n return {\n vmRssKb: parseKb(\"VmRSS\"),\n vmHwmKb: parseKb(\"VmHWM\"),\n rssAnonKb: parseKb(\"RssAnon\"),\n rssFileKb: parseKb(\"RssFile\"),\n rssShmemKb: parseKb(\"RssShmem\"),\n vmSwapKb: parseKb(\"VmSwap\"),\n };\n } catch {\n return null;\n }\n}\n\nfunction classifyFdTarget(target: string): FdGroup {\n const lowered = target.toLowerCase();\n if (lowered.startsWith(\"socket:\")) return \"socket\";\n if (lowered.startsWith(\"pipe:\")) return \"pipe\";\n if (lowered.startsWith(\"anon_inode:\")) return \"anon\";\n if (lowered.endsWith(\"-wal\")) return \"wal\";\n if (lowered.endsWith(\"-shm\")) return \"shm\";\n if (lowered.endsWith(\".db\") || lowered.includes(\".db?\")) return \"sqlite\";\n if (lowered.includes(\".lance\") || lowered.includes(\"/lancedb/\")) return \"lancedb\";\n return \"other\";\n}\n\nfunction collectFdStats(sampleLimit = 5): FdStats | null {\n const fdRoot = \"/proc/self/fd\";\n if (!existsSync(fdRoot)) return null;\n const byGroup: Record<FdGroup, number> = {\n lancedb: 0,\n sqlite: 0,\n wal: 0,\n shm: 0,\n socket: 0,\n pipe: 0,\n anon: 0,\n other: 0,\n };\n const sampleTargets: Record<FdGroup, string[]> = {\n lancedb: [],\n sqlite: [],\n wal: [],\n shm: [],\n socket: [],\n pipe: [],\n anon: [],\n other: [],\n };\n const lanceSet = new Set<string>();\n let total = 0;\n try {\n const entries = readdirSync(fdRoot);\n for (const fd of entries) {\n const fdPath = join(fdRoot, fd);\n let target = \"\";\n try {\n target = readlinkSync(fdPath);\n } catch {\n continue;\n }\n total += 1;\n const group = classifyFdTarget(target);\n byGroup[group] += 1;\n if (sampleTargets[group].length < sampleLimit) {\n sampleTargets[group].push(target);\n }\n if (group === \"lancedb\") {\n const cleaned = target.replace(/\\s+\\(deleted\\)$/, \"\");\n lanceSet.add(cleaned);\n }\n }\n } catch {\n return null;\n }\n return {\n total,\n byGroup,\n sampleTargets,\n lancedbPaths: [...lanceSet].sort(),\n };\n}\n\nfunction measurePathBytes(path: string, maxEntries = 50_000): SizeSummary {\n const out: SizeSummary = { bytes: 0, scannedEntries: 0, truncated: false };\n if (!existsSync(path)) return { bytes: null, scannedEntries: 0, truncated: false };\n const queue = [path];\n while (queue.length > 0) {\n const current = queue.pop();\n if (!current) continue;\n let st: ReturnType<typeof lstatSync>;\n try {\n st = lstatSync(current);\n } catch {\n // Transient ENOENT/EACCES — skip this entry and continue the scan\n continue;\n }\n out.scannedEntries += 1;\n if (out.scannedEntries > maxEntries) {\n out.truncated = true;\n return out;\n }\n if (st.isDirectory()) {\n let children: string[];\n try {\n children = readdirSync(current).map((name) => join(current, name));\n } catch {\n // Directory became unreadable (e.g. concurrent Lance compaction) — skip\n continue;\n }\n queue.push(...children);\n } else if (st.isFile()) {\n if (out.bytes != null) out.bytes += st.size;\n }\n }\n return out;\n}\n\nexport async function collectVectorBackendObservability(opts: {\n vectorDb: VectorDB;\n resolvedLancePath?: string;\n lanceBytes?: number | null;\n fdSampleLimit?: number;\n}): Promise<VectorBackendObservability> {\n const usage = process.memoryUsage();\n const nativeRssEstimateBytes = Math.max(0, usage.rss - usage.heapTotal - usage.external);\n const procStatus = readProcStatusMemory();\n const fdStats = collectFdStats(opts.fdSampleLimit ?? 5);\n\n const vectorDbWithObs = opts.vectorDb as unknown as {\n getPath?: () => string;\n isInitialized?: () => boolean;\n isLanceDbAvailable?: () => boolean;\n getDegradedState?: () => { active: boolean; reason: string | null; sinceEpochMs: number | null };\n getOpenReaderCount?: () => number;\n isOptimizing?: () => boolean;\n getSearchTelemetry?: () => {\n active: number;\n peak: number;\n total: number;\n lastRequestedLimit: number;\n lastEffectiveLimit: number;\n lastResultCount: number;\n lastCompletedAtEpochMs: number | null;\n };\n getSemanticQueryCacheTelemetry?: () => {\n maxRowsPerFilterKey: number;\n candidateLimitMax: number;\n lastFilterKey: string | null;\n lastRemovedRows: number;\n lastPrunedAtEpochMs: number | null;\n };\n getLastOptimizeTelemetry?: () => {\n ranAtEpochMs: number | null;\n compacted: number;\n removedFragments: number;\n freedBytes: number;\n };\n getRuntimeBounds?: () => {\n vectorSearchMaxResults: number;\n semanticCacheMaxRowsPerFilterKey: number;\n semanticCacheCandidateLimitMax: number;\n };\n countSemanticQueryCacheRows?: () => Promise<number>;\n count?: () => Promise<number>;\n };\n\n const basePathRaw = vectorDbWithObs.getPath?.() ?? opts.resolvedLancePath ?? null;\n const basePath = basePathRaw ? resolve(basePathRaw) : null;\n\n const memoriesPath = basePath ? join(basePath, \"memories.lance\") : \"\";\n const cachePath = basePath ? join(basePath, \"semantic_query_cache.lance\") : \"\";\n const [memoriesCount, cacheCount] = await Promise.all([\n typeof vectorDbWithObs.count === \"function\" ? vectorDbWithObs.count().catch(() => null) : Promise.resolve(null),\n typeof vectorDbWithObs.countSemanticQueryCacheRows === \"function\"\n ? vectorDbWithObs.countSemanticQueryCacheRows().catch(() => null)\n : Promise.resolve(null),\n ]);\n\n const memoriesSize = basePath ? measurePathBytes(memoriesPath) : { bytes: null, scannedEntries: 0, truncated: false };\n const cacheSize = basePath ? measurePathBytes(cachePath) : { bytes: null, scannedEntries: 0, truncated: false };\n const totalSizeBytes = opts.lanceBytes ?? null;\n const cacheTelemetry = vectorDbWithObs.getSemanticQueryCacheTelemetry?.() ?? null;\n\n return {\n capturedAt: new Date().toISOString(),\n memory: {\n rssBytes: usage.rss,\n heapTotalBytes: usage.heapTotal,\n heapUsedBytes: usage.heapUsed,\n externalBytes: usage.external,\n arrayBuffersBytes: usage.arrayBuffers,\n nativeRssEstimateBytes,\n procStatus,\n },\n fileDescriptors: fdStats,\n vectorDb: {\n path: basePath,\n initialized: vectorDbWithObs.isInitialized?.() ?? null,\n lanceAvailable: vectorDbWithObs.isLanceDbAvailable?.() ?? null,\n degraded: vectorDbWithObs.getDegradedState?.() ?? null,\n openReaders: vectorDbWithObs.getOpenReaderCount?.() ?? null,\n optimizing: vectorDbWithObs.isOptimizing?.() ?? null,\n search: vectorDbWithObs.getSearchTelemetry?.() ?? null,\n cache:\n cacheTelemetry == null\n ? null\n : {\n rows: cacheCount,\n maxRowsPerFilterKey: cacheTelemetry.maxRowsPerFilterKey,\n candidateLimitMax: cacheTelemetry.candidateLimitMax,\n lastFilterKey: cacheTelemetry.lastFilterKey,\n lastRemovedRows: cacheTelemetry.lastRemovedRows,\n lastPrunedAtEpochMs: cacheTelemetry.lastPrunedAtEpochMs,\n },\n lastOptimize: vectorDbWithObs.getLastOptimizeTelemetry?.() ?? null,\n bounds: vectorDbWithObs.getRuntimeBounds?.() ?? null,\n },\n lancedb: {\n basePath,\n totalSizeBytes,\n tables: basePath\n ? [\n {\n name: \"memories\",\n path: memoriesPath,\n exists: existsSync(memoriesPath),\n sizeBytes: memoriesSize.bytes,\n sizeScanTruncated: memoriesSize.truncated,\n rowCount: memoriesCount,\n },\n {\n name: \"semantic_query_cache\",\n path: cachePath,\n exists: existsSync(cachePath),\n sizeBytes: cacheSize.bytes,\n sizeScanTruncated: cacheSize.truncated,\n rowCount: cacheCount,\n },\n ]\n : [],\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-lifecycle-audit.js","names":[],"sources":["../../services/vector-lifecycle-audit.ts"],"sourcesContent":["import { appendFileSync, mkdirSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport type VectorLifecycleAuditEvent = {\n event:\n | \"reindex_started\"\n | \"reindex_progress\"\n | \"reindex_completed\"\n | \"reindex_aborted\"\n | \"reconcile_completed\"\n | \"repair_vectors_completed\";\n ts: string;\n details: Record<string, unknown>;\n};\n\nexport function getVectorLifecycleAuditPath(resolvedSqlitePath: string): string {\n return join(dirname(resolvedSqlitePath), \".vector_lifecycle_audit.jsonl\");\n}\n\nexport function appendVectorLifecycleAuditEvent(resolvedSqlitePath: string, event: VectorLifecycleAuditEvent): void {\n try {\n const path = getVectorLifecycleAuditPath(resolvedSqlitePath);\n mkdirSync(dirname(path), { recursive: true });\n appendFileSync(path, `${JSON.stringify(event)}\\n`, \"utf-8\");\n } catch {\n // Best-effort observability must not make otherwise safe vector lifecycle operations fail.\n }\n}\n"],"mappings":";;;AAeA,SAAgB,4BAA4B,oBAAoC;CAC9E,OAAO,KAAK,QAAQ,
|
|
1
|
+
{"version":3,"file":"vector-lifecycle-audit.js","names":[],"sources":["../../services/vector-lifecycle-audit.ts"],"sourcesContent":["import { appendFileSync, mkdirSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport type VectorLifecycleAuditEvent = {\n event:\n | \"reindex_started\"\n | \"reindex_progress\"\n | \"reindex_completed\"\n | \"reindex_aborted\"\n | \"reconcile_completed\"\n | \"repair_vectors_completed\";\n ts: string;\n details: Record<string, unknown>;\n};\n\nexport function getVectorLifecycleAuditPath(resolvedSqlitePath: string): string {\n return join(dirname(resolvedSqlitePath), \".vector_lifecycle_audit.jsonl\");\n}\n\nexport function appendVectorLifecycleAuditEvent(resolvedSqlitePath: string, event: VectorLifecycleAuditEvent): void {\n try {\n const path = getVectorLifecycleAuditPath(resolvedSqlitePath);\n mkdirSync(dirname(path), { recursive: true });\n appendFileSync(path, `${JSON.stringify(event)}\\n`, \"utf-8\");\n } catch {\n // Best-effort observability must not make otherwise safe vector lifecycle operations fail.\n }\n}\n"],"mappings":";;;AAeA,SAAgB,4BAA4B,oBAAoC;CAC9E,OAAO,KAAK,QAAQ,kBAAkB,GAAG,+BAA+B;AAC1E;AAEA,SAAgB,gCAAgC,oBAA4B,OAAwC;CAClH,IAAI;EACF,MAAM,OAAO,4BAA4B,kBAAkB;EAC3D,UAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;EAC5C,eAAe,MAAM,GAAG,KAAK,UAAU,KAAK,EAAE,KAAK,OAAO;CAC5D,QAAQ,CAER;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-maintenance.js","names":[],"sources":["../../services/vector-maintenance.ts"],"sourcesContent":["import type { VectorDB } from \"../backends/vector-db.js\";\n\nexport async function deleteVectorsForFactIds(\n vectorDb: Pick<VectorDB, \"delete\"> & Partial<Pick<VectorDB, \"deleteMany\" | \"isLanceDbAvailable\">>,\n factIds: readonly string[],\n options: {\n operation: string;\n logger?: { warn?: (message: string) => void; info?: (message: string) => void; debug?: (message: string) => void };\n },\n): Promise<{ attempted: number; deleted: number; failed: number }> {\n const uniqueIds = [...new Set(factIds.filter((id) => typeof id === \"string\" && id.length > 0))];\n if (uniqueIds.length === 0) return { attempted: 0, deleted: 0, failed: 0 };\n if (typeof vectorDb.isLanceDbAvailable === \"function\" && !vectorDb.isLanceDbAvailable()) {\n return { attempted: 0, deleted: 0, failed: 0 };\n }\n\n if (typeof vectorDb.deleteMany === \"function\") {\n try {\n const deleted = await vectorDb.deleteMany(uniqueIds);\n if (deleted === 0 && typeof vectorDb.isLanceDbAvailable === \"function\" && !vectorDb.isLanceDbAvailable()) {\n return { attempted: 0, deleted: 0, failed: 0 };\n }\n const normalizedDeleted = Number.isFinite(deleted)\n ? Math.max(0, Math.min(uniqueIds.length, Math.floor(deleted)))\n : 0;\n return {\n attempted: uniqueIds.length,\n deleted: normalizedDeleted,\n // Keep failed semantics aligned with the per-id path: only count hard errors.\n failed: 0,\n };\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n options.logger?.warn?.(`memory-hybrid: ${options.operation} vector bulk delete failed: ${error.message}`);\n }\n }\n\n let deleted = 0;\n let failed = 0;\n for (const id of uniqueIds) {\n try {\n if (await vectorDb.delete(id)) deleted++;\n } catch (err) {\n failed++;\n const error = err instanceof Error ? err : new Error(String(err));\n options.logger?.warn?.(`memory-hybrid: ${options.operation} vector delete failed for ${id}: ${error.message}`);\n }\n }\n return { attempted: uniqueIds.length, deleted, failed };\n}\n\nexport async function cleanupEvictedVector(options: {\n vectorDb: Pick<VectorDB, \"delete\">;\n evictedFactId?: string | null;\n logger?: { warn?: (message: string) => void; info?: (message: string) => void; debug?: (message: string) => void };\n context: string;\n}): Promise<boolean> {\n const { evictedFactId } = options;\n if (!evictedFactId) return false;\n const deleted = await deleteVectorForFactId({\n vectorDb: options.vectorDb,\n factId: evictedFactId,\n logger: options.logger,\n context: options.context,\n });\n if (deleted) {\n options.logger?.info?.(`memory-hybrid: ${options.context} evicted fact ${evictedFactId}, vector deleted`);\n }\n return deleted;\n}\n\nexport async function deleteVectorForFactId(options: {\n vectorDb: Pick<VectorDB, \"delete\">;\n factId: string;\n logger?: { warn?: (message: string) => void; info?: (message: string) => void; debug?: (message: string) => void };\n context: string;\n}): Promise<boolean> {\n try {\n return await options.vectorDb.delete(options.factId);\n } catch (err) {\n options.logger?.warn?.(`memory-hybrid: ${options.context} vector delete failed for ${options.factId}: ${err}`);\n return false;\n }\n}\n\nexport async function storeCanonicalVectorForFact(options: {\n vectorDb: Pick<VectorDB, \"store\"> & Partial<Pick<VectorDB, \"isLanceDbAvailable\">>;\n factsDb: {\n setEmbeddingModel: (id: string, model: string | null) => void;\n storeEmbedding: (\n factId: string,\n model: string,\n variant: string,\n embedding: Float32Array,\n dimensions: number,\n ) => void;\n };\n factId: string;\n text: string;\n why?: string | null;\n vector: number[];\n importance: number;\n category: string;\n embeddingModel: string;\n}): Promise<string> {\n const storedId = await options.vectorDb.store({\n text: options.text,\n why: options.why,\n vector: options.vector,\n importance: options.importance,\n category: options.category,\n id: options.factId,\n });\n const canPersistEmbeddingModel =\n typeof options.vectorDb.isLanceDbAvailable === \"function\" ? options.vectorDb.isLanceDbAvailable() : true;\n if (canPersistEmbeddingModel) {\n try {\n options.factsDb.setEmbeddingModel(options.factId, options.embeddingModel);\n options.factsDb.storeEmbedding(\n options.factId,\n options.embeddingModel,\n \"canonical\",\n new Float32Array(options.vector),\n options.vector.length,\n );\n } catch {\n // LanceDB is already updated. Do not make callers treat vector storage as\n // failed; higher-level callers may run their own canonical SQLite\n // embedding retry after this helper returns successfully.\n }\n }\n return storedId;\n}\n"],"mappings":";AAEA,eAAsB,wBACpB,UACA,SACA,SAIiE;CACjE,MAAM,YAAY,CAAC,GAAG,IAAI,IAAI,QAAQ,QAAQ,OAAO,OAAO,OAAO,YAAY,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"vector-maintenance.js","names":[],"sources":["../../services/vector-maintenance.ts"],"sourcesContent":["import type { VectorDB } from \"../backends/vector-db.js\";\n\nexport async function deleteVectorsForFactIds(\n vectorDb: Pick<VectorDB, \"delete\"> & Partial<Pick<VectorDB, \"deleteMany\" | \"isLanceDbAvailable\">>,\n factIds: readonly string[],\n options: {\n operation: string;\n logger?: { warn?: (message: string) => void; info?: (message: string) => void; debug?: (message: string) => void };\n },\n): Promise<{ attempted: number; deleted: number; failed: number }> {\n const uniqueIds = [...new Set(factIds.filter((id) => typeof id === \"string\" && id.length > 0))];\n if (uniqueIds.length === 0) return { attempted: 0, deleted: 0, failed: 0 };\n if (typeof vectorDb.isLanceDbAvailable === \"function\" && !vectorDb.isLanceDbAvailable()) {\n return { attempted: 0, deleted: 0, failed: 0 };\n }\n\n if (typeof vectorDb.deleteMany === \"function\") {\n try {\n const deleted = await vectorDb.deleteMany(uniqueIds);\n if (deleted === 0 && typeof vectorDb.isLanceDbAvailable === \"function\" && !vectorDb.isLanceDbAvailable()) {\n return { attempted: 0, deleted: 0, failed: 0 };\n }\n const normalizedDeleted = Number.isFinite(deleted)\n ? Math.max(0, Math.min(uniqueIds.length, Math.floor(deleted)))\n : 0;\n return {\n attempted: uniqueIds.length,\n deleted: normalizedDeleted,\n // Keep failed semantics aligned with the per-id path: only count hard errors.\n failed: 0,\n };\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n options.logger?.warn?.(`memory-hybrid: ${options.operation} vector bulk delete failed: ${error.message}`);\n }\n }\n\n let deleted = 0;\n let failed = 0;\n for (const id of uniqueIds) {\n try {\n if (await vectorDb.delete(id)) deleted++;\n } catch (err) {\n failed++;\n const error = err instanceof Error ? err : new Error(String(err));\n options.logger?.warn?.(`memory-hybrid: ${options.operation} vector delete failed for ${id}: ${error.message}`);\n }\n }\n return { attempted: uniqueIds.length, deleted, failed };\n}\n\nexport async function cleanupEvictedVector(options: {\n vectorDb: Pick<VectorDB, \"delete\">;\n evictedFactId?: string | null;\n logger?: { warn?: (message: string) => void; info?: (message: string) => void; debug?: (message: string) => void };\n context: string;\n}): Promise<boolean> {\n const { evictedFactId } = options;\n if (!evictedFactId) return false;\n const deleted = await deleteVectorForFactId({\n vectorDb: options.vectorDb,\n factId: evictedFactId,\n logger: options.logger,\n context: options.context,\n });\n if (deleted) {\n options.logger?.info?.(`memory-hybrid: ${options.context} evicted fact ${evictedFactId}, vector deleted`);\n }\n return deleted;\n}\n\nexport async function deleteVectorForFactId(options: {\n vectorDb: Pick<VectorDB, \"delete\">;\n factId: string;\n logger?: { warn?: (message: string) => void; info?: (message: string) => void; debug?: (message: string) => void };\n context: string;\n}): Promise<boolean> {\n try {\n return await options.vectorDb.delete(options.factId);\n } catch (err) {\n options.logger?.warn?.(`memory-hybrid: ${options.context} vector delete failed for ${options.factId}: ${err}`);\n return false;\n }\n}\n\nexport async function storeCanonicalVectorForFact(options: {\n vectorDb: Pick<VectorDB, \"store\"> & Partial<Pick<VectorDB, \"isLanceDbAvailable\">>;\n factsDb: {\n setEmbeddingModel: (id: string, model: string | null) => void;\n storeEmbedding: (\n factId: string,\n model: string,\n variant: string,\n embedding: Float32Array,\n dimensions: number,\n ) => void;\n };\n factId: string;\n text: string;\n why?: string | null;\n vector: number[];\n importance: number;\n category: string;\n embeddingModel: string;\n}): Promise<string> {\n const storedId = await options.vectorDb.store({\n text: options.text,\n why: options.why,\n vector: options.vector,\n importance: options.importance,\n category: options.category,\n id: options.factId,\n });\n const canPersistEmbeddingModel =\n typeof options.vectorDb.isLanceDbAvailable === \"function\" ? options.vectorDb.isLanceDbAvailable() : true;\n if (canPersistEmbeddingModel) {\n try {\n options.factsDb.setEmbeddingModel(options.factId, options.embeddingModel);\n options.factsDb.storeEmbedding(\n options.factId,\n options.embeddingModel,\n \"canonical\",\n new Float32Array(options.vector),\n options.vector.length,\n );\n } catch {\n // LanceDB is already updated. Do not make callers treat vector storage as\n // failed; higher-level callers may run their own canonical SQLite\n // embedding retry after this helper returns successfully.\n }\n }\n return storedId;\n}\n"],"mappings":";AAEA,eAAsB,wBACpB,UACA,SACA,SAIiE;CACjE,MAAM,YAAY,CAAC,GAAG,IAAI,IAAI,QAAQ,QAAQ,OAAO,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC,CAAC,CAAC;CAC9F,IAAI,UAAU,WAAW,GAAG,OAAO;EAAE,WAAW;EAAG,SAAS;EAAG,QAAQ;CAAE;CACzE,IAAI,OAAO,SAAS,uBAAuB,cAAc,CAAC,SAAS,mBAAmB,GACpF,OAAO;EAAE,WAAW;EAAG,SAAS;EAAG,QAAQ;CAAE;CAG/C,IAAI,OAAO,SAAS,eAAe,YACjC,IAAI;EACF,MAAM,UAAU,MAAM,SAAS,WAAW,SAAS;EACnD,IAAI,YAAY,KAAK,OAAO,SAAS,uBAAuB,cAAc,CAAC,SAAS,mBAAmB,GACrG,OAAO;GAAE,WAAW;GAAG,SAAS;GAAG,QAAQ;EAAE;EAE/C,MAAM,oBAAoB,OAAO,SAAS,OAAO,IAC7C,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,QAAQ,KAAK,MAAM,OAAO,CAAC,CAAC,IAC3D;EACJ,OAAO;GACL,WAAW,UAAU;GACrB,SAAS;GAET,QAAQ;EACV;CACF,SAAS,KAAK;EACZ,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;EAChE,QAAQ,QAAQ,OAAO,kBAAkB,QAAQ,UAAU,8BAA8B,MAAM,SAAS;CAC1G;CAGF,IAAI,UAAU;CACd,IAAI,SAAS;CACb,KAAK,MAAM,MAAM,WACf,IAAI;EACF,IAAI,MAAM,SAAS,OAAO,EAAE,GAAG;CACjC,SAAS,KAAK;EACZ;EACA,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;EAChE,QAAQ,QAAQ,OAAO,kBAAkB,QAAQ,UAAU,4BAA4B,GAAG,IAAI,MAAM,SAAS;CAC/G;CAEF,OAAO;EAAE,WAAW,UAAU;EAAQ;EAAS;CAAO;AACxD;AAEA,eAAsB,qBAAqB,SAKtB;CACnB,MAAM,EAAE,kBAAkB;CAC1B,IAAI,CAAC,eAAe,OAAO;CAC3B,MAAM,UAAU,MAAM,sBAAsB;EAC1C,UAAU,QAAQ;EAClB,QAAQ;EACR,QAAQ,QAAQ;EAChB,SAAS,QAAQ;CACnB,CAAC;CACD,IAAI,SACF,QAAQ,QAAQ,OAAO,kBAAkB,QAAQ,QAAQ,gBAAgB,cAAc,iBAAiB;CAE1G,OAAO;AACT;AAEA,eAAsB,sBAAsB,SAKvB;CACnB,IAAI;EACF,OAAO,MAAM,QAAQ,SAAS,OAAO,QAAQ,MAAM;CACrD,SAAS,KAAK;EACZ,QAAQ,QAAQ,OAAO,kBAAkB,QAAQ,QAAQ,4BAA4B,QAAQ,OAAO,IAAI,KAAK;EAC7G,OAAO;CACT;AACF;AAEA,eAAsB,4BAA4B,SAmB9B;CAClB,MAAM,WAAW,MAAM,QAAQ,SAAS,MAAM;EAC5C,MAAM,QAAQ;EACd,KAAK,QAAQ;EACb,QAAQ,QAAQ;EAChB,YAAY,QAAQ;EACpB,UAAU,QAAQ;EAClB,IAAI,QAAQ;CACd,CAAC;CAGD,IADE,OAAO,QAAQ,SAAS,uBAAuB,aAAa,QAAQ,SAAS,mBAAmB,IAAI,MAEpG,IAAI;EACF,QAAQ,QAAQ,kBAAkB,QAAQ,QAAQ,QAAQ,cAAc;EACxE,QAAQ,QAAQ,eACd,QAAQ,QACR,QAAQ,gBACR,aACA,IAAI,aAAa,QAAQ,MAAM,GAC/B,QAAQ,OAAO,MACjB;CACF,QAAQ,CAIR;CAEF,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vector-search.js","names":[],"sources":["../../services/vector-search.ts"],"sourcesContent":["/**\n * Vector search service: find similar memories by embedding.\n */\n\nimport type { VectorDB } from \"../backends/vector-db.js\";\nimport type { MemoryEntry, MemoryScope } from \"../types/memory.js\";\nimport { matchesExactScope } from \"./classification-scope.js\";\n\nexport type ScopedClassificationOptions = {\n scope?: MemoryScope;\n scopeTarget?: string | null;\n};\n\n/**\n * Find similar memories by embedding vector.\n * Returns entries that are not superseded.\n */\nexport async function findSimilarByEmbedding(\n vectorDb: VectorDB,\n factsDb: { getById(id: string): MemoryEntry | null },\n vector: number[],\n limit: number,\n minScore = 0.3,\n options?: ScopedClassificationOptions,\n): Promise<MemoryEntry[]> {\n const scope = options?.scope;\n const scopeTarget = scope === undefined || scope === \"global\" ? null : (options?.scopeTarget ?? null);\n const searchLimit = Math.min(Math.max(limit * 4, limit), 200);\n const results = await vectorDb.search(vector, searchLimit, minScore);\n const entries: MemoryEntry[] = [];\n for (const r of results) {\n const entry = factsDb.getById(r.entry.id);\n if (!entry || entry.supersededAt != null) continue;\n if (scope !== undefined && !matchesExactScope(entry, scope, scopeTarget)) continue;\n entries.push(entry);\n if (entries.length >= limit) break;\n }\n return entries;\n}\n"],"mappings":";;;;;;AAiBA,eAAsB,uBACpB,UACA,SACA,QACA,OACA,WAAW,IACX,SACwB;CACxB,MAAM,QAAQ,SAAS;CACvB,MAAM,cAAc,UAAU,KAAA,KAAa,UAAU,WAAW,OAAQ,SAAS,eAAe;CAChG,MAAM,cAAc,KAAK,IAAI,KAAK,IAAI,QAAQ,GAAG,
|
|
1
|
+
{"version":3,"file":"vector-search.js","names":[],"sources":["../../services/vector-search.ts"],"sourcesContent":["/**\n * Vector search service: find similar memories by embedding.\n */\n\nimport type { VectorDB } from \"../backends/vector-db.js\";\nimport type { MemoryEntry, MemoryScope } from \"../types/memory.js\";\nimport { matchesExactScope } from \"./classification-scope.js\";\n\nexport type ScopedClassificationOptions = {\n scope?: MemoryScope;\n scopeTarget?: string | null;\n};\n\n/**\n * Find similar memories by embedding vector.\n * Returns entries that are not superseded.\n */\nexport async function findSimilarByEmbedding(\n vectorDb: VectorDB,\n factsDb: { getById(id: string): MemoryEntry | null },\n vector: number[],\n limit: number,\n minScore = 0.3,\n options?: ScopedClassificationOptions,\n): Promise<MemoryEntry[]> {\n const scope = options?.scope;\n const scopeTarget = scope === undefined || scope === \"global\" ? null : (options?.scopeTarget ?? null);\n const searchLimit = Math.min(Math.max(limit * 4, limit), 200);\n const results = await vectorDb.search(vector, searchLimit, minScore);\n const entries: MemoryEntry[] = [];\n for (const r of results) {\n const entry = factsDb.getById(r.entry.id);\n if (!entry || entry.supersededAt != null) continue;\n if (scope !== undefined && !matchesExactScope(entry, scope, scopeTarget)) continue;\n entries.push(entry);\n if (entries.length >= limit) break;\n }\n return entries;\n}\n"],"mappings":";;;;;;AAiBA,eAAsB,uBACpB,UACA,SACA,QACA,OACA,WAAW,IACX,SACwB;CACxB,MAAM,QAAQ,SAAS;CACvB,MAAM,cAAc,UAAU,KAAA,KAAa,UAAU,WAAW,OAAQ,SAAS,eAAe;CAChG,MAAM,cAAc,KAAK,IAAI,KAAK,IAAI,QAAQ,GAAG,KAAK,GAAG,GAAG;CAC5D,MAAM,UAAU,MAAM,SAAS,OAAO,QAAQ,aAAa,QAAQ;CACnE,MAAM,UAAyB,CAAC;CAChC,KAAK,MAAM,KAAK,SAAS;EACvB,MAAM,QAAQ,QAAQ,QAAQ,EAAE,MAAM,EAAE;EACxC,IAAI,CAAC,SAAS,MAAM,gBAAgB,MAAM;EAC1C,IAAI,UAAU,KAAA,KAAa,CAAC,kBAAkB,OAAO,OAAO,WAAW,GAAG;EAC1E,QAAQ,KAAK,KAAK;EAClB,IAAI,QAAQ,UAAU,OAAO;CAC/B;CACA,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verification-store.js","names":[],"sources":["../../services/verification-store.ts"],"sourcesContent":["/**\n * Verification Store for Critical Facts (Issue #162).\n *\n * Provides a high-trust storage tier with immutability, integrity checking,\n * and protection against silent decay or corruption.\n */\n\nimport { createHash, randomUUID } from \"node:crypto\";\nimport { appendFileSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { DatabaseSync } from \"node:sqlite\";\nimport { SQLITE_BUSY_TIMEOUT_MS } from \"../utils/constants.js\";\nimport { expandTilde } from \"../utils/path.js\";\nimport { createTransaction } from \"../utils/sqlite-transaction.js\";\nimport { VAULT_POINTER_PREFIX } from \"./auto-capture.js\";\nimport { capturePluginError } from \"./error-reporter.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface VerifiedFact {\n id: string;\n factId: string;\n canonicalText: string;\n checksum: string;\n verifiedAt: string;\n verifiedBy: \"agent\" | \"user\" | \"system\";\n nextVerification: string | null;\n version: number;\n previousVersionId: string | null;\n createdAt: string;\n}\n\ninterface IntegrityReport {\n valid: boolean;\n corrupted?: string[];\n checked: number;\n}\n\nexport class VerificationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"VerificationError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nexport function computeChecksum(text: string): string {\n return createHash(\"sha256\").update(text).digest(\"hex\");\n}\n\nfunction isIpAddress(value: string): boolean {\n const ipPattern = /\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/;\n return ipPattern.test(value);\n}\n\nfunction isHostname(value: string): boolean {\n const trimmed = value.trim().toLowerCase();\n if (!trimmed || trimmed.length < 3) return false;\n if (isIpAddress(trimmed)) return false;\n if (!/^[a-z0-9.-]+$/.test(trimmed)) return false;\n if (!/[a-z0-9]/.test(trimmed)) return false;\n if (trimmed.includes(\"..\") || trimmed.startsWith(\".\") || trimmed.endsWith(\".\")) return false;\n if (!trimmed.includes(\".\")) return false;\n return true;\n}\n\nfunction containsHostname(text: string): boolean {\n const hostnamePattern = /\\b[a-z0-9-]{1,63}(?:\\.[a-z0-9-]{1,63})+\\b/gi;\n const matches = text.match(hostnamePattern);\n if (!matches) return false;\n\n for (const match of matches) {\n if (/[a-z]/i.test(match)) {\n return true;\n }\n }\n return false;\n}\n\nfunction toISODate(d: Date): string {\n return d.toISOString();\n}\n\nfunction addDays(date: Date, days: number): Date {\n const result = new Date(date.getTime());\n result.setDate(result.getDate() + days);\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Raw row type returned from SQLite queries\n// ---------------------------------------------------------------------------\n\nexport interface VerifiedFactRow {\n id: string;\n fact_id: string;\n canonical_text: string;\n checksum: string;\n verified_at: string;\n verified_by: string;\n next_verification: string | null;\n version: number;\n previous_version_id: string | null;\n created_at: string;\n}\n\nexport function rowToVerifiedFact(row: VerifiedFactRow): VerifiedFact {\n return {\n id: row.id,\n factId: row.fact_id,\n canonicalText: row.canonical_text,\n checksum: row.checksum,\n verifiedAt: row.verified_at,\n verifiedBy: row.verified_by as \"agent\" | \"user\" | \"system\",\n nextVerification: row.next_verification,\n version: row.version,\n previousVersionId: row.previous_version_id,\n createdAt: row.created_at,\n };\n}\n\n// ---------------------------------------------------------------------------\n// shouldAutoVerify — heuristic check for critical facts\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true if the fact should be automatically verified.\n */\nexport function shouldAutoVerify(fact: {\n text: string;\n category: string;\n tags: string[];\n entity?: string | null;\n key?: string | null;\n value?: string | null;\n verificationTier?: string | null;\n}): boolean {\n const verificationTier = (fact.verificationTier ?? \"\").trim().toLowerCase();\n if (verificationTier === \"critical\") return true;\n\n const entity = (fact.entity ?? \"\").trim();\n const text = fact.text ?? \"\";\n if (entity && (isIpAddress(entity) || isHostname(entity))) return true;\n if (isIpAddress(text) || containsHostname(text)) return true;\n\n const entityLower = entity.toLowerCase();\n const keyLower = (fact.key ?? \"\").toLowerCase();\n const valueLower = (fact.value ?? \"\").toLowerCase();\n if (\n entityLower.includes(\"credential\") ||\n keyLower.includes(\"credential\") ||\n valueLower.startsWith(VAULT_POINTER_PREFIX)\n ) {\n return true;\n }\n\n // Infrastructure + technical category\n if (fact.tags.map((t) => t.toLowerCase()).includes(\"infrastructure\") && fact.category === \"technical\") {\n return true;\n }\n\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// VerificationStore\n// ---------------------------------------------------------------------------\n\nexport class VerificationStore {\n private db: DatabaseSync;\n private readonly backupPath: string;\n private readonly reverificationDays: number;\n private readonly logger?: { warn?: (msg: string) => void; error?: (msg: string) => void };\n private _dbOpen = true;\n /** When false, connection is shared (e.g. FactsDB.getRawDb()); close() must not call db.close(). */\n private readonly ownsConnection: boolean;\n\n /**\n * @param dbPathOrInstance - Either a file path string (opens its own connection) or an\n * existing Database instance to share (e.g. FactsDB.getRawDb()). When sharing an\n * instance, the caller is responsible for pragma setup and lifecycle.\n */\n constructor(\n dbPathOrInstance: string | DatabaseSync,\n options?: {\n backupPath?: string;\n reverificationDays?: number;\n logger?: { warn?: (msg: string) => void; error?: (msg: string) => void };\n },\n ) {\n if (typeof dbPathOrInstance === \"string\") {\n mkdirSync(dirname(dbPathOrInstance), { recursive: true });\n this.db = new DatabaseSync(dbPathOrInstance);\n this.ownsConnection = true;\n this.applyPragmas();\n } else {\n // Shared instance — caller owns the connection lifecycle\n this.db = dbPathOrInstance;\n this.ownsConnection = false;\n }\n this.reverificationDays = options?.reverificationDays ?? 30;\n this.logger = options?.logger;\n\n const rawBackup = options?.backupPath ?? \"~/.openclaw/verified-facts.json\";\n this.backupPath = expandTilde(rawBackup);\n mkdirSync(dirname(this.backupPath), { recursive: true });\n\n this.initSchema();\n }\n\n private applyPragmas(): void {\n this.db.exec(\"PRAGMA journal_mode = WAL\");\n this.db.exec(`PRAGMA busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`);\n this.db.exec(\"PRAGMA synchronous = NORMAL\");\n }\n\n /** Schema for standalone verification DB (no facts table). When verified_facts lives in FactsDB, the migration in facts-db.ts is used. */\n private initSchema(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS verified_facts (\n id TEXT PRIMARY KEY,\n fact_id TEXT NOT NULL,\n canonical_text TEXT NOT NULL,\n checksum TEXT NOT NULL,\n verified_at TEXT NOT NULL,\n verified_by TEXT NOT NULL,\n next_verification TEXT,\n version INTEGER DEFAULT 1,\n previous_version_id TEXT,\n created_at TEXT NOT NULL\n );\n CREATE INDEX IF NOT EXISTS idx_verified_facts_fact_id ON verified_facts(fact_id);\n CREATE INDEX IF NOT EXISTS idx_verified_facts_next_verification ON verified_facts(next_verification);\n `);\n }\n\n // -------------------------------------------------------------------------\n // verify — add a fact to the verification store\n // -------------------------------------------------------------------------\n\n verify(factId: string, text: string, verifiedBy: \"agent\" | \"user\" | \"system\"): string {\n const existing = this.db.prepare(\"SELECT 1 FROM verified_facts WHERE fact_id = ? LIMIT 1\").get(factId);\n if (existing) {\n throw new VerificationError(`Fact ${factId} is already verified; use update() to create a new version`);\n }\n\n const id = randomUUID();\n const now = toISODate(new Date());\n const nextVerification = toISODate(addDays(new Date(), this.reverificationDays));\n const checksum = computeChecksum(text);\n\n this.db\n .prepare(\n `INSERT INTO verified_facts\n (id, fact_id, canonical_text, checksum, verified_at, verified_by, next_verification, version, previous_version_id, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, 1, NULL, ?)`,\n )\n .run(id, factId, text, checksum, now, verifiedBy, nextVerification, now);\n\n this.writeBackup({\n action: \"verify\",\n id,\n fact_id: factId,\n canonical_text: text,\n checksum,\n verified_at: now,\n verified_by: verifiedBy,\n version: 1,\n nextVerification,\n previousVersionId: null,\n ts: now,\n });\n\n return id;\n }\n\n // -------------------------------------------------------------------------\n // checkIntegrity — verify checksums match stored text\n // -------------------------------------------------------------------------\n\n checkIntegrity(factId?: string): IntegrityReport {\n let rows: VerifiedFactRow[];\n if (factId !== undefined) {\n rows = this.db\n .prepare(\"SELECT * FROM verified_facts WHERE fact_id = ? ORDER BY version DESC\")\n .all(factId) as unknown as VerifiedFactRow[];\n } else {\n rows = this.db.prepare(\"SELECT * FROM verified_facts\").all() as unknown as VerifiedFactRow[];\n }\n\n const corrupted: string[] = [];\n\n for (const row of rows) {\n const live = computeChecksum(row.canonical_text);\n if (live !== row.checksum) {\n corrupted.push(row.id);\n }\n }\n\n return {\n valid: corrupted.length === 0,\n corrupted: corrupted.length > 0 ? corrupted : undefined,\n checked: rows.length,\n };\n }\n\n // -------------------------------------------------------------------------\n // getVerified — retrieve a verified fact, throws on checksum mismatch\n // -------------------------------------------------------------------------\n\n getVerified(factId: string): VerifiedFact | null {\n const row = this.db\n .prepare(\"SELECT * FROM verified_facts WHERE fact_id = ? ORDER BY version DESC LIMIT 1\")\n .get(factId) as VerifiedFactRow | undefined;\n\n if (!row) return null;\n\n const live = computeChecksum(row.canonical_text);\n if (live !== row.checksum) {\n const message = `Checksum mismatch for verified fact ${row.id} (fact_id=${factId}): stored checksum does not match canonical_text`;\n this.logCorruption(message);\n throw new VerificationError(message);\n }\n\n return rowToVerifiedFact(row);\n }\n\n // -------------------------------------------------------------------------\n // listDueForReverification — facts whose next_verification <= now or verified_at is stale\n // -------------------------------------------------------------------------\n\n listDueForReverification(): VerifiedFact[] {\n const now = toISODate(new Date());\n const cutoff = toISODate(addDays(new Date(), -this.reverificationDays));\n const rows = this.db\n .prepare(\n `SELECT vf.*\n FROM verified_facts vf\n JOIN (\n SELECT fact_id, MAX(version) as max_version\n FROM verified_facts\n GROUP BY fact_id\n ) latest\n ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE (vf.next_verification IS NOT NULL AND vf.next_verification <= ?)\n OR vf.verified_at <= ?\n ORDER BY COALESCE(vf.next_verification, vf.verified_at) ASC`,\n )\n .all(now, cutoff) as unknown as VerifiedFactRow[];\n\n return rows.filter((row) => this.validateRowChecksum(row)).map(rowToVerifiedFact);\n }\n\n // -------------------------------------------------------------------------\n // listLatestVerified — latest versions for each fact_id\n // -------------------------------------------------------------------------\n\n listLatestVerified(limit?: number): VerifiedFact[] {\n const limitClause = limit ? `LIMIT ${limit}` : \"\";\n const rows = this.db\n .prepare(\n `SELECT vf.*\n FROM verified_facts vf\n JOIN (\n SELECT fact_id, MAX(version) as max_version\n FROM verified_facts\n GROUP BY fact_id\n ) latest\n ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n ORDER BY vf.verified_at DESC ${limitClause}`,\n )\n .all() as unknown as VerifiedFactRow[];\n\n return rows.filter((row) => this.validateRowChecksum(row)).map(rowToVerifiedFact);\n }\n\n // -------------------------------------------------------------------------\n // update — create a new version, linking to the superseded one\n // -------------------------------------------------------------------------\n\n update(id: string, newText: string, verifiedBy: \"agent\" | \"user\" | \"system\"): string {\n const existing = this.db.prepare(\"SELECT * FROM verified_facts WHERE id = ?\").get(id) as\n | VerifiedFactRow\n | undefined;\n\n if (!existing) {\n throw new VerificationError(`No verified fact found with id=${id}`);\n }\n\n const latest = this.db\n .prepare(\"SELECT id FROM verified_facts WHERE fact_id = ? ORDER BY version DESC LIMIT 1\")\n .get(existing.fact_id) as { id: string } | undefined;\n if (!latest || latest.id !== id) {\n throw new VerificationError(\n `Can only update from the latest version; id=${id} is not the current latest for fact_id=${existing.fact_id}`,\n );\n }\n\n const newId = randomUUID();\n const now = toISODate(new Date());\n const nextVerification = toISODate(addDays(new Date(), this.reverificationDays));\n const checksum = computeChecksum(newText);\n const newVersion = existing.version + 1;\n\n createTransaction(this.db, () => {\n this.db\n .prepare(\n `INSERT INTO verified_facts\n (id, fact_id, canonical_text, checksum, verified_at, verified_by, next_verification, version, previous_version_id, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(newId, existing.fact_id, newText, checksum, now, verifiedBy, nextVerification, newVersion, id, now);\n this.db.prepare(\"UPDATE verified_facts SET next_verification = NULL WHERE id = ?\").run(id);\n })();\n\n this.writeBackup({\n action: \"update\",\n id: newId,\n fact_id: existing.fact_id,\n canonical_text: newText,\n checksum,\n verified_at: now,\n verified_by: verifiedBy,\n version: newVersion,\n nextVerification,\n previousVersionId: id,\n ts: now,\n });\n\n return newId;\n }\n\n // -------------------------------------------------------------------------\n // close — close the underlying SQLite connection\n // -------------------------------------------------------------------------\n\n /** Return the total number of verified fact entries (across all fact_ids). */\n countVerified(): number {\n const row = this.db.prepare(\"SELECT COUNT(*) as cnt FROM verified_facts\").get() as { cnt: number };\n return row.cnt;\n }\n\n close(): void {\n if (this.ownsConnection && this._dbOpen) {\n this.db.close();\n this._dbOpen = false;\n }\n }\n\n private validateRowChecksum(row: VerifiedFactRow): boolean {\n const live = computeChecksum(row.canonical_text);\n if (live !== row.checksum) {\n const message = `Checksum mismatch for verified fact ${row.id} (fact_id=${row.fact_id}): stored checksum does not match canonical_text`;\n this.logCorruption(message);\n return false;\n }\n return true;\n }\n\n private logCorruption(message: string): void {\n if (this.logger?.error) {\n this.logger.error(`memory-hybrid: verification corruption detected: ${message}`);\n return;\n }\n if (this.logger?.warn) {\n this.logger.warn(`memory-hybrid: verification corruption detected: ${message}`);\n }\n }\n\n // -------------------------------------------------------------------------\n // Private: append-only backup\n // -------------------------------------------------------------------------\n\n private hasLoggedBackupError = false;\n\n private writeBackup(entry: {\n action: \"verify\" | \"update\";\n id: string;\n fact_id: string;\n canonical_text: string;\n checksum: string;\n verified_at: string;\n verified_by: string;\n version: number;\n nextVerification: string | null;\n previousVersionId: string | null;\n ts: string;\n }): void {\n try {\n const line = `${JSON.stringify(entry)}\\n`;\n appendFileSync(this.backupPath, line, { encoding: \"utf8\", mode: 0o600 });\n } catch (err) {\n if (!this.hasLoggedBackupError) {\n this.hasLoggedBackupError = true;\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"verification-store\",\n operation: \"writeBackup\",\n });\n }\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"verification-store.js","names":[],"sources":["../../services/verification-store.ts"],"sourcesContent":["/**\n * Verification Store for Critical Facts (Issue #162).\n *\n * Provides a high-trust storage tier with immutability, integrity checking,\n * and protection against silent decay or corruption.\n */\n\nimport { createHash, randomUUID } from \"node:crypto\";\nimport { appendFileSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { DatabaseSync } from \"node:sqlite\";\nimport { SQLITE_BUSY_TIMEOUT_MS } from \"../utils/constants.js\";\nimport { expandTilde } from \"../utils/path.js\";\nimport { createTransaction } from \"../utils/sqlite-transaction.js\";\nimport { VAULT_POINTER_PREFIX } from \"./auto-capture.js\";\nimport { capturePluginError } from \"./error-reporter.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface VerifiedFact {\n id: string;\n factId: string;\n canonicalText: string;\n checksum: string;\n verifiedAt: string;\n verifiedBy: \"agent\" | \"user\" | \"system\";\n nextVerification: string | null;\n version: number;\n previousVersionId: string | null;\n createdAt: string;\n}\n\ninterface IntegrityReport {\n valid: boolean;\n corrupted?: string[];\n checked: number;\n}\n\nexport class VerificationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"VerificationError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nexport function computeChecksum(text: string): string {\n return createHash(\"sha256\").update(text).digest(\"hex\");\n}\n\nfunction isIpAddress(value: string): boolean {\n const ipPattern = /\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/;\n return ipPattern.test(value);\n}\n\nfunction isHostname(value: string): boolean {\n const trimmed = value.trim().toLowerCase();\n if (!trimmed || trimmed.length < 3) return false;\n if (isIpAddress(trimmed)) return false;\n if (!/^[a-z0-9.-]+$/.test(trimmed)) return false;\n if (!/[a-z0-9]/.test(trimmed)) return false;\n if (trimmed.includes(\"..\") || trimmed.startsWith(\".\") || trimmed.endsWith(\".\")) return false;\n if (!trimmed.includes(\".\")) return false;\n return true;\n}\n\nfunction containsHostname(text: string): boolean {\n const hostnamePattern = /\\b[a-z0-9-]{1,63}(?:\\.[a-z0-9-]{1,63})+\\b/gi;\n const matches = text.match(hostnamePattern);\n if (!matches) return false;\n\n for (const match of matches) {\n if (/[a-z]/i.test(match)) {\n return true;\n }\n }\n return false;\n}\n\nfunction toISODate(d: Date): string {\n return d.toISOString();\n}\n\nfunction addDays(date: Date, days: number): Date {\n const result = new Date(date.getTime());\n result.setDate(result.getDate() + days);\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Raw row type returned from SQLite queries\n// ---------------------------------------------------------------------------\n\nexport interface VerifiedFactRow {\n id: string;\n fact_id: string;\n canonical_text: string;\n checksum: string;\n verified_at: string;\n verified_by: string;\n next_verification: string | null;\n version: number;\n previous_version_id: string | null;\n created_at: string;\n}\n\nexport function rowToVerifiedFact(row: VerifiedFactRow): VerifiedFact {\n return {\n id: row.id,\n factId: row.fact_id,\n canonicalText: row.canonical_text,\n checksum: row.checksum,\n verifiedAt: row.verified_at,\n verifiedBy: row.verified_by as \"agent\" | \"user\" | \"system\",\n nextVerification: row.next_verification,\n version: row.version,\n previousVersionId: row.previous_version_id,\n createdAt: row.created_at,\n };\n}\n\n// ---------------------------------------------------------------------------\n// shouldAutoVerify — heuristic check for critical facts\n// ---------------------------------------------------------------------------\n\n/**\n * Returns true if the fact should be automatically verified.\n */\nexport function shouldAutoVerify(fact: {\n text: string;\n category: string;\n tags: string[];\n entity?: string | null;\n key?: string | null;\n value?: string | null;\n verificationTier?: string | null;\n}): boolean {\n const verificationTier = (fact.verificationTier ?? \"\").trim().toLowerCase();\n if (verificationTier === \"critical\") return true;\n\n const entity = (fact.entity ?? \"\").trim();\n const text = fact.text ?? \"\";\n if (entity && (isIpAddress(entity) || isHostname(entity))) return true;\n if (isIpAddress(text) || containsHostname(text)) return true;\n\n const entityLower = entity.toLowerCase();\n const keyLower = (fact.key ?? \"\").toLowerCase();\n const valueLower = (fact.value ?? \"\").toLowerCase();\n if (\n entityLower.includes(\"credential\") ||\n keyLower.includes(\"credential\") ||\n valueLower.startsWith(VAULT_POINTER_PREFIX)\n ) {\n return true;\n }\n\n // Infrastructure + technical category\n if (fact.tags.map((t) => t.toLowerCase()).includes(\"infrastructure\") && fact.category === \"technical\") {\n return true;\n }\n\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// VerificationStore\n// ---------------------------------------------------------------------------\n\nexport class VerificationStore {\n private db: DatabaseSync;\n private readonly backupPath: string;\n private readonly reverificationDays: number;\n private readonly logger?: { warn?: (msg: string) => void; error?: (msg: string) => void };\n private _dbOpen = true;\n /** When false, connection is shared (e.g. FactsDB.getRawDb()); close() must not call db.close(). */\n private readonly ownsConnection: boolean;\n\n /**\n * @param dbPathOrInstance - Either a file path string (opens its own connection) or an\n * existing Database instance to share (e.g. FactsDB.getRawDb()). When sharing an\n * instance, the caller is responsible for pragma setup and lifecycle.\n */\n constructor(\n dbPathOrInstance: string | DatabaseSync,\n options?: {\n backupPath?: string;\n reverificationDays?: number;\n logger?: { warn?: (msg: string) => void; error?: (msg: string) => void };\n },\n ) {\n if (typeof dbPathOrInstance === \"string\") {\n mkdirSync(dirname(dbPathOrInstance), { recursive: true });\n this.db = new DatabaseSync(dbPathOrInstance);\n this.ownsConnection = true;\n this.applyPragmas();\n } else {\n // Shared instance — caller owns the connection lifecycle\n this.db = dbPathOrInstance;\n this.ownsConnection = false;\n }\n this.reverificationDays = options?.reverificationDays ?? 30;\n this.logger = options?.logger;\n\n const rawBackup = options?.backupPath ?? \"~/.openclaw/verified-facts.json\";\n this.backupPath = expandTilde(rawBackup);\n mkdirSync(dirname(this.backupPath), { recursive: true });\n\n this.initSchema();\n }\n\n private applyPragmas(): void {\n this.db.exec(\"PRAGMA journal_mode = WAL\");\n this.db.exec(`PRAGMA busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`);\n this.db.exec(\"PRAGMA synchronous = NORMAL\");\n }\n\n /** Schema for standalone verification DB (no facts table). When verified_facts lives in FactsDB, the migration in facts-db.ts is used. */\n private initSchema(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS verified_facts (\n id TEXT PRIMARY KEY,\n fact_id TEXT NOT NULL,\n canonical_text TEXT NOT NULL,\n checksum TEXT NOT NULL,\n verified_at TEXT NOT NULL,\n verified_by TEXT NOT NULL,\n next_verification TEXT,\n version INTEGER DEFAULT 1,\n previous_version_id TEXT,\n created_at TEXT NOT NULL\n );\n CREATE INDEX IF NOT EXISTS idx_verified_facts_fact_id ON verified_facts(fact_id);\n CREATE INDEX IF NOT EXISTS idx_verified_facts_next_verification ON verified_facts(next_verification);\n `);\n }\n\n // -------------------------------------------------------------------------\n // verify — add a fact to the verification store\n // -------------------------------------------------------------------------\n\n verify(factId: string, text: string, verifiedBy: \"agent\" | \"user\" | \"system\"): string {\n const existing = this.db.prepare(\"SELECT 1 FROM verified_facts WHERE fact_id = ? LIMIT 1\").get(factId);\n if (existing) {\n throw new VerificationError(`Fact ${factId} is already verified; use update() to create a new version`);\n }\n\n const id = randomUUID();\n const now = toISODate(new Date());\n const nextVerification = toISODate(addDays(new Date(), this.reverificationDays));\n const checksum = computeChecksum(text);\n\n this.db\n .prepare(\n `INSERT INTO verified_facts\n (id, fact_id, canonical_text, checksum, verified_at, verified_by, next_verification, version, previous_version_id, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, 1, NULL, ?)`,\n )\n .run(id, factId, text, checksum, now, verifiedBy, nextVerification, now);\n\n this.writeBackup({\n action: \"verify\",\n id,\n fact_id: factId,\n canonical_text: text,\n checksum,\n verified_at: now,\n verified_by: verifiedBy,\n version: 1,\n nextVerification,\n previousVersionId: null,\n ts: now,\n });\n\n return id;\n }\n\n // -------------------------------------------------------------------------\n // checkIntegrity — verify checksums match stored text\n // -------------------------------------------------------------------------\n\n checkIntegrity(factId?: string): IntegrityReport {\n let rows: VerifiedFactRow[];\n if (factId !== undefined) {\n rows = this.db\n .prepare(\"SELECT * FROM verified_facts WHERE fact_id = ? ORDER BY version DESC\")\n .all(factId) as unknown as VerifiedFactRow[];\n } else {\n rows = this.db.prepare(\"SELECT * FROM verified_facts\").all() as unknown as VerifiedFactRow[];\n }\n\n const corrupted: string[] = [];\n\n for (const row of rows) {\n const live = computeChecksum(row.canonical_text);\n if (live !== row.checksum) {\n corrupted.push(row.id);\n }\n }\n\n return {\n valid: corrupted.length === 0,\n corrupted: corrupted.length > 0 ? corrupted : undefined,\n checked: rows.length,\n };\n }\n\n // -------------------------------------------------------------------------\n // getVerified — retrieve a verified fact, throws on checksum mismatch\n // -------------------------------------------------------------------------\n\n getVerified(factId: string): VerifiedFact | null {\n const row = this.db\n .prepare(\"SELECT * FROM verified_facts WHERE fact_id = ? ORDER BY version DESC LIMIT 1\")\n .get(factId) as VerifiedFactRow | undefined;\n\n if (!row) return null;\n\n const live = computeChecksum(row.canonical_text);\n if (live !== row.checksum) {\n const message = `Checksum mismatch for verified fact ${row.id} (fact_id=${factId}): stored checksum does not match canonical_text`;\n this.logCorruption(message);\n throw new VerificationError(message);\n }\n\n return rowToVerifiedFact(row);\n }\n\n // -------------------------------------------------------------------------\n // listDueForReverification — facts whose next_verification <= now or verified_at is stale\n // -------------------------------------------------------------------------\n\n listDueForReverification(): VerifiedFact[] {\n const now = toISODate(new Date());\n const cutoff = toISODate(addDays(new Date(), -this.reverificationDays));\n const rows = this.db\n .prepare(\n `SELECT vf.*\n FROM verified_facts vf\n JOIN (\n SELECT fact_id, MAX(version) as max_version\n FROM verified_facts\n GROUP BY fact_id\n ) latest\n ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE (vf.next_verification IS NOT NULL AND vf.next_verification <= ?)\n OR vf.verified_at <= ?\n ORDER BY COALESCE(vf.next_verification, vf.verified_at) ASC`,\n )\n .all(now, cutoff) as unknown as VerifiedFactRow[];\n\n return rows.filter((row) => this.validateRowChecksum(row)).map(rowToVerifiedFact);\n }\n\n // -------------------------------------------------------------------------\n // listLatestVerified — latest versions for each fact_id\n // -------------------------------------------------------------------------\n\n listLatestVerified(limit?: number): VerifiedFact[] {\n const limitClause = limit ? `LIMIT ${limit}` : \"\";\n const rows = this.db\n .prepare(\n `SELECT vf.*\n FROM verified_facts vf\n JOIN (\n SELECT fact_id, MAX(version) as max_version\n FROM verified_facts\n GROUP BY fact_id\n ) latest\n ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n ORDER BY vf.verified_at DESC ${limitClause}`,\n )\n .all() as unknown as VerifiedFactRow[];\n\n return rows.filter((row) => this.validateRowChecksum(row)).map(rowToVerifiedFact);\n }\n\n // -------------------------------------------------------------------------\n // update — create a new version, linking to the superseded one\n // -------------------------------------------------------------------------\n\n update(id: string, newText: string, verifiedBy: \"agent\" | \"user\" | \"system\"): string {\n const existing = this.db.prepare(\"SELECT * FROM verified_facts WHERE id = ?\").get(id) as\n | VerifiedFactRow\n | undefined;\n\n if (!existing) {\n throw new VerificationError(`No verified fact found with id=${id}`);\n }\n\n const latest = this.db\n .prepare(\"SELECT id FROM verified_facts WHERE fact_id = ? ORDER BY version DESC LIMIT 1\")\n .get(existing.fact_id) as { id: string } | undefined;\n if (!latest || latest.id !== id) {\n throw new VerificationError(\n `Can only update from the latest version; id=${id} is not the current latest for fact_id=${existing.fact_id}`,\n );\n }\n\n const newId = randomUUID();\n const now = toISODate(new Date());\n const nextVerification = toISODate(addDays(new Date(), this.reverificationDays));\n const checksum = computeChecksum(newText);\n const newVersion = existing.version + 1;\n\n createTransaction(this.db, () => {\n this.db\n .prepare(\n `INSERT INTO verified_facts\n (id, fact_id, canonical_text, checksum, verified_at, verified_by, next_verification, version, previous_version_id, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(newId, existing.fact_id, newText, checksum, now, verifiedBy, nextVerification, newVersion, id, now);\n this.db.prepare(\"UPDATE verified_facts SET next_verification = NULL WHERE id = ?\").run(id);\n })();\n\n this.writeBackup({\n action: \"update\",\n id: newId,\n fact_id: existing.fact_id,\n canonical_text: newText,\n checksum,\n verified_at: now,\n verified_by: verifiedBy,\n version: newVersion,\n nextVerification,\n previousVersionId: id,\n ts: now,\n });\n\n return newId;\n }\n\n // -------------------------------------------------------------------------\n // close — close the underlying SQLite connection\n // -------------------------------------------------------------------------\n\n /** Return the total number of verified fact entries (across all fact_ids). */\n countVerified(): number {\n const row = this.db.prepare(\"SELECT COUNT(*) as cnt FROM verified_facts\").get() as { cnt: number };\n return row.cnt;\n }\n\n close(): void {\n if (this.ownsConnection && this._dbOpen) {\n this.db.close();\n this._dbOpen = false;\n }\n }\n\n private validateRowChecksum(row: VerifiedFactRow): boolean {\n const live = computeChecksum(row.canonical_text);\n if (live !== row.checksum) {\n const message = `Checksum mismatch for verified fact ${row.id} (fact_id=${row.fact_id}): stored checksum does not match canonical_text`;\n this.logCorruption(message);\n return false;\n }\n return true;\n }\n\n private logCorruption(message: string): void {\n if (this.logger?.error) {\n this.logger.error(`memory-hybrid: verification corruption detected: ${message}`);\n return;\n }\n if (this.logger?.warn) {\n this.logger.warn(`memory-hybrid: verification corruption detected: ${message}`);\n }\n }\n\n // -------------------------------------------------------------------------\n // Private: append-only backup\n // -------------------------------------------------------------------------\n\n private hasLoggedBackupError = false;\n\n private writeBackup(entry: {\n action: \"verify\" | \"update\";\n id: string;\n fact_id: string;\n canonical_text: string;\n checksum: string;\n verified_at: string;\n verified_by: string;\n version: number;\n nextVerification: string | null;\n previousVersionId: string | null;\n ts: string;\n }): void {\n try {\n const line = `${JSON.stringify(entry)}\\n`;\n appendFileSync(this.backupPath, line, { encoding: \"utf8\", mode: 0o600 });\n } catch (err) {\n if (!this.hasLoggedBackupError) {\n this.hasLoggedBackupError = true;\n capturePluginError(err instanceof Error ? err : new Error(String(err)), {\n subsystem: \"verification-store\",\n operation: \"writeBackup\",\n });\n }\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verified-fact-triage.js","names":[],"sources":["../../services/verified-fact-triage.ts"],"sourcesContent":["import type { DatabaseSync, SQLInputValue } from \"node:sqlite\";\nimport type { FactsDB } from \"../backends/facts-db.js\";\nimport { rowToMemoryEntry } from \"../backends/facts-db/index.js\";\nimport type { MemoryEntry } from \"../types/memory.js\";\nimport {\n computePendingInputHash,\n createPendingAutopilotRunId,\n createStableRunSummary,\n type PendingAutopilotStore,\n type PendingAutopilotCursor,\n type AutopilotAction,\n type AutopilotReasonCode,\n type PendingDecision,\n type PendingDecisionContext,\n type PendingDecisionEvidence,\n type PendingItem,\n type PendingQueueAdapter,\n} from \"./pending-autopilot/index.js\";\nimport { computeChecksum, rowToVerifiedFact, type VerifiedFact, type VerifiedFactRow } from \"./verification-store.js\";\n\nexport const VERIFIED_TRIAGE_POLICY_VERSION = \"verified-fact-triage-v1\";\nconst DEFAULT_REVERIFICATION_DAYS = 30;\nconst DEFAULT_TRIAGE_MAX = 100;\nconst MIN_VERIFIED_TRIAGE_SQL_LIMIT = 25;\nconst MAX_VERIFIED_TRIAGE_SQL_LIMIT = 1000;\nconst VERIFIED_TRIAGE_SQL_OVERFETCH_FACTOR = 4;\nexport const VERIFIED_REVIEW_QUEUE_SOURCE =\n \"Latest verified_facts rows whose next_verification timestamp is due (or whose verified_at is older than the verification window), as returned by VerificationStore.listDueForReverification semantics. This is intentionally not all verified facts.\";\n\nexport const VERIFIED_TRIAGE_POLICIES = [\"report-only\", \"classify\", \"apply-obvious\"] as const;\nexport type VerifiedTriagePolicy = (typeof VERIFIED_TRIAGE_POLICIES)[number];\n\nexport const VERIFIED_TRIAGE_BUCKETS = [\n \"still-current\",\n \"stale-candidate\",\n \"expired-ttl-candidate\",\n \"superseded-candidate\",\n \"contradicted-candidate\",\n \"missing-or-weak-provenance\",\n \"duplicate-candidate\",\n \"scope-or-ownership-unclear\",\n \"sensitive-needs-human\",\n \"needs-human-review\",\n \"failed-review\",\n] as const;\nexport type VerifiedTriageBucket = (typeof VERIFIED_TRIAGE_BUCKETS)[number];\n\nexport const VERIFIED_TRIAGE_ACTIONS = [\n \"reported\",\n \"classified\",\n \"marked-reviewed\",\n \"linked-evidence\",\n \"flagged-stale\",\n \"flagged-superseded\",\n \"flagged-contradicted\",\n \"flagged-sensitive\",\n \"deferred-for-human\",\n \"failed-validation\",\n \"skipped-by-policy\",\n] as const;\nexport type VerifiedTriageAction = (typeof VERIFIED_TRIAGE_ACTIONS)[number];\n\nexport type VerifiedTriageReason =\n | \"policy_report_only\"\n | \"still_current_no_action_needed\"\n | \"ttl_expired\"\n | \"newer_verified_fact_exists\"\n | \"contradicting_verified_fact_exists\"\n | \"weak_or_missing_provenance\"\n | \"duplicate_verified_fact_candidate\"\n | \"sensitive_security_fact\"\n | \"sensitive_privacy_fact\"\n | \"sensitive_personal_fact\"\n | \"sensitive_operational_runbook\"\n | \"scope_unclear\"\n | \"requires_human_approval\"\n | \"stale_due_for_reverification\"\n | \"low_confidence\"\n | \"backend_error\"\n | \"malformed_fact\"\n | \"evidence_query_failed\";\n\nexport interface VerifiedFactTriageItem extends PendingItem<VerifiedFactTriagePayload> {\n queue: \"verified\";\n}\n\nexport interface VerifiedFactTriagePayload extends Record<string, unknown> {\n reviewQueueSource: string;\n verified: VerifiedFact;\n fact: TriageFactSnapshot | null;\n verificationTier: string | null;\n reviewCursor: string | null;\n dueReason: \"next_verification\" | \"verified_at_stale\";\n}\n\nexport interface TriageFactSnapshot {\n id: string;\n text: string;\n category: string;\n entity: string | null;\n key: string | null;\n value: string | null;\n source: string;\n createdAt: number;\n expiresAt: number | null;\n validFrom: number | null;\n validUntil: number | null;\n supersedesId: string | null;\n supersededAt: number | null;\n supersededBy: string | null;\n tier: string | null;\n scope: string;\n scopeTarget: string | null;\n provenanceSession: string | null;\n sourceSessions: string | null;\n provenanceJson: string | null;\n tags: string[] | null;\n confidence: number;\n}\n\nexport interface VerifiedTriageEvidence extends PendingDecisionEvidence {\n fields?: Record<string, unknown>;\n}\n\nexport interface VerifiedTriageResultItem {\n factId: string;\n verifiedFactId: string;\n text: string;\n verificationTier: string | null;\n scope: string | null;\n scopeTarget: string | null;\n entity: string | null;\n key: string | null;\n validFrom: number | null;\n validUntil: number | null;\n expiresAt: number | null;\n provenanceSummary: string;\n bucket: VerifiedTriageBucket;\n recommendedAction: VerifiedTriageAction;\n confidence: number;\n evidence: VerifiedTriageEvidence[];\n sensitivityFlags: string[];\n reason: VerifiedTriageReason;\n humanReviewRequired: boolean;\n action: AutopilotAction;\n reasonCode: AutopilotReasonCode;\n capabilityClass: PendingDecision[\"capabilityClass\"];\n actionClass: PendingDecision[\"actionClass\"];\n inputHash: string;\n applied: boolean;\n}\n\nexport interface VerifiedTriageRunResult {\n runId: string;\n mode: \"dry-run\" | \"apply\";\n policy: VerifiedTriagePolicy;\n policyVersion: string;\n reviewQueueSource: string;\n counts: {\n inspected: number;\n classified: number;\n stillCurrent: number;\n staleCandidates: number;\n expiredTtlCandidates: number;\n supersededCandidates: number;\n contradictedCandidates: number;\n duplicateCandidates: number;\n sensitiveNeedsHuman: number;\n needsHuman: number;\n applied: number;\n failed: number;\n };\n items: VerifiedTriageResultItem[];\n}\n\nexport interface VerifiedFactTriageOptions {\n mode: \"dry-run\" | \"apply\";\n policy: VerifiedTriagePolicy;\n max?: number;\n reverificationDays?: number;\n actor?: PendingDecision[\"actor\"];\n jobId?: string;\n runId?: string;\n store?: PendingAutopilotStore | null;\n nowMs?: number;\n lockTtlSeconds?: number;\n}\n\ninterface RelatedFact extends TriageFactSnapshot {\n verifiedFactId?: string | null;\n verifiedAt?: string | null;\n verifiedVersion?: number | null;\n}\n\nconst SENSITIVE_RULES: Array<{\n flag: string;\n reason: VerifiedTriageReason;\n pattern: RegExp;\n}> = [\n {\n flag: \"credentials\",\n reason: \"sensitive_security_fact\",\n pattern: /\\b(password|passwd|credential|secret|api[-_ ]?key|token|bearer|ssh key|private key|vault|oauth|pat_)\\b/i,\n },\n {\n flag: \"security\",\n reason: \"sensitive_security_fact\",\n pattern: /\\b(security|firewall|ssh|vpn|runbook|incident|breach|auth|mfa|2fa|permission|admin)\\b/i,\n },\n {\n flag: \"privacy\",\n reason: \"sensitive_privacy_fact\",\n pattern: /\\b(privacy|private|personal data|pii|gdpr|address|phone|email|medical|health|passport|identity)\\b/i,\n },\n {\n flag: \"external-comms\",\n reason: \"sensitive_personal_fact\",\n pattern: /\\b(external comms|external communication|email rule|reply rule|send to|contact|customer|client)\\b/i,\n },\n {\n flag: \"persona-preference\",\n reason: \"sensitive_personal_fact\",\n pattern: /\\b(preference|user identity|persona|edict|hard rule|user profile|personal fact)\\b/i,\n },\n {\n flag: \"operational-runbook\",\n reason: \"sensitive_operational_runbook\",\n pattern: /\\b(cron|runbook|operational|ops|production|deploy|restart|backup|restore)\\b/i,\n },\n];\n\nexport function assertVerifiedTriagePolicy(value: string): VerifiedTriagePolicy {\n if ((VERIFIED_TRIAGE_POLICIES as readonly string[]).includes(value)) return value as VerifiedTriagePolicy;\n throw new Error(`Unknown verified triage policy: ${value}`);\n}\n\nexport function createVerifiedFactTriageAdapter(input: {\n factsDb: Pick<FactsDB, \"getRawDb\">;\n max?: number;\n nowMs?: number;\n reverificationDays?: number;\n policy?: VerifiedTriagePolicy;\n}): PendingQueueAdapter<VerifiedFactTriageItem> {\n const db = input.factsDb.getRawDb();\n registerVerifiedChecksumFunction(db);\n return {\n queue: \"verified\",\n listPending: (cursor) =>\n listVerifiedFactTriageItems(db, {\n max: input.max,\n nowMs: input.nowMs,\n reverificationDays: input.reverificationDays,\n policy: input.policy,\n cursor,\n }),\n decide: (item, context) => decideVerifiedFactTriage(item, context, { db, nowMs: input.nowMs }),\n apply: (_decision, _item) => {\n // Verified fact triage intentionally does not mutate core truth fields. Durable\n // state is recorded through PendingAutopilotStore decisions only.\n },\n };\n}\n\nexport function listVerifiedFactTriageItems(\n db: DatabaseSync,\n opts: {\n max?: number;\n nowMs?: number;\n reverificationDays?: number;\n policy?: VerifiedTriagePolicy;\n cursor?: PendingAutopilotCursor | null;\n } = {},\n): VerifiedFactTriageItem[] {\n registerVerifiedChecksumFunction(db);\n const nowMs = opts.nowMs ?? Date.now();\n const nowIso = new Date(nowMs).toISOString();\n const cutoffIso = new Date(\n nowMs - (opts.reverificationDays ?? DEFAULT_REVERIFICATION_DAYS) * 24 * 60 * 60 * 1000,\n ).toISOString();\n const policy = opts.policy ?? \"classify\";\n const cursor = opts.cursor?.cursor ?? null;\n const cursorItemId = opts.cursor\n ? findVerifiedCursorItemId(db, opts.cursor.inputHash, policy, nowIso, cursor, cutoffIso)\n : null;\n const max = normalizeVerifiedTriageMax(opts.max);\n const latestRows = listChecksumValidDueVerifiedRows(db, {\n nowIso,\n cutoffIso,\n cursor,\n cursorItemId,\n max,\n });\n\n return latestRows.map((row) => triageItemFromRow(db, row, { nowIso, policy }));\n}\n\nfunction normalizeVerifiedTriageMax(max: number | undefined): number {\n if (max == null) return DEFAULT_TRIAGE_MAX;\n if (!Number.isFinite(max) || max <= 0) return 0;\n return Math.floor(max);\n}\n\nfunction verifiedTriageSqlLimit(max: number): number {\n if (max <= 0) return MIN_VERIFIED_TRIAGE_SQL_LIMIT;\n return Math.min(\n MAX_VERIFIED_TRIAGE_SQL_LIMIT,\n Math.max(MIN_VERIFIED_TRIAGE_SQL_LIMIT, max * VERIFIED_TRIAGE_SQL_OVERFETCH_FACTOR),\n );\n}\n\nfunction listChecksumValidDueVerifiedRows(\n db: DatabaseSync,\n opts: {\n nowIso: string;\n cutoffIso: string;\n cursor: string | null;\n cursorItemId: string | null;\n max: number;\n },\n): VerifiedFactRow[] {\n if (opts.max <= 0) return [];\n\n const rows: VerifiedFactRow[] = [];\n const sqlLimit = verifiedTriageSqlLimit(opts.max);\n let pageCursor = opts.cursor;\n let pageCursorItemId = opts.cursorItemId;\n\n while (rows.length < opts.max) {\n const page = db\n .prepare(\n `SELECT vf.*\n FROM verified_facts vf\n JOIN (\n SELECT vf2.fact_id, MAX(vf2.version) AS max_version\n FROM verified_facts vf2\n GROUP BY vf2.fact_id\n ) latest ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE ((vf.next_verification IS NOT NULL AND vf.next_verification <= ?)\n OR vf.verified_at <= ?)\n AND (\n ? IS NULL\n OR COALESCE(vf.next_verification, vf.verified_at) > ?\n OR (COALESCE(vf.next_verification, vf.verified_at) = ? AND (? IS NULL OR vf.id > ?))\n )\n ORDER BY COALESCE(vf.next_verification, vf.verified_at) ASC, vf.id ASC\n LIMIT ?`,\n )\n .all(\n opts.nowIso,\n opts.cutoffIso,\n pageCursor,\n pageCursor,\n pageCursor,\n pageCursorItemId,\n pageCursorItemId,\n sqlLimit,\n ) as unknown as VerifiedFactRow[];\n\n if (page.length === 0) break;\n\n for (const row of page) {\n if (isVerifiedRowChecksumValid(row)) rows.push(row);\n if (rows.length >= opts.max) break;\n }\n\n const last = page[page.length - 1];\n pageCursor = last?.next_verification ?? last?.verified_at ?? pageCursor;\n pageCursorItemId = last?.id ?? pageCursorItemId;\n if (page.length < sqlLimit) break;\n }\n\n return rows;\n}\n\nfunction findVerifiedCursorItemId(\n db: DatabaseSync,\n inputHash: string,\n policy: VerifiedTriagePolicy,\n nowIso: string,\n cursor: string | null,\n cutoffIso: string,\n): string | null {\n if (!cursor) return null;\n const rows = db\n .prepare(\n `SELECT vf.*\n FROM verified_facts vf\n JOIN (\n SELECT vf2.fact_id, MAX(vf2.version) AS max_version\n FROM verified_facts vf2\n GROUP BY vf2.fact_id\n ) latest ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE ((vf.next_verification IS NOT NULL AND vf.next_verification <= ?)\n OR vf.verified_at <= ?)\n AND COALESCE(vf.next_verification, vf.verified_at) = ?\n ORDER BY vf.id ASC`,\n )\n .all(nowIso, cutoffIso, cursor) as unknown as VerifiedFactRow[];\n for (const row of rows) {\n if (!isVerifiedRowChecksumValid(row)) continue;\n const item = triageItemFromRow(db, row, { nowIso, policy });\n if (item.inputHash === inputHash) return row.id;\n if (row.next_verification && row.verified_at <= cutoffIso) {\n const staleContextItem = triageItemFromRow(db, row, {\n nowIso,\n policy,\n dueReason: \"verified_at_stale\",\n });\n if (staleContextItem.inputHash === inputHash) return row.id;\n }\n }\n return null;\n}\n\nfunction isVerifiedRowChecksumValid(row: VerifiedFactRow): boolean {\n return computeChecksum(row.canonical_text) === row.checksum;\n}\n\nexport function decideVerifiedFactTriage(\n item: VerifiedFactTriageItem,\n context: PendingDecisionContext,\n opts: { db?: DatabaseSync; nowMs?: number } = {},\n): PendingDecision {\n const triage = classifyVerifiedFact(item, {\n db: opts.db,\n nowMs: opts.nowMs,\n policy: context.policy,\n });\n return triageToPendingDecision(item, context, triage);\n}\n\nexport async function runVerifiedFactTriage(\n factsDb: Pick<FactsDB, \"getRawDb\">,\n opts: VerifiedFactTriageOptions,\n): Promise<VerifiedTriageRunResult> {\n const policy = assertVerifiedTriagePolicy(opts.policy);\n const adapter = createVerifiedFactTriageAdapter({\n factsDb,\n max: opts.max,\n nowMs: opts.nowMs,\n reverificationDays: opts.reverificationDays,\n policy,\n });\n return runVerifiedFactTriageWithAdapter(factsDb, adapter, opts);\n}\n\nexport async function runVerifiedFactTriageWithAdapter(\n factsDb: Pick<FactsDB, \"getRawDb\">,\n adapter: PendingQueueAdapter<VerifiedFactTriageItem>,\n opts: VerifiedFactTriageOptions,\n): Promise<VerifiedTriageRunResult> {\n const policy = assertVerifiedTriagePolicy(opts.policy);\n const mode = opts.mode;\n const store = opts.store ?? null;\n if (mode === \"apply\" && policy !== \"report-only\" && !store) {\n throw new Error(\n `Verified fact triage apply mode with policy '${policy}' requires a PendingAutopilotStore to persist durable review metadata`,\n );\n }\n const runId = opts.runId ?? createPendingAutopilotRunId();\n const actor = opts.actor ?? { type: \"agent\", id: \"verified-triage-cli\" };\n const storedCursor =\n mode === \"apply\" && policy !== \"report-only\" ? (store?.getCursor(\"verified\", policy) ?? null) : null;\n const items = await adapter.listPending(storedCursor);\n const runInputHash = computePendingInputHash({\n queue: \"verified\",\n itemIds: items.map((i) => i.id),\n policy,\n mode,\n });\n const startedAt = Math.floor((opts.nowMs ?? Date.now()) / 1000);\n const db = factsDb.getRawDb();\n\n const durableStore = policy === \"report-only\" ? null : store;\n\n durableStore?.createRun({\n runId,\n mode,\n policy,\n policyVersion: VERIFIED_TRIAGE_POLICY_VERSION,\n inputHash: runInputHash,\n queues: [\"verified\"],\n startedAt,\n });\n\n const decisions: PendingDecision[] = [];\n const resultItems: VerifiedTriageResultItem[] = [];\n for (const item of items) {\n const context: PendingDecisionContext = {\n runId,\n jobId: opts.jobId,\n mode,\n policy,\n policyVersion: VERIFIED_TRIAGE_POLICY_VERSION,\n inputHash: item.inputHash,\n actor,\n };\n let decision: PendingDecision;\n let applied = false;\n if (mode === \"apply\" && policy !== \"report-only\") {\n const locked =\n durableStore?.acquireLock({\n queue: \"verified\",\n itemId: item.id,\n inputHash: item.inputHash,\n owner: actor.id,\n ttlSeconds: opts.lockTtlSeconds ?? 60,\n mode,\n }) ?? false;\n try {\n if (locked) {\n const liveItem =\n loadLiveVerifiedFactTriageItem(db, item.id, {\n nowMs: opts.nowMs,\n reverificationDays: opts.reverificationDays,\n policy,\n }) ?? null;\n const actualInputHash = liveItem?.inputHash ?? \"missing\";\n if (liveItem && actualInputHash === item.inputHash) {\n const liveContext: PendingDecisionContext = {\n ...context,\n inputHash: liveItem.inputHash,\n };\n decision = await adapter.decide(liveItem, liveContext);\n const { inserted } = durableStore?.recordLatestDecision(decision) ?? {\n inserted: false,\n };\n if (decision.action !== \"deferred-for-human\" && decision.action !== \"failed-validation\") {\n durableStore?.advanceCursorIfSafe(decision, liveItem.visibleAfterCursor ?? liveItem.id);\n }\n applied = inserted && (decision.action === \"classified\" || decision.action === \"reported\");\n } else {\n const staleDecision = validationFailureDecision(\n item,\n context,\n \"input-hash-mismatch\",\n liveItem\n ? \"Verified fact/fact row changed between classification and apply.\"\n : \"Verified fact no longer matches due queue before apply.\",\n );\n durableStore?.recordDecision(staleDecision);\n decision = staleDecision;\n }\n } else {\n const staleDecision = validationFailureDecision(\n item,\n context,\n \"lock-conflict\",\n \"Could not acquire lock for verified fact triage (another process may hold it).\",\n );\n durableStore?.recordDecision(staleDecision);\n decision = staleDecision;\n }\n } finally {\n if (locked) {\n durableStore?.releaseLock({\n queue: \"verified\",\n itemId: item.id,\n inputHash: item.inputHash,\n owner: actor.id,\n mode,\n });\n }\n }\n } else {\n decision = await adapter.decide(item, context);\n }\n decisions.push(decision);\n resultItems.push(decisionToResultItem(decision, item, applied));\n }\n\n const summary = createStableRunSummary({\n runId,\n mode,\n policy,\n policyVersion: VERIFIED_TRIAGE_POLICY_VERSION,\n queues: [\"verified\"],\n startedAt,\n finishedAt: Math.floor((opts.nowMs ?? Date.now()) / 1000),\n decisions,\n });\n durableStore?.finishRun(runId, summary, summary.finishedAt);\n\n return buildRunResult({ runId, mode, policy, items: resultItems });\n}\n\nexport function classifyVerifiedFact(\n item: VerifiedFactTriageItem,\n opts: { db?: DatabaseSync; nowMs?: number; policy?: string } = {},\n): Omit<\n VerifiedTriageResultItem,\n | \"factId\"\n | \"verifiedFactId\"\n | \"text\"\n | \"verificationTier\"\n | \"scope\"\n | \"scopeTarget\"\n | \"entity\"\n | \"key\"\n | \"validFrom\"\n | \"validUntil\"\n | \"expiresAt\"\n | \"provenanceSummary\"\n | \"action\"\n | \"reasonCode\"\n | \"capabilityClass\"\n | \"actionClass\"\n | \"inputHash\"\n | \"applied\"\n> {\n if (opts.db) {\n registerVerifiedChecksumFunction(opts.db);\n }\n const fact = item.payload.fact;\n const nowMs = opts.nowMs ?? Date.now();\n const nowSec = Math.floor(nowMs / 1000);\n const nowIso = new Date(nowMs).toISOString();\n\n if (!fact) {\n return {\n bucket: \"failed-review\",\n recommendedAction: \"failed-validation\",\n reason: \"malformed_fact\",\n confidence: 1,\n evidence: [\n {\n type: \"verified-fact\",\n id: item.payload.verified.id,\n summary: \"Verified row references a missing fact row\",\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n\n const sensitivity = detectSensitivity(fact, item.payload.verified.canonicalText);\n if (sensitivity.flags.length > 0) {\n return {\n bucket: \"sensitive-needs-human\",\n recommendedAction: \"flagged-sensitive\",\n reason: sensitivity.reason,\n confidence: 0.95,\n evidence: [\n {\n type: \"sensitivity\",\n id: fact.id,\n summary: `Matched sensitive categories: ${sensitivity.flags.join(\", \")}`,\n },\n ],\n sensitivityFlags: sensitivity.flags,\n humanReviewRequired: true,\n };\n }\n\n if (hasScopeUnclearSignals(fact)) {\n return {\n bucket: \"scope-or-ownership-unclear\",\n recommendedAction: \"deferred-for-human\",\n reason: \"scope_unclear\",\n confidence: 0.9,\n evidence: [\n {\n type: \"scope\",\n id: fact.id,\n summary: \"Fact has session/agent/user scope requiring explicit ownership proof\",\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n\n if (fact.validUntil != null && fact.validUntil <= nowSec) {\n return {\n bucket: \"expired-ttl-candidate\",\n recommendedAction: \"deferred-for-human\",\n reason: \"ttl_expired\",\n confidence: 0.95,\n evidence: [\n {\n type: \"validity\",\n id: fact.id,\n summary: \"Fact valid_until has expired\",\n fields: { validUntil: fact.validUntil, now: nowSec },\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n if (fact.expiresAt != null && fact.expiresAt <= nowSec) {\n return {\n bucket: \"expired-ttl-candidate\",\n recommendedAction: \"deferred-for-human\",\n reason: \"ttl_expired\",\n confidence: 0.95,\n evidence: [\n {\n type: \"ttl\",\n id: fact.id,\n summary: \"Fact expires_at has expired\",\n fields: { expiresAt: fact.expiresAt, now: nowSec },\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n\n const newer = opts.db ? findExplicitNewerVerifiedFact(opts.db, fact) : null;\n if (newer) {\n return {\n bucket: \"superseded-candidate\",\n recommendedAction: \"flagged-superseded\",\n reason: \"newer_verified_fact_exists\",\n confidence: 0.9,\n evidence: [\n {\n type: \"fact\",\n id: newer.id,\n summary: \"Explicit newer verified fact supersedes this fact\",\n fields: {\n newerFactId: newer.id,\n verifiedFactId: newer.verifiedFactId,\n },\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n\n const contradiction = opts.db ? findConcreteContradictingEvidence(opts.db, fact) : null;\n if (contradiction) {\n return {\n bucket: \"contradicted-candidate\",\n recommendedAction: \"flagged-contradicted\",\n reason: \"contradicting_verified_fact_exists\",\n confidence: 0.92,\n evidence: [contradiction],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n\n const duplicate = opts.db ? findSameScopeDuplicateVerifiedFact(opts.db, fact) : null;\n if (duplicate) {\n return {\n bucket: \"duplicate-candidate\",\n recommendedAction: \"deferred-for-human\",\n reason: \"duplicate_verified_fact_candidate\",\n confidence: 0.82,\n evidence: [\n {\n type: \"fact\",\n id: duplicate.id,\n summary: \"Same-scope verified fact has identical normalized text\",\n fields: { duplicateFactId: duplicate.id },\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n\n const weak = weakProvenanceReason(fact);\n if (weak) {\n return {\n bucket: \"missing-or-weak-provenance\",\n recommendedAction: \"deferred-for-human\",\n reason: \"weak_or_missing_provenance\",\n confidence: 0.86,\n evidence: [{ type: \"provenance\", id: fact.id, summary: weak }],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n\n if (\n (item.payload.verified.nextVerification && item.payload.verified.nextVerification <= nowIso) ||\n item.payload.dueReason === \"verified_at_stale\"\n ) {\n return {\n bucket: \"stale-candidate\",\n recommendedAction: \"classified\",\n reason: \"stale_due_for_reverification\",\n confidence: 0.72,\n evidence: [\n {\n type: \"verification\",\n id: item.payload.verified.id,\n summary:\n item.payload.dueReason === \"verified_at_stale\"\n ? \"Fact verified_at is older than the reverification window\"\n : \"Fact is due for scheduled reverification\",\n fields: {\n nextVerification: item.payload.verified.nextVerification,\n verifiedAt: item.payload.verified.verifiedAt,\n dueReason: item.payload.dueReason,\n now: nowIso,\n },\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: false,\n };\n }\n\n return {\n bucket: \"still-current\",\n recommendedAction: opts.policy === \"apply-obvious\" ? \"marked-reviewed\" : \"classified\",\n reason: \"still_current_no_action_needed\",\n confidence: 0.74,\n evidence: [\n {\n type: \"review\",\n id: fact.id,\n summary: \"No concrete TTL, supersession, contradiction, sensitivity, scope, or provenance blocker found\",\n fields: { reviewedAt: nowIso, method: \"deterministic-triage\" },\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: false,\n };\n}\n\nfunction triageToPendingDecision(\n item: VerifiedFactTriageItem,\n context: PendingDecisionContext,\n triage: ReturnType<typeof classifyVerifiedFact>,\n): PendingDecision {\n const mapped = mapTriageAction(context.policy, triage);\n const evidence = triage.evidence.map((ev) => ({\n type: ev.type,\n id: ev.id,\n summary: ev.summary,\n ...(ev.fields ? { fields: ev.fields } : {}),\n }));\n return {\n queue: \"verified\",\n itemId: item.id,\n inputHash: context.inputHash,\n policy: context.policy,\n policyVersion: context.policyVersion,\n mode: context.mode,\n action: mapped.action,\n reasonCode: mapped.reasonCode,\n actionClass: mapped.actionClass,\n capabilityClass: mapped.capabilityClass,\n confidence: triage.confidence,\n humanReviewRequired: triage.humanReviewRequired,\n evidence,\n actor: context.actor,\n runId: context.runId,\n jobId: context.jobId,\n summary: {\n title: `verified fact ${triage.bucket}`,\n body: `${item.payload.fact?.id ?? item.payload.verified.factId}: ${triage.reason}`,\n metadata: {\n bucket: triage.bucket,\n recommendedAction: triage.recommendedAction,\n sensitivityFlags: triage.sensitivityFlags,\n evidenceFields: triage.evidence.map((ev) => ev.fields).filter(Boolean),\n },\n },\n audit: {\n queue: \"verified\",\n itemId: item.id,\n inputHash: context.inputHash,\n policy: context.policy,\n policyVersion: context.policyVersion,\n action: mapped.action,\n reasonCode: mapped.reasonCode,\n capabilityClass: mapped.capabilityClass,\n humanReviewRequired: triage.humanReviewRequired,\n evidence,\n actor: context.actor,\n runId: context.runId,\n summary: {\n title: \"verified-fact-triage\",\n metadata: {\n previous: {\n verificationTier: item.payload.verificationTier,\n verifiedFactId: item.payload.verified.id,\n nextVerification: item.payload.verified.nextVerification,\n },\n after: {\n bucket: triage.bucket,\n recommendedAction: triage.recommendedAction,\n reason: triage.reason,\n },\n mutation: \"none-core-truth-fields-preserved\",\n },\n },\n },\n };\n}\n\nfunction mapTriageAction(\n policy: string,\n triage: Pick<VerifiedTriageResultItem, \"recommendedAction\" | \"humanReviewRequired\" | \"reason\">,\n): Pick<PendingDecision, \"action\" | \"reasonCode\" | \"actionClass\" | \"capabilityClass\"> {\n if (policy === \"report-only\") {\n return {\n action: \"reported\",\n reasonCode: \"dry-run\",\n actionClass: \"preview\",\n capabilityClass: \"read-only\",\n };\n }\n if (triage.recommendedAction === \"failed-validation\") {\n return {\n action: \"failed-validation\",\n reasonCode: toAutopilotReason(triage.reason),\n actionClass: \"observe\",\n capabilityClass: \"read-only\",\n };\n }\n if (triage.humanReviewRequired) {\n return {\n action: \"deferred-for-human\",\n reasonCode: \"human-review-required\",\n actionClass: \"record-review\",\n capabilityClass: \"record-review-metadata\",\n };\n }\n return {\n action: \"classified\",\n reasonCode: toAutopilotReason(triage.reason),\n actionClass: \"record-review\",\n capabilityClass: \"record-review-metadata\",\n };\n}\n\nfunction toAutopilotReason(reason: VerifiedTriageReason): AutopilotReasonCode {\n switch (reason) {\n case \"policy_report_only\":\n return \"dry-run\";\n case \"backend_error\":\n case \"evidence_query_failed\":\n return \"audit-write-failed\";\n case \"malformed_fact\":\n return \"invalid-item\";\n case \"requires_human_approval\":\n case \"scope_unclear\":\n case \"sensitive_security_fact\":\n case \"sensitive_privacy_fact\":\n case \"sensitive_personal_fact\":\n case \"sensitive_operational_runbook\":\n return \"human-review-required\";\n default:\n return \"policy-threshold-not-met\";\n }\n}\n\nfunction decisionToResultItem(\n decision: PendingDecision,\n item: VerifiedFactTriageItem,\n applied: boolean,\n): VerifiedTriageResultItem {\n const meta = decision.summary?.metadata ?? {};\n const fact = item.payload.fact;\n const bucket = String(meta.bucket ?? \"failed-review\") as VerifiedTriageBucket;\n const recommendedAction = String(meta.recommendedAction ?? \"failed-validation\") as VerifiedTriageAction;\n return {\n factId: item.payload.verified.factId,\n verifiedFactId: item.payload.verified.id,\n text: fact?.text ?? item.payload.verified.canonicalText,\n verificationTier: item.payload.verificationTier,\n scope: fact?.scope ?? null,\n scopeTarget: fact?.scopeTarget ?? null,\n entity: fact?.entity ?? null,\n key: fact?.key ?? null,\n validFrom: fact?.validFrom ?? null,\n validUntil: fact?.validUntil ?? null,\n expiresAt: fact?.expiresAt ?? null,\n provenanceSummary: summarizeProvenance(fact),\n bucket,\n recommendedAction,\n confidence: decision.confidence,\n evidence: decision.evidence,\n sensitivityFlags: Array.isArray(meta.sensitivityFlags) ? (meta.sensitivityFlags as string[]) : [],\n reason: extractVerifiedReason(decision, item),\n humanReviewRequired: decision.humanReviewRequired,\n action: decision.action,\n reasonCode: decision.reasonCode,\n capabilityClass: decision.capabilityClass,\n actionClass: decision.actionClass,\n inputHash: decision.inputHash,\n applied,\n };\n}\n\nfunction extractVerifiedReason(decision: PendingDecision, item: VerifiedFactTriageItem): VerifiedTriageReason {\n const after = decision.audit?.summary?.metadata as { after?: { reason?: string } } | undefined;\n const reason = after?.after?.reason;\n if (reason) return reason as VerifiedTriageReason;\n const reasonCodeMap: Partial<Record<AutopilotReasonCode, VerifiedTriageReason>> = {\n \"input-hash-mismatch\": \"backend_error\",\n \"lock-conflict\": \"backend_error\",\n \"lock-missing\": \"backend_error\",\n };\n return reasonCodeMap[decision.reasonCode] ?? (item.validationFailed ? \"malformed_fact\" : \"requires_human_approval\");\n}\n\nfunction buildRunResult(input: {\n runId: string;\n mode: \"dry-run\" | \"apply\";\n policy: VerifiedTriagePolicy;\n items: VerifiedTriageResultItem[];\n}): VerifiedTriageRunResult {\n return {\n runId: input.runId,\n mode: input.mode,\n policy: input.policy,\n policyVersion: VERIFIED_TRIAGE_POLICY_VERSION,\n reviewQueueSource: VERIFIED_REVIEW_QUEUE_SOURCE,\n counts: {\n inspected: input.items.length,\n classified: input.items.filter((i) => i.action === \"classified\" || i.action === \"reported\").length,\n stillCurrent: input.items.filter((i) => i.bucket === \"still-current\").length,\n staleCandidates: input.items.filter((i) => i.bucket === \"stale-candidate\").length,\n expiredTtlCandidates: input.items.filter((i) => i.bucket === \"expired-ttl-candidate\").length,\n supersededCandidates: input.items.filter((i) => i.bucket === \"superseded-candidate\").length,\n contradictedCandidates: input.items.filter((i) => i.bucket === \"contradicted-candidate\").length,\n duplicateCandidates: input.items.filter((i) => i.bucket === \"duplicate-candidate\").length,\n sensitiveNeedsHuman: input.items.filter((i) => i.bucket === \"sensitive-needs-human\").length,\n needsHuman: input.items.filter((i) => i.humanReviewRequired).length,\n applied: input.items.filter((i) => i.applied).length,\n failed: input.items.filter((i) => i.bucket === \"failed-review\").length,\n },\n items: input.items,\n };\n}\n\nfunction triageItemFromRow(\n db: DatabaseSync,\n row: VerifiedFactRow,\n opts: { nowIso: string; policy: VerifiedTriagePolicy; dueReason?: VerifiedFactTriagePayload[\"dueReason\"] },\n): VerifiedFactTriageItem {\n const verified = rowToVerifiedFact(row);\n const fact = loadFactSnapshot(db, verified.factId);\n const payload: VerifiedFactTriagePayload = {\n reviewQueueSource: VERIFIED_REVIEW_QUEUE_SOURCE,\n verified,\n fact,\n verificationTier: fact?.tier ?? null,\n reviewCursor: verified.nextVerification ?? verified.verifiedAt,\n dueReason:\n opts.dueReason ??\n (verified.nextVerification && verified.nextVerification <= opts.nowIso\n ? \"next_verification\"\n : \"verified_at_stale\"),\n };\n const inputHash = computePendingInputHash({\n queue: \"verified\",\n id: verified.id,\n payload,\n policy: opts.policy,\n policyVersion: VERIFIED_TRIAGE_POLICY_VERSION,\n });\n return {\n queue: \"verified\",\n id: verified.id,\n inputHash,\n policyVersion: VERIFIED_TRIAGE_POLICY_VERSION,\n capabilityClasses: [\"read-only\", \"record-review-metadata\"],\n payload,\n visibleAfterCursor: verified.nextVerification ?? verified.verifiedAt,\n requiresHumanReview: false,\n validationFailed: !fact,\n };\n}\n\nfunction loadLiveVerifiedFactTriageItem(\n db: DatabaseSync,\n itemId: string,\n opts: { nowMs?: number; reverificationDays?: number; policy: VerifiedTriagePolicy },\n): VerifiedFactTriageItem | null {\n registerVerifiedChecksumFunction(db);\n const nowMs = opts.nowMs ?? Date.now();\n const nowIso = new Date(nowMs).toISOString();\n const cutoffIso = new Date(\n nowMs - (opts.reverificationDays ?? DEFAULT_REVERIFICATION_DAYS) * 24 * 60 * 60 * 1000,\n ).toISOString();\n const row = db\n .prepare(\n `SELECT vf.*\n FROM verified_facts vf\n JOIN (\n SELECT vf2.fact_id, MAX(vf2.version) AS max_version\n FROM verified_facts vf2\n GROUP BY vf2.fact_id\n ) latest ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE vf.id = ?\n AND ((vf.next_verification IS NOT NULL AND vf.next_verification <= ?)\n OR vf.verified_at <= ?)\n LIMIT 1`,\n )\n .get(itemId, nowIso, cutoffIso) as VerifiedFactRow | undefined;\n if (!row || !isVerifiedRowChecksumValid(row)) return null;\n return triageItemFromRow(db, row, { nowIso, policy: opts.policy });\n}\n\nconst registeredChecksumDbs = new WeakSet<DatabaseSync>();\n\nfunction registerVerifiedChecksumFunction(db: DatabaseSync): void {\n if (registeredChecksumDbs.has(db)) return;\n db.function(\"compute_verified_checksum\", { deterministic: true }, (text: unknown) =>\n typeof text === \"string\" ? computeChecksum(text) : \"\",\n );\n registeredChecksumDbs.add(db);\n}\n\nfunction loadFactSnapshot(db: DatabaseSync, factId: string): TriageFactSnapshot | null {\n const row = db.prepare(\"SELECT * FROM facts WHERE id = ?\").get(factId) as Record<string, unknown> | undefined;\n return row ? memoryEntryToSnapshot(rowToMemoryEntry(row)) : null;\n}\n\nfunction memoryEntryToSnapshot(entry: MemoryEntry): TriageFactSnapshot {\n return {\n id: entry.id,\n text: entry.text,\n category: entry.category,\n entity: entry.entity,\n key: entry.key,\n value: entry.value,\n source: entry.source,\n createdAt: entry.createdAt,\n expiresAt: entry.expiresAt,\n validFrom: entry.validFrom ?? null,\n validUntil: entry.validUntil ?? null,\n supersedesId: entry.supersedesId ?? null,\n supersededAt: entry.supersededAt ?? null,\n supersededBy: entry.supersededBy ?? null,\n tier: entry.tier ?? null,\n scope: entry.scope ?? \"global\",\n scopeTarget: entry.scopeTarget ?? null,\n provenanceSession: entry.provenanceSession ?? null,\n sourceSessions: entry.sourceSessions ?? null,\n provenanceJson: entry.provenanceJson ?? null,\n tags: entry.tags ?? null,\n confidence: entry.confidence,\n };\n}\n\nfunction snapshotFromRow(row: Record<string, unknown>): RelatedFact {\n return {\n ...memoryEntryToSnapshot(rowToMemoryEntry(row)),\n verifiedFactId: (row.verified_fact_id as string | null) ?? null,\n verifiedAt: (row.verified_at as string | null) ?? null,\n verifiedVersion: (row.verified_version as number | null) ?? null,\n };\n}\n\nfunction detectSensitivity(\n fact: TriageFactSnapshot,\n canonicalText: string,\n): { flags: string[]; reason: VerifiedTriageReason } {\n const haystack = [canonicalText, fact.text, fact.category, fact.entity, fact.key, fact.value, fact.tags?.join(\" \")]\n .filter(Boolean)\n .join(\"\\n\");\n const flags: string[] = [];\n let reason: VerifiedTriageReason = \"sensitive_personal_fact\";\n const priorityMap: Partial<Record<VerifiedTriageReason, number>> = {\n sensitive_security_fact: 4,\n sensitive_privacy_fact: 3,\n sensitive_operational_runbook: 2,\n sensitive_personal_fact: 1,\n };\n for (const rule of SENSITIVE_RULES) {\n if (rule.pattern.test(haystack)) {\n flags.push(rule.flag);\n if ((priorityMap[rule.reason] ?? 0) > (priorityMap[reason] ?? 0)) {\n reason = rule.reason;\n }\n }\n }\n return { flags: [...new Set(flags)], reason };\n}\n\nfunction hasScopeUnclearSignals(fact: TriageFactSnapshot): boolean {\n return fact.scope !== \"global\" && !fact.scopeTarget;\n}\n\nfunction sameScope(a: TriageFactSnapshot, b: TriageFactSnapshot): boolean {\n return a.scope === b.scope && (a.scopeTarget ?? null) === (b.scopeTarget ?? null);\n}\n\nfunction findExplicitNewerVerifiedFact(db: DatabaseSync, fact: TriageFactSnapshot): RelatedFact | null {\n if (fact.supersededBy) {\n const newer = loadVerifiedRelatedFact(db, fact.supersededBy);\n if (newer && sameScope(fact, newer) && newer.createdAt >= fact.createdAt) return newer;\n }\n const rows = db\n .prepare(\n `SELECT f.*, vf.id AS verified_fact_id, vf.verified_at AS verified_at, vf.version AS verified_version\n FROM facts f\n JOIN verified_facts vf ON vf.fact_id = f.id\n JOIN (\n SELECT fact_id, MAX(version) AS max_version\n FROM verified_facts\n GROUP BY fact_id\n ) latest ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE f.supersedes_id = ?\n AND f.created_at >= ?\n AND f.superseded_at IS NULL\n AND compute_verified_checksum(vf.canonical_text) = vf.checksum\n ORDER BY f.created_at DESC\n LIMIT 5`,\n )\n .all(fact.id, fact.createdAt) as Array<Record<string, unknown>>;\n for (const row of rows) {\n const newer = snapshotFromRow(row);\n if (sameScope(fact, newer)) return newer;\n }\n return null;\n}\n\nfunction loadVerifiedRelatedFact(db: DatabaseSync, factId: string): RelatedFact | null {\n const row = db\n .prepare(\n `SELECT f.*, vf.id AS verified_fact_id, vf.verified_at AS verified_at, vf.version AS verified_version\n FROM facts f\n JOIN verified_facts vf ON vf.fact_id = f.id\n JOIN (\n SELECT fact_id, MAX(version) AS max_version\n FROM verified_facts\n GROUP BY fact_id\n ) latest ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE f.id = ?\n AND compute_verified_checksum(vf.canonical_text) = vf.checksum\n LIMIT 1`,\n )\n .get(factId) as Record<string, unknown> | undefined;\n if (!row) return null;\n return snapshotFromRow(row);\n}\n\nfunction findConcreteContradictingEvidence(db: DatabaseSync, fact: TriageFactSnapshot): VerifiedTriageEvidence | null {\n if (!fact.entity?.trim() || !fact.key?.trim() || fact.value == null || fact.value.trim() === \"\") return null;\n const scopeClause =\n fact.scopeTarget != null ? \"AND f.scope = ? AND f.scope_target = ?\" : \"AND f.scope = ? AND f.scope_target IS NULL\";\n const scopeParams: SQLInputValue[] = fact.scopeTarget != null ? [fact.scope, fact.scopeTarget] : [fact.scope];\n const row = db\n .prepare(\n `SELECT f.*, vf.id AS verified_fact_id\n FROM facts f\n JOIN verified_facts vf ON vf.fact_id = f.id\n JOIN (\n SELECT fact_id, MAX(version) AS max_version\n FROM verified_facts\n GROUP BY fact_id\n ) latest ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE f.id != ?\n AND compute_verified_checksum(vf.canonical_text) = vf.checksum\n AND lower(f.entity) = lower(?)\n AND lower(f.key) = lower(?)\n AND f.value IS NOT NULL\n AND lower(f.value) != lower(?)\n AND f.superseded_at IS NULL\n ${scopeClause}\n ORDER BY f.created_at DESC\n LIMIT 1`,\n )\n .get(fact.id, fact.entity, fact.key, fact.value, ...scopeParams) as Record<string, unknown> | undefined;\n if (!row) return null;\n return {\n type: \"contradiction\",\n id: row.id as string,\n summary: \"Concrete same-entity/key/scope verified fact has conflicting structured value\",\n fields: {\n subject: fact.entity,\n scope: fact.scope,\n scopeTarget: fact.scopeTarget,\n claimType: fact.key,\n currentValue: fact.value,\n conflictingValue: row.value,\n sourceId: row.id,\n verifiedFactId: row.verified_fact_id,\n },\n };\n}\n\nfunction findSameScopeDuplicateVerifiedFact(db: DatabaseSync, fact: TriageFactSnapshot): RelatedFact | null {\n const normalized = normalizeFactText(fact.text);\n if (!normalized) return null;\n const scopeClause =\n fact.scopeTarget != null ? \"AND f.scope = ? AND f.scope_target = ?\" : \"AND f.scope = ? AND f.scope_target IS NULL\";\n const scopeParams: SQLInputValue[] = fact.scopeTarget != null ? [fact.scope, fact.scopeTarget] : [fact.scope];\n const rows = db\n .prepare(\n `SELECT f.*, vf.id AS verified_fact_id, vf.verified_at AS verified_at, vf.version AS verified_version\n FROM facts f\n JOIN verified_facts vf ON vf.fact_id = f.id\n JOIN (\n SELECT fact_id, MAX(version) AS max_version\n FROM verified_facts\n GROUP BY fact_id\n ) latest ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE f.id != ?\n AND f.superseded_at IS NULL\n AND compute_verified_checksum(vf.canonical_text) = vf.checksum\n ${scopeClause}\n ORDER BY f.created_at DESC\n LIMIT 50`,\n )\n .all(fact.id, ...scopeParams) as Array<Record<string, unknown>>;\n for (const row of rows) {\n const candidate = snapshotFromRow(row);\n if (normalizeFactText(candidate.text) === normalized) return candidate;\n }\n return null;\n}\n\nfunction normalizeFactText(text: string): string {\n return text.trim().toLowerCase().replace(/\\s+/g, \" \");\n}\n\nfunction weakProvenanceReason(fact: TriageFactSnapshot): string | null {\n if (fact.source === \"unknown\" || fact.source === \"\") return \"Fact source is missing or unknown\";\n if (!fact.provenanceJson && !fact.provenanceSession && !fact.sourceSessions) {\n return \"No provenance_json, provenance_session, or source_sessions recorded\";\n }\n return null;\n}\n\nfunction summarizeProvenance(fact: TriageFactSnapshot | null): string {\n if (!fact) return \"missing fact row\";\n const parts = [\n fact.provenanceJson ? \"provenance_json\" : null,\n fact.provenanceSession ? `session:${fact.provenanceSession}` : null,\n fact.sourceSessions ? \"source_sessions\" : null,\n `source:${fact.source}`,\n ].filter(Boolean);\n return parts.join(\", \");\n}\n\nfunction validationFailureDecision(\n item: VerifiedFactTriageItem,\n context: PendingDecisionContext,\n reasonCode: AutopilotReasonCode,\n body: string,\n): PendingDecision {\n const evidence = [{ type: \"input-hash\", id: item.id, summary: body }];\n return {\n queue: \"verified\",\n itemId: item.id,\n inputHash: context.inputHash,\n policy: context.policy,\n policyVersion: context.policyVersion,\n mode: context.mode,\n action: \"failed-validation\",\n reasonCode,\n actionClass: \"observe\",\n capabilityClass: \"read-only\",\n confidence: 0,\n humanReviewRequired: true,\n evidence,\n actor: context.actor,\n runId: context.runId,\n jobId: context.jobId,\n summary: {\n title: \"verified fact failed-review\",\n body,\n metadata: {\n bucket: \"failed-review\",\n recommendedAction: \"failed-validation\",\n sensitivityFlags: [],\n },\n },\n audit: {\n queue: \"verified\",\n itemId: item.id,\n inputHash: context.inputHash,\n policy: context.policy,\n policyVersion: context.policyVersion,\n action: \"failed-validation\",\n reasonCode,\n capabilityClass: \"read-only\",\n humanReviewRequired: true,\n evidence,\n actor: context.actor,\n runId: context.runId,\n summary: {\n title: \"verified-fact-triage\",\n body,\n metadata: {\n previous: { verifiedFactId: item.payload.verified.id },\n after: {\n bucket: \"failed-review\",\n recommendedAction: \"failed-validation\",\n reason: \"backend_error\",\n },\n mutation: \"none-core-truth-fields-preserved\",\n },\n },\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"verified-fact-triage.js","names":[],"sources":["../../services/verified-fact-triage.ts"],"sourcesContent":["import type { DatabaseSync, SQLInputValue } from \"node:sqlite\";\nimport type { FactsDB } from \"../backends/facts-db.js\";\nimport { rowToMemoryEntry } from \"../backends/facts-db/index.js\";\nimport type { MemoryEntry } from \"../types/memory.js\";\nimport {\n computePendingInputHash,\n createPendingAutopilotRunId,\n createStableRunSummary,\n type PendingAutopilotStore,\n type PendingAutopilotCursor,\n type AutopilotAction,\n type AutopilotReasonCode,\n type PendingDecision,\n type PendingDecisionContext,\n type PendingDecisionEvidence,\n type PendingItem,\n type PendingQueueAdapter,\n} from \"./pending-autopilot/index.js\";\nimport { computeChecksum, rowToVerifiedFact, type VerifiedFact, type VerifiedFactRow } from \"./verification-store.js\";\n\nexport const VERIFIED_TRIAGE_POLICY_VERSION = \"verified-fact-triage-v1\";\nconst DEFAULT_REVERIFICATION_DAYS = 30;\nconst DEFAULT_TRIAGE_MAX = 100;\nconst MIN_VERIFIED_TRIAGE_SQL_LIMIT = 25;\nconst MAX_VERIFIED_TRIAGE_SQL_LIMIT = 1000;\nconst VERIFIED_TRIAGE_SQL_OVERFETCH_FACTOR = 4;\nexport const VERIFIED_REVIEW_QUEUE_SOURCE =\n \"Latest verified_facts rows whose next_verification timestamp is due (or whose verified_at is older than the verification window), as returned by VerificationStore.listDueForReverification semantics. This is intentionally not all verified facts.\";\n\nexport const VERIFIED_TRIAGE_POLICIES = [\"report-only\", \"classify\", \"apply-obvious\"] as const;\nexport type VerifiedTriagePolicy = (typeof VERIFIED_TRIAGE_POLICIES)[number];\n\nexport const VERIFIED_TRIAGE_BUCKETS = [\n \"still-current\",\n \"stale-candidate\",\n \"expired-ttl-candidate\",\n \"superseded-candidate\",\n \"contradicted-candidate\",\n \"missing-or-weak-provenance\",\n \"duplicate-candidate\",\n \"scope-or-ownership-unclear\",\n \"sensitive-needs-human\",\n \"needs-human-review\",\n \"failed-review\",\n] as const;\nexport type VerifiedTriageBucket = (typeof VERIFIED_TRIAGE_BUCKETS)[number];\n\nexport const VERIFIED_TRIAGE_ACTIONS = [\n \"reported\",\n \"classified\",\n \"marked-reviewed\",\n \"linked-evidence\",\n \"flagged-stale\",\n \"flagged-superseded\",\n \"flagged-contradicted\",\n \"flagged-sensitive\",\n \"deferred-for-human\",\n \"failed-validation\",\n \"skipped-by-policy\",\n] as const;\nexport type VerifiedTriageAction = (typeof VERIFIED_TRIAGE_ACTIONS)[number];\n\nexport type VerifiedTriageReason =\n | \"policy_report_only\"\n | \"still_current_no_action_needed\"\n | \"ttl_expired\"\n | \"newer_verified_fact_exists\"\n | \"contradicting_verified_fact_exists\"\n | \"weak_or_missing_provenance\"\n | \"duplicate_verified_fact_candidate\"\n | \"sensitive_security_fact\"\n | \"sensitive_privacy_fact\"\n | \"sensitive_personal_fact\"\n | \"sensitive_operational_runbook\"\n | \"scope_unclear\"\n | \"requires_human_approval\"\n | \"stale_due_for_reverification\"\n | \"low_confidence\"\n | \"backend_error\"\n | \"malformed_fact\"\n | \"evidence_query_failed\";\n\nexport interface VerifiedFactTriageItem extends PendingItem<VerifiedFactTriagePayload> {\n queue: \"verified\";\n}\n\nexport interface VerifiedFactTriagePayload extends Record<string, unknown> {\n reviewQueueSource: string;\n verified: VerifiedFact;\n fact: TriageFactSnapshot | null;\n verificationTier: string | null;\n reviewCursor: string | null;\n dueReason: \"next_verification\" | \"verified_at_stale\";\n}\n\nexport interface TriageFactSnapshot {\n id: string;\n text: string;\n category: string;\n entity: string | null;\n key: string | null;\n value: string | null;\n source: string;\n createdAt: number;\n expiresAt: number | null;\n validFrom: number | null;\n validUntil: number | null;\n supersedesId: string | null;\n supersededAt: number | null;\n supersededBy: string | null;\n tier: string | null;\n scope: string;\n scopeTarget: string | null;\n provenanceSession: string | null;\n sourceSessions: string | null;\n provenanceJson: string | null;\n tags: string[] | null;\n confidence: number;\n}\n\nexport interface VerifiedTriageEvidence extends PendingDecisionEvidence {\n fields?: Record<string, unknown>;\n}\n\nexport interface VerifiedTriageResultItem {\n factId: string;\n verifiedFactId: string;\n text: string;\n verificationTier: string | null;\n scope: string | null;\n scopeTarget: string | null;\n entity: string | null;\n key: string | null;\n validFrom: number | null;\n validUntil: number | null;\n expiresAt: number | null;\n provenanceSummary: string;\n bucket: VerifiedTriageBucket;\n recommendedAction: VerifiedTriageAction;\n confidence: number;\n evidence: VerifiedTriageEvidence[];\n sensitivityFlags: string[];\n reason: VerifiedTriageReason;\n humanReviewRequired: boolean;\n action: AutopilotAction;\n reasonCode: AutopilotReasonCode;\n capabilityClass: PendingDecision[\"capabilityClass\"];\n actionClass: PendingDecision[\"actionClass\"];\n inputHash: string;\n applied: boolean;\n}\n\nexport interface VerifiedTriageRunResult {\n runId: string;\n mode: \"dry-run\" | \"apply\";\n policy: VerifiedTriagePolicy;\n policyVersion: string;\n reviewQueueSource: string;\n counts: {\n inspected: number;\n classified: number;\n stillCurrent: number;\n staleCandidates: number;\n expiredTtlCandidates: number;\n supersededCandidates: number;\n contradictedCandidates: number;\n duplicateCandidates: number;\n sensitiveNeedsHuman: number;\n needsHuman: number;\n applied: number;\n failed: number;\n };\n items: VerifiedTriageResultItem[];\n}\n\nexport interface VerifiedFactTriageOptions {\n mode: \"dry-run\" | \"apply\";\n policy: VerifiedTriagePolicy;\n max?: number;\n reverificationDays?: number;\n actor?: PendingDecision[\"actor\"];\n jobId?: string;\n runId?: string;\n store?: PendingAutopilotStore | null;\n nowMs?: number;\n lockTtlSeconds?: number;\n}\n\ninterface RelatedFact extends TriageFactSnapshot {\n verifiedFactId?: string | null;\n verifiedAt?: string | null;\n verifiedVersion?: number | null;\n}\n\nconst SENSITIVE_RULES: Array<{\n flag: string;\n reason: VerifiedTriageReason;\n pattern: RegExp;\n}> = [\n {\n flag: \"credentials\",\n reason: \"sensitive_security_fact\",\n pattern: /\\b(password|passwd|credential|secret|api[-_ ]?key|token|bearer|ssh key|private key|vault|oauth|pat_)\\b/i,\n },\n {\n flag: \"security\",\n reason: \"sensitive_security_fact\",\n pattern: /\\b(security|firewall|ssh|vpn|runbook|incident|breach|auth|mfa|2fa|permission|admin)\\b/i,\n },\n {\n flag: \"privacy\",\n reason: \"sensitive_privacy_fact\",\n pattern: /\\b(privacy|private|personal data|pii|gdpr|address|phone|email|medical|health|passport|identity)\\b/i,\n },\n {\n flag: \"external-comms\",\n reason: \"sensitive_personal_fact\",\n pattern: /\\b(external comms|external communication|email rule|reply rule|send to|contact|customer|client)\\b/i,\n },\n {\n flag: \"persona-preference\",\n reason: \"sensitive_personal_fact\",\n pattern: /\\b(preference|user identity|persona|edict|hard rule|user profile|personal fact)\\b/i,\n },\n {\n flag: \"operational-runbook\",\n reason: \"sensitive_operational_runbook\",\n pattern: /\\b(cron|runbook|operational|ops|production|deploy|restart|backup|restore)\\b/i,\n },\n];\n\nexport function assertVerifiedTriagePolicy(value: string): VerifiedTriagePolicy {\n if ((VERIFIED_TRIAGE_POLICIES as readonly string[]).includes(value)) return value as VerifiedTriagePolicy;\n throw new Error(`Unknown verified triage policy: ${value}`);\n}\n\nexport function createVerifiedFactTriageAdapter(input: {\n factsDb: Pick<FactsDB, \"getRawDb\">;\n max?: number;\n nowMs?: number;\n reverificationDays?: number;\n policy?: VerifiedTriagePolicy;\n}): PendingQueueAdapter<VerifiedFactTriageItem> {\n const db = input.factsDb.getRawDb();\n registerVerifiedChecksumFunction(db);\n return {\n queue: \"verified\",\n listPending: (cursor) =>\n listVerifiedFactTriageItems(db, {\n max: input.max,\n nowMs: input.nowMs,\n reverificationDays: input.reverificationDays,\n policy: input.policy,\n cursor,\n }),\n decide: (item, context) => decideVerifiedFactTriage(item, context, { db, nowMs: input.nowMs }),\n apply: (_decision, _item) => {\n // Verified fact triage intentionally does not mutate core truth fields. Durable\n // state is recorded through PendingAutopilotStore decisions only.\n },\n };\n}\n\nexport function listVerifiedFactTriageItems(\n db: DatabaseSync,\n opts: {\n max?: number;\n nowMs?: number;\n reverificationDays?: number;\n policy?: VerifiedTriagePolicy;\n cursor?: PendingAutopilotCursor | null;\n } = {},\n): VerifiedFactTriageItem[] {\n registerVerifiedChecksumFunction(db);\n const nowMs = opts.nowMs ?? Date.now();\n const nowIso = new Date(nowMs).toISOString();\n const cutoffIso = new Date(\n nowMs - (opts.reverificationDays ?? DEFAULT_REVERIFICATION_DAYS) * 24 * 60 * 60 * 1000,\n ).toISOString();\n const policy = opts.policy ?? \"classify\";\n const cursor = opts.cursor?.cursor ?? null;\n const cursorItemId = opts.cursor\n ? findVerifiedCursorItemId(db, opts.cursor.inputHash, policy, nowIso, cursor, cutoffIso)\n : null;\n const max = normalizeVerifiedTriageMax(opts.max);\n const latestRows = listChecksumValidDueVerifiedRows(db, {\n nowIso,\n cutoffIso,\n cursor,\n cursorItemId,\n max,\n });\n\n return latestRows.map((row) => triageItemFromRow(db, row, { nowIso, policy }));\n}\n\nfunction normalizeVerifiedTriageMax(max: number | undefined): number {\n if (max == null) return DEFAULT_TRIAGE_MAX;\n if (!Number.isFinite(max) || max <= 0) return 0;\n return Math.floor(max);\n}\n\nfunction verifiedTriageSqlLimit(max: number): number {\n if (max <= 0) return MIN_VERIFIED_TRIAGE_SQL_LIMIT;\n return Math.min(\n MAX_VERIFIED_TRIAGE_SQL_LIMIT,\n Math.max(MIN_VERIFIED_TRIAGE_SQL_LIMIT, max * VERIFIED_TRIAGE_SQL_OVERFETCH_FACTOR),\n );\n}\n\nfunction listChecksumValidDueVerifiedRows(\n db: DatabaseSync,\n opts: {\n nowIso: string;\n cutoffIso: string;\n cursor: string | null;\n cursorItemId: string | null;\n max: number;\n },\n): VerifiedFactRow[] {\n if (opts.max <= 0) return [];\n\n const rows: VerifiedFactRow[] = [];\n const sqlLimit = verifiedTriageSqlLimit(opts.max);\n let pageCursor = opts.cursor;\n let pageCursorItemId = opts.cursorItemId;\n\n while (rows.length < opts.max) {\n const page = db\n .prepare(\n `SELECT vf.*\n FROM verified_facts vf\n JOIN (\n SELECT vf2.fact_id, MAX(vf2.version) AS max_version\n FROM verified_facts vf2\n GROUP BY vf2.fact_id\n ) latest ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE ((vf.next_verification IS NOT NULL AND vf.next_verification <= ?)\n OR vf.verified_at <= ?)\n AND (\n ? IS NULL\n OR COALESCE(vf.next_verification, vf.verified_at) > ?\n OR (COALESCE(vf.next_verification, vf.verified_at) = ? AND (? IS NULL OR vf.id > ?))\n )\n ORDER BY COALESCE(vf.next_verification, vf.verified_at) ASC, vf.id ASC\n LIMIT ?`,\n )\n .all(\n opts.nowIso,\n opts.cutoffIso,\n pageCursor,\n pageCursor,\n pageCursor,\n pageCursorItemId,\n pageCursorItemId,\n sqlLimit,\n ) as unknown as VerifiedFactRow[];\n\n if (page.length === 0) break;\n\n for (const row of page) {\n if (isVerifiedRowChecksumValid(row)) rows.push(row);\n if (rows.length >= opts.max) break;\n }\n\n const last = page[page.length - 1];\n pageCursor = last?.next_verification ?? last?.verified_at ?? pageCursor;\n pageCursorItemId = last?.id ?? pageCursorItemId;\n if (page.length < sqlLimit) break;\n }\n\n return rows;\n}\n\nfunction findVerifiedCursorItemId(\n db: DatabaseSync,\n inputHash: string,\n policy: VerifiedTriagePolicy,\n nowIso: string,\n cursor: string | null,\n cutoffIso: string,\n): string | null {\n if (!cursor) return null;\n const rows = db\n .prepare(\n `SELECT vf.*\n FROM verified_facts vf\n JOIN (\n SELECT vf2.fact_id, MAX(vf2.version) AS max_version\n FROM verified_facts vf2\n GROUP BY vf2.fact_id\n ) latest ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE ((vf.next_verification IS NOT NULL AND vf.next_verification <= ?)\n OR vf.verified_at <= ?)\n AND COALESCE(vf.next_verification, vf.verified_at) = ?\n ORDER BY vf.id ASC`,\n )\n .all(nowIso, cutoffIso, cursor) as unknown as VerifiedFactRow[];\n for (const row of rows) {\n if (!isVerifiedRowChecksumValid(row)) continue;\n const item = triageItemFromRow(db, row, { nowIso, policy });\n if (item.inputHash === inputHash) return row.id;\n if (row.next_verification && row.verified_at <= cutoffIso) {\n const staleContextItem = triageItemFromRow(db, row, {\n nowIso,\n policy,\n dueReason: \"verified_at_stale\",\n });\n if (staleContextItem.inputHash === inputHash) return row.id;\n }\n }\n return null;\n}\n\nfunction isVerifiedRowChecksumValid(row: VerifiedFactRow): boolean {\n return computeChecksum(row.canonical_text) === row.checksum;\n}\n\nexport function decideVerifiedFactTriage(\n item: VerifiedFactTriageItem,\n context: PendingDecisionContext,\n opts: { db?: DatabaseSync; nowMs?: number } = {},\n): PendingDecision {\n const triage = classifyVerifiedFact(item, {\n db: opts.db,\n nowMs: opts.nowMs,\n policy: context.policy,\n });\n return triageToPendingDecision(item, context, triage);\n}\n\nexport async function runVerifiedFactTriage(\n factsDb: Pick<FactsDB, \"getRawDb\">,\n opts: VerifiedFactTriageOptions,\n): Promise<VerifiedTriageRunResult> {\n const policy = assertVerifiedTriagePolicy(opts.policy);\n const adapter = createVerifiedFactTriageAdapter({\n factsDb,\n max: opts.max,\n nowMs: opts.nowMs,\n reverificationDays: opts.reverificationDays,\n policy,\n });\n return runVerifiedFactTriageWithAdapter(factsDb, adapter, opts);\n}\n\nexport async function runVerifiedFactTriageWithAdapter(\n factsDb: Pick<FactsDB, \"getRawDb\">,\n adapter: PendingQueueAdapter<VerifiedFactTriageItem>,\n opts: VerifiedFactTriageOptions,\n): Promise<VerifiedTriageRunResult> {\n const policy = assertVerifiedTriagePolicy(opts.policy);\n const mode = opts.mode;\n const store = opts.store ?? null;\n if (mode === \"apply\" && policy !== \"report-only\" && !store) {\n throw new Error(\n `Verified fact triage apply mode with policy '${policy}' requires a PendingAutopilotStore to persist durable review metadata`,\n );\n }\n const runId = opts.runId ?? createPendingAutopilotRunId();\n const actor = opts.actor ?? { type: \"agent\", id: \"verified-triage-cli\" };\n const storedCursor =\n mode === \"apply\" && policy !== \"report-only\" ? (store?.getCursor(\"verified\", policy) ?? null) : null;\n const items = await adapter.listPending(storedCursor);\n const runInputHash = computePendingInputHash({\n queue: \"verified\",\n itemIds: items.map((i) => i.id),\n policy,\n mode,\n });\n const startedAt = Math.floor((opts.nowMs ?? Date.now()) / 1000);\n const db = factsDb.getRawDb();\n\n const durableStore = policy === \"report-only\" ? null : store;\n\n durableStore?.createRun({\n runId,\n mode,\n policy,\n policyVersion: VERIFIED_TRIAGE_POLICY_VERSION,\n inputHash: runInputHash,\n queues: [\"verified\"],\n startedAt,\n });\n\n const decisions: PendingDecision[] = [];\n const resultItems: VerifiedTriageResultItem[] = [];\n for (const item of items) {\n const context: PendingDecisionContext = {\n runId,\n jobId: opts.jobId,\n mode,\n policy,\n policyVersion: VERIFIED_TRIAGE_POLICY_VERSION,\n inputHash: item.inputHash,\n actor,\n };\n let decision: PendingDecision;\n let applied = false;\n if (mode === \"apply\" && policy !== \"report-only\") {\n const locked =\n durableStore?.acquireLock({\n queue: \"verified\",\n itemId: item.id,\n inputHash: item.inputHash,\n owner: actor.id,\n ttlSeconds: opts.lockTtlSeconds ?? 60,\n mode,\n }) ?? false;\n try {\n if (locked) {\n const liveItem =\n loadLiveVerifiedFactTriageItem(db, item.id, {\n nowMs: opts.nowMs,\n reverificationDays: opts.reverificationDays,\n policy,\n }) ?? null;\n const actualInputHash = liveItem?.inputHash ?? \"missing\";\n if (liveItem && actualInputHash === item.inputHash) {\n const liveContext: PendingDecisionContext = {\n ...context,\n inputHash: liveItem.inputHash,\n };\n decision = await adapter.decide(liveItem, liveContext);\n const { inserted } = durableStore?.recordLatestDecision(decision) ?? {\n inserted: false,\n };\n if (decision.action !== \"deferred-for-human\" && decision.action !== \"failed-validation\") {\n durableStore?.advanceCursorIfSafe(decision, liveItem.visibleAfterCursor ?? liveItem.id);\n }\n applied = inserted && (decision.action === \"classified\" || decision.action === \"reported\");\n } else {\n const staleDecision = validationFailureDecision(\n item,\n context,\n \"input-hash-mismatch\",\n liveItem\n ? \"Verified fact/fact row changed between classification and apply.\"\n : \"Verified fact no longer matches due queue before apply.\",\n );\n durableStore?.recordDecision(staleDecision);\n decision = staleDecision;\n }\n } else {\n const staleDecision = validationFailureDecision(\n item,\n context,\n \"lock-conflict\",\n \"Could not acquire lock for verified fact triage (another process may hold it).\",\n );\n durableStore?.recordDecision(staleDecision);\n decision = staleDecision;\n }\n } finally {\n if (locked) {\n durableStore?.releaseLock({\n queue: \"verified\",\n itemId: item.id,\n inputHash: item.inputHash,\n owner: actor.id,\n mode,\n });\n }\n }\n } else {\n decision = await adapter.decide(item, context);\n }\n decisions.push(decision);\n resultItems.push(decisionToResultItem(decision, item, applied));\n }\n\n const summary = createStableRunSummary({\n runId,\n mode,\n policy,\n policyVersion: VERIFIED_TRIAGE_POLICY_VERSION,\n queues: [\"verified\"],\n startedAt,\n finishedAt: Math.floor((opts.nowMs ?? Date.now()) / 1000),\n decisions,\n });\n durableStore?.finishRun(runId, summary, summary.finishedAt);\n\n return buildRunResult({ runId, mode, policy, items: resultItems });\n}\n\nexport function classifyVerifiedFact(\n item: VerifiedFactTriageItem,\n opts: { db?: DatabaseSync; nowMs?: number; policy?: string } = {},\n): Omit<\n VerifiedTriageResultItem,\n | \"factId\"\n | \"verifiedFactId\"\n | \"text\"\n | \"verificationTier\"\n | \"scope\"\n | \"scopeTarget\"\n | \"entity\"\n | \"key\"\n | \"validFrom\"\n | \"validUntil\"\n | \"expiresAt\"\n | \"provenanceSummary\"\n | \"action\"\n | \"reasonCode\"\n | \"capabilityClass\"\n | \"actionClass\"\n | \"inputHash\"\n | \"applied\"\n> {\n if (opts.db) {\n registerVerifiedChecksumFunction(opts.db);\n }\n const fact = item.payload.fact;\n const nowMs = opts.nowMs ?? Date.now();\n const nowSec = Math.floor(nowMs / 1000);\n const nowIso = new Date(nowMs).toISOString();\n\n if (!fact) {\n return {\n bucket: \"failed-review\",\n recommendedAction: \"failed-validation\",\n reason: \"malformed_fact\",\n confidence: 1,\n evidence: [\n {\n type: \"verified-fact\",\n id: item.payload.verified.id,\n summary: \"Verified row references a missing fact row\",\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n\n const sensitivity = detectSensitivity(fact, item.payload.verified.canonicalText);\n if (sensitivity.flags.length > 0) {\n return {\n bucket: \"sensitive-needs-human\",\n recommendedAction: \"flagged-sensitive\",\n reason: sensitivity.reason,\n confidence: 0.95,\n evidence: [\n {\n type: \"sensitivity\",\n id: fact.id,\n summary: `Matched sensitive categories: ${sensitivity.flags.join(\", \")}`,\n },\n ],\n sensitivityFlags: sensitivity.flags,\n humanReviewRequired: true,\n };\n }\n\n if (hasScopeUnclearSignals(fact)) {\n return {\n bucket: \"scope-or-ownership-unclear\",\n recommendedAction: \"deferred-for-human\",\n reason: \"scope_unclear\",\n confidence: 0.9,\n evidence: [\n {\n type: \"scope\",\n id: fact.id,\n summary: \"Fact has session/agent/user scope requiring explicit ownership proof\",\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n\n if (fact.validUntil != null && fact.validUntil <= nowSec) {\n return {\n bucket: \"expired-ttl-candidate\",\n recommendedAction: \"deferred-for-human\",\n reason: \"ttl_expired\",\n confidence: 0.95,\n evidence: [\n {\n type: \"validity\",\n id: fact.id,\n summary: \"Fact valid_until has expired\",\n fields: { validUntil: fact.validUntil, now: nowSec },\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n if (fact.expiresAt != null && fact.expiresAt <= nowSec) {\n return {\n bucket: \"expired-ttl-candidate\",\n recommendedAction: \"deferred-for-human\",\n reason: \"ttl_expired\",\n confidence: 0.95,\n evidence: [\n {\n type: \"ttl\",\n id: fact.id,\n summary: \"Fact expires_at has expired\",\n fields: { expiresAt: fact.expiresAt, now: nowSec },\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n\n const newer = opts.db ? findExplicitNewerVerifiedFact(opts.db, fact) : null;\n if (newer) {\n return {\n bucket: \"superseded-candidate\",\n recommendedAction: \"flagged-superseded\",\n reason: \"newer_verified_fact_exists\",\n confidence: 0.9,\n evidence: [\n {\n type: \"fact\",\n id: newer.id,\n summary: \"Explicit newer verified fact supersedes this fact\",\n fields: {\n newerFactId: newer.id,\n verifiedFactId: newer.verifiedFactId,\n },\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n\n const contradiction = opts.db ? findConcreteContradictingEvidence(opts.db, fact) : null;\n if (contradiction) {\n return {\n bucket: \"contradicted-candidate\",\n recommendedAction: \"flagged-contradicted\",\n reason: \"contradicting_verified_fact_exists\",\n confidence: 0.92,\n evidence: [contradiction],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n\n const duplicate = opts.db ? findSameScopeDuplicateVerifiedFact(opts.db, fact) : null;\n if (duplicate) {\n return {\n bucket: \"duplicate-candidate\",\n recommendedAction: \"deferred-for-human\",\n reason: \"duplicate_verified_fact_candidate\",\n confidence: 0.82,\n evidence: [\n {\n type: \"fact\",\n id: duplicate.id,\n summary: \"Same-scope verified fact has identical normalized text\",\n fields: { duplicateFactId: duplicate.id },\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n\n const weak = weakProvenanceReason(fact);\n if (weak) {\n return {\n bucket: \"missing-or-weak-provenance\",\n recommendedAction: \"deferred-for-human\",\n reason: \"weak_or_missing_provenance\",\n confidence: 0.86,\n evidence: [{ type: \"provenance\", id: fact.id, summary: weak }],\n sensitivityFlags: [],\n humanReviewRequired: true,\n };\n }\n\n if (\n (item.payload.verified.nextVerification && item.payload.verified.nextVerification <= nowIso) ||\n item.payload.dueReason === \"verified_at_stale\"\n ) {\n return {\n bucket: \"stale-candidate\",\n recommendedAction: \"classified\",\n reason: \"stale_due_for_reverification\",\n confidence: 0.72,\n evidence: [\n {\n type: \"verification\",\n id: item.payload.verified.id,\n summary:\n item.payload.dueReason === \"verified_at_stale\"\n ? \"Fact verified_at is older than the reverification window\"\n : \"Fact is due for scheduled reverification\",\n fields: {\n nextVerification: item.payload.verified.nextVerification,\n verifiedAt: item.payload.verified.verifiedAt,\n dueReason: item.payload.dueReason,\n now: nowIso,\n },\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: false,\n };\n }\n\n return {\n bucket: \"still-current\",\n recommendedAction: opts.policy === \"apply-obvious\" ? \"marked-reviewed\" : \"classified\",\n reason: \"still_current_no_action_needed\",\n confidence: 0.74,\n evidence: [\n {\n type: \"review\",\n id: fact.id,\n summary: \"No concrete TTL, supersession, contradiction, sensitivity, scope, or provenance blocker found\",\n fields: { reviewedAt: nowIso, method: \"deterministic-triage\" },\n },\n ],\n sensitivityFlags: [],\n humanReviewRequired: false,\n };\n}\n\nfunction triageToPendingDecision(\n item: VerifiedFactTriageItem,\n context: PendingDecisionContext,\n triage: ReturnType<typeof classifyVerifiedFact>,\n): PendingDecision {\n const mapped = mapTriageAction(context.policy, triage);\n const evidence = triage.evidence.map((ev) => ({\n type: ev.type,\n id: ev.id,\n summary: ev.summary,\n ...(ev.fields ? { fields: ev.fields } : {}),\n }));\n return {\n queue: \"verified\",\n itemId: item.id,\n inputHash: context.inputHash,\n policy: context.policy,\n policyVersion: context.policyVersion,\n mode: context.mode,\n action: mapped.action,\n reasonCode: mapped.reasonCode,\n actionClass: mapped.actionClass,\n capabilityClass: mapped.capabilityClass,\n confidence: triage.confidence,\n humanReviewRequired: triage.humanReviewRequired,\n evidence,\n actor: context.actor,\n runId: context.runId,\n jobId: context.jobId,\n summary: {\n title: `verified fact ${triage.bucket}`,\n body: `${item.payload.fact?.id ?? item.payload.verified.factId}: ${triage.reason}`,\n metadata: {\n bucket: triage.bucket,\n recommendedAction: triage.recommendedAction,\n sensitivityFlags: triage.sensitivityFlags,\n evidenceFields: triage.evidence.map((ev) => ev.fields).filter(Boolean),\n },\n },\n audit: {\n queue: \"verified\",\n itemId: item.id,\n inputHash: context.inputHash,\n policy: context.policy,\n policyVersion: context.policyVersion,\n action: mapped.action,\n reasonCode: mapped.reasonCode,\n capabilityClass: mapped.capabilityClass,\n humanReviewRequired: triage.humanReviewRequired,\n evidence,\n actor: context.actor,\n runId: context.runId,\n summary: {\n title: \"verified-fact-triage\",\n metadata: {\n previous: {\n verificationTier: item.payload.verificationTier,\n verifiedFactId: item.payload.verified.id,\n nextVerification: item.payload.verified.nextVerification,\n },\n after: {\n bucket: triage.bucket,\n recommendedAction: triage.recommendedAction,\n reason: triage.reason,\n },\n mutation: \"none-core-truth-fields-preserved\",\n },\n },\n },\n };\n}\n\nfunction mapTriageAction(\n policy: string,\n triage: Pick<VerifiedTriageResultItem, \"recommendedAction\" | \"humanReviewRequired\" | \"reason\">,\n): Pick<PendingDecision, \"action\" | \"reasonCode\" | \"actionClass\" | \"capabilityClass\"> {\n if (policy === \"report-only\") {\n return {\n action: \"reported\",\n reasonCode: \"dry-run\",\n actionClass: \"preview\",\n capabilityClass: \"read-only\",\n };\n }\n if (triage.recommendedAction === \"failed-validation\") {\n return {\n action: \"failed-validation\",\n reasonCode: toAutopilotReason(triage.reason),\n actionClass: \"observe\",\n capabilityClass: \"read-only\",\n };\n }\n if (triage.humanReviewRequired) {\n return {\n action: \"deferred-for-human\",\n reasonCode: \"human-review-required\",\n actionClass: \"record-review\",\n capabilityClass: \"record-review-metadata\",\n };\n }\n return {\n action: \"classified\",\n reasonCode: toAutopilotReason(triage.reason),\n actionClass: \"record-review\",\n capabilityClass: \"record-review-metadata\",\n };\n}\n\nfunction toAutopilotReason(reason: VerifiedTriageReason): AutopilotReasonCode {\n switch (reason) {\n case \"policy_report_only\":\n return \"dry-run\";\n case \"backend_error\":\n case \"evidence_query_failed\":\n return \"audit-write-failed\";\n case \"malformed_fact\":\n return \"invalid-item\";\n case \"requires_human_approval\":\n case \"scope_unclear\":\n case \"sensitive_security_fact\":\n case \"sensitive_privacy_fact\":\n case \"sensitive_personal_fact\":\n case \"sensitive_operational_runbook\":\n return \"human-review-required\";\n default:\n return \"policy-threshold-not-met\";\n }\n}\n\nfunction decisionToResultItem(\n decision: PendingDecision,\n item: VerifiedFactTriageItem,\n applied: boolean,\n): VerifiedTriageResultItem {\n const meta = decision.summary?.metadata ?? {};\n const fact = item.payload.fact;\n const bucket = String(meta.bucket ?? \"failed-review\") as VerifiedTriageBucket;\n const recommendedAction = String(meta.recommendedAction ?? \"failed-validation\") as VerifiedTriageAction;\n return {\n factId: item.payload.verified.factId,\n verifiedFactId: item.payload.verified.id,\n text: fact?.text ?? item.payload.verified.canonicalText,\n verificationTier: item.payload.verificationTier,\n scope: fact?.scope ?? null,\n scopeTarget: fact?.scopeTarget ?? null,\n entity: fact?.entity ?? null,\n key: fact?.key ?? null,\n validFrom: fact?.validFrom ?? null,\n validUntil: fact?.validUntil ?? null,\n expiresAt: fact?.expiresAt ?? null,\n provenanceSummary: summarizeProvenance(fact),\n bucket,\n recommendedAction,\n confidence: decision.confidence,\n evidence: decision.evidence,\n sensitivityFlags: Array.isArray(meta.sensitivityFlags) ? (meta.sensitivityFlags as string[]) : [],\n reason: extractVerifiedReason(decision, item),\n humanReviewRequired: decision.humanReviewRequired,\n action: decision.action,\n reasonCode: decision.reasonCode,\n capabilityClass: decision.capabilityClass,\n actionClass: decision.actionClass,\n inputHash: decision.inputHash,\n applied,\n };\n}\n\nfunction extractVerifiedReason(decision: PendingDecision, item: VerifiedFactTriageItem): VerifiedTriageReason {\n const after = decision.audit?.summary?.metadata as { after?: { reason?: string } } | undefined;\n const reason = after?.after?.reason;\n if (reason) return reason as VerifiedTriageReason;\n const reasonCodeMap: Partial<Record<AutopilotReasonCode, VerifiedTriageReason>> = {\n \"input-hash-mismatch\": \"backend_error\",\n \"lock-conflict\": \"backend_error\",\n \"lock-missing\": \"backend_error\",\n };\n return reasonCodeMap[decision.reasonCode] ?? (item.validationFailed ? \"malformed_fact\" : \"requires_human_approval\");\n}\n\nfunction buildRunResult(input: {\n runId: string;\n mode: \"dry-run\" | \"apply\";\n policy: VerifiedTriagePolicy;\n items: VerifiedTriageResultItem[];\n}): VerifiedTriageRunResult {\n return {\n runId: input.runId,\n mode: input.mode,\n policy: input.policy,\n policyVersion: VERIFIED_TRIAGE_POLICY_VERSION,\n reviewQueueSource: VERIFIED_REVIEW_QUEUE_SOURCE,\n counts: {\n inspected: input.items.length,\n classified: input.items.filter((i) => i.action === \"classified\" || i.action === \"reported\").length,\n stillCurrent: input.items.filter((i) => i.bucket === \"still-current\").length,\n staleCandidates: input.items.filter((i) => i.bucket === \"stale-candidate\").length,\n expiredTtlCandidates: input.items.filter((i) => i.bucket === \"expired-ttl-candidate\").length,\n supersededCandidates: input.items.filter((i) => i.bucket === \"superseded-candidate\").length,\n contradictedCandidates: input.items.filter((i) => i.bucket === \"contradicted-candidate\").length,\n duplicateCandidates: input.items.filter((i) => i.bucket === \"duplicate-candidate\").length,\n sensitiveNeedsHuman: input.items.filter((i) => i.bucket === \"sensitive-needs-human\").length,\n needsHuman: input.items.filter((i) => i.humanReviewRequired).length,\n applied: input.items.filter((i) => i.applied).length,\n failed: input.items.filter((i) => i.bucket === \"failed-review\").length,\n },\n items: input.items,\n };\n}\n\nfunction triageItemFromRow(\n db: DatabaseSync,\n row: VerifiedFactRow,\n opts: { nowIso: string; policy: VerifiedTriagePolicy; dueReason?: VerifiedFactTriagePayload[\"dueReason\"] },\n): VerifiedFactTriageItem {\n const verified = rowToVerifiedFact(row);\n const fact = loadFactSnapshot(db, verified.factId);\n const payload: VerifiedFactTriagePayload = {\n reviewQueueSource: VERIFIED_REVIEW_QUEUE_SOURCE,\n verified,\n fact,\n verificationTier: fact?.tier ?? null,\n reviewCursor: verified.nextVerification ?? verified.verifiedAt,\n dueReason:\n opts.dueReason ??\n (verified.nextVerification && verified.nextVerification <= opts.nowIso\n ? \"next_verification\"\n : \"verified_at_stale\"),\n };\n const inputHash = computePendingInputHash({\n queue: \"verified\",\n id: verified.id,\n payload,\n policy: opts.policy,\n policyVersion: VERIFIED_TRIAGE_POLICY_VERSION,\n });\n return {\n queue: \"verified\",\n id: verified.id,\n inputHash,\n policyVersion: VERIFIED_TRIAGE_POLICY_VERSION,\n capabilityClasses: [\"read-only\", \"record-review-metadata\"],\n payload,\n visibleAfterCursor: verified.nextVerification ?? verified.verifiedAt,\n requiresHumanReview: false,\n validationFailed: !fact,\n };\n}\n\nfunction loadLiveVerifiedFactTriageItem(\n db: DatabaseSync,\n itemId: string,\n opts: { nowMs?: number; reverificationDays?: number; policy: VerifiedTriagePolicy },\n): VerifiedFactTriageItem | null {\n registerVerifiedChecksumFunction(db);\n const nowMs = opts.nowMs ?? Date.now();\n const nowIso = new Date(nowMs).toISOString();\n const cutoffIso = new Date(\n nowMs - (opts.reverificationDays ?? DEFAULT_REVERIFICATION_DAYS) * 24 * 60 * 60 * 1000,\n ).toISOString();\n const row = db\n .prepare(\n `SELECT vf.*\n FROM verified_facts vf\n JOIN (\n SELECT vf2.fact_id, MAX(vf2.version) AS max_version\n FROM verified_facts vf2\n GROUP BY vf2.fact_id\n ) latest ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE vf.id = ?\n AND ((vf.next_verification IS NOT NULL AND vf.next_verification <= ?)\n OR vf.verified_at <= ?)\n LIMIT 1`,\n )\n .get(itemId, nowIso, cutoffIso) as VerifiedFactRow | undefined;\n if (!row || !isVerifiedRowChecksumValid(row)) return null;\n return triageItemFromRow(db, row, { nowIso, policy: opts.policy });\n}\n\nconst registeredChecksumDbs = new WeakSet<DatabaseSync>();\n\nfunction registerVerifiedChecksumFunction(db: DatabaseSync): void {\n if (registeredChecksumDbs.has(db)) return;\n db.function(\"compute_verified_checksum\", { deterministic: true }, (text: unknown) =>\n typeof text === \"string\" ? computeChecksum(text) : \"\",\n );\n registeredChecksumDbs.add(db);\n}\n\nfunction loadFactSnapshot(db: DatabaseSync, factId: string): TriageFactSnapshot | null {\n const row = db.prepare(\"SELECT * FROM facts WHERE id = ?\").get(factId) as Record<string, unknown> | undefined;\n return row ? memoryEntryToSnapshot(rowToMemoryEntry(row)) : null;\n}\n\nfunction memoryEntryToSnapshot(entry: MemoryEntry): TriageFactSnapshot {\n return {\n id: entry.id,\n text: entry.text,\n category: entry.category,\n entity: entry.entity,\n key: entry.key,\n value: entry.value,\n source: entry.source,\n createdAt: entry.createdAt,\n expiresAt: entry.expiresAt,\n validFrom: entry.validFrom ?? null,\n validUntil: entry.validUntil ?? null,\n supersedesId: entry.supersedesId ?? null,\n supersededAt: entry.supersededAt ?? null,\n supersededBy: entry.supersededBy ?? null,\n tier: entry.tier ?? null,\n scope: entry.scope ?? \"global\",\n scopeTarget: entry.scopeTarget ?? null,\n provenanceSession: entry.provenanceSession ?? null,\n sourceSessions: entry.sourceSessions ?? null,\n provenanceJson: entry.provenanceJson ?? null,\n tags: entry.tags ?? null,\n confidence: entry.confidence,\n };\n}\n\nfunction snapshotFromRow(row: Record<string, unknown>): RelatedFact {\n return {\n ...memoryEntryToSnapshot(rowToMemoryEntry(row)),\n verifiedFactId: (row.verified_fact_id as string | null) ?? null,\n verifiedAt: (row.verified_at as string | null) ?? null,\n verifiedVersion: (row.verified_version as number | null) ?? null,\n };\n}\n\nfunction detectSensitivity(\n fact: TriageFactSnapshot,\n canonicalText: string,\n): { flags: string[]; reason: VerifiedTriageReason } {\n const haystack = [canonicalText, fact.text, fact.category, fact.entity, fact.key, fact.value, fact.tags?.join(\" \")]\n .filter(Boolean)\n .join(\"\\n\");\n const flags: string[] = [];\n let reason: VerifiedTriageReason = \"sensitive_personal_fact\";\n const priorityMap: Partial<Record<VerifiedTriageReason, number>> = {\n sensitive_security_fact: 4,\n sensitive_privacy_fact: 3,\n sensitive_operational_runbook: 2,\n sensitive_personal_fact: 1,\n };\n for (const rule of SENSITIVE_RULES) {\n if (rule.pattern.test(haystack)) {\n flags.push(rule.flag);\n if ((priorityMap[rule.reason] ?? 0) > (priorityMap[reason] ?? 0)) {\n reason = rule.reason;\n }\n }\n }\n return { flags: [...new Set(flags)], reason };\n}\n\nfunction hasScopeUnclearSignals(fact: TriageFactSnapshot): boolean {\n return fact.scope !== \"global\" && !fact.scopeTarget;\n}\n\nfunction sameScope(a: TriageFactSnapshot, b: TriageFactSnapshot): boolean {\n return a.scope === b.scope && (a.scopeTarget ?? null) === (b.scopeTarget ?? null);\n}\n\nfunction findExplicitNewerVerifiedFact(db: DatabaseSync, fact: TriageFactSnapshot): RelatedFact | null {\n if (fact.supersededBy) {\n const newer = loadVerifiedRelatedFact(db, fact.supersededBy);\n if (newer && sameScope(fact, newer) && newer.createdAt >= fact.createdAt) return newer;\n }\n const rows = db\n .prepare(\n `SELECT f.*, vf.id AS verified_fact_id, vf.verified_at AS verified_at, vf.version AS verified_version\n FROM facts f\n JOIN verified_facts vf ON vf.fact_id = f.id\n JOIN (\n SELECT fact_id, MAX(version) AS max_version\n FROM verified_facts\n GROUP BY fact_id\n ) latest ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE f.supersedes_id = ?\n AND f.created_at >= ?\n AND f.superseded_at IS NULL\n AND compute_verified_checksum(vf.canonical_text) = vf.checksum\n ORDER BY f.created_at DESC\n LIMIT 5`,\n )\n .all(fact.id, fact.createdAt) as Array<Record<string, unknown>>;\n for (const row of rows) {\n const newer = snapshotFromRow(row);\n if (sameScope(fact, newer)) return newer;\n }\n return null;\n}\n\nfunction loadVerifiedRelatedFact(db: DatabaseSync, factId: string): RelatedFact | null {\n const row = db\n .prepare(\n `SELECT f.*, vf.id AS verified_fact_id, vf.verified_at AS verified_at, vf.version AS verified_version\n FROM facts f\n JOIN verified_facts vf ON vf.fact_id = f.id\n JOIN (\n SELECT fact_id, MAX(version) AS max_version\n FROM verified_facts\n GROUP BY fact_id\n ) latest ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE f.id = ?\n AND compute_verified_checksum(vf.canonical_text) = vf.checksum\n LIMIT 1`,\n )\n .get(factId) as Record<string, unknown> | undefined;\n if (!row) return null;\n return snapshotFromRow(row);\n}\n\nfunction findConcreteContradictingEvidence(db: DatabaseSync, fact: TriageFactSnapshot): VerifiedTriageEvidence | null {\n if (!fact.entity?.trim() || !fact.key?.trim() || fact.value == null || fact.value.trim() === \"\") return null;\n const scopeClause =\n fact.scopeTarget != null ? \"AND f.scope = ? AND f.scope_target = ?\" : \"AND f.scope = ? AND f.scope_target IS NULL\";\n const scopeParams: SQLInputValue[] = fact.scopeTarget != null ? [fact.scope, fact.scopeTarget] : [fact.scope];\n const row = db\n .prepare(\n `SELECT f.*, vf.id AS verified_fact_id\n FROM facts f\n JOIN verified_facts vf ON vf.fact_id = f.id\n JOIN (\n SELECT fact_id, MAX(version) AS max_version\n FROM verified_facts\n GROUP BY fact_id\n ) latest ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE f.id != ?\n AND compute_verified_checksum(vf.canonical_text) = vf.checksum\n AND lower(f.entity) = lower(?)\n AND lower(f.key) = lower(?)\n AND f.value IS NOT NULL\n AND lower(f.value) != lower(?)\n AND f.superseded_at IS NULL\n ${scopeClause}\n ORDER BY f.created_at DESC\n LIMIT 1`,\n )\n .get(fact.id, fact.entity, fact.key, fact.value, ...scopeParams) as Record<string, unknown> | undefined;\n if (!row) return null;\n return {\n type: \"contradiction\",\n id: row.id as string,\n summary: \"Concrete same-entity/key/scope verified fact has conflicting structured value\",\n fields: {\n subject: fact.entity,\n scope: fact.scope,\n scopeTarget: fact.scopeTarget,\n claimType: fact.key,\n currentValue: fact.value,\n conflictingValue: row.value,\n sourceId: row.id,\n verifiedFactId: row.verified_fact_id,\n },\n };\n}\n\nfunction findSameScopeDuplicateVerifiedFact(db: DatabaseSync, fact: TriageFactSnapshot): RelatedFact | null {\n const normalized = normalizeFactText(fact.text);\n if (!normalized) return null;\n const scopeClause =\n fact.scopeTarget != null ? \"AND f.scope = ? AND f.scope_target = ?\" : \"AND f.scope = ? AND f.scope_target IS NULL\";\n const scopeParams: SQLInputValue[] = fact.scopeTarget != null ? [fact.scope, fact.scopeTarget] : [fact.scope];\n const rows = db\n .prepare(\n `SELECT f.*, vf.id AS verified_fact_id, vf.verified_at AS verified_at, vf.version AS verified_version\n FROM facts f\n JOIN verified_facts vf ON vf.fact_id = f.id\n JOIN (\n SELECT fact_id, MAX(version) AS max_version\n FROM verified_facts\n GROUP BY fact_id\n ) latest ON vf.fact_id = latest.fact_id AND vf.version = latest.max_version\n WHERE f.id != ?\n AND f.superseded_at IS NULL\n AND compute_verified_checksum(vf.canonical_text) = vf.checksum\n ${scopeClause}\n ORDER BY f.created_at DESC\n LIMIT 50`,\n )\n .all(fact.id, ...scopeParams) as Array<Record<string, unknown>>;\n for (const row of rows) {\n const candidate = snapshotFromRow(row);\n if (normalizeFactText(candidate.text) === normalized) return candidate;\n }\n return null;\n}\n\nfunction normalizeFactText(text: string): string {\n return text.trim().toLowerCase().replace(/\\s+/g, \" \");\n}\n\nfunction weakProvenanceReason(fact: TriageFactSnapshot): string | null {\n if (fact.source === \"unknown\" || fact.source === \"\") return \"Fact source is missing or unknown\";\n if (!fact.provenanceJson && !fact.provenanceSession && !fact.sourceSessions) {\n return \"No provenance_json, provenance_session, or source_sessions recorded\";\n }\n return null;\n}\n\nfunction summarizeProvenance(fact: TriageFactSnapshot | null): string {\n if (!fact) return \"missing fact row\";\n const parts = [\n fact.provenanceJson ? \"provenance_json\" : null,\n fact.provenanceSession ? `session:${fact.provenanceSession}` : null,\n fact.sourceSessions ? \"source_sessions\" : null,\n `source:${fact.source}`,\n ].filter(Boolean);\n return parts.join(\", \");\n}\n\nfunction validationFailureDecision(\n item: VerifiedFactTriageItem,\n context: PendingDecisionContext,\n reasonCode: AutopilotReasonCode,\n body: string,\n): PendingDecision {\n const evidence = [{ type: \"input-hash\", id: item.id, summary: body }];\n return {\n queue: \"verified\",\n itemId: item.id,\n inputHash: context.inputHash,\n policy: context.policy,\n policyVersion: context.policyVersion,\n mode: context.mode,\n action: \"failed-validation\",\n reasonCode,\n actionClass: \"observe\",\n capabilityClass: \"read-only\",\n confidence: 0,\n humanReviewRequired: true,\n evidence,\n actor: context.actor,\n runId: context.runId,\n jobId: context.jobId,\n summary: {\n title: \"verified fact failed-review\",\n body,\n metadata: {\n bucket: \"failed-review\",\n recommendedAction: \"failed-validation\",\n sensitivityFlags: [],\n },\n },\n audit: {\n queue: \"verified\",\n itemId: item.id,\n inputHash: context.inputHash,\n policy: context.policy,\n policyVersion: context.policyVersion,\n action: \"failed-validation\",\n reasonCode,\n capabilityClass: \"read-only\",\n humanReviewRequired: true,\n evidence,\n actor: context.actor,\n runId: context.runId,\n summary: {\n title: \"verified-fact-triage\",\n body,\n metadata: {\n previous: { verifiedFactId: item.payload.verified.id },\n after: {\n bucket: \"failed-review\",\n recommendedAction: \"failed-validation\",\n reason: \"backend_error\",\n },\n mutation: \"none-core-truth-fields-preserved\",\n },\n },\n },\n };\n}\n"],"mappings":"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"}
|