nlm-memory 0.21.0 → 0.21.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -12
- package/assets/replay-eval-dark.svg +26 -0
- package/assets/replay-eval-light.svg +26 -0
- package/dist/cli/digest.js +34 -7
- package/dist/cli/digest.js.map +1 -1
- package/dist/cli/nlm.d.ts +14 -0
- package/dist/cli/nlm.js +450 -65
- package/dist/cli/nlm.js.map +1 -1
- package/dist/cli/reprocess-job-adapters.d.ts +35 -0
- package/dist/cli/reprocess-job-adapters.js +80 -0
- package/dist/cli/reprocess-job-adapters.js.map +1 -0
- package/dist/cli/scope-coverage.js +4 -1
- package/dist/cli/scope-coverage.js.map +1 -1
- package/dist/cli/supersede.js +8 -7
- package/dist/cli/supersede.js.map +1 -1
- package/dist/core/actions/actions-log.d.ts +65 -8
- package/dist/core/actions/actions-log.js +134 -17
- package/dist/core/actions/actions-log.js.map +1 -1
- package/dist/core/actions/overlay.d.ts +11 -2
- package/dist/core/actions/overlay.js +18 -6
- package/dist/core/actions/overlay.js.map +1 -1
- package/dist/core/adapters/from-source.js +11 -3
- package/dist/core/adapters/from-source.js.map +1 -1
- package/dist/core/adapters/fs-wiki-writer.d.ts +44 -0
- package/dist/core/adapters/fs-wiki-writer.js +132 -0
- package/dist/core/adapters/fs-wiki-writer.js.map +1 -0
- package/dist/core/adapters/hermes-agent.d.ts +15 -2
- package/dist/core/adapters/hermes-agent.js +57 -11
- package/dist/core/adapters/hermes-agent.js.map +1 -1
- package/dist/core/adapters/memory-wiki-writer.d.ts +8 -0
- package/dist/core/adapters/memory-wiki-writer.js +16 -0
- package/dist/core/adapters/memory-wiki-writer.js.map +1 -0
- package/dist/core/adapters/muse.d.ts +51 -0
- package/dist/core/adapters/muse.js +271 -0
- package/dist/core/adapters/muse.js.map +1 -0
- package/dist/core/adapters/opencode.d.ts +11 -4
- package/dist/core/adapters/opencode.js +41 -7
- package/dist/core/adapters/opencode.js.map +1 -1
- package/dist/core/alerts/alert-state.d.ts +17 -0
- package/dist/core/alerts/alert-state.js +45 -0
- package/dist/core/alerts/alert-state.js.map +1 -0
- package/dist/core/alerts/check-and-alert.d.ts +28 -0
- package/dist/core/alerts/check-and-alert.js +53 -0
- package/dist/core/alerts/check-and-alert.js.map +1 -0
- package/dist/core/alerts/drift-transition.d.ts +27 -0
- package/dist/core/alerts/drift-transition.js +56 -0
- package/dist/core/alerts/drift-transition.js.map +1 -0
- package/dist/core/alerts/embedder-transition.d.ts +23 -0
- package/dist/core/alerts/embedder-transition.js +40 -0
- package/dist/core/alerts/embedder-transition.js.map +1 -0
- package/dist/core/alerts/fire-alert.d.ts +24 -0
- package/dist/core/alerts/fire-alert.js +72 -0
- package/dist/core/alerts/fire-alert.js.map +1 -0
- package/dist/core/alerts/job-alert.d.ts +12 -0
- package/dist/core/alerts/job-alert.js +37 -0
- package/dist/core/alerts/job-alert.js.map +1 -0
- package/dist/core/alerts/types.d.ts +104 -0
- package/dist/core/alerts/types.js +11 -0
- package/dist/core/alerts/types.js.map +1 -0
- package/dist/core/alerts/wiki-alert.d.ts +15 -0
- package/dist/core/alerts/wiki-alert.js +31 -0
- package/dist/core/alerts/wiki-alert.js.map +1 -0
- package/dist/core/classifier/prompt.d.ts +13 -0
- package/dist/core/classifier/prompt.js +52 -2
- package/dist/core/classifier/prompt.js.map +1 -1
- package/dist/core/dataset/build-dataset.d.ts +16 -1
- package/dist/core/dataset/build-dataset.js +105 -45
- package/dist/core/dataset/build-dataset.js.map +1 -1
- package/dist/core/digest/compose.d.ts +8 -0
- package/dist/core/digest/compose.js +54 -0
- package/dist/core/digest/compose.js.map +1 -1
- package/dist/core/digest/hook-injection.d.ts +1 -1
- package/dist/core/digest/hook-injection.js +9 -1
- package/dist/core/digest/hook-injection.js.map +1 -1
- package/dist/core/digest/hook-version-parity.d.ts +31 -0
- package/dist/core/digest/hook-version-parity.js +56 -0
- package/dist/core/digest/hook-version-parity.js.map +1 -0
- package/dist/core/embedding/pg-embed-backfill.js +1 -1
- package/dist/core/embedding/pg-embed-backfill.js.map +1 -1
- package/dist/core/exemplars/capture-from-session.d.ts +1 -1
- package/dist/core/exemplars/capture-from-session.js +3 -3
- package/dist/core/exemplars/capture-from-session.js.map +1 -1
- package/dist/core/exemplars/embed-backfill.d.ts +9 -0
- package/dist/core/exemplars/embed-backfill.js +9 -1
- package/dist/core/exemplars/embed-backfill.js.map +1 -1
- package/dist/core/exemplars/recall-code.d.ts +1 -1
- package/dist/core/exemplars/recall-code.js +2 -2
- package/dist/core/exemplars/recall-code.js.map +1 -1
- package/dist/core/facts/backfill-facts.d.ts +1 -1
- package/dist/core/facts/backfill-facts.js +4 -4
- package/dist/core/facts/backfill-facts.js.map +1 -1
- package/dist/core/facts/embed-backfill.d.ts +54 -0
- package/dist/core/facts/embed-backfill.js +109 -0
- package/dist/core/facts/embed-backfill.js.map +1 -0
- package/dist/core/facts/reconcile-facts.d.ts +42 -0
- package/dist/core/facts/reconcile-facts.js +133 -0
- package/dist/core/facts/reconcile-facts.js.map +1 -0
- package/dist/core/health/embed-failure-state.d.ts +4 -0
- package/dist/core/health/embed-failure-state.js +12 -0
- package/dist/core/health/embed-failure-state.js.map +1 -0
- package/dist/core/health/warmup-retry.d.ts +27 -0
- package/dist/core/health/warmup-retry.js +53 -0
- package/dist/core/health/warmup-retry.js.map +1 -0
- package/dist/core/health/warmup-state.d.ts +15 -0
- package/dist/core/health/warmup-state.js +15 -1
- package/dist/core/health/warmup-state.js.map +1 -1
- package/dist/core/hook/cite-memo.d.ts +11 -7
- package/dist/core/hook/cite-memo.js +25 -17
- package/dist/core/hook/cite-memo.js.map +1 -1
- package/dist/core/hook/hook-log.d.ts +13 -2
- package/dist/core/hook/hook-log.js +16 -8
- package/dist/core/hook/hook-log.js.map +1 -1
- package/dist/core/hook/memo.d.ts +10 -6
- package/dist/core/hook/memo.js +25 -17
- package/dist/core/hook/memo.js.map +1 -1
- package/dist/core/hook/pointer-block.d.ts +8 -1
- package/dist/core/hook/pointer-block.js +17 -4
- package/dist/core/hook/pointer-block.js.map +1 -1
- package/dist/core/hook/resolve-conversation-by-query.d.ts +6 -5
- package/dist/core/hook/resolve-conversation-by-query.js +24 -12
- package/dist/core/hook/resolve-conversation-by-query.js.map +1 -1
- package/dist/core/ingest/ingest-session.d.ts +1 -1
- package/dist/core/ingest/ingest-session.js +3 -3
- package/dist/core/ingest/ingest-session.js.map +1 -1
- package/dist/core/ingest/reclassify-oversized.d.ts +1 -1
- package/dist/core/ingest/reclassify-oversized.js +2 -2
- package/dist/core/ingest/reclassify-oversized.js.map +1 -1
- package/dist/core/ingest/reprocess.d.ts +1 -1
- package/dist/core/ingest/reprocess.js +2 -2
- package/dist/core/ingest/reprocess.js.map +1 -1
- package/dist/core/jobs/job-supervisor.d.ts +168 -0
- package/dist/core/jobs/job-supervisor.js +335 -0
- package/dist/core/jobs/job-supervisor.js.map +1 -0
- package/dist/core/learner/model.d.ts +63 -0
- package/dist/core/learner/model.js +30 -0
- package/dist/core/learner/model.js.map +1 -0
- package/dist/core/learner/service.d.ts +42 -0
- package/dist/core/learner/service.js +74 -0
- package/dist/core/learner/service.js.map +1 -0
- package/dist/core/learner/summary.d.ts +28 -0
- package/dist/core/learner/summary.js +70 -0
- package/dist/core/learner/summary.js.map +1 -0
- package/dist/core/learner/validate.d.ts +18 -0
- package/dist/core/learner/validate.js +95 -0
- package/dist/core/learner/validate.js.map +1 -0
- package/dist/core/metrics/re-derivation.d.ts +31 -2
- package/dist/core/metrics/re-derivation.js +36 -4
- package/dist/core/metrics/re-derivation.js.map +1 -1
- package/dist/core/outcome/coverage.d.ts +1 -1
- package/dist/core/outcome/coverage.js +2 -2
- package/dist/core/outcome/coverage.js.map +1 -1
- package/dist/core/outcome/rollup.d.ts +1 -1
- package/dist/core/outcome/rollup.js +4 -4
- package/dist/core/outcome/rollup.js.map +1 -1
- package/dist/core/providers/provider-registry.d.ts +40 -23
- package/dist/core/providers/provider-registry.js +99 -81
- package/dist/core/providers/provider-registry.js.map +1 -1
- package/dist/core/recall/citation-log.d.ts +10 -5
- package/dist/core/recall/citation-log.js +21 -10
- package/dist/core/recall/citation-log.js.map +1 -1
- package/dist/core/recall/hook-recall-log.d.ts +5 -2
- package/dist/core/recall/hook-recall-log.js +12 -6
- package/dist/core/recall/hook-recall-log.js.map +1 -1
- package/dist/core/recall/miss-log.d.ts +7 -4
- package/dist/core/recall/miss-log.js +18 -11
- package/dist/core/recall/miss-log.js.map +1 -1
- package/dist/core/recall/query-log.d.ts +8 -5
- package/dist/core/recall/query-log.js +16 -9
- package/dist/core/recall/query-log.js.map +1 -1
- package/dist/core/recall/recall-service.d.ts +10 -1
- package/dist/core/recall/recall-service.js +31 -12
- package/dist/core/recall/recall-service.js.map +1 -1
- package/dist/core/recall/recent-log.d.ts +6 -1
- package/dist/core/recall/recent-log.js +13 -5
- package/dist/core/recall/recent-log.js.map +1 -1
- package/dist/core/recall/related-concepts.d.ts +29 -0
- package/dist/core/recall/related-concepts.js +67 -0
- package/dist/core/recall/related-concepts.js.map +1 -0
- package/dist/core/recall/related-exemplars.d.ts +1 -1
- package/dist/core/recall/related-exemplars.js +2 -2
- package/dist/core/recall/related-exemplars.js.map +1 -1
- package/dist/core/recall/related-facts.d.ts +1 -1
- package/dist/core/recall/related-facts.js +3 -3
- package/dist/core/recall/related-facts.js.map +1 -1
- package/dist/core/recall-facts/fact-query-log.d.ts +8 -4
- package/dist/core/recall-facts/fact-query-log.js +16 -8
- package/dist/core/recall-facts/fact-query-log.js.map +1 -1
- package/dist/core/recall-facts/fact-recall-service.d.ts +2 -2
- package/dist/core/recall-facts/fact-recall-service.js +12 -12
- package/dist/core/recall-facts/fact-recall-service.js.map +1 -1
- package/dist/core/scheduler/scan-once.js +15 -14
- package/dist/core/scheduler/scan-once.js.map +1 -1
- package/dist/core/scheduler/scheduler.d.ts +3 -0
- package/dist/core/scheduler/scheduler.js +15 -11
- package/dist/core/scheduler/scheduler.js.map +1 -1
- package/dist/core/signals/failure-mode-recall.d.ts +1 -1
- package/dist/core/signals/failure-mode-recall.js +2 -2
- package/dist/core/signals/failure-mode-recall.js.map +1 -1
- package/dist/core/signals/stamp-scope.d.ts +2 -2
- package/dist/core/signals/stamp-scope.js +2 -2
- package/dist/core/signals/stamp-scope.js.map +1 -1
- package/dist/core/sources/source-registry.d.ts +49 -28
- package/dist/core/sources/source-registry.js +113 -70
- package/dist/core/sources/source-registry.js.map +1 -1
- package/dist/core/storage/pg-code-exemplar-store.d.ts +19 -10
- package/dist/core/storage/pg-code-exemplar-store.js +58 -27
- package/dist/core/storage/pg-code-exemplar-store.js.map +1 -1
- package/dist/core/storage/pg-entity-store.d.ts +6 -1
- package/dist/core/storage/pg-entity-store.js +33 -18
- package/dist/core/storage/pg-entity-store.js.map +1 -1
- package/dist/core/storage/pg-fact-ingest.d.ts +1 -1
- package/dist/core/storage/pg-fact-ingest.js +10 -7
- package/dist/core/storage/pg-fact-ingest.js.map +1 -1
- package/dist/core/storage/pg-fact-store.d.ts +29 -17
- package/dist/core/storage/pg-fact-store.js +99 -46
- package/dist/core/storage/pg-fact-store.js.map +1 -1
- package/dist/core/storage/pg-learner-store.d.ts +27 -0
- package/dist/core/storage/pg-learner-store.js +174 -0
- package/dist/core/storage/pg-learner-store.js.map +1 -0
- package/dist/core/storage/pg-session-store.d.ts +24 -20
- package/dist/core/storage/pg-session-store.js +162 -90
- package/dist/core/storage/pg-session-store.js.map +1 -1
- package/dist/core/storage/pg-signal-store.d.ts +10 -5
- package/dist/core/storage/pg-signal-store.js +24 -12
- package/dist/core/storage/pg-signal-store.js.map +1 -1
- package/dist/core/storage/pg-storage.d.ts +4 -0
- package/dist/core/storage/pg-storage.js +6 -0
- package/dist/core/storage/pg-storage.js.map +1 -1
- package/dist/core/storage/pg-workstream-store.d.ts +16 -11
- package/dist/core/storage/pg-workstream-store.js +46 -29
- package/dist/core/storage/pg-workstream-store.js.map +1 -1
- package/dist/core/storage/sqlite-code-exemplar-store.d.ts +24 -10
- package/dist/core/storage/sqlite-code-exemplar-store.js +84 -40
- package/dist/core/storage/sqlite-code-exemplar-store.js.map +1 -1
- package/dist/core/storage/sqlite-entity-store.d.ts +8 -1
- package/dist/core/storage/sqlite-entity-store.js +46 -27
- package/dist/core/storage/sqlite-entity-store.js.map +1 -1
- package/dist/core/storage/sqlite-fact-store.d.ts +45 -19
- package/dist/core/storage/sqlite-fact-store.js +172 -64
- package/dist/core/storage/sqlite-fact-store.js.map +1 -1
- package/dist/core/storage/sqlite-learner-store.d.ts +33 -0
- package/dist/core/storage/sqlite-learner-store.js +178 -0
- package/dist/core/storage/sqlite-learner-store.js.map +1 -0
- package/dist/core/storage/sqlite-outcome-store.d.ts +37 -22
- package/dist/core/storage/sqlite-outcome-store.js +90 -37
- package/dist/core/storage/sqlite-outcome-store.js.map +1 -1
- package/dist/core/storage/sqlite-session-store.d.ts +29 -20
- package/dist/core/storage/sqlite-session-store.js +207 -121
- package/dist/core/storage/sqlite-session-store.js.map +1 -1
- package/dist/core/storage/sqlite-signal-store.d.ts +12 -5
- package/dist/core/storage/sqlite-signal-store.js +27 -15
- package/dist/core/storage/sqlite-signal-store.js.map +1 -1
- package/dist/core/storage/sqlite-storage.d.ts +4 -0
- package/dist/core/storage/sqlite-storage.js +10 -2
- package/dist/core/storage/sqlite-storage.js.map +1 -1
- package/dist/core/storage/sqlite-workstream-store.d.ts +16 -11
- package/dist/core/storage/sqlite-workstream-store.js +52 -31
- package/dist/core/storage/sqlite-workstream-store.js.map +1 -1
- package/dist/core/storage/supersedence-log.d.ts +10 -7
- package/dist/core/storage/supersedence-log.js +19 -14
- package/dist/core/storage/supersedence-log.js.map +1 -1
- package/dist/core/tenancy/default-team.d.ts +6 -0
- package/dist/core/tenancy/default-team.js +7 -0
- package/dist/core/tenancy/default-team.js.map +1 -0
- package/dist/core/tenancy/hosted-mode.d.ts +9 -0
- package/dist/core/tenancy/hosted-mode.js +12 -0
- package/dist/core/tenancy/hosted-mode.js.map +1 -0
- package/dist/core/tenancy/team-auth.d.ts +16 -0
- package/dist/core/tenancy/team-auth.js +22 -0
- package/dist/core/tenancy/team-auth.js.map +1 -0
- package/dist/core/tenancy/team-token-store.d.ts +45 -0
- package/dist/core/tenancy/team-token-store.js +52 -0
- package/dist/core/tenancy/team-token-store.js.map +1 -0
- package/dist/core/tenancy/tenant-clause.d.ts +37 -0
- package/dist/core/tenancy/tenant-clause.js +11 -0
- package/dist/core/tenancy/tenant-clause.js.map +1 -0
- package/dist/core/tenancy/tenant-state-path.d.ts +28 -0
- package/dist/core/tenancy/tenant-state-path.js +49 -0
- package/dist/core/tenancy/tenant-state-path.js.map +1 -0
- package/dist/core/wiki/project.d.ts +17 -0
- package/dist/core/wiki/project.js +37 -0
- package/dist/core/wiki/project.js.map +1 -0
- package/dist/core/wiki/reconcile.d.ts +15 -0
- package/dist/core/wiki/reconcile.js +14 -0
- package/dist/core/wiki/reconcile.js.map +1 -0
- package/dist/core/wiki/render.d.ts +5 -0
- package/dist/core/wiki/render.js +84 -0
- package/dist/core/wiki/render.js.map +1 -0
- package/dist/core/wiki/rollup.d.ts +28 -0
- package/dist/core/wiki/rollup.js +91 -0
- package/dist/core/wiki/rollup.js.map +1 -0
- package/dist/core/wiki/select.d.ts +8 -0
- package/dist/core/wiki/select.js +7 -0
- package/dist/core/wiki/select.js.map +1 -0
- package/dist/core/wiki/slug.d.ts +36 -0
- package/dist/core/wiki/slug.js +71 -0
- package/dist/core/wiki/slug.js.map +1 -0
- package/dist/core/wiki/types.d.ts +37 -0
- package/dist/core/wiki/types.js +2 -0
- package/dist/core/wiki/types.js.map +1 -0
- package/dist/core/work-digest/build-work-digest.d.ts +1 -1
- package/dist/core/work-digest/build-work-digest.js +3 -3
- package/dist/core/work-digest/build-work-digest.js.map +1 -1
- package/dist/core/workstream/bind.d.ts +1 -1
- package/dist/core/workstream/bind.js +10 -10
- package/dist/core/workstream/bind.js.map +1 -1
- package/dist/core/workstream/rollup.d.ts +1 -1
- package/dist/core/workstream/rollup.js +6 -6
- package/dist/core/workstream/rollup.js.map +1 -1
- package/dist/hook/hook-helpers.d.ts +14 -0
- package/dist/hook/hook-helpers.js +29 -2
- package/dist/hook/hook-helpers.js.map +1 -1
- package/dist/hook/pre-compact-hook.js +6 -4
- package/dist/hook/pre-compact-hook.js.map +1 -1
- package/dist/hook/prompt-recall-hook.d.ts +5 -2
- package/dist/hook/prompt-recall-hook.js +28 -17
- package/dist/hook/prompt-recall-hook.js.map +1 -1
- package/dist/hook/recall-over-http.d.ts +27 -3
- package/dist/hook/recall-over-http.js +44 -11
- package/dist/hook/recall-over-http.js.map +1 -1
- package/dist/hook/session-end-hook.js +7 -5
- package/dist/hook/session-end-hook.js.map +1 -1
- package/dist/hook/session-start-hook.d.ts +14 -1
- package/dist/hook/session-start-hook.js +55 -15
- package/dist/hook/session-start-hook.js.map +1 -1
- package/dist/hook/stop-hook.js +9 -7
- package/dist/hook/stop-hook.js.map +1 -1
- package/dist/http/app.d.ts +41 -3
- package/dist/http/app.js +355 -96
- package/dist/http/app.js.map +1 -1
- package/dist/install/claude-code.d.ts +17 -0
- package/dist/install/claude-code.js +44 -5
- package/dist/install/claude-code.js.map +1 -1
- package/dist/install/codex.d.ts +23 -2
- package/dist/install/codex.js +111 -14
- package/dist/install/codex.js.map +1 -1
- package/dist/install/cursor.d.ts +2 -2
- package/dist/install/cursor.js +7 -7
- package/dist/install/cursor.js.map +1 -1
- package/dist/install/hermes.d.ts +8 -0
- package/dist/install/hermes.js +28 -5
- package/dist/install/hermes.js.map +1 -1
- package/dist/install/local-source.d.ts +20 -0
- package/dist/install/local-source.js +28 -0
- package/dist/install/local-source.js.map +1 -0
- package/dist/install/mcp-block.d.ts +77 -0
- package/dist/install/mcp-block.js +99 -0
- package/dist/install/mcp-block.js.map +1 -0
- package/dist/install/pi.d.ts +26 -0
- package/dist/install/pi.js +43 -0
- package/dist/install/pi.js.map +1 -1
- package/dist/install/setup.js +6 -0
- package/dist/install/setup.js.map +1 -1
- package/dist/install/windsurf.d.ts +2 -2
- package/dist/install/windsurf.js +7 -7
- package/dist/install/windsurf.js.map +1 -1
- package/dist/llm/classifier-box.d.ts +5 -0
- package/dist/llm/classifier-box.js +5 -0
- package/dist/llm/classifier-box.js.map +1 -1
- package/dist/mcp/server.d.ts +73 -16
- package/dist/mcp/server.js +306 -83
- package/dist/mcp/server.js.map +1 -1
- package/dist/ports/clock.d.ts +12 -0
- package/dist/ports/clock.js +10 -0
- package/dist/ports/clock.js.map +1 -0
- package/dist/ports/code-exemplar-store.d.ts +13 -13
- package/dist/ports/entity-store.d.ts +5 -1
- package/dist/ports/fact-store.d.ts +0 -0
- package/dist/ports/fact-store.js +0 -0
- package/dist/ports/fact-store.js.map +1 -1
- package/dist/ports/learner-store.d.ts +80 -0
- package/dist/ports/learner-store.js +19 -0
- package/dist/ports/learner-store.js.map +1 -0
- package/dist/ports/outcome.d.ts +3 -3
- package/dist/ports/session-store.d.ts +20 -14
- package/dist/ports/session-store.js +5 -0
- package/dist/ports/session-store.js.map +1 -1
- package/dist/ports/signal-store.d.ts +12 -8
- package/dist/ports/spawn-child.d.ts +14 -0
- package/dist/ports/spawn-child.js +10 -0
- package/dist/ports/spawn-child.js.map +1 -0
- package/dist/ports/storage.d.ts +6 -0
- package/dist/ports/transcript-adapter.d.ts +11 -0
- package/dist/ports/wiki-writer.d.ts +19 -0
- package/dist/ports/wiki-writer.js +12 -0
- package/dist/ports/wiki-writer.js.map +1 -0
- package/dist/ports/workstream-store.d.ts +19 -12
- package/dist/shared/types.d.ts +22 -0
- package/dist/shared/types.js.map +1 -1
- package/dist/shared/version.d.ts +9 -0
- package/dist/shared/version.js +11 -0
- package/dist/shared/version.js.map +1 -0
- package/dist/ui/assets/index-D6F3xAis.js +11 -0
- package/dist/ui/index.html +1 -1
- package/migrations/033_actions_kind_check.sql +58 -0
- package/migrations/034_tenancy_teams_and_stamps.sql +40 -0
- package/migrations/035_tenancy_entity_rekey.sql +75 -0
- package/migrations/036_tenant_name_uniqueness.sql +59 -0
- package/migrations/037_sessions_covering_index.sql +25 -0
- package/migrations/038_sources_muse.sql +33 -0
- package/migrations/039_learner_evidence.sql +51 -0
- package/migrations/pg/033_actions_kind_check.sql +17 -0
- package/migrations/pg/034_tenancy.sql +77 -0
- package/migrations/pg/035_tenant_name_uniqueness.sql +15 -0
- package/migrations/pg/036_sources_muse.sql +12 -0
- package/migrations/pg/037_learner_evidence.sql +55 -0
- package/nlm/index.js +246 -55
- package/package.json +10 -5
- package/plugin/.codex-plugin/plugin.json +2 -2
- package/plugin/scripts/prompt-recall-hook.mjs +244 -55
- package/plugin/scripts/session-start-hook.mjs +273 -53
- package/plugin/scripts/stop-hook.mjs +195 -37
- package/dist/ui/assets/index-CSaBtgXD.js +0 -11
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version-drift alert transition logic — decides WHEN to fire, not
|
|
3
|
+
* whether to fire on every poll. Firing on every `behind: true` read
|
|
4
|
+
* would spam the webhook on every scheduled check; instead this tracks
|
|
5
|
+
* the false→true edge (fire once) and a daily re-fire while the daemon
|
|
6
|
+
* stays behind past a 48h grace window (so a long-ignored update still
|
|
7
|
+
* resurfaces, but not hourly).
|
|
8
|
+
*
|
|
9
|
+
* Pure and clock-injected — no fs/network here. Callers (see
|
|
10
|
+
* check-and-alert.ts) own reading/writing the persisted state and
|
|
11
|
+
* calling fireAlert with the returned event.
|
|
12
|
+
*/
|
|
13
|
+
export const DEFAULT_DRIFT_ALERT_STATE = {
|
|
14
|
+
behindSince: null,
|
|
15
|
+
lastFiredAt: null,
|
|
16
|
+
};
|
|
17
|
+
const SUSTAIN_THRESHOLD_MS = 48 * 60 * 60 * 1000;
|
|
18
|
+
const REFIRE_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
19
|
+
export function evaluateDriftTransition(state, status, now) {
|
|
20
|
+
if (!status.behind) {
|
|
21
|
+
// Recovered (or never behind) — reset so a future false→true edge
|
|
22
|
+
// fires again instead of being suppressed by stale state.
|
|
23
|
+
if (state.behindSince === null)
|
|
24
|
+
return { fire: false, event: null, next: state };
|
|
25
|
+
return { fire: false, event: null, next: DEFAULT_DRIFT_ALERT_STATE };
|
|
26
|
+
}
|
|
27
|
+
const nowIso = now.toISOString();
|
|
28
|
+
const latest = status.latest ?? "unknown";
|
|
29
|
+
if (state.behindSince === null) {
|
|
30
|
+
// false → true edge: fire once.
|
|
31
|
+
return {
|
|
32
|
+
fire: true,
|
|
33
|
+
event: {
|
|
34
|
+
type: "nlm.drift.version_behind",
|
|
35
|
+
data: { current: status.current, latest, since: nowIso },
|
|
36
|
+
},
|
|
37
|
+
next: { behindSince: nowIso, lastFiredAt: nowIso },
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const sustainedMs = now.getTime() - Date.parse(state.behindSince);
|
|
41
|
+
const sinceLastFireMs = state.lastFiredAt
|
|
42
|
+
? now.getTime() - Date.parse(state.lastFiredAt)
|
|
43
|
+
: Infinity;
|
|
44
|
+
if (sustainedMs >= SUSTAIN_THRESHOLD_MS && sinceLastFireMs >= REFIRE_INTERVAL_MS) {
|
|
45
|
+
return {
|
|
46
|
+
fire: true,
|
|
47
|
+
event: {
|
|
48
|
+
type: "nlm.drift.version_behind",
|
|
49
|
+
data: { current: status.current, latest, since: state.behindSince },
|
|
50
|
+
},
|
|
51
|
+
next: { behindSince: state.behindSince, lastFiredAt: nowIso },
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return { fire: false, event: null, next: state };
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=drift-transition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift-transition.js","sourceRoot":"","sources":["../../../src/core/alerts/drift-transition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAYH,MAAM,CAAC,MAAM,yBAAyB,GAAoB;IACxD,WAAW,EAAE,IAAI;IACjB,WAAW,EAAE,IAAI;CAClB,CAAC;AAEF,MAAM,oBAAoB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACjD,MAAM,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAQ/C,MAAM,UAAU,uBAAuB,CACrC,KAAsB,EACtB,MAA2D,EAC3D,GAAS;IAET,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,kEAAkE;QAClE,0DAA0D;QAC1D,IAAI,KAAK,CAAC,WAAW,KAAK,IAAI;YAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACjF,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,yBAAyB,EAAE,CAAC;IACvE,CAAC;IAED,MAAM,MAAM,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IACjC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,SAAS,CAAC;IAE1C,IAAI,KAAK,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;QAC/B,gCAAgC;QAChC,OAAO;YACL,IAAI,EAAE,IAAI;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,0BAA0B;gBAChC,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;aACzD;YACD,IAAI,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE;SACnD,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAClE,MAAM,eAAe,GAAG,KAAK,CAAC,WAAW;QACvC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC;QAC/C,CAAC,CAAC,QAAQ,CAAC;IAEb,IAAI,WAAW,IAAI,oBAAoB,IAAI,eAAe,IAAI,kBAAkB,EAAE,CAAC;QACjF,OAAO;YACL,IAAI,EAAE,IAAI;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,0BAA0B;gBAChC,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE;aACpE;YACD,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE;SAC9D,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedder-cold alert transition logic — fires once when the embedder
|
|
3
|
+
* warmup flag flips ready→not-ready and STAYS not-ready across two
|
|
4
|
+
* consecutive checks. A single-check dip is treated as a transient
|
|
5
|
+
* blip (e.g. a lane restart mid-check), not an outage worth alerting on.
|
|
6
|
+
*
|
|
7
|
+
* Pure and clock-injected. See check-and-alert.ts for the caller that
|
|
8
|
+
* reads warmupSnapshot(), threads the persisted state, and fires.
|
|
9
|
+
*/
|
|
10
|
+
import type { EmbedderAlertEvent } from "./types.js";
|
|
11
|
+
export interface EmbedderAlertState {
|
|
12
|
+
/** Consecutive not-ready checks seen so far (resets to 0 once ready again). */
|
|
13
|
+
readonly notReadyStreak: number;
|
|
14
|
+
/** ISO timestamp of the first not-ready check in the current streak, or null. */
|
|
15
|
+
readonly since: string | null;
|
|
16
|
+
}
|
|
17
|
+
export declare const DEFAULT_EMBEDDER_ALERT_STATE: EmbedderAlertState;
|
|
18
|
+
export interface EmbedderTransitionResult {
|
|
19
|
+
readonly fire: boolean;
|
|
20
|
+
readonly event: EmbedderAlertEvent | null;
|
|
21
|
+
readonly next: EmbedderAlertState;
|
|
22
|
+
}
|
|
23
|
+
export declare function evaluateEmbedderTransition(state: EmbedderAlertState, ready: boolean, now: Date): EmbedderTransitionResult;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedder-cold alert transition logic — fires once when the embedder
|
|
3
|
+
* warmup flag flips ready→not-ready and STAYS not-ready across two
|
|
4
|
+
* consecutive checks. A single-check dip is treated as a transient
|
|
5
|
+
* blip (e.g. a lane restart mid-check), not an outage worth alerting on.
|
|
6
|
+
*
|
|
7
|
+
* Pure and clock-injected. See check-and-alert.ts for the caller that
|
|
8
|
+
* reads warmupSnapshot(), threads the persisted state, and fires.
|
|
9
|
+
*/
|
|
10
|
+
export const DEFAULT_EMBEDDER_ALERT_STATE = {
|
|
11
|
+
notReadyStreak: 0,
|
|
12
|
+
since: null,
|
|
13
|
+
};
|
|
14
|
+
const SUSTAIN_CHECK_COUNT = 2;
|
|
15
|
+
export function evaluateEmbedderTransition(state, ready, now) {
|
|
16
|
+
if (ready) {
|
|
17
|
+
if (state.notReadyStreak === 0 && state.since === null) {
|
|
18
|
+
return { fire: false, event: null, next: state };
|
|
19
|
+
}
|
|
20
|
+
// Recovered — reset so the next ready→not-ready edge can fire again.
|
|
21
|
+
return { fire: false, event: null, next: DEFAULT_EMBEDDER_ALERT_STATE };
|
|
22
|
+
}
|
|
23
|
+
const streak = state.notReadyStreak + 1;
|
|
24
|
+
const since = state.since ?? now.toISOString();
|
|
25
|
+
if (streak === SUSTAIN_CHECK_COUNT) {
|
|
26
|
+
// Sustained across the 2nd consecutive check — fire once. Streak
|
|
27
|
+
// keeps climbing on later checks but never re-hits exactly this
|
|
28
|
+
// value, so this is a single edge-triggered fire per cold episode.
|
|
29
|
+
return {
|
|
30
|
+
fire: true,
|
|
31
|
+
event: {
|
|
32
|
+
type: "nlm.health.embedder_cold",
|
|
33
|
+
data: { current: "cold", latest: "ready", since },
|
|
34
|
+
},
|
|
35
|
+
next: { notReadyStreak: streak, since },
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return { fire: false, event: null, next: { notReadyStreak: streak, since } };
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=embedder-transition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedder-transition.js","sourceRoot":"","sources":["../../../src/core/alerts/embedder-transition.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH,MAAM,CAAC,MAAM,4BAA4B,GAAuB;IAC9D,cAAc,EAAE,CAAC;IACjB,KAAK,EAAE,IAAI;CACZ,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAQ9B,MAAM,UAAU,0BAA0B,CACxC,KAAyB,EACzB,KAAc,EACd,GAAS;IAET,IAAI,KAAK,EAAE,CAAC;QACV,IAAI,KAAK,CAAC,cAAc,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACvD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACnD,CAAC;QACD,qEAAqE;QACrE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,4BAA4B,EAAE,CAAC;IAC1E,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC;IACxC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;IAE/C,IAAI,MAAM,KAAK,mBAAmB,EAAE,CAAC;QACnC,iEAAiE;QACjE,gEAAgE;QAChE,mEAAmE;QACnE,OAAO;YACL,IAAI,EAAE,IAAI;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,0BAA0B;gBAChC,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE;aAClD;YACD,IAAI,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE;SACxC,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;AAC/E,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fireAlert — POST a CloudEvents-shaped daemon self-report to an
|
|
3
|
+
* operator-owned webhook.
|
|
4
|
+
*
|
|
5
|
+
* What this is: an opt-in outbound notification for drift/health
|
|
6
|
+
* transitions (see drift-transition.ts, embedder-transition.ts) that the
|
|
7
|
+
* operator wants pushed somewhere (Slack relay, PagerDuty, a log sink)
|
|
8
|
+
* instead of only surfacing on the next `nlm start` banner or
|
|
9
|
+
* `GET /api/health` poll.
|
|
10
|
+
*
|
|
11
|
+
* What this is not: telemetry back to an NLM-owned server. Nothing
|
|
12
|
+
* fires unless the operator sets NLM_ALERT_WEBHOOK themselves, and the
|
|
13
|
+
* payload never leaves the process until then.
|
|
14
|
+
*
|
|
15
|
+
* Contract: skip silently (zero network calls) when NLM_ALERT_WEBHOOK is
|
|
16
|
+
* unset. Otherwise POST with a 5s timeout, one retry on failure, and
|
|
17
|
+
* never throw — a webhook outage must never take the daemon down.
|
|
18
|
+
*/
|
|
19
|
+
import type { AlertEvent } from "./types.js";
|
|
20
|
+
export interface FireAlertDeps {
|
|
21
|
+
readonly now?: () => Date;
|
|
22
|
+
readonly fetchImpl?: typeof fetch;
|
|
23
|
+
}
|
|
24
|
+
export declare function fireAlert(event: AlertEvent, deps?: FireAlertDeps): Promise<void>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fireAlert — POST a CloudEvents-shaped daemon self-report to an
|
|
3
|
+
* operator-owned webhook.
|
|
4
|
+
*
|
|
5
|
+
* What this is: an opt-in outbound notification for drift/health
|
|
6
|
+
* transitions (see drift-transition.ts, embedder-transition.ts) that the
|
|
7
|
+
* operator wants pushed somewhere (Slack relay, PagerDuty, a log sink)
|
|
8
|
+
* instead of only surfacing on the next `nlm start` banner or
|
|
9
|
+
* `GET /api/health` poll.
|
|
10
|
+
*
|
|
11
|
+
* What this is not: telemetry back to an NLM-owned server. Nothing
|
|
12
|
+
* fires unless the operator sets NLM_ALERT_WEBHOOK themselves, and the
|
|
13
|
+
* payload never leaves the process until then.
|
|
14
|
+
*
|
|
15
|
+
* Contract: skip silently (zero network calls) when NLM_ALERT_WEBHOOK is
|
|
16
|
+
* unset. Otherwise POST with a 5s timeout, one retry on failure, and
|
|
17
|
+
* never throw — a webhook outage must never take the daemon down.
|
|
18
|
+
*/
|
|
19
|
+
import { randomUUID } from "node:crypto";
|
|
20
|
+
const TIMEOUT_MS = 5_000;
|
|
21
|
+
const SOURCE = "nlm-memory";
|
|
22
|
+
export async function fireAlert(event, deps = {}) {
|
|
23
|
+
const url = process.env["NLM_ALERT_WEBHOOK"];
|
|
24
|
+
if (!url)
|
|
25
|
+
return;
|
|
26
|
+
const now = deps.now ?? (() => new Date());
|
|
27
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
28
|
+
const envelope = {
|
|
29
|
+
specversion: "1.0",
|
|
30
|
+
id: randomUUID(),
|
|
31
|
+
source: SOURCE,
|
|
32
|
+
type: event.type,
|
|
33
|
+
time: now().toISOString(),
|
|
34
|
+
datacontenttype: "application/json",
|
|
35
|
+
data: event.data,
|
|
36
|
+
};
|
|
37
|
+
const ok = await attemptPost(url, envelope, fetchImpl);
|
|
38
|
+
if (!ok) {
|
|
39
|
+
// Single retry on the first failure (network error, timeout, or
|
|
40
|
+
// non-2xx) — best-effort delivery, no third attempt.
|
|
41
|
+
await attemptPost(url, envelope, fetchImpl);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function attemptPost(url, envelope, fetchImpl) {
|
|
45
|
+
const controller = new AbortController();
|
|
46
|
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
47
|
+
try {
|
|
48
|
+
const token = process.env["NLM_ALERT_WEBHOOK_TOKEN"];
|
|
49
|
+
const headers = {
|
|
50
|
+
"content-type": "application/cloudevents+json",
|
|
51
|
+
};
|
|
52
|
+
if (token)
|
|
53
|
+
headers["authorization"] = `Bearer ${token}`;
|
|
54
|
+
const r = await fetchImpl(url, {
|
|
55
|
+
method: "POST",
|
|
56
|
+
headers,
|
|
57
|
+
body: JSON.stringify(envelope),
|
|
58
|
+
signal: controller.signal,
|
|
59
|
+
});
|
|
60
|
+
return r.ok;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Network failure, abort-on-timeout, or a thrown Response error —
|
|
64
|
+
// alert delivery is best-effort, so the caller decides whether to
|
|
65
|
+
// retry rather than propagating this up.
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
clearTimeout(timer);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=fire-alert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fire-alert.js","sourceRoot":"","sources":["../../../src/core/alerts/fire-alert.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,MAAM,UAAU,GAAG,KAAK,CAAC;AACzB,MAAM,MAAM,GAAG,YAAY,CAAC;AAO5B,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,KAAiB,EACjB,OAAsB,EAAE;IAExB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAC7C,IAAI,CAAC,GAAG;QAAE,OAAO;IAEjB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;IAC1C,MAAM,QAAQ,GAAG;QACf,WAAW,EAAE,KAAK;QAClB,EAAE,EAAE,UAAU,EAAE;QAChB,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI,EAAE,GAAG,EAAE,CAAC,WAAW,EAAE;QACzB,eAAe,EAAE,kBAAkB;QACnC,IAAI,EAAE,KAAK,CAAC,IAAI;KACjB,CAAC;IAEF,MAAM,EAAE,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IACvD,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,gEAAgE;QAChE,qDAAqD;QACrD,MAAM,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,GAAW,EACX,QAAiC,EACjC,SAAuB;IAEvB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,UAAU,CAAC,CAAC;IAC/D,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QACrD,MAAM,OAAO,GAA2B;YACtC,cAAc,EAAE,8BAA8B;SAC/C,CAAC;QACF,IAAI,KAAK;YAAE,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,KAAK,EAAE,CAAC;QACxD,MAAM,CAAC,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;YAC7B,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;YAC9B,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,OAAO,CAAC,CAAC,EAAE,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,kEAAkE;QAClE,kEAAkE;QAClE,yCAAyC;QACzC,OAAO,KAAK,CAAC;IACf,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the `nlm.job.stalled` AlertEvent from a JobSupervisor event
|
|
3
|
+
* (core/jobs/job-supervisor.ts). Pure — no fs/network, no debounce state
|
|
4
|
+
* (unlike drift-transition.ts / embedder-transition.ts): JobSupervisor
|
|
5
|
+
* already only emits one event per stalled/exhausted/spawn_failed episode,
|
|
6
|
+
* so every event maps 1:1 to a fired alert. The daemon composition
|
|
7
|
+
* root wires JobSupervisor's `onEvent` straight to
|
|
8
|
+
* `fireAlert(buildJobAlertEvent(event))`.
|
|
9
|
+
*/
|
|
10
|
+
import type { JobSupervisorEvent } from "../jobs/job-supervisor.js";
|
|
11
|
+
import type { JobAlertEvent } from "./types.js";
|
|
12
|
+
export declare function buildJobAlertEvent(event: JobSupervisorEvent): JobAlertEvent;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the `nlm.job.stalled` AlertEvent from a JobSupervisor event
|
|
3
|
+
* (core/jobs/job-supervisor.ts). Pure — no fs/network, no debounce state
|
|
4
|
+
* (unlike drift-transition.ts / embedder-transition.ts): JobSupervisor
|
|
5
|
+
* already only emits one event per stalled/exhausted/spawn_failed episode,
|
|
6
|
+
* so every event maps 1:1 to a fired alert. The daemon composition
|
|
7
|
+
* root wires JobSupervisor's `onEvent` straight to
|
|
8
|
+
* `fireAlert(buildJobAlertEvent(event))`.
|
|
9
|
+
*/
|
|
10
|
+
export function buildJobAlertEvent(event) {
|
|
11
|
+
// `restarts` at "exhausted" is the number of respawns that actually
|
|
12
|
+
// happened before the cap refused the next one — not restarts still
|
|
13
|
+
// ahead. Spelling that out in prose here is the fix for a reviewer
|
|
14
|
+
// misreading "restarts: 3" as "3 more restarts about to happen".
|
|
15
|
+
const message = event.kind === "exhausted"
|
|
16
|
+
? `${event.job} gave up after ${event.restarts} fruitless restart${event.restarts === 1 ? "" : "s"} ` +
|
|
17
|
+
`(${event.processed}/${event.total} processed)`
|
|
18
|
+
: event.kind === "spawn_failed"
|
|
19
|
+
? `${event.job} failed to start — the child process itself would not spawn ` +
|
|
20
|
+
`(${event.processed}/${event.total} processed, ${event.restarts} prior restarts)`
|
|
21
|
+
: `${event.job} stalled — no progress since ${event.lastAdvanceAt ?? "start"} ` +
|
|
22
|
+
`(${event.processed}/${event.total} processed)`;
|
|
23
|
+
return {
|
|
24
|
+
type: "nlm.job.stalled",
|
|
25
|
+
data: {
|
|
26
|
+
job: event.job,
|
|
27
|
+
reason: event.kind,
|
|
28
|
+
processed: event.processed,
|
|
29
|
+
total: event.total,
|
|
30
|
+
restarts: event.restarts,
|
|
31
|
+
restartsTotal: event.restartsTotal,
|
|
32
|
+
lastAdvanceAt: event.lastAdvanceAt,
|
|
33
|
+
message,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=job-alert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job-alert.js","sourceRoot":"","sources":["../../../src/core/alerts/job-alert.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,MAAM,UAAU,kBAAkB,CAAC,KAAyB;IAC1D,oEAAoE;IACpE,oEAAoE;IACpE,mEAAmE;IACnE,iEAAiE;IACjE,MAAM,OAAO,GACX,KAAK,CAAC,IAAI,KAAK,WAAW;QACxB,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,kBAAkB,KAAK,CAAC,QAAQ,qBAAqB,KAAK,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG;YACnG,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,aAAa;QACjD,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,cAAc;YAC7B,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,8DAA8D;gBAC1E,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,eAAe,KAAK,CAAC,QAAQ,kBAAkB;YACnF,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,gCAAgC,KAAK,CAAC,aAAa,IAAI,OAAO,GAAG;gBAC7E,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,KAAK,aAAa,CAAC;IAExD,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,IAAI,EAAE;YACJ,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,MAAM,EAAE,KAAK,CAAC,IAAI;YAClB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,OAAO;SACR;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alert event shapes for NLM_ALERT_WEBHOOK daemon self-reporting.
|
|
3
|
+
*
|
|
4
|
+
* Field naming follows the CloudEvents 1.0 attribute set (specversion,
|
|
5
|
+
* id, source, type, time, data) so a receiving webhook can decode the
|
|
6
|
+
* envelope with an off-the-shelf CloudEvents SDK instead of a bespoke
|
|
7
|
+
* NLM schema. `fireAlert` (see fire-alert.ts) builds the envelope; this
|
|
8
|
+
* file only defines the event-specific `data` payload callers construct.
|
|
9
|
+
*/
|
|
10
|
+
export type AlertEventType = "nlm.drift.version_behind" | "nlm.health.embedder_cold" | "nlm.job.stalled" | "nlm.wiki.projection_failed" | "nlm.wiki.coverage_drift";
|
|
11
|
+
/**
|
|
12
|
+
* Generic across both transition-based event types: `current` is the
|
|
13
|
+
* observed value, `latest` is the target/expected value, `since` is the
|
|
14
|
+
* ISO timestamp the current state began holding. For version drift that's
|
|
15
|
+
* the installed vs. npm-latest version; for embedder health it's the
|
|
16
|
+
* degraded ("cold") vs. healthy ("ready") state label.
|
|
17
|
+
*/
|
|
18
|
+
export interface AlertEventData {
|
|
19
|
+
readonly current: string;
|
|
20
|
+
readonly latest: string;
|
|
21
|
+
readonly since: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* `nlm.job.stalled` payload — built by core/alerts/job-alert.ts from a
|
|
25
|
+
* JobSupervisor event (core/jobs/job-supervisor.ts). Unlike the two
|
|
26
|
+
* transition-based events above there's no debounce state: JobSupervisor
|
|
27
|
+
* itself only emits "stalled"/"exhausted"/"spawn_failed" once per episode,
|
|
28
|
+
* so every JobSupervisorEvent maps 1:1 to a fired alert.
|
|
29
|
+
*
|
|
30
|
+
* `restarts` is the restarts-without-progress counter AT the moment of
|
|
31
|
+
* firing — for an "exhausted" event this is the number of respawns that
|
|
32
|
+
* actually happened (it is always exactly the configured cap, e.g. 3), not
|
|
33
|
+
* a count of restarts still to come, and not the cap plus the refused final
|
|
34
|
+
* attempt. `message` spells this out in prose so a receiving Slack
|
|
35
|
+
* relay/PagerDuty rule can't misread the number as restarts remaining.
|
|
36
|
+
*
|
|
37
|
+
* `restartsTotal` is the run's lifetime respawn count (never reset by
|
|
38
|
+
* progress, unlike `restarts`) — see job-supervisor.ts's file-level doc.
|
|
39
|
+
* It surfaces OOM-churn on a run that keeps making progress between
|
|
40
|
+
* crashes, where `restarts` alone would read 0.
|
|
41
|
+
*
|
|
42
|
+
* `reason: "spawn_failed"` covers the case where `spawnChild` itself threw
|
|
43
|
+
* synchronously (EMFILE/ENOMEM/bad binary) instead of the child ever
|
|
44
|
+
* running — distinct from "exhausted" (ran, kept dying, used up its
|
|
45
|
+
* restart budget) so an operator isn't left guessing why a job never
|
|
46
|
+
* produced a single progress line.
|
|
47
|
+
*/
|
|
48
|
+
export interface JobAlertEventData {
|
|
49
|
+
readonly job: "reprocess";
|
|
50
|
+
readonly reason: "stalled" | "exhausted" | "spawn_failed";
|
|
51
|
+
readonly processed: number;
|
|
52
|
+
readonly total: number;
|
|
53
|
+
readonly restarts: number;
|
|
54
|
+
readonly restartsTotal: number;
|
|
55
|
+
readonly lastAdvanceAt: string | null;
|
|
56
|
+
readonly message: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Wiki projection self-report. `drift` is qualifying-subjects minus
|
|
60
|
+
* pages-on-disk after a run: positive means pages the corpus earned are
|
|
61
|
+
* missing, negative means stale pages survived removal. Either direction
|
|
62
|
+
* means the run did not fully apply, so both fire.
|
|
63
|
+
*/
|
|
64
|
+
export interface WikiAlertEventData {
|
|
65
|
+
readonly reason: "projection_failed" | "coverage_drift";
|
|
66
|
+
readonly qualifying: number;
|
|
67
|
+
readonly onDisk: number;
|
|
68
|
+
readonly drift: number;
|
|
69
|
+
readonly message: string;
|
|
70
|
+
}
|
|
71
|
+
export type AlertEvent = {
|
|
72
|
+
readonly type: "nlm.drift.version_behind";
|
|
73
|
+
readonly data: AlertEventData;
|
|
74
|
+
} | {
|
|
75
|
+
readonly type: "nlm.health.embedder_cold";
|
|
76
|
+
readonly data: AlertEventData;
|
|
77
|
+
} | {
|
|
78
|
+
readonly type: "nlm.job.stalled";
|
|
79
|
+
readonly data: JobAlertEventData;
|
|
80
|
+
} | {
|
|
81
|
+
readonly type: "nlm.wiki.projection_failed";
|
|
82
|
+
readonly data: WikiAlertEventData;
|
|
83
|
+
} | {
|
|
84
|
+
readonly type: "nlm.wiki.coverage_drift";
|
|
85
|
+
readonly data: WikiAlertEventData;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Per-producer narrowings of `AlertEvent`. Each transition/builder module
|
|
89
|
+
* only ever constructs one union member, but declaring its return type as
|
|
90
|
+
* the full `AlertEvent` erases the discriminant for callers (including
|
|
91
|
+
* tests) that don't re-narrow via a type guard — `event.type` checked
|
|
92
|
+
* through `expect()` doesn't narrow `event.data`. Producers should return
|
|
93
|
+
* these instead; `fireAlert` still accepts any of them since each is a
|
|
94
|
+
* subtype of `AlertEvent`.
|
|
95
|
+
*/
|
|
96
|
+
export type DriftAlertEvent = Extract<AlertEvent, {
|
|
97
|
+
type: "nlm.drift.version_behind";
|
|
98
|
+
}>;
|
|
99
|
+
export type EmbedderAlertEvent = Extract<AlertEvent, {
|
|
100
|
+
type: "nlm.health.embedder_cold";
|
|
101
|
+
}>;
|
|
102
|
+
export type JobAlertEvent = Extract<AlertEvent, {
|
|
103
|
+
type: "nlm.job.stalled";
|
|
104
|
+
}>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alert event shapes for NLM_ALERT_WEBHOOK daemon self-reporting.
|
|
3
|
+
*
|
|
4
|
+
* Field naming follows the CloudEvents 1.0 attribute set (specversion,
|
|
5
|
+
* id, source, type, time, data) so a receiving webhook can decode the
|
|
6
|
+
* envelope with an off-the-shelf CloudEvents SDK instead of a bespoke
|
|
7
|
+
* NLM schema. `fireAlert` (see fire-alert.ts) builds the envelope; this
|
|
8
|
+
* file only defines the event-specific `data` payload callers construct.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/alerts/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wiki projection alert builders.
|
|
3
|
+
*
|
|
4
|
+
* Return types are Extract<> narrowings rather than the bare AlertEvent union
|
|
5
|
+
* so callers and tests keep the discriminant, matching the convention the
|
|
6
|
+
* other producers in this directory follow.
|
|
7
|
+
*/
|
|
8
|
+
import type { AlertEvent } from "./types.js";
|
|
9
|
+
import type { ProjectionResult } from "../wiki/types.js";
|
|
10
|
+
export declare function buildWikiFailureEvent(error: unknown): Extract<AlertEvent, {
|
|
11
|
+
type: "nlm.wiki.projection_failed";
|
|
12
|
+
}>;
|
|
13
|
+
export declare function buildWikiDriftEvent(result: ProjectionResult): Extract<AlertEvent, {
|
|
14
|
+
type: "nlm.wiki.coverage_drift";
|
|
15
|
+
}> | null;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export function buildWikiFailureEvent(error) {
|
|
2
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
3
|
+
return {
|
|
4
|
+
type: "nlm.wiki.projection_failed",
|
|
5
|
+
data: {
|
|
6
|
+
reason: "projection_failed",
|
|
7
|
+
qualifying: 0,
|
|
8
|
+
onDisk: 0,
|
|
9
|
+
drift: 0,
|
|
10
|
+
message: `wiki projection failed and the previous tree was left untouched: ${detail}`,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export function buildWikiDriftEvent(result) {
|
|
15
|
+
if (result.coverageDrift === 0)
|
|
16
|
+
return null;
|
|
17
|
+
const direction = result.coverageDrift > 0
|
|
18
|
+
? `${result.coverageDrift} page(s) the corpus earned are missing from disk`
|
|
19
|
+
: `${-result.coverageDrift} stale page(s) survived removal`;
|
|
20
|
+
return {
|
|
21
|
+
type: "nlm.wiki.coverage_drift",
|
|
22
|
+
data: {
|
|
23
|
+
reason: "coverage_drift",
|
|
24
|
+
qualifying: result.qualifying,
|
|
25
|
+
onDisk: result.onDisk,
|
|
26
|
+
drift: result.coverageDrift,
|
|
27
|
+
message: `wiki coverage drift: ${direction} (${result.qualifying} qualifying, ${result.onDisk} on disk)`,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=wiki-alert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiki-alert.js","sourceRoot":"","sources":["../../../src/core/alerts/wiki-alert.ts"],"names":[],"mappings":"AAUA,MAAM,UAAU,qBAAqB,CACnC,KAAc;IAEd,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtE,OAAO;QACL,IAAI,EAAE,4BAA4B;QAClC,IAAI,EAAE;YACJ,MAAM,EAAE,mBAAmB;YAC3B,UAAU,EAAE,CAAC;YACb,MAAM,EAAE,CAAC;YACT,KAAK,EAAE,CAAC;YACR,OAAO,EAAE,oEAAoE,MAAM,EAAE;SACtF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,MAAwB;IAExB,IAAI,MAAM,CAAC,aAAa,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,MAAM,SAAS,GACb,MAAM,CAAC,aAAa,GAAG,CAAC;QACtB,CAAC,CAAC,GAAG,MAAM,CAAC,aAAa,kDAAkD;QAC3E,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,iCAAiC,CAAC;IAChE,OAAO;QACL,IAAI,EAAE,yBAAyB;QAC/B,IAAI,EAAE;YACJ,MAAM,EAAE,gBAAgB;YACxB,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,KAAK,EAAE,MAAM,CAAC,aAAa;YAC3B,OAAO,EAAE,wBAAwB,SAAS,KAAK,MAAM,CAAC,UAAU,gBAAgB,MAAM,CAAC,MAAM,WAAW;SACzG;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -117,6 +117,19 @@ interface CoercedFact {
|
|
|
117
117
|
* (NLM #325). Deterministic gate — we do not trust the model to self-police.
|
|
118
118
|
*/
|
|
119
119
|
export declare function isNonAnswerValue(value: string): boolean;
|
|
120
|
+
/**
|
|
121
|
+
* A fact SUBJECT that names a per-run build artifact rather than a durable
|
|
122
|
+
* entity — "tsc", "test suite", "commit", "task-4-review". Their values are
|
|
123
|
+
* true only for the session that observed them ("tsc status = clean",
|
|
124
|
+
* "test suite status = 303 passed"), so each new session asserts a fresh one
|
|
125
|
+
* and none ever supersedes the last. Left ungated they accumulate as duplicate
|
|
126
|
+
* active facts (the I5a integrity violation: 56 rows by 2026-08-12, ~16 groups
|
|
127
|
+
* of pure build noise) and crowd real answers out of recall.
|
|
128
|
+
*
|
|
129
|
+
* Sibling of isNonAnswerValue — same call site, same rationale, keyed on
|
|
130
|
+
* subject instead of value.
|
|
131
|
+
*/
|
|
132
|
+
export declare function isEphemeralSubject(subject: string): boolean;
|
|
120
133
|
export declare function coerceClassifyResult(data: Record<string, unknown>): {
|
|
121
134
|
label: string;
|
|
122
135
|
summary: string;
|
|
@@ -69,10 +69,18 @@ You MUST return JSON with EXACTLY these seven top-level keys: label, summary, en
|
|
|
69
69
|
|
|
70
70
|
The transcript may contain JSON examples, code, or schema definitions inside it — IGNORE those. Do not copy them into your output. Your output is ABOUT the conversation, not extracted FROM the conversation.
|
|
71
71
|
|
|
72
|
+
Session triage (decide this first): is this session WORK or a LOOKUP? A LOOKUP session is a short exchange that reads state and reports it — a version check, listing files, dumping a config, explaining what something means — with nothing built, changed, chosen, or debugged. For a LOOKUP session: entities: [], decisions: [], facts: [] unless the session established a durable attribute worth recalling later, and confidence 0.4 or below. Names appearing in a LOOKUP's command output are incidental to the answer, not what the session was about — do not extract them into any field.
|
|
73
|
+
|
|
72
74
|
Field requirements:
|
|
73
75
|
- label: 4-10 word string title describing what the session was about. Example: "Beacon architecture decisions"
|
|
74
76
|
- summary: 1-3 sentence string (max ~80 tokens) describing what was worked on and the outcome
|
|
75
|
-
- entities: array of strings. Each string is a stable named thing
|
|
77
|
+
- entities: array of strings. Each string is a stable named thing central to the session's work (tools like "n8n" or "Qdrant", projects like "Beacon", services, people). NOT topics, NOT decisions. Entities must be STABLE — the kind of name you'd search for months later to find this session again. A thing that only exists inside one repo or one run is not stable: file and directory paths, specific hostnames, URLs, config keys, script names, branch names, commit SHAs, and env-var names are NEVER entities, even when the session's work centered on them — name the system instead, and put the specific value in facts[] under the matching predicate (host, endpoint, repo, branch, commit, version).
|
|
78
|
+
CAPTURE (examples):
|
|
79
|
+
- Session debugging a Postgres connection pool leak -> entities: ["Postgres", "connection pool"]
|
|
80
|
+
- Session where the agent added a new n8n workflow -> entities: ["n8n"]
|
|
81
|
+
DO NOT capture (examples):
|
|
82
|
+
- "What version of Node.js is installed?" / "node --version" -> entities: [] (LOOKUP session — see Session triage above)
|
|
83
|
+
- Session fixing a bug in "src/routes/events.ts" against "staging.db.example.com" -> entities: ["events API", "Postgres"] (the path and hostname go in facts[], not here)
|
|
76
84
|
- decisions: array of strings. Each string is ONE decision that changed what was built or done in this session. A decision counts if the user chose it, OR the agent proposed it and the user accepted — explicitly ("yes", "do it", "go with that") or implicitly (the agent stated the proposal and then proceeded under it with no user objection). Implicit acceptance applies ONLY to proposals that changed the direction of the work — never to the agent's routine implementation choices (helper names, file layout, minor refactors) that were never surfaced as a choice. Capture the decision AND its reason when given ("X instead of Y because Z"). Do NOT include: options discussed but not chosen, approaches considered and rejected, next-step suggestions the agent raised at the end that the user never acted on, or decisions already listed in PRIOR CONTEXT unless they were reversed this session. Scan the WHOLE transcript, including the middle, for decision signals such as (not only): "let's", "go with", "instead of", "switch to", "actually,", "agreed", and any point where one approach was abandoned and replaced. Return [] if no commitments were made.
|
|
77
85
|
CAPTURE (examples):
|
|
78
86
|
- "Use HTTP polling instead of Kafka for the event pipeline (lower ops overhead)" [user choice]
|
|
@@ -84,7 +92,7 @@ Field requirements:
|
|
|
84
92
|
- At the end the agent suggested "we could add rate limiting next" and the user didn't respond [unratified next-step]
|
|
85
93
|
- The agent picked a helper-function name and file layout without asking [routine implementation, not a decision]
|
|
86
94
|
- open: array of strings. Each string is one unresolved question. Skip if none.
|
|
87
|
-
- confidence: number between 0.0 and 1.0. How sure you are the extraction is good.
|
|
95
|
+
- confidence: number between 0.0 and 1.0. How sure you are the extraction is good. See Session triage above for the LOOKUP-session threshold.
|
|
88
96
|
- facts: array of objects. Each object has exactly these keys: kind, subject, predicate, value, sourceQuote (optional).
|
|
89
97
|
- kind: "decision" (a commitment) | "open" (an unresolved question) | "attribute" (a property of an entity)
|
|
90
98
|
- subject: lowercase, hyphenated entity or topic name. Examples: "nlm-memory-ts", "local-llm-host", "acme-client"
|
|
@@ -189,6 +197,44 @@ export function isNonAnswerValue(value) {
|
|
|
189
197
|
return true;
|
|
190
198
|
return NON_ANSWER_SUBSTRINGS.some((p) => v.includes(p));
|
|
191
199
|
}
|
|
200
|
+
const EPHEMERAL_SUBJECTS = new Set([
|
|
201
|
+
"tsc",
|
|
202
|
+
"typecheck",
|
|
203
|
+
"test suite",
|
|
204
|
+
"tests",
|
|
205
|
+
"test-result",
|
|
206
|
+
"test-results",
|
|
207
|
+
"npm test",
|
|
208
|
+
"commit",
|
|
209
|
+
"commit-sha",
|
|
210
|
+
"main",
|
|
211
|
+
"security-review",
|
|
212
|
+
"code-quality",
|
|
213
|
+
]);
|
|
214
|
+
// A numbered work item from one plan — "task-4", "task-3.1", "task-12b",
|
|
215
|
+
// "task-8-task-quality", "task-2-brief.md". The number is only meaningful
|
|
216
|
+
// inside the plan that issued it, so every plan mints a fresh colliding set.
|
|
217
|
+
// Requiring a digit right after "task-" keeps durable subjects that merely
|
|
218
|
+
// start with the word ("task-tracking", "taskwarrior") out of the gate.
|
|
219
|
+
const EPHEMERAL_SUBJECT_PATTERNS = [/^task-\d/];
|
|
220
|
+
/**
|
|
221
|
+
* A fact SUBJECT that names a per-run build artifact rather than a durable
|
|
222
|
+
* entity — "tsc", "test suite", "commit", "task-4-review". Their values are
|
|
223
|
+
* true only for the session that observed them ("tsc status = clean",
|
|
224
|
+
* "test suite status = 303 passed"), so each new session asserts a fresh one
|
|
225
|
+
* and none ever supersedes the last. Left ungated they accumulate as duplicate
|
|
226
|
+
* active facts (the I5a integrity violation: 56 rows by 2026-08-12, ~16 groups
|
|
227
|
+
* of pure build noise) and crowd real answers out of recall.
|
|
228
|
+
*
|
|
229
|
+
* Sibling of isNonAnswerValue — same call site, same rationale, keyed on
|
|
230
|
+
* subject instead of value.
|
|
231
|
+
*/
|
|
232
|
+
export function isEphemeralSubject(subject) {
|
|
233
|
+
const s = subject.trim().toLowerCase();
|
|
234
|
+
if (EPHEMERAL_SUBJECTS.has(s))
|
|
235
|
+
return true;
|
|
236
|
+
return EPHEMERAL_SUBJECT_PATTERNS.some((p) => p.test(s));
|
|
237
|
+
}
|
|
192
238
|
function coerceFacts(raw) {
|
|
193
239
|
if (!Array.isArray(raw))
|
|
194
240
|
return [];
|
|
@@ -209,6 +255,10 @@ function coerceFacts(raw) {
|
|
|
209
255
|
// not knowledge, and pollute recall at high confidence (NLM #325).
|
|
210
256
|
if (isNonAnswerValue(value))
|
|
211
257
|
continue;
|
|
258
|
+
// Drop per-run build artifacts — durable-looking subjects whose value is
|
|
259
|
+
// only true for one session, so they never supersede and pile up (I5a).
|
|
260
|
+
if (isEphemeralSubject(subject))
|
|
261
|
+
continue;
|
|
212
262
|
// Closed vocab — drop the fact entirely if the predicate isn't recognized.
|
|
213
263
|
// Pilot data (Phase B.5) showed `other` was 43% of writes and almost all
|
|
214
264
|
// slop; the prompt now instructs the model to leave such observations in
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../../src/core/classifier/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,WAAW;IACX,UAAU;IACV,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;IACP,SAAS;IACT,MAAM;IACN,UAAU;IACV,QAAQ;IACR,OAAO;IACP,SAAS;IACT,SAAS;IACT,SAAS;IACT,YAAY;IACZ,QAAQ;IACR,aAAa;IACb,YAAY;IACZ,MAAM;IACN,QAAQ;IACR,QAAQ;IACR,aAAa;IACb,YAAY;IACZ,YAAY;IACZ,SAAS;CACD,CAAC;AAEX,MAAM,SAAS,GAAG,IAAI,GAAG,CAAS,oBAAoB,CAAC,CAAC;AAExD,MAAM,CAAC,MAAM,wBAAwB,GAAG
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../../src/core/classifier/prompt.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,21 @@
|
|
|
6
6
|
* alerts, snoozed entities, retired labels, merged variants) are deferred:
|
|
7
7
|
* the action log isn't yet exposed by the TS daemon. Returns persisted
|
|
8
8
|
* state directly.
|
|
9
|
+
*
|
|
10
|
+
* Tenancy (program spec §4.6 hardening 1, M2 plan Wave B6): `buildDataset`
|
|
11
|
+
* takes `tenantId` and constrains every table read — direct WHERE via
|
|
12
|
+
* `tenantClause` for the STAMP tables (`sessions`, `entities`), a join back
|
|
13
|
+
* to the tenant-filtered session id set for the DERIVE tables
|
|
14
|
+
* (`session_entities`, `markers`, `session_edges`), and the same
|
|
15
|
+
* subject-resolvability predicate as `actions-log.ts` for the action
|
|
16
|
+
* overlay — even though the `GET /api/dataset` route itself is
|
|
17
|
+
* LOCAL-dispositioned and 403s in hosted mode (Wave C's hosted-mode gate).
|
|
18
|
+
* This is defense-in-depth: the guard test scans this file's SQL
|
|
19
|
+
* regardless of the route's gate, and a future caller that reuses this
|
|
20
|
+
* function outside the gated route stays safe by construction.
|
|
21
|
+
* `computeIntegrityAlerts` (below) is the one exception, documented at its
|
|
22
|
+
* call site — it stays whole-DB, matching the `sqliteDataStats` treatment
|
|
23
|
+
* of migration/structural bookkeeping.
|
|
9
24
|
*/
|
|
10
25
|
import type { SessionStatus } from "../../shared/types.js";
|
|
11
26
|
export interface DatasetSession {
|
|
@@ -109,5 +124,5 @@ export interface BuildDatasetOptions {
|
|
|
109
124
|
* Default false — they pollute the catalog without adding signal. */
|
|
110
125
|
readonly includePaths?: boolean;
|
|
111
126
|
}
|
|
112
|
-
export declare function buildDataset(dbPath: string, options?: BuildDatasetOptions): DatasetResponse;
|
|
127
|
+
export declare function buildDataset(dbPath: string, tenantId: string, options?: BuildDatasetOptions): DatasetResponse;
|
|
113
128
|
export declare function isPathShapedEntity(canonical: string): boolean;
|