@remnic/core 9.54.5 → 9.54.7
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/dist/access-admin-ops-surface.d.ts +24 -24
- package/dist/access-admin-ops-surface.js +32 -29
- package/dist/access-authorization-probe.d.ts +25 -23
- package/dist/access-authorization-probe.js +35 -30
- package/dist/access-boundary.d.ts +26 -24
- package/dist/access-boundary.js +36 -31
- package/dist/access-cli.js +86 -80
- package/dist/access-cli.js.map +1 -1
- package/dist/access-coding-context-resolution.d.ts +1 -1
- package/dist/access-extraction-force-flush.d.ts +19 -19
- package/dist/access-extraction-force-flush.js +32 -29
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-lcm-compaction.d.ts +22 -22
- package/dist/access-http-lifecycle-flush.d.ts +22 -22
- package/dist/access-http-offline-stream.d.ts +18 -18
- package/dist/access-http-query.js +32 -29
- package/dist/access-http.d.ts +55 -37
- package/dist/access-http.js +52 -43
- package/dist/access-identity-continuity-surface.d.ts +9 -9
- package/dist/access-identity-continuity-surface.js +32 -29
- package/dist/access-lcm-surface.d.ts +21 -21
- package/dist/access-lcm-surface.js +32 -29
- package/dist/access-mcp.d.ts +22 -22
- package/dist/access-mcp.js +40 -36
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-BdHlGd_T.d.ts → access-namespace-preflight-CCNn_6NE.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +32 -29
- package/dist/access-observe-write-surface.d.ts +22 -22
- package/dist/access-observe-write-surface.js +32 -29
- package/dist/access-offline-manifest.d.ts +9 -9
- package/dist/access-offline-manifest.js +2 -2
- package/dist/access-operations-batch.js +34 -31
- package/dist/access-operations.d.ts +23 -23
- package/dist/access-operations.js +38 -34
- package/dist/access-recall-concurrency.d.ts +21 -21
- package/dist/access-recall-concurrency.js +32 -29
- package/dist/access-recall-response.d.ts +19 -19
- package/dist/access-recall-response.js +32 -29
- package/dist/access-recall-surface.d.ts +19 -19
- package/dist/access-recall-surface.js +32 -29
- package/dist/access-schema.js +3 -3
- package/dist/{access-service-DL7X9hrg.d.ts → access-service-DK82xdNi.d.ts} +1314 -83
- package/dist/access-service-helpers.d.ts +22 -22
- package/dist/access-service.d.ts +31 -31
- package/dist/access-service.js +32 -29
- package/dist/access-surface-catalog.d.ts +22 -22
- package/dist/access-surface-catalog.js +209 -2
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-wearables-meetings-surface.d.ts +3 -3
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +6 -5
- package/dist/active-memory-bridge.js +2 -2
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +2 -1
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/admin-console/public/what-helps-me/app.js +1594 -0
- package/dist/admin-console/public/what-helps-me/index.html +339 -0
- package/dist/admin-console/public/what-helps-me/model.js +685 -0
- package/dist/admin-console/public/what-helps-me/what-helps-me.css +1296 -0
- package/dist/ambient-provenance.d.ts +1 -1
- package/dist/artifact-search.d.ts +1 -1
- package/dist/{auto-sync-TDHLZPVP.js → auto-sync-NR3GPCOA.js} +4 -4
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +9 -9
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +14 -14
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer-turn-helpers.d.ts +1 -1
- package/dist/buffer.d.ts +2 -2
- package/dist/buffer.js +2 -2
- package/dist/bulk-import/index.d.ts +3 -3
- package/dist/calibration.d.ts +1 -1
- package/dist/calibration.js +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{catalog-B90is4d8.d.ts → catalog-DGFf8mD9.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +15 -15
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-CSY44OKU.js → chunk-26ZXBTYN.js} +4 -4
- package/dist/chunk-26ZXBTYN.js.map +1 -0
- package/dist/{chunk-LLJMAULE.js → chunk-2FKEIPIT.js} +5 -5
- package/dist/{chunk-AU7Q3LSC.js → chunk-2QSZNTDO.js} +4 -4
- package/dist/chunk-37DZZFFM.js +502 -0
- package/dist/chunk-37DZZFFM.js.map +1 -0
- package/dist/chunk-3HSRWJTC.js +9 -0
- package/dist/chunk-3HSRWJTC.js.map +1 -0
- package/dist/{chunk-TKFGFDPJ.js → chunk-3TIZPSJC.js} +4 -4
- package/dist/{chunk-B4T3FQMT.js → chunk-43SEBY2M.js} +1 -1
- package/dist/{chunk-LVKYLMSM.js → chunk-46SZBVDS.js} +2 -2
- package/dist/{chunk-YKZLOPTC.js → chunk-5FD7JMTX.js} +2 -2
- package/dist/{chunk-2PNXOQ4P.js → chunk-5NB726GV.js} +3 -7
- package/dist/chunk-5NB726GV.js.map +1 -0
- package/dist/chunk-62OKGIJA.js +39 -0
- package/dist/chunk-62OKGIJA.js.map +1 -0
- package/dist/{chunk-WM5LD6AT.js → chunk-6CYHUWCO.js} +2 -2
- package/dist/{chunk-BIF4SHMD.js → chunk-76JJSXK7.js} +1 -1
- package/dist/chunk-76JJSXK7.js.map +1 -0
- package/dist/{chunk-3SXLD5T3.js → chunk-7BD6O7ZV.js} +189 -4
- package/dist/chunk-7BD6O7ZV.js.map +1 -0
- package/dist/chunk-7TBXNYLO.js +346 -0
- package/dist/chunk-7TBXNYLO.js.map +1 -0
- package/dist/{chunk-YR65W7BV.js → chunk-BRR5EUTF.js} +3 -3
- package/dist/{chunk-JKW663ZN.js → chunk-CIAI24TQ.js} +2 -2
- package/dist/{chunk-3WGI7F4V.js → chunk-D3LBIUWV.js} +9219 -5233
- package/dist/chunk-D3LBIUWV.js.map +1 -0
- package/dist/{chunk-YDWPYDML.js → chunk-EKTP7MNS.js} +4 -4
- package/dist/{chunk-6LEIWWAF.js → chunk-F2JRDPON.js} +2 -2
- package/dist/{chunk-VYQ4URQB.js → chunk-FFRTNF3L.js} +2 -2
- package/dist/{chunk-TY6MKIWP.js → chunk-FONWBCVY.js} +3 -3
- package/dist/{chunk-XSV2YDCJ.js → chunk-FPLM2TKD.js} +2 -2
- package/dist/{chunk-VTU5IEKY.js → chunk-FTPONF6B.js} +2 -2
- package/dist/{chunk-6PZGKGAO.js → chunk-FWX7W5PM.js} +2 -2
- package/dist/{chunk-QPW3PAIH.js → chunk-G6DFSS6A.js} +2 -2
- package/dist/{chunk-2DD6ZHOM.js → chunk-GJ776BC2.js} +3 -3
- package/dist/{chunk-XKAR4RF6.js → chunk-GN3WRFJY.js} +6 -6
- package/dist/{chunk-RG426DJO.js → chunk-H7NAZ3UB.js} +2 -2
- package/dist/{chunk-BSXGTDVJ.js → chunk-HBUFQRIM.js} +2 -2
- package/dist/{chunk-FFEBSFVT.js → chunk-HGJ6NJ4E.js} +2 -2
- package/dist/{chunk-WB7JSQCP.js → chunk-HIEWDJ2O.js} +5 -2
- package/dist/{chunk-WB7JSQCP.js.map → chunk-HIEWDJ2O.js.map} +1 -1
- package/dist/{chunk-QTO6BMQZ.js → chunk-I3MSGFGD.js} +17 -6
- package/dist/chunk-I3MSGFGD.js.map +1 -0
- package/dist/{chunk-5JKUSBMX.js → chunk-IKP5OYQQ.js} +2 -2
- package/dist/{chunk-KQAFEZQX.js → chunk-IPLYGWQF.js} +5 -5
- package/dist/{chunk-DBY26JJJ.js → chunk-IQ4NVWEF.js} +2 -2
- package/dist/{chunk-7Q7JWLQ4.js → chunk-JYG4OLWH.js} +2 -2
- package/dist/{chunk-3OTSVCPK.js → chunk-K26NWEOC.js} +4 -4
- package/dist/{chunk-WZWZRZ2V.js → chunk-K2UGPTYY.js} +484 -43
- package/dist/chunk-K2UGPTYY.js.map +1 -0
- package/dist/{chunk-L6CQ7WIW.js → chunk-KFBOPMF6.js} +11 -11
- package/dist/chunk-KFBOPMF6.js.map +1 -0
- package/dist/{chunk-HOIRB77A.js → chunk-L6Z5OAS4.js} +2 -2
- package/dist/{chunk-7RZJWZ46.js → chunk-LEPOP46W.js} +5 -5
- package/dist/{chunk-QQXWFDRD.js → chunk-M4YHAODQ.js} +270 -684
- package/dist/chunk-M4YHAODQ.js.map +1 -0
- package/dist/{chunk-NGT35IGQ.js → chunk-MIH3CJPN.js} +3 -3
- package/dist/{chunk-QPAQSG3F.js → chunk-MK5VEWCR.js} +2 -2
- package/dist/chunk-NISZQW72.js +140 -0
- package/dist/chunk-NISZQW72.js.map +1 -0
- package/dist/{chunk-L7RTUEDG.js → chunk-OCIP6YMD.js} +2 -2
- package/dist/{chunk-2INWPC6E.js → chunk-PG4QBPVG.js} +20 -10
- package/dist/chunk-PG4QBPVG.js.map +1 -0
- package/dist/{chunk-DDA55IVB.js → chunk-PT54WISF.js} +189 -55
- package/dist/chunk-PT54WISF.js.map +1 -0
- package/dist/{chunk-UWJNKGBA.js → chunk-QZLDRQ4I.js} +5 -5
- package/dist/{chunk-UYOXFFEY.js → chunk-RUNORG2P.js} +3 -3
- package/dist/{chunk-LC3FD4BV.js → chunk-RZQ6W2W4.js} +39 -39
- package/dist/{chunk-MRGJZ75M.js → chunk-SMNYAMJD.js} +3 -3
- package/dist/{chunk-MKQBXQKU.js → chunk-TB6CBZ5V.js} +22 -15
- package/dist/chunk-TB6CBZ5V.js.map +1 -0
- package/dist/{chunk-DN2IDKI5.js → chunk-TO7ZTWJW.js} +2 -2
- package/dist/{chunk-K2TDK7GG.js → chunk-TWTUGCTY.js} +2 -2
- package/dist/{chunk-CUTFSLSD.js → chunk-UCTS3DDH.js} +2 -2
- package/dist/{chunk-JYIJNNN3.js → chunk-UG6VXIOK.js} +2 -2
- package/dist/{chunk-QOQQMVR2.js → chunk-UKYS3NU5.js} +2 -2
- package/dist/{chunk-VZRFGJCH.js → chunk-UPLZNJKN.js} +2 -2
- package/dist/{chunk-C23BYTJV.js → chunk-UW5NPZJ2.js} +40 -12
- package/dist/chunk-UW5NPZJ2.js.map +1 -0
- package/dist/{chunk-DOOWFDWN.js → chunk-V6ERBR7U.js} +2 -2
- package/dist/{chunk-7HG7MGAP.js → chunk-W5ZKPI34.js} +462 -2673
- package/dist/chunk-W5ZKPI34.js.map +1 -0
- package/dist/{chunk-HNDIND7P.js → chunk-XX4HPFFM.js} +54 -15
- package/dist/chunk-XX4HPFFM.js.map +1 -0
- package/dist/{chunk-N7CXQ5TA.js → chunk-XZHE2DEN.js} +1 -1
- package/dist/chunk-YXQEKCZM.js +223 -0
- package/dist/chunk-YXQEKCZM.js.map +1 -0
- package/dist/{chunk-6NNNURLK.js → chunk-Z54EM5YZ.js} +4 -4
- package/dist/{chunk-F2Y6I74C.js → chunk-ZRZVLB7O.js} +2 -2
- package/dist/{chunk-CLKBV3Z3.js → chunk-ZUKIUXHQ.js} +9 -9
- package/dist/{cli-jfuZXixq.d.ts → cli-BPDUXnAl.d.ts} +5 -5
- package/dist/cli.d.ts +22 -22
- package/dist/cli.js +66 -58
- package/dist/coding/pre-action-gate.d.ts +1 -1
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +14 -14
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +2 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +14 -14
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +14 -14
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/contradiction/index.d.ts +2 -2
- package/dist/contradiction/index.js +2 -2
- package/dist/{contradiction-scan-KCADHXPE.js → contradiction-scan-JDTBXRGW.js} +3 -3
- package/dist/converge-config.d.ts +1 -1
- package/dist/convergence-refresh.d.ts +2 -2
- package/dist/convergence-refresh.js +16 -16
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/backend.js +2 -2
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/corpus-watermark.d.ts +1 -1
- package/dist/corpus-watermark.js +16 -16
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/dependency-propagation-config.d.ts +1 -1
- package/dist/{dependency-propagation-delivery-CTDuAVJc.d.ts → dependency-propagation-delivery-CzEfB31P.d.ts} +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +14 -14
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +9 -9
- package/dist/explicit-capture.js +4 -3
- package/dist/external-wiki-access.d.ts +22 -22
- package/dist/external-wiki-access.js +33 -30
- package/dist/external-wiki-collection-registration.d.ts +1 -1
- package/dist/external-wiki-collection.d.ts +1 -1
- package/dist/external-wiki-mcp-tools.d.ts +22 -22
- package/dist/extraction-error-classification.d.ts +1 -1
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-faithfulness.js +2 -2
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction-judge.js +2 -2
- package/dist/extraction-liveness.d.ts +1 -1
- package/dist/extraction-normalization.d.ts +1 -1
- package/dist/extraction-prompt.d.ts +1 -1
- package/dist/extraction-source-grounding-rules.d.ts +1 -1
- package/dist/extraction-source-grounding.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +20 -20
- package/dist/fallback-llm.d.ts +14 -1
- package/dist/fallback-llm.js +1 -1
- package/dist/{first-start-migration-LMMZFLKK.js → first-start-migration-CRZCZAJN.js} +5 -5
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-path-reconstruction.d.ts +1 -1
- package/dist/graph-path-scoring.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/importers/index.d.ts +1 -1
- package/dist/in-flight-reads.d.ts +1 -1
- package/dist/index.d.ts +30 -747
- package/dist/index.js +203 -118
- package/dist/inline-script.d.ts +3 -0
- package/dist/inline-script.js +8 -0
- package/dist/inline-script.js.map +1 -0
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +2 -2
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +2 -1
- package/dist/local-llm.js +2 -2
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +14 -14
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +14 -14
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +15 -15
- package/dist/{maintenance-heMZSq7G.d.ts → maintenance-C8aRWfhq.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +22 -22
- package/dist/mcp-read-only-tools.js +1 -1
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-snapshot.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +2 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +3 -3
- package/dist/namespaces/migrate.js +15 -15
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +6 -6
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +14 -14
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/operator-doctor-corpus.d.ts +1 -1
- package/dist/operator-doctor-corpus.js +17 -17
- package/dist/operator-doctor-replica.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +3 -3
- package/dist/operator-toolkit.js +23 -22
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +4 -4
- package/dist/orchestration/maintenance.js +19 -19
- package/dist/{orchestrator-BQQPsSjs.d.ts → orchestrator-D85CzDDY.d.ts} +8 -8
- package/dist/orchestrator.d.ts +9 -9
- package/dist/orchestrator.js +86 -80
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-DFfmsnGk.d.ts → pipeline-DPcUifCO.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/proactive-contention.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/public-http-D3GBeII4.d.ts +25 -0
- package/dist/{qmd-BF5bcVRs.d.ts → qmd-dFCHp1r0.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +2 -2
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +2 -2
- package/dist/recall-concurrency-config.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-planner-llm.js +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-timings.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -1
- package/dist/recall-xray.js +2 -2
- package/dist/reconcile/cursor.d.ts +1 -1
- package/dist/reconcile/manifest.d.ts +1 -1
- package/dist/reconcile/plan.d.ts +1 -1
- package/dist/replay/normalizers/chatgpt.d.ts +1 -1
- package/dist/replay/normalizers/claude.d.ts +1 -1
- package/dist/replay/normalizers/openclaw.d.ts +1 -1
- package/dist/replay/normalizers/shared.d.ts +1 -1
- package/dist/replay/runner.d.ts +1 -1
- package/dist/replay/types.d.ts +1 -1
- package/dist/replica-divergence.d.ts +1 -1
- package/dist/replica-peers-config.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +3 -2
- package/dist/retrieval-agents.d.ts +2 -2
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/salvage-envelope.d.ts +1 -1
- package/dist/{scope-profiles-CbUOsE_E.d.ts → scope-profiles-DICK7GtN.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +5 -5
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +9 -9
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-DAB3xdKM.d.ts → semantic-consolidation-BP7NAX0N.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +15 -15
- package/dist/semantic-rule-promotion.js +14 -14
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +14 -14
- package/dist/{service-DGKg2O6r.d.ts → service-DT-pJyda.d.ts} +660 -660
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/source-agent-qualifier.d.ts +1 -1
- package/dist/source-agent-qualifier.js +16 -16
- package/dist/{storage-CC1jKcWg.d.ts → storage-qOnaJ1Lw.d.ts} +4 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +13 -13
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +5 -5
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/support-passport/index.d.ts +518 -0
- package/dist/support-passport/index.js +357 -0
- package/dist/support-passport/index.js.map +1 -0
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-timeline-recall.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +2 -2
- package/dist/tier-routing.d.ts +1 -1
- package/dist/tier-routing.js +2 -2
- package/dist/{tier-stats-JDN6HRNT.js → tier-stats-EXYSKSVN.js} +3 -3
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/autodetect.js +1 -1
- package/dist/transfer/backup.js +1 -1
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/types.d.ts +24 -24
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-BnQza1y8.d.ts → types-ed-SvS2t.d.ts} +7 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +14 -14
- package/dist/write-envelope.d.ts +1 -1
- package/dist/write-rate-limiter.d.ts +11 -5
- package/dist/write-rate-limiter.js +1 -1
- package/package.json +12 -2
- package/scripts/build-with-heap.mjs +11 -1
- package/src/access-authorization-probe.ts +20 -2
- package/src/access-boundary.ts +32 -0
- package/src/access-http.test.ts +1940 -643
- package/src/access-http.ts +81 -74
- package/src/access-mcp.ts +3 -1
- package/src/access-operations.ts +2 -0
- package/src/access-service.ts +612 -845
- package/src/access-surface-catalog.test.ts +40 -10
- package/src/access-surface-catalog.ts +15 -0
- package/src/active-memory-bridge.ts +17 -19
- package/src/config.ts +18 -9
- package/src/fallback-llm.test.ts +54 -0
- package/src/fallback-llm.ts +54 -9
- package/src/inline-script.ts +6 -0
- package/src/local-llm-headers-timeout.test.ts +42 -0
- package/src/local-llm.ts +8 -8
- package/src/mcp-read-only-tools.ts +3 -0
- package/src/relay/mission-access.test.ts +11 -11
- package/src/relay/mission-ui.test.ts +3 -1
- package/src/storage/tombstone-blocked-capture-sync.ts +31 -0
- package/src/storage-contract/failure-semantics.test.ts +102 -0
- package/src/support-passport/access-http-base.ts +143 -0
- package/src/support-passport/access-http.ts +172 -0
- package/src/support-passport/access-operations.ts +272 -0
- package/src/support-passport/access-service-base.test.ts +193 -0
- package/src/support-passport/access-service-base.ts +176 -0
- package/src/support-passport/access-surface.test.ts +283 -0
- package/src/support-passport/access-surface.ts +286 -0
- package/src/support-passport/card-projection.test.ts +8 -0
- package/src/support-passport/card-projection.ts +77 -16
- package/src/support-passport/card-replacement.ts +126 -0
- package/src/support-passport/card-service-commit-forwarding.test.ts +160 -0
- package/src/support-passport/card-service.test.ts +533 -31
- package/src/support-passport/card-service.ts +506 -364
- package/src/support-passport/card-state.ts +158 -0
- package/src/support-passport/config-model-routing.test.ts +37 -0
- package/src/support-passport/config.test.ts +34 -0
- package/src/support-passport/config.ts +41 -0
- package/src/support-passport/contracts.test.ts +15 -2
- package/src/support-passport/contracts.ts +13 -0
- package/src/support-passport/errors.ts +6 -0
- package/src/support-passport/generated-batch.test.ts +185 -0
- package/src/support-passport/generated-batch.ts +338 -0
- package/src/support-passport/grant-contracts.ts +45 -1
- package/src/support-passport/grant-generated-batch-scope.test.ts +201 -0
- package/src/support-passport/grant-service-cache.test.ts +2 -2
- package/src/support-passport/grant-service-cancellation.test.ts +2 -0
- package/src/support-passport/grant-service-marker-cache.test.ts +62 -0
- package/src/support-passport/grant-service.test.ts +853 -239
- package/src/support-passport/grant-service.ts +206 -57
- package/src/support-passport/grant-store.ts +7 -3
- package/src/support-passport/index.ts +10 -0
- package/src/support-passport/mcp-tools.test.ts +222 -0
- package/src/support-passport/mcp-tools.ts +187 -0
- package/src/support-passport/model-adapter.test.ts +840 -0
- package/src/support-passport/model-adapter.ts +602 -0
- package/src/support-passport/model-audit-pinned-write.test.ts +59 -0
- package/src/support-passport/model-audit.ts +152 -0
- package/src/support-passport/model-bridge.test.ts +456 -0
- package/src/support-passport/model-bridge.ts +439 -0
- package/src/support-passport/model-contracts.ts +124 -0
- package/src/support-passport/model-service.test.ts +1731 -0
- package/src/support-passport/model-service.ts +399 -0
- package/src/support-passport/owner-http.test.ts +671 -0
- package/src/support-passport/owner-lock.ts +26 -9
- package/src/support-passport/private-file.test.ts +99 -0
- package/src/support-passport/private-file.ts +139 -12
- package/src/support-passport/public-http.test.ts +476 -0
- package/src/support-passport/public-http.ts +601 -0
- package/src/support-passport/ui.test.ts +181 -0
- package/src/types.ts +7 -0
- package/src/write-rate-limiter.test.ts +30 -6
- package/src/write-rate-limiter.ts +29 -18
- package/dist/chunk-2INWPC6E.js.map +0 -1
- package/dist/chunk-2PNXOQ4P.js.map +0 -1
- package/dist/chunk-3SXLD5T3.js.map +0 -1
- package/dist/chunk-3WGI7F4V.js.map +0 -1
- package/dist/chunk-7HG7MGAP.js.map +0 -1
- package/dist/chunk-BIF4SHMD.js.map +0 -1
- package/dist/chunk-C23BYTJV.js.map +0 -1
- package/dist/chunk-CSY44OKU.js.map +0 -1
- package/dist/chunk-DDA55IVB.js.map +0 -1
- package/dist/chunk-HNDIND7P.js.map +0 -1
- package/dist/chunk-L6CQ7WIW.js.map +0 -1
- package/dist/chunk-MKQBXQKU.js.map +0 -1
- package/dist/chunk-QQXWFDRD.js.map +0 -1
- package/dist/chunk-QTO6BMQZ.js.map +0 -1
- package/dist/chunk-WZWZRZ2V.js.map +0 -1
- /package/dist/{auto-sync-TDHLZPVP.js.map → auto-sync-NR3GPCOA.js.map} +0 -0
- /package/dist/{chunk-LLJMAULE.js.map → chunk-2FKEIPIT.js.map} +0 -0
- /package/dist/{chunk-AU7Q3LSC.js.map → chunk-2QSZNTDO.js.map} +0 -0
- /package/dist/{chunk-TKFGFDPJ.js.map → chunk-3TIZPSJC.js.map} +0 -0
- /package/dist/{chunk-B4T3FQMT.js.map → chunk-43SEBY2M.js.map} +0 -0
- /package/dist/{chunk-LVKYLMSM.js.map → chunk-46SZBVDS.js.map} +0 -0
- /package/dist/{chunk-YKZLOPTC.js.map → chunk-5FD7JMTX.js.map} +0 -0
- /package/dist/{chunk-WM5LD6AT.js.map → chunk-6CYHUWCO.js.map} +0 -0
- /package/dist/{chunk-YR65W7BV.js.map → chunk-BRR5EUTF.js.map} +0 -0
- /package/dist/{chunk-JKW663ZN.js.map → chunk-CIAI24TQ.js.map} +0 -0
- /package/dist/{chunk-YDWPYDML.js.map → chunk-EKTP7MNS.js.map} +0 -0
- /package/dist/{chunk-6LEIWWAF.js.map → chunk-F2JRDPON.js.map} +0 -0
- /package/dist/{chunk-VYQ4URQB.js.map → chunk-FFRTNF3L.js.map} +0 -0
- /package/dist/{chunk-TY6MKIWP.js.map → chunk-FONWBCVY.js.map} +0 -0
- /package/dist/{chunk-XSV2YDCJ.js.map → chunk-FPLM2TKD.js.map} +0 -0
- /package/dist/{chunk-VTU5IEKY.js.map → chunk-FTPONF6B.js.map} +0 -0
- /package/dist/{chunk-6PZGKGAO.js.map → chunk-FWX7W5PM.js.map} +0 -0
- /package/dist/{chunk-QPW3PAIH.js.map → chunk-G6DFSS6A.js.map} +0 -0
- /package/dist/{chunk-2DD6ZHOM.js.map → chunk-GJ776BC2.js.map} +0 -0
- /package/dist/{chunk-XKAR4RF6.js.map → chunk-GN3WRFJY.js.map} +0 -0
- /package/dist/{chunk-RG426DJO.js.map → chunk-H7NAZ3UB.js.map} +0 -0
- /package/dist/{chunk-BSXGTDVJ.js.map → chunk-HBUFQRIM.js.map} +0 -0
- /package/dist/{chunk-FFEBSFVT.js.map → chunk-HGJ6NJ4E.js.map} +0 -0
- /package/dist/{chunk-5JKUSBMX.js.map → chunk-IKP5OYQQ.js.map} +0 -0
- /package/dist/{chunk-KQAFEZQX.js.map → chunk-IPLYGWQF.js.map} +0 -0
- /package/dist/{chunk-DBY26JJJ.js.map → chunk-IQ4NVWEF.js.map} +0 -0
- /package/dist/{chunk-7Q7JWLQ4.js.map → chunk-JYG4OLWH.js.map} +0 -0
- /package/dist/{chunk-3OTSVCPK.js.map → chunk-K26NWEOC.js.map} +0 -0
- /package/dist/{chunk-HOIRB77A.js.map → chunk-L6Z5OAS4.js.map} +0 -0
- /package/dist/{chunk-7RZJWZ46.js.map → chunk-LEPOP46W.js.map} +0 -0
- /package/dist/{chunk-NGT35IGQ.js.map → chunk-MIH3CJPN.js.map} +0 -0
- /package/dist/{chunk-QPAQSG3F.js.map → chunk-MK5VEWCR.js.map} +0 -0
- /package/dist/{chunk-L7RTUEDG.js.map → chunk-OCIP6YMD.js.map} +0 -0
- /package/dist/{chunk-UWJNKGBA.js.map → chunk-QZLDRQ4I.js.map} +0 -0
- /package/dist/{chunk-UYOXFFEY.js.map → chunk-RUNORG2P.js.map} +0 -0
- /package/dist/{chunk-LC3FD4BV.js.map → chunk-RZQ6W2W4.js.map} +0 -0
- /package/dist/{chunk-MRGJZ75M.js.map → chunk-SMNYAMJD.js.map} +0 -0
- /package/dist/{chunk-DN2IDKI5.js.map → chunk-TO7ZTWJW.js.map} +0 -0
- /package/dist/{chunk-K2TDK7GG.js.map → chunk-TWTUGCTY.js.map} +0 -0
- /package/dist/{chunk-CUTFSLSD.js.map → chunk-UCTS3DDH.js.map} +0 -0
- /package/dist/{chunk-JYIJNNN3.js.map → chunk-UG6VXIOK.js.map} +0 -0
- /package/dist/{chunk-QOQQMVR2.js.map → chunk-UKYS3NU5.js.map} +0 -0
- /package/dist/{chunk-VZRFGJCH.js.map → chunk-UPLZNJKN.js.map} +0 -0
- /package/dist/{chunk-DOOWFDWN.js.map → chunk-V6ERBR7U.js.map} +0 -0
- /package/dist/{chunk-N7CXQ5TA.js.map → chunk-XZHE2DEN.js.map} +0 -0
- /package/dist/{chunk-6NNNURLK.js.map → chunk-Z54EM5YZ.js.map} +0 -0
- /package/dist/{chunk-F2Y6I74C.js.map → chunk-ZRZVLB7O.js.map} +0 -0
- /package/dist/{chunk-CLKBV3Z3.js.map → chunk-ZUKIUXHQ.js.map} +0 -0
- /package/dist/{contradiction-scan-KCADHXPE.js.map → contradiction-scan-JDTBXRGW.js.map} +0 -0
- /package/dist/{first-start-migration-LMMZFLKK.js.map → first-start-migration-CRZCZAJN.js.map} +0 -0
- /package/dist/{tier-stats-JDN6HRNT.js.map → tier-stats-EXYSKSVN.js.map} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
-
import { mkdtemp, rm } from "node:fs/promises";
|
|
2
|
+
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { test } from "node:test";
|
|
@@ -47,7 +47,7 @@ async function makeSubject() {
|
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
async function makeSharedStorageSubject() {
|
|
50
|
+
async function makeSharedStorageSubject(namespaceOverride?: string) {
|
|
51
51
|
StorageManager.clearAllStaticCaches();
|
|
52
52
|
const root = await mkdtemp(path.join(tmpdir(), "remnic-support-passport-shared-"));
|
|
53
53
|
const storage = new StorageManager(path.join(root, "shared"));
|
|
@@ -55,8 +55,8 @@ async function makeSharedStorageSubject() {
|
|
|
55
55
|
const service = new SupportPassportCardService({
|
|
56
56
|
now: () => new Date("2026-08-11T12:00:00.000Z"),
|
|
57
57
|
resolveOwner: async (principal) => {
|
|
58
|
-
if (principal === "owner:alice") return { principal, namespace: "alice", storage };
|
|
59
|
-
if (principal === "owner:bob") return { principal, namespace: "bob", storage };
|
|
58
|
+
if (principal === "owner:alice") return { principal, namespace: namespaceOverride ?? "alice", storage };
|
|
59
|
+
if (principal === "owner:bob") return { principal, namespace: namespaceOverride ?? "bob", storage };
|
|
60
60
|
throw new Error("unknown test principal");
|
|
61
61
|
},
|
|
62
62
|
});
|
|
@@ -344,12 +344,8 @@ test("card operations preserve configured default namespace identities", async (
|
|
|
344
344
|
reviewBy: OWNER_REVIEW_BY,
|
|
345
345
|
});
|
|
346
346
|
assert.deepEqual(await service.listCards({ principal: "owner:alice" }), [card]);
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
(await storage.getMemoryById(card.cardId))?.frontmatter.structuredAttributes ?? {},
|
|
350
|
-
),
|
|
351
|
-
namespace
|
|
352
|
-
);
|
|
347
|
+
const stored = await storage.getMemoryById(card.cardId);
|
|
348
|
+
assert.equal(decodeSupportPassportNamespaceAttributes(stored?.frontmatter.structuredAttributes ?? {}), namespace);
|
|
353
349
|
} finally {
|
|
354
350
|
StorageManager.clearAllStaticCaches();
|
|
355
351
|
await rm(root, { recursive: true, force: true });
|
|
@@ -382,6 +378,71 @@ test("card operations reject a resolved principal that differs from the authenti
|
|
|
382
378
|
}
|
|
383
379
|
});
|
|
384
380
|
|
|
381
|
+
test("generated draft creation rejects a non-canonical resolved namespace before writing", async () => {
|
|
382
|
+
StorageManager.clearAllStaticCaches();
|
|
383
|
+
const root = await mkdtemp(path.join(tmpdir(), "remnic-support-passport-generated-namespace-"));
|
|
384
|
+
const storage = new StorageManager(path.join(root, "shared"));
|
|
385
|
+
await storage.ensureDirectories();
|
|
386
|
+
const service = new SupportPassportCardService({
|
|
387
|
+
resolveOwner: async (principal) => ({ principal, namespace: " alice ", storage }),
|
|
388
|
+
});
|
|
389
|
+
try {
|
|
390
|
+
await assert.rejects(
|
|
391
|
+
service.createGeneratedDrafts({
|
|
392
|
+
principal: "owner:alice",
|
|
393
|
+
cards: [
|
|
394
|
+
{
|
|
395
|
+
title: "Quiet place",
|
|
396
|
+
statement: "Offer me a quiet place.",
|
|
397
|
+
category: "environment",
|
|
398
|
+
sourceMemoryIds: ["source-1"],
|
|
399
|
+
},
|
|
400
|
+
],
|
|
401
|
+
}),
|
|
402
|
+
(error: unknown) => error instanceof SupportPassportError && error.code === "card_data_invalid"
|
|
403
|
+
);
|
|
404
|
+
assert.deepEqual(await storage.readAllMemories(), []);
|
|
405
|
+
} finally {
|
|
406
|
+
StorageManager.clearAllStaticCaches();
|
|
407
|
+
await rm(root, { recursive: true, force: true });
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
test("generated draft batches scan the owner corpus once", async () => {
|
|
412
|
+
const subject = await makeSubject();
|
|
413
|
+
try {
|
|
414
|
+
const readAllMemories = subject.aliceStorage.readAllMemories.bind(subject.aliceStorage);
|
|
415
|
+
let corpusScans = 0;
|
|
416
|
+
subject.aliceStorage.readAllMemories = async (...args) => {
|
|
417
|
+
corpusScans += 1;
|
|
418
|
+
return await readAllMemories(...args);
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
const cards = await subject.service.createGeneratedDrafts({
|
|
422
|
+
principal: "owner:alice",
|
|
423
|
+
cards: [
|
|
424
|
+
{
|
|
425
|
+
title: "Quiet place",
|
|
426
|
+
statement: "Offer me a quiet place.",
|
|
427
|
+
category: "environment",
|
|
428
|
+
sourceMemoryIds: ["source-1"],
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
title: "Plan changes",
|
|
432
|
+
statement: "Tell me before plans change.",
|
|
433
|
+
category: "transitions",
|
|
434
|
+
sourceMemoryIds: ["source-2"],
|
|
435
|
+
},
|
|
436
|
+
],
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
assert.equal(cards.length, 2);
|
|
440
|
+
assert.equal(corpusScans, 1);
|
|
441
|
+
} finally {
|
|
442
|
+
await subject.cleanup();
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
|
|
385
446
|
test("manual draft creation returns the committed card without a post-write corpus reload", async () => {
|
|
386
447
|
const subject = await makeSubject();
|
|
387
448
|
try {
|
|
@@ -409,6 +470,81 @@ test("manual draft creation returns the committed card without a post-write corp
|
|
|
409
470
|
}
|
|
410
471
|
});
|
|
411
472
|
|
|
473
|
+
test("manual draft creation rolls back when its request is cancelled after persistence", async () => {
|
|
474
|
+
const subject = await makeSubject();
|
|
475
|
+
const controller = new AbortController();
|
|
476
|
+
const writeSealedMemory = subject.aliceStorage.writeSealedMemory.bind(subject.aliceStorage);
|
|
477
|
+
subject.aliceStorage.writeSealedMemory = async (...args) => {
|
|
478
|
+
const written = await writeSealedMemory(...args);
|
|
479
|
+
controller.abort(new Error("simulated owner request timeout"));
|
|
480
|
+
return written;
|
|
481
|
+
};
|
|
482
|
+
try {
|
|
483
|
+
await assert.rejects(
|
|
484
|
+
subject.service.createManualDraft(
|
|
485
|
+
{
|
|
486
|
+
principal: "owner:alice",
|
|
487
|
+
title: "Quiet place",
|
|
488
|
+
statement: "Offer me a quiet place and time.",
|
|
489
|
+
category: "environment",
|
|
490
|
+
reviewBy: OWNER_REVIEW_BY,
|
|
491
|
+
},
|
|
492
|
+
{ signal: controller.signal }
|
|
493
|
+
),
|
|
494
|
+
/simulated owner request timeout/
|
|
495
|
+
);
|
|
496
|
+
assert.deepEqual(await subject.service.listCards({ principal: "owner:alice" }), []);
|
|
497
|
+
const stored = await subject.aliceStorage.readAllMemories();
|
|
498
|
+
assert.equal(stored.length, 1);
|
|
499
|
+
assert.equal(stored[0]?.frontmatter.status, "rejected");
|
|
500
|
+
} finally {
|
|
501
|
+
await subject.cleanup();
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
test("card replacement rolls back when its request is cancelled after persistence", async () => {
|
|
506
|
+
const subject = await makeSubject();
|
|
507
|
+
const controller = new AbortController();
|
|
508
|
+
try {
|
|
509
|
+
const draft = await subject.service.createManualDraft({
|
|
510
|
+
principal: "owner:alice",
|
|
511
|
+
title: "Quiet place",
|
|
512
|
+
statement: "Offer me a quiet place.",
|
|
513
|
+
category: "environment",
|
|
514
|
+
reviewBy: OWNER_REVIEW_BY,
|
|
515
|
+
});
|
|
516
|
+
const writeSealedMemory = subject.aliceStorage.writeSealedMemory.bind(subject.aliceStorage);
|
|
517
|
+
subject.aliceStorage.writeSealedMemory = async (...args) => {
|
|
518
|
+
const written = await writeSealedMemory(...args);
|
|
519
|
+
controller.abort(new Error("simulated owner request timeout"));
|
|
520
|
+
return written;
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
await assert.rejects(
|
|
524
|
+
subject.service.replaceCard(
|
|
525
|
+
{
|
|
526
|
+
principal: "owner:alice",
|
|
527
|
+
cardId: draft.cardId,
|
|
528
|
+
expectedRevision: draft.revision,
|
|
529
|
+
title: "Quiet place and time",
|
|
530
|
+
statement: "Offer me a quiet place and time.",
|
|
531
|
+
category: "environment",
|
|
532
|
+
reviewBy: OWNER_REVIEW_BY,
|
|
533
|
+
},
|
|
534
|
+
{ signal: controller.signal }
|
|
535
|
+
),
|
|
536
|
+
/simulated owner request timeout/
|
|
537
|
+
);
|
|
538
|
+
assert.deepEqual(await subject.service.listCards({ principal: "owner:alice" }), [draft]);
|
|
539
|
+
const stored = await subject.aliceStorage.readAllMemories();
|
|
540
|
+
assert.equal(stored.length, 2);
|
|
541
|
+
assert.equal(stored.find((memory) => memory.frontmatter.id === draft.cardId)?.frontmatter.status, "pending_review");
|
|
542
|
+
assert.equal(stored.find((memory) => memory.frontmatter.id !== draft.cardId)?.frontmatter.status, "rejected");
|
|
543
|
+
} finally {
|
|
544
|
+
await subject.cleanup();
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
|
|
412
548
|
test("listing linkless drafts does not rescan the corpus by card ID", async () => {
|
|
413
549
|
const subject = await makeSubject();
|
|
414
550
|
try {
|
|
@@ -466,7 +602,7 @@ test("listing a pending replacement does not add a final unchanged-corpus reload
|
|
|
466
602
|
|
|
467
603
|
await subject.service.listCards({ principal: "owner:alice" });
|
|
468
604
|
|
|
469
|
-
assert.equal(corpusReads,
|
|
605
|
+
assert.equal(corpusReads, 1);
|
|
470
606
|
} finally {
|
|
471
607
|
await subject.cleanup();
|
|
472
608
|
}
|
|
@@ -701,7 +837,8 @@ test("rejecting a source draft rejects its interrupted hidden replacement", asyn
|
|
|
701
837
|
});
|
|
702
838
|
|
|
703
839
|
test("replacement audits retain the card owner scope and omit internal attributes", async () => {
|
|
704
|
-
const
|
|
840
|
+
const namespace = "team]primary\ncare";
|
|
841
|
+
const subject = await makeSharedStorageSubject(namespace);
|
|
705
842
|
try {
|
|
706
843
|
const draft = await subject.service.createManualDraft({
|
|
707
844
|
principal: "owner:alice",
|
|
@@ -743,10 +880,10 @@ test("replacement audits retain the card owner scope and omit internal attribute
|
|
|
743
880
|
);
|
|
744
881
|
assert.equal(stripAttributesSuffix(audit.content).includes("support-passport-title"), false);
|
|
745
882
|
assert.equal(audit.frontmatter.source, "support-passport");
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
);
|
|
883
|
+
const auditAttributes = audit.frontmatter.structuredAttributes;
|
|
884
|
+
assert.ok(auditAttributes);
|
|
885
|
+
assert.equal(decodeSupportPassportNamespaceAttributes(auditAttributes), namespace);
|
|
886
|
+
assert.notEqual(auditAttributes["support-passport-namespace"], namespace);
|
|
750
887
|
assert.equal(
|
|
751
888
|
audit.frontmatter.structuredAttributes?.["support-passport-owner"],
|
|
752
889
|
(await subject.storage.getMemoryById(active.cardId))?.frontmatter.structuredAttributes?.["support-passport-owner"]
|
|
@@ -1394,8 +1531,8 @@ test("retrying an interrupted pending-draft replacement rejects changed content"
|
|
|
1394
1531
|
);
|
|
1395
1532
|
const visible = await subject.service.listCards({ principal: "owner:alice" });
|
|
1396
1533
|
assert.equal(visible.length, 1);
|
|
1397
|
-
assert.equal(visible[0]?.cardId,
|
|
1398
|
-
assert.equal(visible[0]?.statement, "Offer me a quiet place
|
|
1534
|
+
assert.equal(visible[0]?.cardId, draft.cardId);
|
|
1535
|
+
assert.equal(visible[0]?.statement, "Offer me a quiet place.");
|
|
1399
1536
|
assert.equal((await subject.aliceStorage.readAllMemories()).length, 2);
|
|
1400
1537
|
} finally {
|
|
1401
1538
|
await subject.cleanup();
|
|
@@ -1496,7 +1633,7 @@ test("replacement approval rolls back when predecessor retirement returns false"
|
|
|
1496
1633
|
}
|
|
1497
1634
|
});
|
|
1498
1635
|
|
|
1499
|
-
test("listing
|
|
1636
|
+
test("listing projects an incomplete active replacement without recovery writes", async () => {
|
|
1500
1637
|
const subject = await makeSubject();
|
|
1501
1638
|
try {
|
|
1502
1639
|
const draft = await subject.service.createManualDraft({
|
|
@@ -1534,19 +1671,76 @@ test("listing rolls back an incomplete active replacement when retirement return
|
|
|
1534
1671
|
cardId: replacement.cardId,
|
|
1535
1672
|
expectedRevision: replacement.revision,
|
|
1536
1673
|
});
|
|
1537
|
-
|
|
1674
|
+
let recoveryWrites = 0;
|
|
1675
|
+
subject.aliceStorage.supersedeMemory = async () => {
|
|
1676
|
+
recoveryWrites += 1;
|
|
1677
|
+
return false;
|
|
1678
|
+
};
|
|
1679
|
+
const writeFrontmatter = subject.aliceStorage.writeMemoryFrontmatterIfUnchanged.bind(subject.aliceStorage);
|
|
1680
|
+
subject.aliceStorage.writeMemoryFrontmatterIfUnchanged = async (...args) => {
|
|
1681
|
+
recoveryWrites += 1;
|
|
1682
|
+
return await writeFrontmatter(...args);
|
|
1683
|
+
};
|
|
1538
1684
|
|
|
1539
1685
|
const visible = await subject.service.listCards({ principal: "owner:alice" });
|
|
1540
1686
|
|
|
1541
1687
|
subject.aliceStorage.supersedeMemory = originalSupersede;
|
|
1542
1688
|
assert.deepEqual(
|
|
1543
1689
|
visible.map((card) => [card.cardId, card.status]),
|
|
1544
|
-
[
|
|
1545
|
-
[active.cardId, "active"],
|
|
1546
|
-
[replacement.cardId, "pending_review"],
|
|
1547
|
-
]
|
|
1690
|
+
[[replacement.cardId, "active"]]
|
|
1548
1691
|
);
|
|
1692
|
+
assert.equal(recoveryWrites, 0);
|
|
1693
|
+
assert.equal((await subject.aliceStorage.getMemoryById(active.cardId))?.frontmatter.status, "superseded");
|
|
1694
|
+
} finally {
|
|
1695
|
+
await subject.cleanup();
|
|
1696
|
+
}
|
|
1697
|
+
});
|
|
1698
|
+
|
|
1699
|
+
test("listing projects one card when predecessor retirement has not started", async () => {
|
|
1700
|
+
const subject = await makeSubject();
|
|
1701
|
+
try {
|
|
1702
|
+
const draft = await subject.service.createManualDraft({
|
|
1703
|
+
principal: "owner:alice",
|
|
1704
|
+
title: "Plan changes",
|
|
1705
|
+
statement: "Tell me before plans change.",
|
|
1706
|
+
category: "transitions",
|
|
1707
|
+
reviewBy: OWNER_REVIEW_BY,
|
|
1708
|
+
});
|
|
1709
|
+
const active = await subject.service.approveCard({
|
|
1710
|
+
principal: "owner:alice",
|
|
1711
|
+
cardId: draft.cardId,
|
|
1712
|
+
expectedRevision: draft.revision,
|
|
1713
|
+
});
|
|
1714
|
+
const replacement = await subject.service.replaceCard({
|
|
1715
|
+
principal: "owner:alice",
|
|
1716
|
+
cardId: active.cardId,
|
|
1717
|
+
expectedRevision: active.revision,
|
|
1718
|
+
title: "Plan changes",
|
|
1719
|
+
statement: "Tell me early when plans change.",
|
|
1720
|
+
category: "transitions",
|
|
1721
|
+
reviewBy: OWNER_REVIEW_BY,
|
|
1722
|
+
});
|
|
1723
|
+
const originalWrite = subject.aliceStorage.writeMemoryFrontmatterIfUnchanged.bind(subject.aliceStorage);
|
|
1724
|
+
subject.aliceStorage.writeMemoryFrontmatterIfUnchanged = async (memory, patch, lifecycle) => {
|
|
1725
|
+
if (lifecycle?.reasonCode === "support-passport-replacement-pending") {
|
|
1726
|
+
throw new Error("simulated interruption before predecessor retirement");
|
|
1727
|
+
}
|
|
1728
|
+
return await originalWrite(memory, patch, lifecycle);
|
|
1729
|
+
};
|
|
1730
|
+
|
|
1731
|
+
const approved = await subject.service.approveCard({
|
|
1732
|
+
principal: "owner:alice",
|
|
1733
|
+
cardId: replacement.cardId,
|
|
1734
|
+
expectedRevision: replacement.revision,
|
|
1735
|
+
});
|
|
1736
|
+
const visible = await subject.service.listCards({ principal: "owner:alice" });
|
|
1737
|
+
|
|
1738
|
+
assert.equal(approved.status, "active");
|
|
1549
1739
|
assert.equal((await subject.aliceStorage.getMemoryById(active.cardId))?.frontmatter.status, "active");
|
|
1740
|
+
assert.deepEqual(
|
|
1741
|
+
visible.map((card) => [card.cardId, card.status]),
|
|
1742
|
+
[[replacement.cardId, "active"]]
|
|
1743
|
+
);
|
|
1550
1744
|
} finally {
|
|
1551
1745
|
await subject.cleanup();
|
|
1552
1746
|
}
|
|
@@ -1825,7 +2019,7 @@ test("rejection stops when a retired predecessor cannot be restored", async () =
|
|
|
1825
2019
|
}
|
|
1826
2020
|
});
|
|
1827
2021
|
|
|
1828
|
-
test("an orphaned replacement
|
|
2022
|
+
test("listing hides an orphaned replacement without recovery writes", async () => {
|
|
1829
2023
|
const subject = await makeSubject();
|
|
1830
2024
|
try {
|
|
1831
2025
|
const { approved, replacement } = await createOrphanedReplacement(subject);
|
|
@@ -1926,7 +2120,7 @@ test("failed replacement activation stays pending through recovery", async () =>
|
|
|
1926
2120
|
}
|
|
1927
2121
|
});
|
|
1928
2122
|
|
|
1929
|
-
test("a draft rollback failure
|
|
2123
|
+
test("a draft rollback failure keeps one visible card", async () => {
|
|
1930
2124
|
const subject = await makeSubject();
|
|
1931
2125
|
try {
|
|
1932
2126
|
const draft = await subject.service.createManualDraft({
|
|
@@ -1963,19 +2157,19 @@ test("a draft rollback failure recovers to one visible card", async () => {
|
|
|
1963
2157
|
assert.equal(rollbackAttempts, 1);
|
|
1964
2158
|
const visible = await subject.service.listCards({ principal: "owner:alice" });
|
|
1965
2159
|
assert.equal(visible.length, 1);
|
|
1966
|
-
assert.
|
|
2160
|
+
assert.equal(visible[0]?.cardId, draft.cardId);
|
|
1967
2161
|
const cards = (await subject.aliceStorage.readAllMemories()).filter((memory) =>
|
|
1968
2162
|
memory.frontmatter.tags?.includes("support-passport-card")
|
|
1969
2163
|
);
|
|
1970
2164
|
assert.equal(cards.length, 2);
|
|
1971
|
-
assert.equal(cards.filter((memory) => memory.frontmatter.status === "pending_review").length,
|
|
1972
|
-
assert.equal(cards.filter((memory) => memory.frontmatter.status === "rejected").length,
|
|
2165
|
+
assert.equal(cards.filter((memory) => memory.frontmatter.status === "pending_review").length, 2);
|
|
2166
|
+
assert.equal(cards.filter((memory) => memory.frontmatter.status === "rejected").length, 0);
|
|
1973
2167
|
} finally {
|
|
1974
2168
|
await subject.cleanup();
|
|
1975
2169
|
}
|
|
1976
2170
|
});
|
|
1977
2171
|
|
|
1978
|
-
test("a missing replaced draft
|
|
2172
|
+
test("a missing replaced draft stays hidden without recovery writes", async () => {
|
|
1979
2173
|
const subject = await makeSubject();
|
|
1980
2174
|
try {
|
|
1981
2175
|
const draft = await subject.service.createManualDraft({
|
|
@@ -2015,11 +2209,33 @@ test("a missing replaced draft rejects its orphaned replacement without blocking
|
|
|
2015
2209
|
await rm(original.path);
|
|
2016
2210
|
StorageManager.clearAllStaticCaches();
|
|
2017
2211
|
|
|
2212
|
+
let recoveryWrites = 0;
|
|
2213
|
+
subject.aliceStorage.writeMemoryFrontmatterIfUnchanged = async (...args) => {
|
|
2214
|
+
recoveryWrites += 1;
|
|
2215
|
+
return await originalWrite(...args);
|
|
2216
|
+
};
|
|
2018
2217
|
assert.deepEqual(await subject.service.listCards({ principal: "owner:alice" }), []);
|
|
2019
2218
|
assert.equal(
|
|
2020
2219
|
(await subject.aliceStorage.getMemoryById(replacement.frontmatter.id))?.frontmatter.status,
|
|
2021
|
-
"
|
|
2220
|
+
"pending_review"
|
|
2022
2221
|
);
|
|
2222
|
+
assert.equal(recoveryWrites, 0);
|
|
2223
|
+
const readStoredMemories = subject.aliceStorage.readAllMemories.bind(subject.aliceStorage);
|
|
2224
|
+
subject.aliceStorage.readAllMemories = async () => [
|
|
2225
|
+
replacement,
|
|
2226
|
+
...Array.from({ length: 99 }, (_, index) => ({
|
|
2227
|
+
...original,
|
|
2228
|
+
path: `${original.path}-capacity-${index}`,
|
|
2229
|
+
frontmatter: {
|
|
2230
|
+
...original.frontmatter,
|
|
2231
|
+
id: `support-card-capacity-${index}`,
|
|
2232
|
+
structuredAttributes: {
|
|
2233
|
+
...original.frontmatter.structuredAttributes,
|
|
2234
|
+
"support-passport-order": String(index),
|
|
2235
|
+
},
|
|
2236
|
+
},
|
|
2237
|
+
})),
|
|
2238
|
+
];
|
|
2023
2239
|
const newDraft = await subject.service.createManualDraft({
|
|
2024
2240
|
principal: "owner:alice",
|
|
2025
2241
|
title: "New guide",
|
|
@@ -2027,6 +2243,7 @@ test("a missing replaced draft rejects its orphaned replacement without blocking
|
|
|
2027
2243
|
category: "other",
|
|
2028
2244
|
reviewBy: OWNER_REVIEW_BY,
|
|
2029
2245
|
});
|
|
2246
|
+
subject.aliceStorage.readAllMemories = readStoredMemories;
|
|
2030
2247
|
assert.equal(newDraft.status, "pending_review");
|
|
2031
2248
|
} finally {
|
|
2032
2249
|
await subject.cleanup();
|
|
@@ -2460,3 +2677,288 @@ test("draft creation aborts when the owner lock is lost before its write", async
|
|
|
2460
2677
|
await subject.cleanup();
|
|
2461
2678
|
}
|
|
2462
2679
|
});
|
|
2680
|
+
|
|
2681
|
+
test("generated draft rollback retries a compare-and-swap conflict", async () => {
|
|
2682
|
+
const subject = await makeSubject();
|
|
2683
|
+
try {
|
|
2684
|
+
const writeSealedMemory = subject.aliceStorage.writeSealedMemory.bind(subject.aliceStorage);
|
|
2685
|
+
const readAllMemories = subject.aliceStorage.readAllMemories.bind(subject.aliceStorage);
|
|
2686
|
+
let writes = 0;
|
|
2687
|
+
subject.aliceStorage.writeSealedMemory = async (...args) => {
|
|
2688
|
+
writes += 1;
|
|
2689
|
+
if (writes === 2) throw new Error("second draft write failed");
|
|
2690
|
+
return await writeSealedMemory(...args);
|
|
2691
|
+
};
|
|
2692
|
+
const writeFrontmatter = subject.aliceStorage.writeMemoryFrontmatterIfUnchanged.bind(subject.aliceStorage);
|
|
2693
|
+
let rollbackAttempts = 0;
|
|
2694
|
+
subject.aliceStorage.writeMemoryFrontmatterIfUnchanged = async (memory, patch, lifecycle) => {
|
|
2695
|
+
if (lifecycle?.reasonCode === "draft-batch-failed") {
|
|
2696
|
+
rollbackAttempts += 1;
|
|
2697
|
+
if (rollbackAttempts === 1) return false;
|
|
2698
|
+
}
|
|
2699
|
+
return await writeFrontmatter(memory, patch, lifecycle);
|
|
2700
|
+
};
|
|
2701
|
+
|
|
2702
|
+
await assert.rejects(
|
|
2703
|
+
subject.service.createGeneratedDrafts({
|
|
2704
|
+
principal: "owner:alice",
|
|
2705
|
+
cards: [
|
|
2706
|
+
{
|
|
2707
|
+
title: "First draft",
|
|
2708
|
+
statement: "Give me time to answer.",
|
|
2709
|
+
category: "communication",
|
|
2710
|
+
sourceMemoryIds: ["source-1"],
|
|
2711
|
+
},
|
|
2712
|
+
{
|
|
2713
|
+
title: "Second draft",
|
|
2714
|
+
statement: "Tell me before plans change.",
|
|
2715
|
+
category: "transitions",
|
|
2716
|
+
sourceMemoryIds: ["source-2"],
|
|
2717
|
+
},
|
|
2718
|
+
],
|
|
2719
|
+
}),
|
|
2720
|
+
/second draft write failed/
|
|
2721
|
+
);
|
|
2722
|
+
assert.equal(rollbackAttempts, 2);
|
|
2723
|
+
assert.deepEqual(await subject.service.listCards({ principal: "owner:alice" }), []);
|
|
2724
|
+
const rollbackEvent = (await subject.aliceStorage.readAllMemoryLifecycleEvents()).find(
|
|
2725
|
+
(event) => event.reasonCode === "draft-batch-failed"
|
|
2726
|
+
);
|
|
2727
|
+
assert.equal(rollbackEvent?.actor, "owner:alice");
|
|
2728
|
+
} finally {
|
|
2729
|
+
await subject.cleanup();
|
|
2730
|
+
}
|
|
2731
|
+
});
|
|
2732
|
+
|
|
2733
|
+
test("generated draft rollback continues after one cleanup throws", async () => {
|
|
2734
|
+
const subject = await makeSubject();
|
|
2735
|
+
try {
|
|
2736
|
+
const writeSealedMemory = subject.aliceStorage.writeSealedMemory.bind(subject.aliceStorage);
|
|
2737
|
+
let writes = 0;
|
|
2738
|
+
subject.aliceStorage.writeSealedMemory = async (...args) => {
|
|
2739
|
+
writes += 1;
|
|
2740
|
+
if (writes === 3) throw new Error("third draft write failed");
|
|
2741
|
+
return await writeSealedMemory(...args);
|
|
2742
|
+
};
|
|
2743
|
+
const writeFrontmatter = subject.aliceStorage.writeMemoryFrontmatterIfUnchanged.bind(subject.aliceStorage);
|
|
2744
|
+
let rollbackAttempts = 0;
|
|
2745
|
+
subject.aliceStorage.writeMemoryFrontmatterIfUnchanged = async (memory, patch, lifecycle) => {
|
|
2746
|
+
if (lifecycle?.reasonCode === "draft-batch-failed") {
|
|
2747
|
+
rollbackAttempts += 1;
|
|
2748
|
+
if (rollbackAttempts === 1) throw new Error("first cleanup failed");
|
|
2749
|
+
}
|
|
2750
|
+
return await writeFrontmatter(memory, patch, lifecycle);
|
|
2751
|
+
};
|
|
2752
|
+
|
|
2753
|
+
await assert.rejects(
|
|
2754
|
+
subject.service.createGeneratedDrafts({
|
|
2755
|
+
principal: "owner:alice",
|
|
2756
|
+
cards: [
|
|
2757
|
+
{
|
|
2758
|
+
title: "First draft",
|
|
2759
|
+
statement: "Give me time to answer.",
|
|
2760
|
+
category: "communication",
|
|
2761
|
+
sourceMemoryIds: ["source-1"],
|
|
2762
|
+
},
|
|
2763
|
+
{
|
|
2764
|
+
title: "Second draft",
|
|
2765
|
+
statement: "Tell me before plans change.",
|
|
2766
|
+
category: "transitions",
|
|
2767
|
+
sourceMemoryIds: ["source-2"],
|
|
2768
|
+
},
|
|
2769
|
+
{
|
|
2770
|
+
title: "Third draft",
|
|
2771
|
+
statement: "Dim bright lights when possible.",
|
|
2772
|
+
category: "sensory",
|
|
2773
|
+
sourceMemoryIds: ["source-3"],
|
|
2774
|
+
},
|
|
2775
|
+
],
|
|
2776
|
+
}),
|
|
2777
|
+
(error: unknown) => error instanceof SupportPassportError && error.code === "storage_conflict"
|
|
2778
|
+
);
|
|
2779
|
+
assert.equal(rollbackAttempts, 2);
|
|
2780
|
+
const remaining = await subject.service.listCards({ principal: "owner:alice" });
|
|
2781
|
+
assert.deepEqual(remaining, []);
|
|
2782
|
+
} finally {
|
|
2783
|
+
await subject.cleanup();
|
|
2784
|
+
}
|
|
2785
|
+
});
|
|
2786
|
+
|
|
2787
|
+
test("generated draft rollback rejects known cards when the corpus scan fails", async () => {
|
|
2788
|
+
const subject = await makeSubject();
|
|
2789
|
+
try {
|
|
2790
|
+
const writeSealedMemory = subject.aliceStorage.writeSealedMemory.bind(subject.aliceStorage);
|
|
2791
|
+
const readAllMemories = subject.aliceStorage.readAllMemories.bind(subject.aliceStorage);
|
|
2792
|
+
let writes = 0;
|
|
2793
|
+
subject.aliceStorage.writeSealedMemory = async (...args) => {
|
|
2794
|
+
const written = await writeSealedMemory(...args);
|
|
2795
|
+
writes += 1;
|
|
2796
|
+
if (writes === 1) {
|
|
2797
|
+
let failNextCorpusScan = true;
|
|
2798
|
+
subject.aliceStorage.readAllMemories = async (...readArgs) => {
|
|
2799
|
+
if (!failNextCorpusScan) return await readAllMemories(...readArgs);
|
|
2800
|
+
failNextCorpusScan = false;
|
|
2801
|
+
throw new Error("simulated corpus scan failure");
|
|
2802
|
+
};
|
|
2803
|
+
}
|
|
2804
|
+
if (writes === 2) throw new Error("second draft write failed");
|
|
2805
|
+
return written;
|
|
2806
|
+
};
|
|
2807
|
+
|
|
2808
|
+
await assert.rejects(
|
|
2809
|
+
subject.service.createGeneratedDrafts({
|
|
2810
|
+
principal: "owner:alice",
|
|
2811
|
+
cards: [
|
|
2812
|
+
{
|
|
2813
|
+
title: "First draft",
|
|
2814
|
+
statement: "Give me time to answer.",
|
|
2815
|
+
category: "communication",
|
|
2816
|
+
sourceMemoryIds: ["source-1"],
|
|
2817
|
+
},
|
|
2818
|
+
{
|
|
2819
|
+
title: "Second draft",
|
|
2820
|
+
statement: "Tell me before plans change.",
|
|
2821
|
+
category: "transitions",
|
|
2822
|
+
sourceMemoryIds: ["source-2"],
|
|
2823
|
+
},
|
|
2824
|
+
],
|
|
2825
|
+
}),
|
|
2826
|
+
(error: unknown) => error instanceof SupportPassportError && error.code === "storage_conflict"
|
|
2827
|
+
);
|
|
2828
|
+
const persisted = (await readAllMemories()).find((memory) =>
|
|
2829
|
+
memory.frontmatter.tags?.includes("support-passport-card")
|
|
2830
|
+
);
|
|
2831
|
+
assert.equal(persisted?.frontmatter.status, "rejected");
|
|
2832
|
+
} finally {
|
|
2833
|
+
await subject.cleanup();
|
|
2834
|
+
}
|
|
2835
|
+
});
|
|
2836
|
+
|
|
2837
|
+
test("listing stays read-only before a later mutation recovers an incomplete batch", async () => {
|
|
2838
|
+
const subject = await makeSubject();
|
|
2839
|
+
try {
|
|
2840
|
+
const commitWithValidatedSources = async (_commit: () => Promise<void>) => {
|
|
2841
|
+
if ((await subject.aliceStorage.readAllMemories()).length > 0) {
|
|
2842
|
+
throw new Error("simulated process exit after generated card persistence");
|
|
2843
|
+
}
|
|
2844
|
+
};
|
|
2845
|
+
const writeFrontmatter = subject.aliceStorage.writeMemoryFrontmatterIfUnchanged.bind(subject.aliceStorage);
|
|
2846
|
+
subject.aliceStorage.writeMemoryFrontmatterIfUnchanged = async (memory, patch, lifecycle) => {
|
|
2847
|
+
if (lifecycle?.reasonCode === "draft-batch-failed") {
|
|
2848
|
+
throw new Error("simulated process exit before cleanup");
|
|
2849
|
+
}
|
|
2850
|
+
return await writeFrontmatter(memory, patch, lifecycle);
|
|
2851
|
+
};
|
|
2852
|
+
|
|
2853
|
+
await assert.rejects(
|
|
2854
|
+
subject.service.createGeneratedDraftsForOwner({
|
|
2855
|
+
authenticatedPrincipal: "owner:alice",
|
|
2856
|
+
owner: { principal: "owner:alice", namespace: "alice", storage: subject.aliceStorage },
|
|
2857
|
+
cards: [
|
|
2858
|
+
{
|
|
2859
|
+
title: "First draft",
|
|
2860
|
+
statement: "Give me time to answer.",
|
|
2861
|
+
category: "communication",
|
|
2862
|
+
sourceMemoryIds: ["source-1"],
|
|
2863
|
+
},
|
|
2864
|
+
],
|
|
2865
|
+
commitWithValidatedSources,
|
|
2866
|
+
}),
|
|
2867
|
+
(error: unknown) => error instanceof SupportPassportError && error.code === "storage_conflict"
|
|
2868
|
+
);
|
|
2869
|
+
subject.aliceStorage.writeMemoryFrontmatterIfUnchanged = writeFrontmatter;
|
|
2870
|
+
|
|
2871
|
+
const persisted = await subject.aliceStorage.readAllMemories();
|
|
2872
|
+
const card = persisted.find((memory) => memory.frontmatter.tags?.includes("support-passport-card"));
|
|
2873
|
+
assert.ok(card);
|
|
2874
|
+
assert.equal(card.frontmatter.status, "pending_review");
|
|
2875
|
+
const batchId = card.frontmatter.structuredAttributes?.["support-passport-generated-batch-id"];
|
|
2876
|
+
assert.match(batchId ?? "", /^[0-9a-f-]{36}$/);
|
|
2877
|
+
const markerPath = path.join(
|
|
2878
|
+
subject.aliceStorage.dir,
|
|
2879
|
+
"state",
|
|
2880
|
+
"support-passport",
|
|
2881
|
+
"generated-batches",
|
|
2882
|
+
`${batchId}.json`
|
|
2883
|
+
);
|
|
2884
|
+
const marker = JSON.parse(await readFile(markerPath, "utf8")) as { complete?: unknown; size?: unknown };
|
|
2885
|
+
assert.equal(marker.complete, false);
|
|
2886
|
+
assert.equal(marker.size, 1);
|
|
2887
|
+
|
|
2888
|
+
StorageManager.clearAllStaticCaches();
|
|
2889
|
+
const restartedStorage = new StorageManager(subject.aliceStorage.dir);
|
|
2890
|
+
await restartedStorage.ensureDirectories();
|
|
2891
|
+
const restarted = new SupportPassportCardService({
|
|
2892
|
+
resolveOwner: async (principal) => ({ principal, namespace: "alice", storage: restartedStorage }),
|
|
2893
|
+
});
|
|
2894
|
+
assert.deepEqual(await restarted.listCards({ principal: "owner:alice" }), []);
|
|
2895
|
+
assert.equal(
|
|
2896
|
+
(await restartedStorage.readAllMemories()).find((memory) => memory.frontmatter.id === card.frontmatter.id)
|
|
2897
|
+
?.frontmatter.status,
|
|
2898
|
+
"pending_review"
|
|
2899
|
+
);
|
|
2900
|
+
await readFile(markerPath, "utf8");
|
|
2901
|
+
await restarted.createManualDraft({
|
|
2902
|
+
principal: "owner:alice",
|
|
2903
|
+
title: "Recovery draft",
|
|
2904
|
+
statement: "This mutation recovers an interrupted generated batch.",
|
|
2905
|
+
category: "other",
|
|
2906
|
+
reviewBy: OWNER_REVIEW_BY,
|
|
2907
|
+
});
|
|
2908
|
+
assert.equal(
|
|
2909
|
+
(await restartedStorage.readAllMemories()).find((memory) => memory.frontmatter.id === card.frontmatter.id)
|
|
2910
|
+
?.frontmatter.status,
|
|
2911
|
+
"rejected"
|
|
2912
|
+
);
|
|
2913
|
+
await assert.rejects(readFile(markerPath, "utf8"), (error: unknown) => {
|
|
2914
|
+
return (error as NodeJS.ErrnoException).code === "ENOENT";
|
|
2915
|
+
});
|
|
2916
|
+
} finally {
|
|
2917
|
+
await subject.cleanup();
|
|
2918
|
+
}
|
|
2919
|
+
});
|
|
2920
|
+
|
|
2921
|
+
test("completed generated batches survive individual card withdrawal", async () => {
|
|
2922
|
+
const subject = await makeSubject();
|
|
2923
|
+
try {
|
|
2924
|
+
const drafts = await subject.service.createGeneratedDrafts({
|
|
2925
|
+
principal: "owner:alice",
|
|
2926
|
+
cards: [
|
|
2927
|
+
{
|
|
2928
|
+
title: "Communication",
|
|
2929
|
+
statement: "Give me time to answer.",
|
|
2930
|
+
category: "communication",
|
|
2931
|
+
sourceMemoryIds: ["source-1"],
|
|
2932
|
+
},
|
|
2933
|
+
{
|
|
2934
|
+
title: "Transitions",
|
|
2935
|
+
statement: "Tell me before plans change.",
|
|
2936
|
+
category: "transitions",
|
|
2937
|
+
sourceMemoryIds: ["source-2"],
|
|
2938
|
+
},
|
|
2939
|
+
],
|
|
2940
|
+
});
|
|
2941
|
+
const active = [];
|
|
2942
|
+
for (const draft of drafts) {
|
|
2943
|
+
active.push(
|
|
2944
|
+
await subject.service.approveCard({
|
|
2945
|
+
principal: "owner:alice",
|
|
2946
|
+
cardId: draft.cardId,
|
|
2947
|
+
expectedRevision: draft.revision,
|
|
2948
|
+
})
|
|
2949
|
+
);
|
|
2950
|
+
}
|
|
2951
|
+
await subject.service.withdrawCard({
|
|
2952
|
+
principal: "owner:alice",
|
|
2953
|
+
cardId: active[0]!.cardId,
|
|
2954
|
+
expectedRevision: active[0]!.revision,
|
|
2955
|
+
});
|
|
2956
|
+
|
|
2957
|
+
assert.deepEqual(
|
|
2958
|
+
(await subject.service.listCards({ principal: "owner:alice" })).map((card) => card.cardId),
|
|
2959
|
+
[active[1]!.cardId]
|
|
2960
|
+
);
|
|
2961
|
+
} finally {
|
|
2962
|
+
await subject.cleanup();
|
|
2963
|
+
}
|
|
2964
|
+
});
|