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,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Learner summary derivation — port of the Gnos deterministic summary rule
|
|
3
|
+
* (`skills/learner-tracking/references/evidence.md`, MIT, attribution kept).
|
|
4
|
+
*
|
|
5
|
+
* Per concept, from events in `listEvents` order ((date, id) ascending):
|
|
6
|
+
*
|
|
7
|
+
* - covered, never attempted: **exposed**
|
|
8
|
+
* - latest attempt assisted, partial, or incorrect: **practicing**
|
|
9
|
+
* - latest attempt correct + unassisted: **demonstrated**
|
|
10
|
+
* - latest success is retrieval/transfer on a strictly later date than an
|
|
11
|
+
* earlier unassisted success: **retained**
|
|
12
|
+
*
|
|
13
|
+
* Latest failure demotes back to practicing; earlier evidence is preserved in
|
|
14
|
+
* the events, not in the label. These are workflow labels, not calibrated
|
|
15
|
+
* scores — the summary never issues "mastered".
|
|
16
|
+
*/
|
|
17
|
+
function isUnassistedSuccess(a) {
|
|
18
|
+
return a.result === "correct" && a.help === "none";
|
|
19
|
+
}
|
|
20
|
+
export function summarizeConcepts(events) {
|
|
21
|
+
const coveredOn = new Map();
|
|
22
|
+
const attemptsByConcept = new Map();
|
|
23
|
+
for (const event of events) {
|
|
24
|
+
for (const concept of event.covered)
|
|
25
|
+
coveredOn.set(concept, event.date);
|
|
26
|
+
for (const attempt of event.attempts) {
|
|
27
|
+
let list = attemptsByConcept.get(attempt.concept);
|
|
28
|
+
if (!list) {
|
|
29
|
+
list = [];
|
|
30
|
+
attemptsByConcept.set(attempt.concept, list);
|
|
31
|
+
}
|
|
32
|
+
list.push({ attempt, date: event.date });
|
|
33
|
+
if (!coveredOn.has(attempt.concept))
|
|
34
|
+
coveredOn.set(attempt.concept, event.date);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const concepts = [...new Set([...coveredOn.keys(), ...attemptsByConcept.keys()])].sort();
|
|
38
|
+
return concepts.map((concept) => {
|
|
39
|
+
const attempts = attemptsByConcept.get(concept) ?? [];
|
|
40
|
+
if (attempts.length === 0) {
|
|
41
|
+
return {
|
|
42
|
+
concept,
|
|
43
|
+
status: "exposed",
|
|
44
|
+
attemptCount: 0,
|
|
45
|
+
latestDate: coveredOn.get(concept) ?? null,
|
|
46
|
+
latestTask: null,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const latest = attempts[attempts.length - 1];
|
|
50
|
+
let status;
|
|
51
|
+
if (!isUnassistedSuccess(latest.attempt)) {
|
|
52
|
+
status = "practicing";
|
|
53
|
+
}
|
|
54
|
+
else if ((latest.attempt.kind === "retrieval" || latest.attempt.kind === "transfer") &&
|
|
55
|
+
attempts.some((a) => a.date < latest.date && isUnassistedSuccess(a.attempt))) {
|
|
56
|
+
status = "retained";
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
status = "demonstrated";
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
concept,
|
|
63
|
+
status,
|
|
64
|
+
attemptCount: attempts.length,
|
|
65
|
+
latestDate: latest.date,
|
|
66
|
+
latestTask: latest.attempt.task,
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../../../src/core/learner/summary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Learner evidence validation — port of the Gnos evidence contract
|
|
3
|
+
* (`skills/learner-tracking/scripts/learner_state.py`, MIT, attribution kept).
|
|
4
|
+
*
|
|
5
|
+
* Shape rules only: slug/concept formats, required fields, enum membership,
|
|
6
|
+
* real calendar dates that are never in the future. Cross-row rules
|
|
7
|
+
* (fingerprint match, idempotent retry) live in the store; orchestration in
|
|
8
|
+
* service.ts. All failures throw `Error`; the MCP layer (M3) maps them to
|
|
9
|
+
* tool errors.
|
|
10
|
+
*/
|
|
11
|
+
import type { EnrollmentInput, LearnerInit, LearningEventInput } from "../../ports/learner-store.js";
|
|
12
|
+
export declare function assertValidSlug(value: unknown, label: string): asserts value is string;
|
|
13
|
+
export declare function assertValidConceptId(value: unknown): asserts value is string;
|
|
14
|
+
export declare function assertNonempty(value: unknown, label: string): asserts value is string;
|
|
15
|
+
export declare function assertValidDate(value: unknown, label?: string): asserts value is string;
|
|
16
|
+
export declare function assertValidLearnerInit(input: LearnerInit): void;
|
|
17
|
+
export declare function assertValidEnrollmentInput(input: EnrollmentInput): void;
|
|
18
|
+
export declare function assertValidEventInput(event: LearningEventInput): void;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Learner evidence validation — port of the Gnos evidence contract
|
|
3
|
+
* (`skills/learner-tracking/scripts/learner_state.py`, MIT, attribution kept).
|
|
4
|
+
*
|
|
5
|
+
* Shape rules only: slug/concept formats, required fields, enum membership,
|
|
6
|
+
* real calendar dates that are never in the future. Cross-row rules
|
|
7
|
+
* (fingerprint match, idempotent retry) live in the store; orchestration in
|
|
8
|
+
* service.ts. All failures throw `Error`; the MCP layer (M3) maps them to
|
|
9
|
+
* tool errors.
|
|
10
|
+
*/
|
|
11
|
+
const SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
12
|
+
const CONCEPT_PATTERN = /^[a-z][a-z0-9-]*\.[a-z0-9]+(?:[.-][a-z0-9]+)*$/;
|
|
13
|
+
const DATE_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
14
|
+
const ATTEMPT_RESULTS = ["correct", "partial", "incorrect"];
|
|
15
|
+
const ATTEMPT_HELPS = ["none", "hint", "worked-example"];
|
|
16
|
+
const ATTEMPT_KINDS = ["application", "retrieval", "transfer"];
|
|
17
|
+
export function assertValidSlug(value, label) {
|
|
18
|
+
if (typeof value !== "string" || value.length > 80 || !SLUG_PATTERN.test(value)) {
|
|
19
|
+
throw new Error(`learner validation: ${label} must be a lowercase slug of at most 80 characters`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function assertValidConceptId(value) {
|
|
23
|
+
if (typeof value !== "string" || !CONCEPT_PATTERN.test(value)) {
|
|
24
|
+
throw new Error(`learner validation: invalid concept ID: ${JSON.stringify(value)}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function assertNonempty(value, label) {
|
|
28
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
29
|
+
throw new Error(`learner validation: ${label} must be nonempty text`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function assertValidDate(value, label = "event.date") {
|
|
33
|
+
if (typeof value !== "string") {
|
|
34
|
+
throw new Error(`learner validation: ${label} must be YYYY-MM-DD`);
|
|
35
|
+
}
|
|
36
|
+
const match = DATE_PATTERN.exec(value);
|
|
37
|
+
if (!match)
|
|
38
|
+
throw new Error(`learner validation: ${label} must be YYYY-MM-DD`);
|
|
39
|
+
const year = Number(match[1]);
|
|
40
|
+
const month = Number(match[2]);
|
|
41
|
+
const day = Number(match[3]);
|
|
42
|
+
const dt = new Date(Date.UTC(year, month - 1, day));
|
|
43
|
+
if (dt.getUTCFullYear() !== year || dt.getUTCMonth() !== month - 1 || dt.getUTCDate() !== day) {
|
|
44
|
+
throw new Error(`learner validation: ${label} is not a real calendar date: ${value}`);
|
|
45
|
+
}
|
|
46
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
47
|
+
if (value > today) {
|
|
48
|
+
throw new Error(`learner validation: ${label} cannot be in the future: ${value}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function assertValidLearnerInit(input) {
|
|
52
|
+
assertValidSlug(input.id, "learner.id");
|
|
53
|
+
assertNonempty(input.label, "learner.label");
|
|
54
|
+
}
|
|
55
|
+
export function assertValidEnrollmentInput(input) {
|
|
56
|
+
assertValidSlug(input.learnerId, "enrollment.learnerId");
|
|
57
|
+
assertValidSlug(input.courseId, "enrollment.courseId");
|
|
58
|
+
assertNonempty(input.workstreamId, "enrollment.workstreamId");
|
|
59
|
+
assertNonempty(input.planRef, "enrollment.planRef");
|
|
60
|
+
assertNonempty(input.planFingerprint, "enrollment.planFingerprint");
|
|
61
|
+
if (!Number.isInteger(input.planRevision) || input.planRevision < 1) {
|
|
62
|
+
throw new Error("learner validation: enrollment.planRevision must be a positive integer");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export function assertValidEventInput(event) {
|
|
66
|
+
assertValidSlug(event.id, "event.id");
|
|
67
|
+
assertValidDate(event.date);
|
|
68
|
+
if (!Array.isArray(event.covered)) {
|
|
69
|
+
throw new Error("learner validation: event.covered must be a list");
|
|
70
|
+
}
|
|
71
|
+
for (const concept of event.covered)
|
|
72
|
+
assertValidConceptId(concept);
|
|
73
|
+
assertNonempty(event.nextStep, "event.nextStep");
|
|
74
|
+
if (typeof event.interpretation !== "string") {
|
|
75
|
+
throw new Error("learner validation: event.interpretation must be text (may be empty)");
|
|
76
|
+
}
|
|
77
|
+
if (!Array.isArray(event.attempts)) {
|
|
78
|
+
throw new Error("learner validation: event.attempts must be a list");
|
|
79
|
+
}
|
|
80
|
+
for (const attempt of event.attempts) {
|
|
81
|
+
assertValidConceptId(attempt.concept);
|
|
82
|
+
assertNonempty(attempt.task, "attempt.task");
|
|
83
|
+
assertNonempty(attempt.response, "attempt.response");
|
|
84
|
+
if (!ATTEMPT_RESULTS.includes(attempt.result)) {
|
|
85
|
+
throw new Error(`learner validation: attempt.result must be one of ${ATTEMPT_RESULTS.join(", ")}`);
|
|
86
|
+
}
|
|
87
|
+
if (!ATTEMPT_HELPS.includes(attempt.help)) {
|
|
88
|
+
throw new Error(`learner validation: attempt.help must be one of ${ATTEMPT_HELPS.join(", ")}`);
|
|
89
|
+
}
|
|
90
|
+
if (!ATTEMPT_KINDS.includes(attempt.kind)) {
|
|
91
|
+
throw new Error(`learner validation: attempt.kind must be one of ${ATTEMPT_KINDS.join(", ")}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/core/learner/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,8 +31,25 @@ export interface ReDerivationPair {
|
|
|
31
31
|
export interface ReDerivationReport {
|
|
32
32
|
readonly rate: number;
|
|
33
33
|
readonly pairs: ReadonlyArray<ReDerivationPair>;
|
|
34
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* Denominator of the legacy pair-space rate: entity-sharing session pairs
|
|
36
|
+
* where BOTH sides carry at least one decision. A pair with a decisionless
|
|
37
|
+
* side cannot be a re-derivation by construction, and counting it inflated
|
|
38
|
+
* this figure roughly 3x - measured 2026-08-04 on the live 90-day window,
|
|
39
|
+
* 1,266,809 of 1,905,497 eligible pairs (66.5%) had a decisionless side.
|
|
40
|
+
*/
|
|
35
41
|
readonly eligible: number;
|
|
42
|
+
/** Sessions in the window carrying at least one decision. Linear in corpus size. */
|
|
43
|
+
readonly decisionBearingSessions: number;
|
|
44
|
+
/** Distinct later-side sessions appearing in `pairs`. Counted once each. */
|
|
45
|
+
readonly reDerivingSessions: number;
|
|
46
|
+
/**
|
|
47
|
+
* reDerivingSessions / decisionBearingSessions. This is the trendable metric:
|
|
48
|
+
* the pair-space `rate` divides by a denominator that grows quadratically with
|
|
49
|
+
* the corpus, so it mechanically falls the more the product is used, which is
|
|
50
|
+
* backwards for a number whose job is to show improvement.
|
|
51
|
+
*/
|
|
52
|
+
readonly sessionRate: number;
|
|
36
53
|
}
|
|
37
54
|
interface SqliteLike {
|
|
38
55
|
prepare(sql: string): {
|
|
@@ -42,7 +59,19 @@ interface SqliteLike {
|
|
|
42
59
|
/**
|
|
43
60
|
* SQLite-backed deps for the CLI readout. Reads sessions started within the
|
|
44
61
|
* window along with their entity links and decision markers, plus all edges.
|
|
62
|
+
* `tenantId` scopes the sessions SELECT via tenantClause — the pairs this
|
|
63
|
+
* produces get persisted to a tenant-derived cache file (see
|
|
64
|
+
* `@core/storage/sqlite-outcome-store.js`), so an un-tenanted scan here would
|
|
65
|
+
* leak every tenant's sessions into whichever tenant's file reads it back.
|
|
45
66
|
*/
|
|
46
|
-
export declare function sqliteReDerivationDeps(db: SqliteLike): ReDerivationDeps;
|
|
67
|
+
export declare function sqliteReDerivationDeps(db: SqliteLike, tenantId: string): ReDerivationDeps;
|
|
68
|
+
/**
|
|
69
|
+
* Parses the on-disk cache the 24h corpus-monitor job writes to
|
|
70
|
+
* (`~/.nlm/re-derivation-pairs.json`, see `src/cli/nlm.ts`) and the SQLite
|
|
71
|
+
* outcome adapters read back (`@core/storage/sqlite-outcome-store.js`).
|
|
72
|
+
* The file is a plain `ReDerivationPair[]` - anything else (corrupt JSON,
|
|
73
|
+
* a non-array shape) is treated as no pairs rather than thrown.
|
|
74
|
+
*/
|
|
75
|
+
export declare function parseReDerivationPairsFile(raw: string): ReadonlyArray<ReDerivationPair>;
|
|
47
76
|
export declare function computeReDerivationRate(deps: ReDerivationDeps, windowDays: number): Promise<ReDerivationReport>;
|
|
48
77
|
export {};
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* entity, sit more than GAP_DAYS apart, have decision text overlapping at or
|
|
8
8
|
* above JACCARD_FLOOR, and have no `continues`/`supersedes` edge linking them.
|
|
9
9
|
*/
|
|
10
|
+
import { tenantClause } from "../tenancy/tenant-clause.js";
|
|
10
11
|
const JACCARD_FLOOR = 0.5;
|
|
11
12
|
const GAP_DAYS = 7;
|
|
12
13
|
const MS_PER_DAY = 86_400_000;
|
|
@@ -28,16 +29,21 @@ function jaccard(a, b) {
|
|
|
28
29
|
/**
|
|
29
30
|
* SQLite-backed deps for the CLI readout. Reads sessions started within the
|
|
30
31
|
* window along with their entity links and decision markers, plus all edges.
|
|
32
|
+
* `tenantId` scopes the sessions SELECT via tenantClause — the pairs this
|
|
33
|
+
* produces get persisted to a tenant-derived cache file (see
|
|
34
|
+
* `@core/storage/sqlite-outcome-store.js`), so an un-tenanted scan here would
|
|
35
|
+
* leak every tenant's sessions into whichever tenant's file reads it back.
|
|
31
36
|
*/
|
|
32
|
-
export function sqliteReDerivationDeps(db) {
|
|
37
|
+
export function sqliteReDerivationDeps(db, tenantId) {
|
|
38
|
+
const tc = tenantClause(tenantId);
|
|
33
39
|
return {
|
|
34
40
|
async listSessionsWithin(windowDays) {
|
|
35
41
|
const rows = db
|
|
36
42
|
.prepare(`SELECT id, started_at AS startedAt
|
|
37
43
|
FROM sessions
|
|
38
|
-
WHERE started_at >= datetime('now', ?)
|
|
44
|
+
WHERE started_at >= datetime('now', ?) AND ${tc.sql}
|
|
39
45
|
ORDER BY started_at ASC`)
|
|
40
|
-
.all(`-${windowDays} days
|
|
46
|
+
.all(`-${windowDays} days`, tc.param);
|
|
41
47
|
const entStmt = db.prepare("SELECT entity_canonical AS e FROM session_entities WHERE session_id = ?");
|
|
42
48
|
const decStmt = db.prepare("SELECT text AS t FROM markers WHERE session_id = ? AND kind = 'decision' ORDER BY position ASC");
|
|
43
49
|
return rows.map((r) => ({
|
|
@@ -54,6 +60,17 @@ export function sqliteReDerivationDeps(db) {
|
|
|
54
60
|
},
|
|
55
61
|
};
|
|
56
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Parses the on-disk cache the 24h corpus-monitor job writes to
|
|
65
|
+
* (`~/.nlm/re-derivation-pairs.json`, see `src/cli/nlm.ts`) and the SQLite
|
|
66
|
+
* outcome adapters read back (`@core/storage/sqlite-outcome-store.js`).
|
|
67
|
+
* The file is a plain `ReDerivationPair[]` - anything else (corrupt JSON,
|
|
68
|
+
* a non-array shape) is treated as no pairs rather than thrown.
|
|
69
|
+
*/
|
|
70
|
+
export function parseReDerivationPairsFile(raw) {
|
|
71
|
+
const parsed = JSON.parse(raw);
|
|
72
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
73
|
+
}
|
|
57
74
|
export async function computeReDerivationRate(deps, windowDays) {
|
|
58
75
|
const sessions = await deps.listSessionsWithin(windowDays);
|
|
59
76
|
const edges = await deps.listEdges();
|
|
@@ -61,11 +78,16 @@ export async function computeReDerivationRate(deps, windowDays) {
|
|
|
61
78
|
.filter((e) => e.kind === "continues" || e.kind === "supersedes")
|
|
62
79
|
.map((e) => [e.from_session, e.to_session].sort().join("|")));
|
|
63
80
|
const pairs = [];
|
|
81
|
+
const reDeriving = new Set();
|
|
64
82
|
let eligible = 0;
|
|
65
83
|
for (let i = 0; i < sessions.length; i++) {
|
|
66
84
|
for (let j = i + 1; j < sessions.length; j++) {
|
|
67
85
|
const s = sessions[i];
|
|
68
86
|
const t = sessions[j];
|
|
87
|
+
// A decisionless side can never be a re-derivation, so such a pair does
|
|
88
|
+
// not belong in the denominator at all.
|
|
89
|
+
if (s.decisions.length === 0 || t.decisions.length === 0)
|
|
90
|
+
continue;
|
|
69
91
|
const shared = s.entities.filter((e) => t.entities.includes(e));
|
|
70
92
|
if (shared.length === 0)
|
|
71
93
|
continue;
|
|
@@ -79,9 +101,19 @@ export async function computeReDerivationRate(deps, windowDays) {
|
|
|
79
101
|
const jac = jaccard(s.decisions, t.decisions);
|
|
80
102
|
if (jac >= JACCARD_FLOOR) {
|
|
81
103
|
pairs.push({ a: s.id, b: t.id, sharedEntities: shared, jaccard: round2(jac) });
|
|
104
|
+
const later = new Date(t.startedAt).getTime() >= new Date(s.startedAt).getTime() ? t.id : s.id;
|
|
105
|
+
reDeriving.add(later);
|
|
82
106
|
}
|
|
83
107
|
}
|
|
84
108
|
}
|
|
85
|
-
|
|
109
|
+
const decisionBearingSessions = sessions.filter((s) => s.decisions.length > 0).length;
|
|
110
|
+
return {
|
|
111
|
+
rate: eligible ? pairs.length / eligible : 0,
|
|
112
|
+
pairs,
|
|
113
|
+
eligible,
|
|
114
|
+
decisionBearingSessions,
|
|
115
|
+
reDerivingSessions: reDeriving.size,
|
|
116
|
+
sessionRate: decisionBearingSessions ? reDeriving.size / decisionBearingSessions : 0,
|
|
117
|
+
};
|
|
86
118
|
}
|
|
87
119
|
//# sourceMappingURL=re-derivation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"re-derivation.js","sourceRoot":"","sources":["../../../src/core/metrics/re-derivation.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"re-derivation.js","sourceRoot":"","sources":["../../../src/core/metrics/re-derivation.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,4 +30,4 @@ export interface OutcomeCoverage {
|
|
|
30
30
|
readonly reDerivedLater: number;
|
|
31
31
|
readonly unobserved: number;
|
|
32
32
|
}
|
|
33
|
-
export declare function computeOutcomeCoverage(input: OutcomeCoverageInput): Promise<OutcomeCoverage>;
|
|
33
|
+
export declare function computeOutcomeCoverage(tenantId: string, input: OutcomeCoverageInput): Promise<OutcomeCoverage>;
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
* the precedence logic itself is never duplicated, only its I/O is batched.
|
|
12
12
|
*/
|
|
13
13
|
import { deriveOutcome } from "./rollup.js";
|
|
14
|
-
export async function computeOutcomeCoverage(input) {
|
|
14
|
+
export async function computeOutcomeCoverage(tenantId, input) {
|
|
15
15
|
const counts = { held: 0, overturned: 0, builtUpon: 0, reDerivedLater: 0, unobserved: 0 };
|
|
16
16
|
for (const session of input.sessions) {
|
|
17
|
-
const verdict = await deriveOutcome(session.id, {
|
|
17
|
+
const verdict = await deriveOutcome(tenantId, session.id, {
|
|
18
18
|
sessions: { getById: async () => session },
|
|
19
19
|
signals: { listForSession: async () => input.signalsBySession.get(session.id) ?? [] },
|
|
20
20
|
edges: { listForSession: async () => input.edgesBySession.get(session.id) ?? [] },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../../src/core/outcome/coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA6B5C,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,KAA2B;
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../../src/core/outcome/coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AA6B5C,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,QAAgB,EAAE,KAA2B;IACxF,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;IAE1F,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,EAAE;YACxD,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,EAAE;YAC1C,OAAO,EAAE,EAAE,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE;YACrF,KAAK,EAAE,EAAE,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE;YACjF,SAAS,EAAE,EAAE,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE;YACzF,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;YAC1C,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxC,GAAG,CAAC,KAAK,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACrF,CAAC,CAAC;QAEH,QAAQ,OAAO,CAAC,OAAO,EAAE,CAAC;YACxB,KAAK,MAAM;gBACT,MAAM,CAAC,IAAI,EAAE,CAAC;gBACd,MAAM;YACR,KAAK,YAAY;gBACf,MAAM,CAAC,UAAU,EAAE,CAAC;gBACpB,MAAM;YACR,KAAK,YAAY;gBACf,MAAM,CAAC,SAAS,EAAE,CAAC;gBACnB,MAAM;YACR,KAAK,kBAAkB;gBACrB,MAAM,CAAC,cAAc,EAAE,CAAC;gBACxB,MAAM;YACR,KAAK,YAAY;gBACf,MAAM,CAAC,UAAU,EAAE,CAAC;gBACpB,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;AACrD,CAAC"}
|
|
@@ -30,4 +30,4 @@
|
|
|
30
30
|
* correlation is left to a follow-up task if it proves to matter in practice.
|
|
31
31
|
*/
|
|
32
32
|
import type { OutcomeDeps, OutcomeVerdict } from "../../ports/outcome.js";
|
|
33
|
-
export declare function deriveOutcome(sessionId: string, deps: OutcomeDeps): Promise<OutcomeVerdict>;
|
|
33
|
+
export declare function deriveOutcome(tenantId: string, sessionId: string, deps: OutcomeDeps): Promise<OutcomeVerdict>;
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
*/
|
|
32
32
|
const DEFAULT_HELD_AFTER_DAYS = 14;
|
|
33
33
|
const MS_PER_DAY = 86_400_000;
|
|
34
|
-
export async function deriveOutcome(sessionId, deps) {
|
|
35
|
-
const session = await deps.sessions.getById(sessionId);
|
|
34
|
+
export async function deriveOutcome(tenantId, sessionId, deps) {
|
|
35
|
+
const session = await deps.sessions.getById(tenantId, sessionId);
|
|
36
36
|
if (!session) {
|
|
37
37
|
return { verdict: "unobserved", tier: "B", confidence: "low", evidence: [] };
|
|
38
38
|
}
|
|
39
39
|
// 1. Tier A: correlated signal rows are the strongest evidence and settle
|
|
40
40
|
// the verdict outright, ahead of every heuristic below.
|
|
41
|
-
const signals = await deps.signals.listForSession(sessionId);
|
|
41
|
+
const signals = await deps.signals.listForSession(tenantId, sessionId);
|
|
42
42
|
if (signals.length > 0) {
|
|
43
43
|
const anyNegative = signals.some((s) => s.outcome !== "pass");
|
|
44
44
|
return {
|
|
@@ -48,7 +48,7 @@ export async function deriveOutcome(sessionId, deps) {
|
|
|
48
48
|
evidence: signals.map((s) => `signal:${s.id}`),
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
|
-
const edges = await deps.edges.listForSession(sessionId);
|
|
51
|
+
const edges = await deps.edges.listForSession(tenantId, sessionId);
|
|
52
52
|
// 2. Supersession beats "held" beats continuation beats re-derivation.
|
|
53
53
|
const supersedingEdge = edges.find((e) => e.toSession === sessionId && (e.kind === "supersedes" || e.kind === "replaces"));
|
|
54
54
|
if (session.status === "superseded" || session.status === "replaced" || supersedingEdge) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rollup.js","sourceRoot":"","sources":["../../../src/core/outcome/rollup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAIH,MAAM,uBAAuB,GAAG,EAAE,CAAC;AACnC,MAAM,UAAU,GAAG,UAAU,CAAC;AAE9B,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAAiB,EAAE,IAAiB;
|
|
1
|
+
{"version":3,"file":"rollup.js","sourceRoot":"","sources":["../../../src/core/outcome/rollup.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,11 +11,20 @@
|
|
|
11
11
|
* `redact()` strips secrets on the way out — every HTTP response sends
|
|
12
12
|
* redacted rows, with the key only retrievable via getSecret() inside the
|
|
13
13
|
* daemon process.
|
|
14
|
+
*
|
|
15
|
+
* Tenancy (program spec §4, M2 plan Wave B5): `providers` is a STAMP table.
|
|
16
|
+
* Every method takes `tenantId` as its non-optional first parameter and
|
|
17
|
+
* routes its WHERE fragment through `tenantClause`; INSERTs stamp
|
|
18
|
+
* `tenant_id`. `getSecret` is the top-risk-3 surface (spec §4.5): a
|
|
19
|
+
* tenant-mismatched id returns the same not-found shape (`null`) as a
|
|
20
|
+
* missing row — no existence oracle, and no plaintext key crosses a tenant
|
|
21
|
+
* boundary via an id an attacker merely guessed.
|
|
14
22
|
*/
|
|
15
23
|
import type Database from "better-sqlite3";
|
|
16
24
|
export type ProviderKind = "deepseek" | "ollama" | "openai" | "anthropic" | "openrouter" | "openai-compatible";
|
|
17
25
|
export interface ProviderRow {
|
|
18
26
|
readonly id: number;
|
|
27
|
+
readonly tenantId: string;
|
|
19
28
|
readonly kind: ProviderKind;
|
|
20
29
|
readonly name: string;
|
|
21
30
|
readonly baseUrl: string | null;
|
|
@@ -52,32 +61,36 @@ export interface ProviderUpdate {
|
|
|
52
61
|
* operator's env would be wrong, so the PG adapter never seeds providers.
|
|
53
62
|
*/
|
|
54
63
|
export interface ProviderRegistryPort {
|
|
55
|
-
list(): Promise<ProviderRow[]>;
|
|
56
|
-
get(id: number): Promise<ProviderRow | null>;
|
|
57
|
-
getByName(name: string): Promise<ProviderRow | null>;
|
|
58
|
-
getSecret(id: number): Promise<string | null>;
|
|
59
|
-
insert(input: ProviderInsert): Promise<ProviderRow>;
|
|
60
|
-
update(id: number, patch: ProviderUpdate): Promise<ProviderRow | null>;
|
|
61
|
-
delete(id: number): Promise<boolean>;
|
|
64
|
+
list(tenantId: string): Promise<ProviderRow[]>;
|
|
65
|
+
get(tenantId: string, id: number): Promise<ProviderRow | null>;
|
|
66
|
+
getByName(tenantId: string, name: string): Promise<ProviderRow | null>;
|
|
67
|
+
getSecret(tenantId: string, id: number): Promise<string | null>;
|
|
68
|
+
insert(tenantId: string, input: ProviderInsert): Promise<ProviderRow>;
|
|
69
|
+
update(tenantId: string, id: number, patch: ProviderUpdate): Promise<ProviderRow | null>;
|
|
70
|
+
delete(tenantId: string, id: number): Promise<boolean>;
|
|
62
71
|
}
|
|
63
72
|
export declare class ProviderRegistry implements ProviderRegistryPort {
|
|
64
73
|
private readonly db;
|
|
65
74
|
constructor(db: Database.Database);
|
|
66
|
-
list(): Promise<ProviderRow[]>;
|
|
67
|
-
get(id: number): Promise<ProviderRow | null>;
|
|
68
|
-
getByName(name: string): Promise<ProviderRow | null>;
|
|
69
|
-
/**
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
list(tenantId: string): Promise<ProviderRow[]>;
|
|
76
|
+
get(tenantId: string, id: number): Promise<ProviderRow | null>;
|
|
77
|
+
getByName(tenantId: string, name: string): Promise<ProviderRow | null>;
|
|
78
|
+
/**
|
|
79
|
+
* Returns the secret. Use only inside the daemon — never echo to HTTP.
|
|
80
|
+
* A tenant-mismatched id returns null, identical to a missing row (top
|
|
81
|
+
* risk 3, spec §4.5) — no existence oracle, no cross-tenant key leak.
|
|
82
|
+
*/
|
|
83
|
+
getSecret(tenantId: string, id: number): Promise<string | null>;
|
|
84
|
+
insert(tenantId: string, input: ProviderInsert): Promise<ProviderRow>;
|
|
85
|
+
update(tenantId: string, id: number, patch: ProviderUpdate): Promise<ProviderRow | null>;
|
|
86
|
+
delete(tenantId: string, id: number): Promise<boolean>;
|
|
74
87
|
/**
|
|
75
88
|
* Seed defaults on an empty registry. Bridges from the legacy env-var
|
|
76
89
|
* setup: if DEEPSEEK_API_KEY is present, the DeepSeek row carries it
|
|
77
90
|
* forward; Ollama is always seeded since it needs no key. SQLite-only —
|
|
78
91
|
* not on ProviderRegistryPort (see the port's doc comment).
|
|
79
92
|
*/
|
|
80
|
-
seedDefaults(): Promise<void>;
|
|
93
|
+
seedDefaults(tenantId: string): Promise<void>;
|
|
81
94
|
}
|
|
82
95
|
import type { Pool } from "pg";
|
|
83
96
|
/**
|
|
@@ -87,11 +100,15 @@ import type { Pool } from "pg";
|
|
|
87
100
|
export declare class PgProviderRegistry implements ProviderRegistryPort {
|
|
88
101
|
private readonly pool;
|
|
89
102
|
constructor(pool: Pool);
|
|
90
|
-
list(): Promise<ProviderRow[]>;
|
|
91
|
-
get(id: number): Promise<ProviderRow | null>;
|
|
92
|
-
getByName(name: string): Promise<ProviderRow | null>;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
103
|
+
list(tenantId: string): Promise<ProviderRow[]>;
|
|
104
|
+
get(tenantId: string, id: number): Promise<ProviderRow | null>;
|
|
105
|
+
getByName(tenantId: string, name: string): Promise<ProviderRow | null>;
|
|
106
|
+
/**
|
|
107
|
+
* A tenant-mismatched id returns null, identical to a missing row (top
|
|
108
|
+
* risk 3, spec §4.5) — no existence oracle, no cross-tenant key leak.
|
|
109
|
+
*/
|
|
110
|
+
getSecret(tenantId: string, id: number): Promise<string | null>;
|
|
111
|
+
insert(tenantId: string, input: ProviderInsert): Promise<ProviderRow>;
|
|
112
|
+
update(tenantId: string, id: number, patch: ProviderUpdate): Promise<ProviderRow | null>;
|
|
113
|
+
delete(tenantId: string, id: number): Promise<boolean>;
|
|
97
114
|
}
|