@remnic/core 9.69.10 → 9.69.12
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 +15 -13
- package/dist/access-admin-ops-surface.js +46 -34
- package/dist/access-authorization-probe.d.ts +13 -11
- package/dist/access-authorization-probe.js +47 -35
- package/dist/access-boundary.d.ts +13 -11
- package/dist/access-boundary.js +46 -34
- package/dist/access-cli.js +108 -97
- package/dist/access-cli.js.map +1 -1
- package/dist/access-coding-context-resolution.d.ts +2 -1
- package/dist/access-extraction-force-flush.d.ts +13 -11
- package/dist/access-extraction-force-flush.js +46 -34
- package/dist/access-health-types.d.ts +2 -1
- package/dist/access-http-lcm-compaction.d.ts +13 -11
- package/dist/access-http-lifecycle-flush.d.ts +13 -11
- package/dist/access-http-offline-stream.d.ts +13 -11
- package/dist/access-http-query.d.ts +3 -2
- package/dist/access-http-query.js +48 -36
- package/dist/access-http.d.ts +14 -12
- package/dist/access-http.js +67 -53
- package/dist/access-identity-continuity-surface.d.ts +10 -9
- package/dist/access-identity-continuity-surface.js +46 -34
- package/dist/access-lcm-surface.d.ts +13 -11
- package/dist/access-lcm-surface.js +46 -34
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.d.ts +13 -11
- package/dist/access-mcp.js +58 -45
- package/dist/access-memory-search-fanout.d.ts +3 -2
- package/dist/{access-namespace-preflight-S8fhQcCo.d.ts → access-namespace-preflight-Cy0yPsaE.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +4 -3
- package/dist/access-namespace-preflight.js +46 -34
- package/dist/access-observe-write-surface.d.ts +15 -13
- package/dist/access-observe-write-surface.js +46 -34
- package/dist/access-offline-manifest.d.ts +10 -9
- package/dist/access-offline-manifest.js +3 -3
- package/dist/access-operations-batch.js +49 -37
- package/dist/access-operations.d.ts +19 -17
- package/dist/access-operations.js +54 -42
- package/dist/access-recall-concurrency.d.ts +13 -11
- package/dist/access-recall-concurrency.js +46 -34
- package/dist/access-recall-response.d.ts +13 -11
- package/dist/access-recall-response.js +46 -34
- package/dist/access-recall-surface.d.ts +13 -11
- package/dist/access-recall-surface.js +46 -34
- package/dist/access-schema.d.ts +107 -90
- package/dist/access-schema.js +7 -5
- package/dist/{access-service-DcfM0Vf0.d.ts → access-service-Baz5xW5X.d.ts} +89 -72
- package/dist/access-service-helpers.d.ts +13 -11
- package/dist/access-service.d.ts +13 -11
- package/dist/access-service.js +46 -34
- package/dist/access-surface-catalog.d.ts +13 -11
- package/dist/access-surface-catalog.js +50 -36
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-wearables-meetings-surface.d.ts +4 -3
- package/dist/action-confidence.d.ts +2 -1
- package/dist/active-memory-bridge.d.ts +2 -1
- package/dist/active-recall.d.ts +2 -1
- package/dist/active-recall.js +6 -5
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/ambient-provenance.d.ts +2 -1
- package/dist/artifact-search.d.ts +2 -1
- package/dist/behavior-learner.d.ts +2 -1
- package/dist/behavior-signals.d.ts +2 -1
- package/dist/bootstrap.d.ts +10 -9
- package/dist/briefing-window.d.ts +3 -2
- package/dist/briefing.d.ts +3 -2
- package/dist/briefing.js +13 -13
- package/dist/buffer-surprise-report.d.ts +2 -1
- package/dist/buffer-turn-helpers.d.ts +2 -1
- package/dist/buffer.d.ts +3 -2
- package/dist/bulk-import/index.d.ts +4 -3
- package/dist/calibration.d.ts +2 -1
- package/dist/capabilities.d.ts +2 -1
- package/dist/{catalog-BmBXTtOs.d.ts → catalog-9X8WpZNO.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +2 -1
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.d.ts +2 -1
- package/dist/causal-consolidation.js +16 -16
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.d.ts +2 -1
- package/dist/causal-trajectory-graph.js +2 -2
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-D5VPIJN3.js → chunk-227WJVPY.js} +2 -2
- package/dist/{chunk-Y3BWCIY2.js → chunk-2EHDPHMD.js} +2 -2
- package/dist/{chunk-2LKW6OO7.js → chunk-2XJDAEAM.js} +2 -2
- package/dist/{chunk-P23JWI3D.js → chunk-3ITTF7YH.js} +52 -52
- package/dist/{chunk-3DT2F5OI.js → chunk-3YKOFCKP.js} +11 -6
- package/dist/chunk-3YKOFCKP.js.map +1 -0
- package/dist/{chunk-NGP2FPB2.js → chunk-4UVDLNHQ.js} +2 -2
- package/dist/{chunk-HXWOVCS6.js → chunk-4WIKMOE3.js} +44 -22
- package/dist/chunk-4WIKMOE3.js.map +1 -0
- package/dist/{chunk-6RPB2TDG.js → chunk-5HO3QBAD.js} +11 -6
- package/dist/chunk-5HO3QBAD.js.map +1 -0
- package/dist/{chunk-AYWPIH4M.js → chunk-5P2KNFJZ.js} +149 -25
- package/dist/chunk-5P2KNFJZ.js.map +1 -0
- package/dist/{chunk-FJMIQTMH.js → chunk-5YQ7RFSO.js} +2 -2
- package/dist/{chunk-KQAFEZQX.js → chunk-7LCGFUMB.js} +4 -4
- package/dist/{chunk-EESYTBXV.js → chunk-7NCUHD5U.js} +2 -2
- package/dist/{chunk-X574KX52.js → chunk-7ZMU4XQT.js} +2 -2
- package/dist/{chunk-SG3Z67FB.js → chunk-APZXA4WI.js} +2 -2
- package/dist/{chunk-2QSZNTDO.js → chunk-AU7Q3LSC.js} +4 -4
- package/dist/{chunk-VGMRI4J6.js → chunk-B75VCEX5.js} +4 -4
- package/dist/{chunk-D35XLYQ7.js → chunk-BE4Y6GK6.js} +11 -11
- package/dist/{chunk-ELKD5PCD.js → chunk-BEXFNGQ3.js} +3 -3
- package/dist/{chunk-U5SRTYFS.js → chunk-BFDOBESV.js} +2 -2
- package/dist/{chunk-OLT3YTDH.js → chunk-BIJAWZYW.js} +4 -4
- package/dist/{chunk-FU2NYFX6.js → chunk-BO4PWIJY.js} +3 -3
- package/dist/{chunk-JMAG7WZ7.js → chunk-BX6GW4KC.js} +2 -2
- package/dist/chunk-CC37E3QM.js +198 -0
- package/dist/chunk-CC37E3QM.js.map +1 -0
- package/dist/{chunk-J2R275FN.js → chunk-CTCGHNWN.js} +4 -4
- package/dist/{chunk-X5PIDJ3L.js → chunk-DA4ZMCBU.js} +3 -3
- package/dist/{chunk-IVAW3HBF.js → chunk-DH3V7RCQ.js} +21 -13
- package/dist/chunk-DH3V7RCQ.js.map +1 -0
- package/dist/chunk-DXFG2VGN.js +50 -0
- package/dist/chunk-DXFG2VGN.js.map +1 -0
- package/dist/{chunk-4OFKZAJG.js → chunk-EAARGPWI.js} +2 -1
- package/dist/chunk-EAARGPWI.js.map +1 -0
- package/dist/{chunk-H6RSANGQ.js → chunk-ETZ7KKOS.js} +2 -2
- package/dist/{chunk-K4E3Y3ZX.js → chunk-G7VEQEMG.js} +2 -1
- package/dist/chunk-G7VEQEMG.js.map +1 -0
- package/dist/{chunk-XZBXINXZ.js → chunk-GIC6BASP.js} +4 -4
- package/dist/{chunk-SXQZMC7R.js → chunk-GR4C3FHT.js} +2 -2
- package/dist/{chunk-7DYGPGCT.js → chunk-H5IIBGDM.js} +2 -2
- package/dist/{chunk-CNNXMIS6.js → chunk-HFRGCNFY.js} +10 -10
- package/dist/chunk-HRATODNO.js +28 -0
- package/dist/chunk-HRATODNO.js.map +1 -0
- package/dist/{chunk-MAG6M3B6.js → chunk-HTOWFFAI.js} +2 -2
- package/dist/chunk-HUSTM6PU.js +27 -0
- package/dist/chunk-HUSTM6PU.js.map +1 -0
- package/dist/{chunk-FOCMJEHH.js → chunk-I4QAH4SY.js} +3 -3
- package/dist/{chunk-FSGCXGK6.js → chunk-I6DUKBUI.js} +2 -2
- package/dist/{chunk-VI637ILW.js → chunk-IN673LEP.js} +48 -15
- package/dist/chunk-IN673LEP.js.map +1 -0
- package/dist/{chunk-6FUMA6AA.js → chunk-JGXMA6HL.js} +2 -2
- package/dist/{chunk-TA7UZZMW.js → chunk-JHTF22NQ.js} +2 -2
- package/dist/{chunk-DZ3CNJPB.js → chunk-LDOQE34V.js} +2 -2
- package/dist/{chunk-MEW53VQJ.js → chunk-LDWIPYJ6.js} +7 -7
- package/dist/{chunk-227UFSEQ.js → chunk-LEPOP46W.js} +4 -4
- package/dist/{chunk-KJTSWJZN.js → chunk-LF6SHWVV.js} +2 -2
- package/dist/{chunk-G6OZZX7P.js → chunk-LJAP4KSW.js} +2 -2
- package/dist/{chunk-NV6BTBUI.js → chunk-LJNLLNEM.js} +2 -2
- package/dist/{chunk-FFFZEF6B.js → chunk-LUDXSSTW.js} +2 -2
- package/dist/{chunk-PCH2CVCS.js → chunk-LWBSEYW3.js} +6 -6
- package/dist/chunk-M6RORUO5.js +59 -0
- package/dist/chunk-M6RORUO5.js.map +1 -0
- package/dist/{chunk-FMUJGGKW.js → chunk-M7DGN6JZ.js} +3 -3
- package/dist/{chunk-TZIHB2LP.js → chunk-MNH2GM4O.js} +5 -5
- package/dist/{chunk-RACZB5HT.js → chunk-N37X5RU7.js} +4 -4
- package/dist/{chunk-LK4TOYPU.js → chunk-NF3NMAG7.js} +2 -2
- package/dist/{chunk-QL4U3SJA.js → chunk-NHLEFBE2.js} +11 -3
- package/dist/chunk-NHLEFBE2.js.map +1 -0
- package/dist/chunk-NN5CQTAJ.js +42 -0
- package/dist/chunk-NN5CQTAJ.js.map +1 -0
- package/dist/{chunk-AG46P24C.js → chunk-NNBZS3DY.js} +4 -4
- package/dist/{chunk-LZ2JTO7N.js → chunk-OASGWNYL.js} +2 -2
- package/dist/chunk-OEDW4ER7.js +62 -0
- package/dist/chunk-OEDW4ER7.js.map +1 -0
- package/dist/{chunk-C2JCVZWX.js → chunk-OLBZ2WGG.js} +2 -2
- package/dist/{chunk-Z3SQEEB6.js → chunk-OUKBMQ2O.js} +2 -2
- package/dist/{chunk-XXW32OL7.js → chunk-OYV6RKPM.js} +1 -1
- package/dist/chunk-OYV6RKPM.js.map +1 -0
- package/dist/{chunk-2Z3DG5CQ.js → chunk-P6GKRT2H.js} +1 -1
- package/dist/{chunk-UGA6PZTX.js → chunk-P7LVYPIX.js} +3 -3
- package/dist/{chunk-26JWBSWD.js → chunk-PGCZLHRB.js} +11 -3
- package/dist/chunk-PGCZLHRB.js.map +1 -0
- package/dist/{chunk-VE45LRCE.js → chunk-QRDSXR3V.js} +2 -2
- package/dist/{chunk-KS67VHXA.js → chunk-QUVWFZOU.js} +2 -2
- package/dist/{chunk-AI4QFDPR.js → chunk-R7FXPG4T.js} +2 -2
- package/dist/chunk-RF2SMMPP.js +37 -0
- package/dist/chunk-RF2SMMPP.js.map +1 -0
- package/dist/{chunk-X66BHMAU.js → chunk-RJ57OOCD.js} +2 -2
- package/dist/chunk-S5G2LAL7.js +354 -0
- package/dist/chunk-S5G2LAL7.js.map +1 -0
- package/dist/{chunk-VXMKW7YN.js → chunk-TRLCMLX7.js} +2 -2
- package/dist/{chunk-ELCMVOQT.js → chunk-V3HUBF7T.js} +2 -2
- package/dist/{chunk-KMIAD7JR.js → chunk-VHAKBUBD.js} +2 -2
- package/dist/{chunk-GS5IFIVE.js → chunk-VYD63IFH.js} +3 -3
- package/dist/chunk-VZIAVM72.js +49 -0
- package/dist/chunk-VZIAVM72.js.map +1 -0
- package/dist/chunk-WTWQA7BB.js +28 -0
- package/dist/chunk-WTWQA7BB.js.map +1 -0
- package/dist/{chunk-TBRG2SYY.js → chunk-X4FIZAVQ.js} +94 -52
- package/dist/chunk-X4FIZAVQ.js.map +1 -0
- package/dist/{chunk-WSFPNCRA.js → chunk-XFPHV65N.js} +2 -2
- package/dist/{chunk-JCUG7AXZ.js → chunk-XJJYSX6F.js} +4 -4
- package/dist/{chunk-I6DURYZI.js → chunk-XMIAU4CO.js} +2 -2
- package/dist/{chunk-PJIGYPO5.js → chunk-XQGFIAG7.js} +2 -2
- package/dist/{chunk-B2URC6LJ.js → chunk-YWN3GYI2.js} +2 -2
- package/dist/{chunk-TG6JEJDV.js → chunk-Z33VUMKY.js} +3 -3
- package/dist/{cli-CFpMhqz5.d.ts → cli-CMtkGBdz.d.ts} +5 -5
- package/dist/cli.d.ts +15 -13
- package/dist/cli.js +88 -77
- package/dist/coding/export-okf-codegraph.d.ts +2 -1
- package/dist/coding/export-okf-codegraph.js +13 -13
- package/dist/coding/pre-action-gate.d.ts +2 -1
- package/dist/coding/pre-action-gate.js +2 -2
- package/dist/compounding/engine.d.ts +3 -2
- package/dist/compounding/engine.js +15 -14
- package/dist/compounding/preference-consolidator.d.ts +2 -1
- package/dist/compression-optimizer.d.ts +2 -1
- package/dist/config.d.ts +2 -1
- package/dist/config.js +6 -5
- package/dist/connectors/codex-materialize-runner.d.ts +2 -1
- package/dist/connectors/codex-materialize-runner.js +13 -13
- package/dist/connectors/codex-materialize.d.ts +2 -1
- package/dist/connectors/index.d.ts +2 -1
- package/dist/connectors/index.js +13 -13
- package/dist/consolidation-provenance-check.d.ts +3 -2
- package/dist/consolidation-undo.d.ts +3 -2
- package/dist/contradiction/index.d.ts +4 -3
- package/dist/converge-config.d.ts +2 -1
- package/dist/convergence-refresh.d.ts +3 -2
- package/dist/convergence-refresh.js +15 -15
- package/dist/conversation-index/backend.d.ts +2 -1
- package/dist/conversation-index/backend.js +2 -2
- package/dist/conversation-index/chunker.d.ts +2 -1
- package/dist/conversation-index/faiss-adapter.d.ts +2 -1
- package/dist/conversation-index/indexer.d.ts +2 -1
- package/dist/conversation-index/search.d.ts +2 -1
- package/dist/corpus-watermark.d.ts +2 -1
- package/dist/corpus-watermark.js +15 -15
- package/dist/cross-lingual-recall.d.ts +2 -1
- package/dist/day-summary.d.ts +2 -1
- package/dist/deep-recall-config.d.ts +32 -0
- package/dist/deep-recall-config.js +12 -0
- package/dist/deep-recall-http-glue.d.ts +170 -0
- package/dist/deep-recall-http-glue.js +31 -0
- package/dist/deep-recall-http-glue.js.map +1 -0
- package/dist/deep-recall-mcp-tools.d.ts +144 -0
- package/dist/deep-recall-mcp-tools.js +8 -0
- package/dist/deep-recall-mcp-tools.js.map +1 -0
- package/dist/deep-recall-policy-llm.d.ts +37 -0
- package/dist/deep-recall-policy-llm.js +19 -0
- package/dist/deep-recall-policy-llm.js.map +1 -0
- package/dist/deep-recall-renderer.d.ts +16 -0
- package/dist/deep-recall-renderer.js +8 -0
- package/dist/deep-recall-renderer.js.map +1 -0
- package/dist/deep-recall-seeds.d.ts +83 -0
- package/dist/deep-recall-seeds.js +8 -0
- package/dist/deep-recall-seeds.js.map +1 -0
- package/dist/deep-recall.d.ts +97 -0
- package/dist/deep-recall.js +13 -0
- package/dist/deep-recall.js.map +1 -0
- package/dist/delinearize.d.ts +2 -1
- package/dist/dependency-propagation-config.d.ts +2 -1
- package/dist/{dependency-propagation-delivery-BC3bCEet.d.ts → dependency-propagation-delivery-BZGUecZf.d.ts} +1 -1
- package/dist/direct-answer-wiring.d.ts +2 -1
- package/dist/direct-answer.d.ts +2 -1
- package/dist/embedding-fallback.d.ts +2 -1
- package/dist/enrichment/index.d.ts +2 -1
- package/dist/entity-origin-fields.d.ts +2 -1
- package/dist/entity-retrieval.d.ts +3 -2
- package/dist/entity-retrieval.js +13 -13
- package/dist/entity-schema.d.ts +2 -1
- package/dist/episodic-context.d.ts +2 -1
- package/dist/eval-trajectory-contracts.d.ts +2 -1
- package/dist/eval-trajectory-store.d.ts +2 -1
- package/dist/eval-trajectory.d.ts +2 -1
- package/dist/explicit-capture.d.ts +10 -9
- package/dist/external-wiki-access.d.ts +13 -11
- package/dist/external-wiki-access.js +47 -35
- package/dist/external-wiki-collection-registration.d.ts +2 -1
- package/dist/external-wiki-collection.d.ts +2 -1
- package/dist/external-wiki-mcp-tools.d.ts +13 -11
- package/dist/extraction-error-classification.d.ts +2 -1
- package/dist/extraction-faithfulness.d.ts +2 -1
- package/dist/extraction-judge-telemetry.d.ts +2 -1
- package/dist/extraction-judge-training.d.ts +2 -1
- package/dist/extraction-judge.d.ts +2 -1
- package/dist/extraction-liveness.d.ts +2 -1
- package/dist/extraction-normalization.d.ts +2 -1
- package/dist/extraction-prompt.d.ts +2 -1
- package/dist/extraction-source-grounding-rules.d.ts +2 -1
- package/dist/extraction-source-grounding.d.ts +2 -1
- package/dist/extraction.d.ts +2 -1
- package/dist/extraction.js +15 -15
- package/dist/fallback-llm.d.ts +2 -1
- package/dist/graph-dashboard-diff.d.ts +2 -1
- package/dist/graph-dashboard-key.d.ts +2 -1
- package/dist/graph-dashboard-parser.d.ts +2 -1
- package/dist/{graph-edge-decay-DGTBFALQ.js → graph-edge-decay-FXGELBFA.js} +4 -4
- package/dist/graph-edge-decay-FXGELBFA.js.map +1 -0
- package/dist/graph-edge-reinforcement.d.ts +2 -1
- package/dist/graph-path-reconstruction.d.ts +2 -1
- package/dist/graph-path-scoring.d.ts +2 -1
- package/dist/graph-snapshot.d.ts +2 -1
- package/dist/graph-snapshot.js +3 -3
- package/dist/graph.d.ts +2 -1
- package/dist/graph.js +2 -2
- package/dist/harmonic-construction.js +3 -3
- package/dist/harmonic-retrieval.d.ts +38 -2
- package/dist/harmonic-retrieval.js +12 -3
- package/dist/importance.d.ts +2 -1
- package/dist/importers/index.d.ts +2 -1
- package/dist/in-flight-reads.d.ts +2 -1
- package/dist/{index-D4hS9uxK.d.ts → index-B4iTvT-w.d.ts} +2 -2
- package/dist/index.d.ts +701 -699
- package/dist/index.js +126 -115
- package/dist/intent.d.ts +2 -1
- package/dist/lcm/engine.d.ts +2 -1
- package/dist/lcm/index.d.ts +2 -1
- package/dist/lcm/tools.d.ts +2 -1
- package/dist/lifecycle.d.ts +2 -1
- package/dist/live-connectors-runner.d.ts +2 -1
- package/dist/local-llm.d.ts +2 -1
- package/dist/local-model-endpoint.d.ts +2 -1
- package/dist/location/index.d.ts +4 -3
- package/dist/location/index.js +15 -15
- package/dist/maintenance/memory-governance.d.ts +2 -1
- package/dist/maintenance/memory-governance.js +13 -13
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +3 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +13 -13
- package/dist/maintenance/rebuild-memory-projection.d.ts +3 -2
- package/dist/maintenance/rebuild-memory-projection.js +14 -14
- package/dist/{maintenance-BRcc3Hx8.d.ts → maintenance-BBpNqEeJ.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +13 -11
- package/dist/mcp-read-only-tools.js +1 -1
- package/dist/memory-action-policy.d.ts +2 -1
- package/dist/memory-cache.d.ts +2 -1
- package/dist/memory-controller.d.ts +2 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +2 -1
- package/dist/memory-projection-store.d.ts +2 -1
- package/dist/memory-provenance.d.ts +2 -1
- package/dist/memory-snapshot.d.ts +2 -1
- package/dist/memory-subject-cli.d.ts +13 -11
- package/dist/memory-subject.d.ts +13 -11
- package/dist/memory-worth-outcomes.d.ts +3 -2
- package/dist/models-json.d.ts +2 -1
- package/dist/namespaces/migrate.d.ts +4 -3
- package/dist/namespaces/migrate.js +14 -14
- package/dist/namespaces/principal.d.ts +2 -1
- package/dist/namespaces/search.d.ts +2 -1
- package/dist/namespaces/search.js +9 -9
- package/dist/namespaces/storage.d.ts +4 -3
- package/dist/namespaces/storage.js +13 -13
- package/dist/native-knowledge.d.ts +2 -1
- package/dist/offline-sync-impression-drain.d.ts +2 -1
- package/dist/offline-sync.js +2 -2
- package/dist/operator-doctor-corpus.d.ts +2 -1
- package/dist/operator-doctor-corpus.js +16 -16
- package/dist/operator-doctor-replica.d.ts +2 -1
- package/dist/operator-toolkit.d.ts +4 -3
- package/dist/operator-toolkit.js +29 -28
- package/dist/orchestration/compression-guideline-coordinator.d.ts +3 -2
- package/dist/orchestration/maintenance.d.ts +5 -4
- package/dist/orchestration/maintenance.js +21 -21
- package/dist/{orchestrator-Btq9lzAN.d.ts → orchestrator-DglY1H0w.d.ts} +8 -8
- package/dist/orchestrator.d.ts +10 -9
- package/dist/orchestrator.js +108 -97
- package/dist/patterns-cli.d.ts +2 -1
- package/dist/{pipeline-CZoNdFb5.d.ts → pipeline-C7qRsy6g.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +2 -1
- package/dist/proactive-contention.d.ts +2 -1
- package/dist/provenance.d.ts +2 -1
- package/dist/{public-http-C9-CHc40.d.ts → public-http-CU-Cwwdb.d.ts} +1 -1
- package/dist/{qmd-VIjSCKIE.d.ts → qmd-YRLTa3AE.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +3 -2
- package/dist/qmd-recall-cache.d.ts +2 -1
- package/dist/qmd.d.ts +3 -2
- package/dist/recall-concurrency-config.d.ts +2 -1
- package/dist/recall-deep-expand-select.js +4 -44
- package/dist/recall-deep-expand-select.js.map +1 -1
- package/dist/recall-deep-frontier.js +4 -23
- package/dist/recall-deep-frontier.js.map +1 -1
- package/dist/recall-deep-rewrite.js +4 -23
- package/dist/recall-deep-rewrite.js.map +1 -1
- package/dist/recall-disclosure-escalation.d.ts +2 -1
- package/dist/recall-explain-renderer.d.ts +2 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +2 -1
- package/dist/recall-navigate-access.d.ts +2 -1
- package/dist/recall-navigate-access.js +2 -2
- package/dist/recall-navigate-disclosure.d.ts +2 -1
- package/dist/recall-navigate-disclosure.js +1 -1
- package/dist/recall-navigate.d.ts +2 -1
- package/dist/recall-navigate.js +2 -2
- package/dist/recall-planner-llm.d.ts +2 -1
- package/dist/recall-state.d.ts +2 -1
- package/dist/recall-tag-filter.d.ts +2 -1
- package/dist/recall-timings.d.ts +2 -1
- package/dist/recall-xray-cli.d.ts +2 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +2 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +2 -1
- package/dist/recall-xray.js +2 -2
- package/dist/reconcile/cursor.d.ts +2 -1
- package/dist/reconcile/manifest.d.ts +2 -1
- package/dist/reconcile/plan.d.ts +2 -1
- package/dist/replay/normalizers/chatgpt.d.ts +2 -1
- package/dist/replay/normalizers/claude.d.ts +2 -1
- package/dist/replay/normalizers/openclaw.d.ts +2 -1
- package/dist/replay/normalizers/shared.d.ts +2 -1
- package/dist/replay/runner.d.ts +2 -1
- package/dist/replay/types.d.ts +2 -1
- package/dist/replica-divergence.d.ts +2 -1
- package/dist/replica-peers-config.d.ts +2 -1
- package/dist/resolve-auth-token.d.ts +2 -1
- package/dist/resume-bundles.js +7 -6
- package/dist/retrieval-agents.d.ts +3 -2
- package/dist/retrieval-tiers.d.ts +2 -1
- package/dist/routing/engine.d.ts +2 -1
- package/dist/routing/store.d.ts +2 -1
- package/dist/salvage-envelope.d.ts +2 -1
- package/dist/schemas.d.ts +176 -176
- package/dist/{scope-profiles-DqbxQXIS.d.ts → scope-profiles-BVvqVzJX.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +2 -1
- package/dist/search/factory.d.ts +2 -1
- package/dist/search/factory.js +8 -8
- package/dist/search/index.d.ts +2 -1
- package/dist/search/index.js +13 -13
- package/dist/search/lancedb-backend.d.ts +2 -1
- package/dist/search/lancedb-backend.js +2 -2
- package/dist/search/meilisearch-backend.d.ts +2 -1
- package/dist/search/meilisearch-backend.js +2 -2
- package/dist/search/noop-backend.d.ts +2 -1
- package/dist/search/orama-backend.d.ts +2 -1
- package/dist/search/orama-backend.js +2 -2
- package/dist/search/port.d.ts +2 -1
- package/dist/search/remote-backend.d.ts +2 -1
- package/dist/{semantic-consolidation-DW3rEUoW.d.ts → semantic-consolidation-BzCI6Kuu.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +3 -2
- package/dist/semantic-consolidation.js +14 -14
- package/dist/semantic-rule-promotion.js +13 -13
- package/dist/semantic-rule-verifier.d.ts +2 -1
- package/dist/semantic-rule-verifier.js +13 -13
- package/dist/{service-B2vJU_Bx.d.ts → service-DQ3Gscy5.d.ts} +2 -2
- package/dist/session-observer-bands.d.ts +2 -1
- package/dist/session-observer-state.d.ts +2 -1
- package/dist/shared-context/manager.d.ts +43 -7
- package/dist/shared-context/manager.js +2 -1
- package/dist/signal.d.ts +2 -1
- package/dist/source-agent-qualifier.d.ts +2 -1
- package/dist/source-agent-qualifier.js +13 -13
- package/dist/standup/build.js +13 -13
- package/dist/{storage-6fn7BPmb.d.ts → storage-DmTbQdD0.d.ts} +1 -1
- package/dist/storage.d.ts +3 -2
- package/dist/storage.js +12 -12
- package/dist/subject-config.d.ts +2 -1
- package/dist/summarizer.d.ts +2 -1
- package/dist/summary-snapshot.d.ts +2 -1
- package/dist/support-passport/index.d.ts +16 -14
- package/dist/support-passport/index.js +49 -37
- package/dist/temporal-supersession.d.ts +3 -2
- package/dist/temporal-timeline-recall.d.ts +2 -1
- package/dist/temporal-validity.d.ts +2 -1
- package/dist/threading.d.ts +2 -1
- package/dist/tier-migration.d.ts +3 -2
- package/dist/tier-routing.d.ts +2 -1
- package/dist/topics.d.ts +2 -1
- package/dist/transcript.d.ts +2 -1
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +2 -2
- package/dist/transfer/export-okf.d.ts +2 -1
- package/dist/transfer/export-okf.js +14 -14
- package/dist/transfer/types.d.ts +78 -78
- package/dist/trust-score-stage.d.ts +2 -1
- package/dist/trust-score.d.ts +2 -1
- package/dist/{types-eM7QIcX2.d.ts → types-CLRTESSD.d.ts} +3 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +2 -1
- package/dist/verified-recall.js +13 -13
- package/dist/who-knows-cli.d.ts +13 -11
- package/dist/who-knows-cli.js +14 -14
- package/dist/who-knows.d.ts +13 -11
- package/dist/who-knows.js +13 -13
- package/dist/write-envelope.d.ts +2 -1
- package/package.json +2 -2
- package/src/access-boundary.ts +1 -0
- package/src/access-http.ts +5 -5
- package/src/access-mcp-output-schemas.ts +1 -0
- package/src/access-mcp.ts +3 -3
- package/src/access-operations-batch.ts +3 -1
- package/src/access-schema.ts +12 -0
- package/src/access-service.ts +162 -5
- package/src/access-surface-catalog.ts +2 -0
- package/src/cli/deep-recall-commands.ts +60 -0
- package/src/cli.ts +2 -2
- package/src/config.test.ts +19 -0
- package/src/config.ts +7 -0
- package/src/deep-recall-config.ts +83 -0
- package/src/deep-recall-http-glue.ts +75 -0
- package/src/deep-recall-mcp-tools.ts +33 -0
- package/src/deep-recall-policy-llm.ts +65 -0
- package/src/deep-recall-renderer.ts +41 -0
- package/src/deep-recall-seeds.ts +134 -0
- package/src/deep-recall-surface.test.ts +902 -0
- package/src/deep-recall.test.ts +348 -0
- package/src/deep-recall.ts +572 -0
- package/src/harmonic-retrieval.ts +78 -25
- package/src/mcp-read-only-tools.ts +1 -0
- package/src/shared-context/envelope-at.test.ts +23 -0
- package/src/shared-context/envelope-at.ts +12 -6
- package/src/shared-context/envelope-io.ts +184 -0
- package/src/shared-context/envelope-wiring.test.ts +193 -0
- package/src/shared-context/governance.ts +28 -9
- package/src/shared-context/iso-instant.ts +43 -0
- package/src/shared-context/manager.ts +74 -15
- package/src/shared-context/provenance.ts +3 -26
- package/src/shared-context/write-origin.test.ts +145 -0
- package/src/types.ts +3 -1
- package/dist/chunk-26JWBSWD.js.map +0 -1
- package/dist/chunk-3DT2F5OI.js.map +0 -1
- package/dist/chunk-4OFKZAJG.js.map +0 -1
- package/dist/chunk-6RPB2TDG.js.map +0 -1
- package/dist/chunk-AYWPIH4M.js.map +0 -1
- package/dist/chunk-HXWOVCS6.js.map +0 -1
- package/dist/chunk-IVAW3HBF.js.map +0 -1
- package/dist/chunk-K4E3Y3ZX.js.map +0 -1
- package/dist/chunk-QL4U3SJA.js.map +0 -1
- package/dist/chunk-TBRG2SYY.js.map +0 -1
- package/dist/chunk-VI637ILW.js.map +0 -1
- package/dist/chunk-XXW32OL7.js.map +0 -1
- /package/dist/{chunk-D5VPIJN3.js.map → chunk-227WJVPY.js.map} +0 -0
- /package/dist/{chunk-Y3BWCIY2.js.map → chunk-2EHDPHMD.js.map} +0 -0
- /package/dist/{chunk-2LKW6OO7.js.map → chunk-2XJDAEAM.js.map} +0 -0
- /package/dist/{chunk-P23JWI3D.js.map → chunk-3ITTF7YH.js.map} +0 -0
- /package/dist/{chunk-NGP2FPB2.js.map → chunk-4UVDLNHQ.js.map} +0 -0
- /package/dist/{chunk-FJMIQTMH.js.map → chunk-5YQ7RFSO.js.map} +0 -0
- /package/dist/{chunk-KQAFEZQX.js.map → chunk-7LCGFUMB.js.map} +0 -0
- /package/dist/{chunk-EESYTBXV.js.map → chunk-7NCUHD5U.js.map} +0 -0
- /package/dist/{chunk-X574KX52.js.map → chunk-7ZMU4XQT.js.map} +0 -0
- /package/dist/{chunk-SG3Z67FB.js.map → chunk-APZXA4WI.js.map} +0 -0
- /package/dist/{chunk-2QSZNTDO.js.map → chunk-AU7Q3LSC.js.map} +0 -0
- /package/dist/{chunk-VGMRI4J6.js.map → chunk-B75VCEX5.js.map} +0 -0
- /package/dist/{chunk-D35XLYQ7.js.map → chunk-BE4Y6GK6.js.map} +0 -0
- /package/dist/{chunk-ELKD5PCD.js.map → chunk-BEXFNGQ3.js.map} +0 -0
- /package/dist/{chunk-U5SRTYFS.js.map → chunk-BFDOBESV.js.map} +0 -0
- /package/dist/{chunk-OLT3YTDH.js.map → chunk-BIJAWZYW.js.map} +0 -0
- /package/dist/{chunk-FU2NYFX6.js.map → chunk-BO4PWIJY.js.map} +0 -0
- /package/dist/{chunk-JMAG7WZ7.js.map → chunk-BX6GW4KC.js.map} +0 -0
- /package/dist/{chunk-J2R275FN.js.map → chunk-CTCGHNWN.js.map} +0 -0
- /package/dist/{chunk-X5PIDJ3L.js.map → chunk-DA4ZMCBU.js.map} +0 -0
- /package/dist/{chunk-H6RSANGQ.js.map → chunk-ETZ7KKOS.js.map} +0 -0
- /package/dist/{chunk-XZBXINXZ.js.map → chunk-GIC6BASP.js.map} +0 -0
- /package/dist/{chunk-SXQZMC7R.js.map → chunk-GR4C3FHT.js.map} +0 -0
- /package/dist/{chunk-7DYGPGCT.js.map → chunk-H5IIBGDM.js.map} +0 -0
- /package/dist/{chunk-CNNXMIS6.js.map → chunk-HFRGCNFY.js.map} +0 -0
- /package/dist/{chunk-MAG6M3B6.js.map → chunk-HTOWFFAI.js.map} +0 -0
- /package/dist/{chunk-FOCMJEHH.js.map → chunk-I4QAH4SY.js.map} +0 -0
- /package/dist/{chunk-FSGCXGK6.js.map → chunk-I6DUKBUI.js.map} +0 -0
- /package/dist/{chunk-6FUMA6AA.js.map → chunk-JGXMA6HL.js.map} +0 -0
- /package/dist/{chunk-TA7UZZMW.js.map → chunk-JHTF22NQ.js.map} +0 -0
- /package/dist/{chunk-DZ3CNJPB.js.map → chunk-LDOQE34V.js.map} +0 -0
- /package/dist/{chunk-MEW53VQJ.js.map → chunk-LDWIPYJ6.js.map} +0 -0
- /package/dist/{chunk-227UFSEQ.js.map → chunk-LEPOP46W.js.map} +0 -0
- /package/dist/{chunk-KJTSWJZN.js.map → chunk-LF6SHWVV.js.map} +0 -0
- /package/dist/{chunk-G6OZZX7P.js.map → chunk-LJAP4KSW.js.map} +0 -0
- /package/dist/{chunk-NV6BTBUI.js.map → chunk-LJNLLNEM.js.map} +0 -0
- /package/dist/{chunk-FFFZEF6B.js.map → chunk-LUDXSSTW.js.map} +0 -0
- /package/dist/{chunk-PCH2CVCS.js.map → chunk-LWBSEYW3.js.map} +0 -0
- /package/dist/{chunk-FMUJGGKW.js.map → chunk-M7DGN6JZ.js.map} +0 -0
- /package/dist/{chunk-TZIHB2LP.js.map → chunk-MNH2GM4O.js.map} +0 -0
- /package/dist/{chunk-RACZB5HT.js.map → chunk-N37X5RU7.js.map} +0 -0
- /package/dist/{chunk-LK4TOYPU.js.map → chunk-NF3NMAG7.js.map} +0 -0
- /package/dist/{chunk-AG46P24C.js.map → chunk-NNBZS3DY.js.map} +0 -0
- /package/dist/{chunk-LZ2JTO7N.js.map → chunk-OASGWNYL.js.map} +0 -0
- /package/dist/{chunk-C2JCVZWX.js.map → chunk-OLBZ2WGG.js.map} +0 -0
- /package/dist/{chunk-Z3SQEEB6.js.map → chunk-OUKBMQ2O.js.map} +0 -0
- /package/dist/{chunk-2Z3DG5CQ.js.map → chunk-P6GKRT2H.js.map} +0 -0
- /package/dist/{chunk-UGA6PZTX.js.map → chunk-P7LVYPIX.js.map} +0 -0
- /package/dist/{chunk-VE45LRCE.js.map → chunk-QRDSXR3V.js.map} +0 -0
- /package/dist/{chunk-KS67VHXA.js.map → chunk-QUVWFZOU.js.map} +0 -0
- /package/dist/{chunk-AI4QFDPR.js.map → chunk-R7FXPG4T.js.map} +0 -0
- /package/dist/{chunk-X66BHMAU.js.map → chunk-RJ57OOCD.js.map} +0 -0
- /package/dist/{chunk-VXMKW7YN.js.map → chunk-TRLCMLX7.js.map} +0 -0
- /package/dist/{chunk-ELCMVOQT.js.map → chunk-V3HUBF7T.js.map} +0 -0
- /package/dist/{chunk-KMIAD7JR.js.map → chunk-VHAKBUBD.js.map} +0 -0
- /package/dist/{chunk-GS5IFIVE.js.map → chunk-VYD63IFH.js.map} +0 -0
- /package/dist/{chunk-WSFPNCRA.js.map → chunk-XFPHV65N.js.map} +0 -0
- /package/dist/{chunk-JCUG7AXZ.js.map → chunk-XJJYSX6F.js.map} +0 -0
- /package/dist/{chunk-I6DURYZI.js.map → chunk-XMIAU4CO.js.map} +0 -0
- /package/dist/{chunk-PJIGYPO5.js.map → chunk-XQGFIAG7.js.map} +0 -0
- /package/dist/{chunk-B2URC6LJ.js.map → chunk-YWN3GYI2.js.map} +0 -0
- /package/dist/{chunk-TG6JEJDV.js.map → chunk-Z33VUMKY.js.map} +0 -0
- /package/dist/{graph-edge-decay-DGTBFALQ.js.map → deep-recall-config.js.map} +0 -0
|
@@ -14,6 +14,7 @@ import { countRecallTokenOverlap, normalizeRecallTokens } from "./recall-tokeniz
|
|
|
14
14
|
import { stripAttributesSuffix } from "./structured-attributes.js";
|
|
15
15
|
import { isValidityExpiredNow } from "./temporal-validity.js";
|
|
16
16
|
import { isRecord } from "./store-contract.js";
|
|
17
|
+
import { isSupportPassportPrivateMemory } from "./support-passport/card-projection.js";
|
|
17
18
|
import type { MemoryFile } from "./types.js";
|
|
18
19
|
|
|
19
20
|
type SourceMemoryMap = Map<string, MemoryFile>;
|
|
@@ -73,6 +74,11 @@ function projectSourceBackedNode(
|
|
|
73
74
|
const memory = sourceMemories.get(memoryId);
|
|
74
75
|
return (
|
|
75
76
|
memory !== undefined &&
|
|
77
|
+
// #2332: a private support-passport record leaves the eligible set the
|
|
78
|
+
// same way a rejected one does — a node title or anchor attribution
|
|
79
|
+
// rebuilt from it would leak governed metadata into the deep-recall
|
|
80
|
+
// frontier (and every other graph reader) before any content check runs.
|
|
81
|
+
!isSupportPassportPrivateMemory(memory) &&
|
|
76
82
|
inferMemoryStatus(memory.frontmatter, toMemoryPathRel(memoryDir, memory.path)) === "active" &&
|
|
77
83
|
(temporalExpiredInInjection || !isValidityExpiredNow(memory.frontmatter, nowMs))
|
|
78
84
|
);
|
|
@@ -232,7 +238,7 @@ function scoreAnchor(
|
|
|
232
238
|
return { score, matchedFields };
|
|
233
239
|
}
|
|
234
240
|
|
|
235
|
-
async function readAbstractionNodes(options: {
|
|
241
|
+
export async function readAbstractionNodes(options: {
|
|
236
242
|
memoryDir: string;
|
|
237
243
|
abstractionNodeStoreDir?: string;
|
|
238
244
|
}): Promise<AbstractionNode[]> {
|
|
@@ -249,7 +255,7 @@ async function readAbstractionNodes(options: {
|
|
|
249
255
|
return nodes;
|
|
250
256
|
}
|
|
251
257
|
|
|
252
|
-
async function readCueAnchors(options: {
|
|
258
|
+
export async function readCueAnchors(options: {
|
|
253
259
|
memoryDir: string;
|
|
254
260
|
abstractionNodeStoreDir?: string;
|
|
255
261
|
}): Promise<CueAnchor[]> {
|
|
@@ -267,27 +273,46 @@ async function readCueAnchors(options: {
|
|
|
267
273
|
return anchors;
|
|
268
274
|
}
|
|
269
275
|
|
|
270
|
-
export
|
|
276
|
+
export interface ProjectedHarmonicGraph {
|
|
277
|
+
nodes: AbstractionNode[];
|
|
278
|
+
anchors: CueAnchor[];
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Read nodes + anchors and project BOTH against the namespace's current active
|
|
283
|
+
* memories. This is the single projection every graph reader shares: a raw
|
|
284
|
+
* `readAbstractionNodes` / `readCueAnchors` pair still carries the stored title,
|
|
285
|
+
* summary, tags, and anchor attribution of a memory that was later rejected,
|
|
286
|
+
* quarantined, or otherwise moved out of the active set, so a second reader
|
|
287
|
+
* that skipped the projection could leak governed metadata even when the
|
|
288
|
+
* memory itself is excluded from the final results.
|
|
289
|
+
*
|
|
290
|
+
* - A node whose every source memory left the active set is dropped.
|
|
291
|
+
* - A surviving node's title/summary/tags/entityRefs are rebuilt from its
|
|
292
|
+
* active sources only.
|
|
293
|
+
* - An anchor keeps a node reference only while its attribution runs through
|
|
294
|
+
* one of that node's surviving active sources, and is dropped once no
|
|
295
|
+
* reference survives.
|
|
296
|
+
*/
|
|
297
|
+
export async function readProjectedHarmonicGraph(options: {
|
|
271
298
|
memoryDir: string;
|
|
272
299
|
abstractionNodeStoreDir?: string;
|
|
273
|
-
query: string;
|
|
274
|
-
maxResults: number;
|
|
275
|
-
sessionKey?: string;
|
|
276
300
|
anchorsEnabled: boolean;
|
|
277
301
|
abortSignal?: AbortSignal;
|
|
278
302
|
temporalExpiredInInjection?: boolean;
|
|
279
|
-
|
|
303
|
+
nowMs?: number;
|
|
304
|
+
}): Promise<ProjectedHarmonicGraph> {
|
|
280
305
|
throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
|
|
281
|
-
const queryTokens = new Set(normalizeRecallTokens(options.query, ["what", "which"]));
|
|
282
|
-
if (queryTokens.size === 0 || options.maxResults <= 0) return [];
|
|
283
|
-
|
|
284
306
|
const nodes = await readAbstractionNodes(options);
|
|
285
|
-
const
|
|
286
|
-
const sourceMemories: SourceMemoryMap =
|
|
287
|
-
|
|
307
|
+
const sourceBacked = nodes.some((node) => (node.sourceMemoryIds?.length ?? 0) > 0);
|
|
308
|
+
const sourceMemories: SourceMemoryMap = sourceBacked
|
|
309
|
+
? await readSourceMemories(options)
|
|
310
|
+
: new Map<string, MemoryFile>();
|
|
311
|
+
const nowMs = options.nowMs ?? Date.now();
|
|
312
|
+
// A node whose full stored source set survived projection keeps legacy
|
|
313
|
+
// anchor attribution (an anchor written before per-node source ids existed).
|
|
288
314
|
const legacyCompatibleNodeRefs = new Set<string>();
|
|
289
|
-
const
|
|
290
|
-
const eligibleNodes = nodes.flatMap((node) => {
|
|
315
|
+
const projectedNodes = nodes.flatMap((node) => {
|
|
291
316
|
const projected = projectSourceBackedNode(
|
|
292
317
|
node,
|
|
293
318
|
sourceMemories,
|
|
@@ -304,6 +329,40 @@ export async function searchHarmonicRetrieval(options: {
|
|
|
304
329
|
}
|
|
305
330
|
return projected ? [projected] : [];
|
|
306
331
|
});
|
|
332
|
+
if (!options.anchorsEnabled) return { nodes: projectedNodes, anchors: [] };
|
|
333
|
+
throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
|
|
334
|
+
const nodeIndex = new Map(projectedNodes.map((node) => [node.nodeId, node]));
|
|
335
|
+
const anchors = (await readCueAnchors(options)).flatMap((anchor) => {
|
|
336
|
+
throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
|
|
337
|
+
const nodeRefs = anchor.nodeRefs.filter((nodeRef) => {
|
|
338
|
+
const node = nodeIndex.get(nodeRef);
|
|
339
|
+
return (
|
|
340
|
+
node !== undefined &&
|
|
341
|
+
anchorMatchesProjectedNode(anchor, nodeRef, node, legacyCompatibleNodeRefs.has(nodeRef))
|
|
342
|
+
);
|
|
343
|
+
});
|
|
344
|
+
return nodeRefs.length > 0 ? [{ ...anchor, nodeRefs }] : [];
|
|
345
|
+
});
|
|
346
|
+
return { nodes: projectedNodes, anchors };
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export async function searchHarmonicRetrieval(options: {
|
|
350
|
+
memoryDir: string;
|
|
351
|
+
abstractionNodeStoreDir?: string;
|
|
352
|
+
query: string;
|
|
353
|
+
maxResults: number;
|
|
354
|
+
sessionKey?: string;
|
|
355
|
+
anchorsEnabled: boolean;
|
|
356
|
+
abortSignal?: AbortSignal;
|
|
357
|
+
temporalExpiredInInjection?: boolean;
|
|
358
|
+
}): Promise<HarmonicRetrievalResult[]> {
|
|
359
|
+
throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
|
|
360
|
+
const queryTokens = new Set(normalizeRecallTokens(options.query, ["what", "which"]));
|
|
361
|
+
if (queryTokens.size === 0 || options.maxResults <= 0) return [];
|
|
362
|
+
|
|
363
|
+
// One projection for every graph reader: nodes and anchors both arrive
|
|
364
|
+
// already narrowed to the namespace's current active memories.
|
|
365
|
+
const { nodes: eligibleNodes, anchors } = await readProjectedHarmonicGraph(options);
|
|
307
366
|
const candidates = new Map<string, HarmonicCandidate>();
|
|
308
367
|
|
|
309
368
|
for (const node of eligibleNodes) {
|
|
@@ -321,19 +380,13 @@ export async function searchHarmonicRetrieval(options: {
|
|
|
321
380
|
|
|
322
381
|
if (options.anchorsEnabled) {
|
|
323
382
|
throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
|
|
324
|
-
const anchors = await readCueAnchors(options);
|
|
325
383
|
const nodeIndex = new Map(eligibleNodes.map((node) => [node.nodeId, node]));
|
|
326
384
|
for (const anchor of anchors) {
|
|
327
385
|
throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
anchorMatchesProjectedNode(anchor, nodeRef, node, legacyCompatibleNodeRefs.has(nodeRef))
|
|
333
|
-
);
|
|
334
|
-
});
|
|
335
|
-
const eligibleNodeTags = new Set(eligibleNodeRefs.flatMap((nodeRef) => nodeIndex.get(nodeRef)?.tags ?? []));
|
|
336
|
-
const eligibleAnchorTags = anchor.tags?.filter((tag) => eligibleNodeTags.has(tag)) ?? [];
|
|
386
|
+
// `nodeRefs` are the projection's surviving references already.
|
|
387
|
+
const eligibleNodeRefs = anchor.nodeRefs;
|
|
388
|
+
const eligibleNodeTags = new Set(eligibleNodeRefs.flatMap((nodeRef) => nodeIndex.get(nodeRef)?.tags ?? []));
|
|
389
|
+
const eligibleAnchorTags = anchor.tags?.filter((tag) => eligibleNodeTags.has(tag)) ?? [];
|
|
337
390
|
const { score, matchedFields } = scoreAnchor(anchor, queryTokens, eligibleAnchorTags);
|
|
338
391
|
if (score <= 0) continue;
|
|
339
392
|
for (const nodeRef of eligibleNodeRefs) {
|
|
@@ -17,3 +17,26 @@ test("empty at is missing_at", () => {
|
|
|
17
17
|
test("invalid at is invalid_at", () => {
|
|
18
18
|
assert.deepEqual(parseEnvelopeAt("not-a-date"), { ok: false, error: "invalid_at" });
|
|
19
19
|
});
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Regression (issue #1957 review round 3): permissive `Date.parse` accepted
|
|
23
|
+
* these and silently reinterpreted them — "2026-02-30" as March 2 2026, "1"
|
|
24
|
+
* as January 1 2001 — so the persisted governance deadline differed from the
|
|
25
|
+
* caller's input. The calendar components are validated against the exact
|
|
26
|
+
* value now, and an out-of-range or non-string input is rejected.
|
|
27
|
+
*/
|
|
28
|
+
test("Date.parse-permissive expiries are rejected, not reinterpreted", () => {
|
|
29
|
+
for (const value of ["2026-02-30T00:00:00.000Z", "2026-02-30", "1", "2026-13-01T00:00:00Z", "2026-08-18T25:00:00Z"]) {
|
|
30
|
+
assert.deepEqual(parseEnvelopeAt(value), { ok: false, error: "invalid_at" }, value);
|
|
31
|
+
}
|
|
32
|
+
// Non-finite / non-string inputs an in-process JS caller can still pass.
|
|
33
|
+
for (const value of [Number.NaN, Number.POSITIVE_INFINITY, 1, null, undefined, {}]) {
|
|
34
|
+
assert.deepEqual(parseEnvelopeAt(value as never), { ok: false, error: "invalid_at" }, String(value));
|
|
35
|
+
}
|
|
36
|
+
// A whitespace-padded timestamp is not the value the caller supplied.
|
|
37
|
+
assert.deepEqual(parseEnvelopeAt(` ${AT} `), { ok: false, error: "invalid_at" });
|
|
38
|
+
// Valid ISO instants still pass through unchanged.
|
|
39
|
+
assert.deepEqual(parseEnvelopeAt(AT), { ok: true, at: AT });
|
|
40
|
+
assert.deepEqual(parseEnvelopeAt("2026-02-28T23:59:59Z"), { ok: true, at: "2026-02-28T23:59:59.000Z" });
|
|
41
|
+
assert.deepEqual(parseEnvelopeAt("2024-02-29T00:00:00Z"), { ok: true, at: "2024-02-29T00:00:00.000Z" });
|
|
42
|
+
});
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared-item envelope at parse (issue #1957 leftover).
|
|
3
3
|
*
|
|
4
|
-
* Pure.
|
|
4
|
+
* Pure. Blank is missing_at. Anything that is not a calendar-valid ISO-8601
|
|
5
|
+
* instant is invalid_at — including values permissive `Date.parse` would
|
|
6
|
+
* silently reinterpret (`"2026-02-30"` -> March 2, `"1"` -> January 1 2001),
|
|
7
|
+
* a whitespace-padded timestamp, and any non-string or non-finite input
|
|
8
|
+
* (review round 3). `trim()` only detects blankness; validation reads the
|
|
9
|
+
* exact value, so normalization can never widen what passes.
|
|
5
10
|
*/
|
|
6
11
|
|
|
12
|
+
import { isStrictIsoInstant } from "./iso-instant.js";
|
|
13
|
+
|
|
7
14
|
export type ParseEnvelopeAtResult =
|
|
8
15
|
| { ok: true; at: string }
|
|
9
16
|
| { ok: false; error: "missing_at" | "invalid_at" };
|
|
10
17
|
|
|
11
18
|
export function parseEnvelopeAt(value: string): ParseEnvelopeAtResult {
|
|
12
|
-
|
|
13
|
-
if (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return { ok: true, at: new Date(ms).toISOString() };
|
|
19
|
+
if (typeof value !== "string") return { ok: false, error: "invalid_at" };
|
|
20
|
+
if (value.trim().length === 0) return { ok: false, error: "missing_at" };
|
|
21
|
+
if (!isStrictIsoInstant(value)) return { ok: false, error: "invalid_at" };
|
|
22
|
+
return { ok: true, at: new Date(Date.parse(value)).toISOString() };
|
|
17
23
|
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared-item envelope wiring (issue #1957, control 1: origin + authority).
|
|
3
|
+
*
|
|
4
|
+
* Bridges the pure envelope helpers onto the markdown frontmatter the
|
|
5
|
+
* shared-context manager reads and writes.
|
|
6
|
+
*
|
|
7
|
+
* Write side rejects invalid input (an unrecognized authority or a binding
|
|
8
|
+
* request without the config opt-in throws — never silently reinterpreted).
|
|
9
|
+
* Read side resolves least privilege: a missing, malformed, or unrecognized
|
|
10
|
+
* authority never resolves above informational, and stored binding
|
|
11
|
+
* downgrades to advisory unless config opted in.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { applyDefaultEnvelope, parseSharedEnvelope, type SharedEnvelope } from "./governance.js";
|
|
15
|
+
import { resolveSharedAuthority } from "./authority-precedence.js";
|
|
16
|
+
import type { SharedAuthority } from "./governance.js";
|
|
17
|
+
import { parseEnvelopeActor } from "./envelope-actor.js";
|
|
18
|
+
import { parseEnvelopeAt } from "./envelope-at.js";
|
|
19
|
+
import { parseEnvelopeId } from "./envelope-id.js";
|
|
20
|
+
|
|
21
|
+
export interface ComposeWriteEnvelopeInput {
|
|
22
|
+
/** Governance origin. Becomes the envelope's `sharedBy`. */
|
|
23
|
+
origin: string;
|
|
24
|
+
/** Requested authority class. Unrecognized values throw. */
|
|
25
|
+
authority?: string;
|
|
26
|
+
/** Optional ISO-8601 expiry. Invalid timestamps throw. */
|
|
27
|
+
expiresAt?: string;
|
|
28
|
+
/** Optional id of the item this one supersedes. */
|
|
29
|
+
supersedes?: string;
|
|
30
|
+
/** Config opt-in (`sharedContextAllowBindingAuthority`). Binding throws without it. */
|
|
31
|
+
allowBinding: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function requireEnvelopeActor(agentId: string): string {
|
|
35
|
+
const parsed = parseEnvelopeActor(agentId);
|
|
36
|
+
if (!parsed.ok) {
|
|
37
|
+
throw new Error(`composeWriteEnvelope: agentId must be a non-blank single-line string (${parsed.error})`);
|
|
38
|
+
}
|
|
39
|
+
return parsed.actor;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function optionalEnvelopeAt(expiresAt: string | undefined): string | undefined {
|
|
43
|
+
if (expiresAt === undefined) return undefined;
|
|
44
|
+
const parsed = parseEnvelopeAt(expiresAt);
|
|
45
|
+
if (!parsed.ok) {
|
|
46
|
+
throw new Error(`composeWriteEnvelope: expiresAt must be a valid ISO-8601 timestamp (${parsed.error})`);
|
|
47
|
+
}
|
|
48
|
+
return parsed.at;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function optionalEnvelopeId(supersedes: string | undefined): string | undefined {
|
|
52
|
+
if (supersedes === undefined) return undefined;
|
|
53
|
+
const parsed = parseEnvelopeId(supersedes);
|
|
54
|
+
if (!parsed.ok) {
|
|
55
|
+
throw new Error(`composeWriteEnvelope: supersedes must be a non-blank single-line id (${parsed.error})`);
|
|
56
|
+
}
|
|
57
|
+
return parsed.id;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Reserved governance origin for an authenticated external access write that
|
|
62
|
+
* resolved no principal (`agentAccessHttp.principal` unset, no adapter
|
|
63
|
+
* identity). Server-owned: the caller cannot mint or influence it, and the
|
|
64
|
+
* caller-supplied `agentId` never becomes audit metadata on that path.
|
|
65
|
+
*/
|
|
66
|
+
export const UNATTRIBUTED_ACCESS_WRITE_ORIGIN = "unattributed:access-surface";
|
|
67
|
+
|
|
68
|
+
export interface ResolvedWriteIdentity {
|
|
69
|
+
/**
|
|
70
|
+
* Producer identity: frontmatter `agent`, on-disk segment, and the
|
|
71
|
+
* cross-signals grouping key. Self-declared by the caller only on
|
|
72
|
+
* surfaces that resolved no server identity; never decides authority.
|
|
73
|
+
*/
|
|
74
|
+
agent: string;
|
|
75
|
+
/** Governance origin stamped as the envelope's `sharedBy`. */
|
|
76
|
+
origin: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Resolve the producer identity and governance origin for a shared-context
|
|
81
|
+
* write. They are different fields with different trust requirements:
|
|
82
|
+
*
|
|
83
|
+
* - The origin (`sharedBy`) is audit metadata and is always server-derived.
|
|
84
|
+
* When the surface resolved an authenticated identity, that identity IS the
|
|
85
|
+
* origin; when it resolved none but the write crosses an external
|
|
86
|
+
* boundary, the caller-supplied `unattributedOrigin` token is stamped
|
|
87
|
+
* instead — never the caller's value. Only a trusted in-process caller
|
|
88
|
+
* (no identity, no token) may stamp its own id as the origin.
|
|
89
|
+
* - The producer (`agent`) drives grouping and display only. When an
|
|
90
|
+
* authenticated identity exists it is also the producer, and a
|
|
91
|
+
* caller-supplied `agentId` naming a different agent is REJECTED, so a
|
|
92
|
+
* caller can never publish an item attributed to another agent. Without a
|
|
93
|
+
* server identity the caller's label stands as the producer — collapsing
|
|
94
|
+
* it instead would merge every writer into one agent and erase
|
|
95
|
+
* multi-agent overlaps from `synthesizeCrossSignals`.
|
|
96
|
+
*/
|
|
97
|
+
export function resolveWriteOrigin(input: {
|
|
98
|
+
agentId: string;
|
|
99
|
+
authenticatedIdentity?: string;
|
|
100
|
+
unattributedOrigin?: string;
|
|
101
|
+
}): ResolvedWriteIdentity {
|
|
102
|
+
const identity = input.authenticatedIdentity?.trim() ?? "";
|
|
103
|
+
if (identity.length > 0) {
|
|
104
|
+
const requested = input.agentId.trim();
|
|
105
|
+
if (requested.length > 0 && requested !== identity) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
`shared-context write origin mismatch: authenticated identity ${JSON.stringify(identity)} cannot publish as ${JSON.stringify(requested)}`,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
return { agent: identity, origin: identity };
|
|
111
|
+
}
|
|
112
|
+
const unattributed = input.unattributedOrigin?.trim() ?? "";
|
|
113
|
+
if (unattributed.length > 0) {
|
|
114
|
+
const label = input.agentId.trim();
|
|
115
|
+
return {
|
|
116
|
+
agent: label.length > 0 ? requireProducer(label) : requireProducer(unattributed),
|
|
117
|
+
origin: requireProducer(unattributed),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const actor = requireProducer(input.agentId);
|
|
121
|
+
return { agent: actor, origin: actor };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function requireProducer(value: string): string {
|
|
125
|
+
const parsed = parseEnvelopeActor(value);
|
|
126
|
+
if (!parsed.ok) {
|
|
127
|
+
throw new Error(`shared-context write producer must be a non-blank single-line string (${parsed.error})`);
|
|
128
|
+
}
|
|
129
|
+
return parsed.actor;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Validate and compose the envelope for a shared-context write.
|
|
134
|
+
* `sharedBy` is stamped from the server-derived origin — provenance is
|
|
135
|
+
* never injected through item content or the caller's producer label.
|
|
136
|
+
*/
|
|
137
|
+
export function composeWriteEnvelope(input: ComposeWriteEnvelopeInput): SharedEnvelope {
|
|
138
|
+
const sharedBy = requireEnvelopeActor(input.origin);
|
|
139
|
+
const expiresAt = optionalEnvelopeAt(input.expiresAt);
|
|
140
|
+
const supersedes = optionalEnvelopeId(input.supersedes);
|
|
141
|
+
return applyDefaultEnvelope(
|
|
142
|
+
{ sharedBy, authority: input.authority, expiresAt, supersedes },
|
|
143
|
+
{ binding: input.allowBinding },
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Serialize an envelope into frontmatter lines (caller adds the `---` fences). */
|
|
148
|
+
export function envelopeToFrontmatterLines(envelope: SharedEnvelope): string[] {
|
|
149
|
+
const line = (key: string, value: string) => `${key}: ${JSON.stringify(value)}`;
|
|
150
|
+
const lines = [line("sharedBy", envelope.sharedBy ?? ""), line("authority", envelope.authority)];
|
|
151
|
+
if (envelope.expiresAt !== undefined) lines.push(line("expiresAt", envelope.expiresAt));
|
|
152
|
+
if (envelope.supersedes !== undefined) lines.push(line("supersedes", envelope.supersedes));
|
|
153
|
+
return lines;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Build an envelope from frontmatter scalars already read off a stored item.
|
|
158
|
+
* Missing scalars (legacy items) compose to informational with no expiry.
|
|
159
|
+
*/
|
|
160
|
+
export function envelopeFromScalars(scalars: {
|
|
161
|
+
sharedBy: string | null;
|
|
162
|
+
authority: string | null;
|
|
163
|
+
expiresAt: string | null;
|
|
164
|
+
supersedes: string | null;
|
|
165
|
+
}): SharedEnvelope {
|
|
166
|
+
const record: Record<string, string> = {};
|
|
167
|
+
if (scalars.sharedBy !== null) record.sharedBy = scalars.sharedBy;
|
|
168
|
+
if (scalars.authority !== null) record.authority = scalars.authority;
|
|
169
|
+
if (scalars.expiresAt !== null) record.expiresAt = scalars.expiresAt;
|
|
170
|
+
if (scalars.supersedes !== null) record.supersedes = scalars.supersedes;
|
|
171
|
+
return parseSharedEnvelope(record);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Resolve a stored envelope's authority for read-side consumption.
|
|
176
|
+
* Least privilege: unrecognized/missing stays informational; binding
|
|
177
|
+
* requires the config opt-in or downgrades to advisory.
|
|
178
|
+
*/
|
|
179
|
+
export function resolveReadAuthority(
|
|
180
|
+
envelope: Pick<SharedEnvelope, "authority">,
|
|
181
|
+
allowBinding: boolean,
|
|
182
|
+
): SharedAuthority {
|
|
183
|
+
return resolveSharedAuthority({ authority: envelope.authority, allowBinding });
|
|
184
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression: shared-item authority envelope wiring (issue #1957, control 1).
|
|
3
|
+
*
|
|
4
|
+
* Exercises the REAL manager write/read paths end to end:
|
|
5
|
+
* writeAgentOutput stamps `sharedBy`/`authority` (+ optional `expiresAt`/
|
|
6
|
+
* `supersedes`) frontmatter; cross-signals and daily curation resolve and
|
|
7
|
+
* surface them. Least privilege holds everywhere: a missing, unrecognized,
|
|
8
|
+
* or un-flagged binding authority denies — it never elevates.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import test from "node:test";
|
|
12
|
+
import assert from "node:assert/strict";
|
|
13
|
+
import os from "node:os";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
16
|
+
import { SharedContextManager } from "./manager.js";
|
|
17
|
+
import { parseConfig } from "../config.js";
|
|
18
|
+
|
|
19
|
+
async function makeManager(overrides: Record<string, unknown> = {}) {
|
|
20
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-shared-envelope-"));
|
|
21
|
+
const config = parseConfig({
|
|
22
|
+
sharedContextEnabled: true,
|
|
23
|
+
sharedContextDir: dir,
|
|
24
|
+
...overrides,
|
|
25
|
+
});
|
|
26
|
+
const manager = new SharedContextManager(config);
|
|
27
|
+
await manager.ensureStructure();
|
|
28
|
+
return { manager, dir };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function today(): string {
|
|
32
|
+
return new Date().toISOString().slice(0, 10);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
test("authority envelope round-trips write -> cross-signals -> curation", async (t) => {
|
|
36
|
+
const { manager, dir } = await makeManager();
|
|
37
|
+
t.after(() => rm(dir, { recursive: true, force: true }));
|
|
38
|
+
|
|
39
|
+
const fp = await manager.writeAgentOutput({
|
|
40
|
+
agentId: "agent-alpha",
|
|
41
|
+
title: "Deploy checklist",
|
|
42
|
+
content: "Verified the deploy checklist end to end.",
|
|
43
|
+
authority: "advisory",
|
|
44
|
+
expiresAt: "2099-01-01T00:00:00.000Z",
|
|
45
|
+
supersedes: "out-0001",
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const raw = await readFile(fp, "utf-8");
|
|
49
|
+
assert.match(raw, /^kind: agent_output$/m);
|
|
50
|
+
assert.match(raw, /^sharedBy: "agent-alpha"$/m);
|
|
51
|
+
assert.match(raw, /^authority: "advisory"$/m);
|
|
52
|
+
assert.match(raw, /^expiresAt: "2099-01-01T00:00:00\.000Z"$/m);
|
|
53
|
+
assert.match(raw, /^supersedes: "out-0001"$/m);
|
|
54
|
+
|
|
55
|
+
const signals = await manager.synthesizeCrossSignals({ date: today() });
|
|
56
|
+
const source = signals.report.sources.find((s) => s.path === fp);
|
|
57
|
+
assert.ok(source, "written output must appear in cross-signals sources");
|
|
58
|
+
assert.equal(source.authority, "advisory");
|
|
59
|
+
assert.equal(source.sharedBy, "agent-alpha");
|
|
60
|
+
const curation = await manager.curateDaily({ date: today() });
|
|
61
|
+
const roundtable = await readFile(curation.roundtablePath, "utf-8");
|
|
62
|
+
assert.match(roundtable, /authority: advisory; sharedBy: agent-alpha/);
|
|
63
|
+
assert.ok(roundtable.includes(fp), "roundtable cites the source path");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("missing or unrecognized authority denies — never elevates", async (t) => {
|
|
67
|
+
const { manager, dir } = await makeManager();
|
|
68
|
+
t.after(() => rm(dir, { recursive: true, force: true }));
|
|
69
|
+
|
|
70
|
+
// Unrecognized authority at write time is rejected, not reinterpreted.
|
|
71
|
+
await assert.rejects(
|
|
72
|
+
manager.writeAgentOutput({
|
|
73
|
+
agentId: "agent-alpha",
|
|
74
|
+
title: "Malformed",
|
|
75
|
+
content: "x",
|
|
76
|
+
authority: " BINDING ",
|
|
77
|
+
}),
|
|
78
|
+
/authority must be informational, advisory, or binding/,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
// Legacy item with no envelope resolves least-privileged on read.
|
|
82
|
+
const date = today();
|
|
83
|
+
const legacyDir = path.join(dir, "agent-outputs", "agent-legacy", date);
|
|
84
|
+
await mkdir(legacyDir, { recursive: true });
|
|
85
|
+
const legacyPath = path.join(legacyDir, "120000-legacy.md");
|
|
86
|
+
await writeFile(
|
|
87
|
+
legacyPath,
|
|
88
|
+
'---\nkind: agent_output\nagent: "agent-legacy"\ntitle: "Legacy"\n---\n\nOld item.\n',
|
|
89
|
+
"utf-8",
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const signals = await manager.synthesizeCrossSignals({ date });
|
|
93
|
+
const legacy = signals.report.sources.find((s) => s.path === legacyPath);
|
|
94
|
+
assert.ok(legacy, "legacy item still appears in sources");
|
|
95
|
+
assert.equal(legacy.authority, "informational");
|
|
96
|
+
assert.equal(legacy.sharedBy, "agent-legacy");
|
|
97
|
+
|
|
98
|
+
// A stored unrecognized authority value also denies on read.
|
|
99
|
+
const bogusPath = path.join(legacyDir, "120100-bogus.md");
|
|
100
|
+
await writeFile(
|
|
101
|
+
bogusPath,
|
|
102
|
+
'---\nkind: agent_output\nagent: "agent-legacy"\ntitle: "Bogus"\nsharedBy: "agent-legacy"\nauthority: "imperative"\n---\n\nBogus item.\n',
|
|
103
|
+
"utf-8",
|
|
104
|
+
);
|
|
105
|
+
const reread = await manager.synthesizeCrossSignals({ date });
|
|
106
|
+
const bogus = reread.report.sources.find((s) => s.path === bogusPath);
|
|
107
|
+
assert.equal(bogus?.authority, "informational");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("binding authority requires the config opt-in at write and on read", async (t) => {
|
|
111
|
+
const gated = await makeManager();
|
|
112
|
+
t.after(() => rm(gated.dir, { recursive: true, force: true }));
|
|
113
|
+
|
|
114
|
+
// Default config: a binding request is denied at the write boundary.
|
|
115
|
+
await assert.rejects(
|
|
116
|
+
gated.manager.writeAgentOutput({
|
|
117
|
+
agentId: "agent-alpha",
|
|
118
|
+
title: "Directive",
|
|
119
|
+
content: "x",
|
|
120
|
+
authority: "binding",
|
|
121
|
+
}),
|
|
122
|
+
/requires an explicit binding flag/,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Stored binding without the flag downgrades to advisory on read.
|
|
126
|
+
const date = today();
|
|
127
|
+
const bindingDir = path.join(gated.dir, "agent-outputs", "agent-alpha", date);
|
|
128
|
+
await mkdir(bindingDir, { recursive: true });
|
|
129
|
+
const bindingPath = path.join(bindingDir, "130000-directive.md");
|
|
130
|
+
await writeFile(
|
|
131
|
+
bindingPath,
|
|
132
|
+
'---\nkind: agent_output\nagent: "agent-alpha"\ntitle: "Directive"\nsharedBy: "agent-alpha"\nauthority: "binding"\n---\n\nDirective.\n',
|
|
133
|
+
"utf-8",
|
|
134
|
+
);
|
|
135
|
+
const gatedSignals = await gated.manager.synthesizeCrossSignals({ date });
|
|
136
|
+
const stored = gatedSignals.report.sources.find((s) => s.path === bindingPath);
|
|
137
|
+
assert.equal(stored?.authority, "advisory", "un-flagged stored binding must downgrade");
|
|
138
|
+
|
|
139
|
+
// Opt-in config: binding writes succeed and resolve as binding on read.
|
|
140
|
+
const open = await makeManager({ sharedContextAllowBindingAuthority: true });
|
|
141
|
+
t.after(() => rm(open.dir, { recursive: true, force: true }));
|
|
142
|
+
const fp = await open.manager.writeAgentOutput({
|
|
143
|
+
agentId: "agent-alpha",
|
|
144
|
+
title: "Directive",
|
|
145
|
+
content: "x",
|
|
146
|
+
authority: "binding",
|
|
147
|
+
});
|
|
148
|
+
const raw = await readFile(fp, "utf-8");
|
|
149
|
+
assert.match(raw, /^authority: "binding"$/m);
|
|
150
|
+
const openSignals = await open.manager.synthesizeCrossSignals({ date });
|
|
151
|
+
const source = openSignals.report.sources.find((s) => s.path === fp);
|
|
152
|
+
assert.equal(source?.authority, "binding");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("a whitespace-padded stored authority stays informational even with binding enabled", async (t) => {
|
|
156
|
+
// Regression (issue #1957 review): the stored token is validated EXACTLY.
|
|
157
|
+
// Trimming first would let `" binding "` resolve as binding when the opt-in
|
|
158
|
+
// is on, and as advisory when it is off — both above informational.
|
|
159
|
+
const date = today();
|
|
160
|
+
for (const allowBinding of [false, true]) {
|
|
161
|
+
const { manager, dir } = await makeManager({ sharedContextAllowBindingAuthority: allowBinding });
|
|
162
|
+
t.after(() => rm(dir, { recursive: true, force: true }));
|
|
163
|
+
const paddedDir = path.join(dir, "agent-outputs", "agent-padded", date);
|
|
164
|
+
await mkdir(paddedDir, { recursive: true });
|
|
165
|
+
const paddedPath = path.join(paddedDir, "140000-padded.md");
|
|
166
|
+
await writeFile(
|
|
167
|
+
paddedPath,
|
|
168
|
+
'---\nkind: agent_output\nagent: "agent-padded"\ntitle: "Padded"\nsharedBy: "agent-padded"\nauthority: " binding "\n---\n\nPadded item.\n',
|
|
169
|
+
"utf-8",
|
|
170
|
+
);
|
|
171
|
+
const signals = await manager.synthesizeCrossSignals({ date });
|
|
172
|
+
const padded = signals.report.sources.find((s) => s.path === paddedPath);
|
|
173
|
+
assert.equal(
|
|
174
|
+
padded?.authority,
|
|
175
|
+
"informational",
|
|
176
|
+
`padded authority must stay informational (allowBinding=${allowBinding})`,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// The same exactness holds at the write boundary: padded is rejected, not
|
|
181
|
+
// normalized into a privileged class.
|
|
182
|
+
const open = await makeManager({ sharedContextAllowBindingAuthority: true });
|
|
183
|
+
t.after(() => rm(open.dir, { recursive: true, force: true }));
|
|
184
|
+
await assert.rejects(
|
|
185
|
+
open.manager.writeAgentOutput({
|
|
186
|
+
agentId: "agent-padded",
|
|
187
|
+
title: "Padded",
|
|
188
|
+
content: "x",
|
|
189
|
+
authority: " binding ",
|
|
190
|
+
}),
|
|
191
|
+
/authority must be informational, advisory, or binding/,
|
|
192
|
+
);
|
|
193
|
+
});
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared-item authority envelope (issue #1957).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Pure parse/default/expiry helpers over the authority classes. Binding is
|
|
5
|
+
* never inferred, and the authority token is validated exactly as supplied
|
|
6
|
+
* or stored — a padded value never resolves to a privileged class.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
9
|
export const SHARED_AUTHORITIES = ["informational", "advisory", "binding"] as const;
|
|
@@ -36,6 +37,24 @@ function optionalString(value: unknown): string | undefined {
|
|
|
36
37
|
return trimmed.length > 0 ? trimmed : undefined;
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
type AuthorityToken =
|
|
41
|
+
| { kind: "absent" }
|
|
42
|
+
| { kind: "invalid"; raw: string }
|
|
43
|
+
| { kind: "valid"; authority: SharedAuthority };
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Read the authority token EXACTLY as supplied or stored. A padded value
|
|
47
|
+
* such as `" binding "` is malformed data, never a normalized match for a
|
|
48
|
+
* privileged class: trimming first would let stored whitespace resolve as
|
|
49
|
+
* binding/advisory (AGENTS.md rule 45). Only the empty string counts as
|
|
50
|
+
* "unspecified"; whitespace-only is invalid.
|
|
51
|
+
*/
|
|
52
|
+
function readExactAuthority(value: unknown): AuthorityToken {
|
|
53
|
+
if (typeof value !== "string" || value.length === 0) return { kind: "absent" };
|
|
54
|
+
if (!isSharedAuthority(value)) return { kind: "invalid", raw: value };
|
|
55
|
+
return { kind: "valid", authority: value };
|
|
56
|
+
}
|
|
57
|
+
|
|
39
58
|
function withOptionalFields(
|
|
40
59
|
authority: SharedAuthority,
|
|
41
60
|
source: { sharedBy?: unknown; expiresAt?: unknown; supersedes?: unknown },
|
|
@@ -54,16 +73,16 @@ export function applyDefaultEnvelope(
|
|
|
54
73
|
input: SharedEnvelopeInput = {},
|
|
55
74
|
options: ApplyDefaultEnvelopeOptions = {},
|
|
56
75
|
): SharedEnvelope {
|
|
57
|
-
const requested =
|
|
58
|
-
if (requested
|
|
76
|
+
const requested = readExactAuthority(input.authority);
|
|
77
|
+
if (requested.kind === "invalid") {
|
|
59
78
|
throw new Error(
|
|
60
|
-
`applyDefaultEnvelope: authority must be informational, advisory, or binding; got ${JSON.stringify(requested)}`,
|
|
79
|
+
`applyDefaultEnvelope: authority must be informational, advisory, or binding; got ${JSON.stringify(requested.raw)}`,
|
|
61
80
|
);
|
|
62
81
|
}
|
|
63
|
-
if (requested === "binding" && options.binding !== true) {
|
|
82
|
+
if (requested.kind === "valid" && requested.authority === "binding" && options.binding !== true) {
|
|
64
83
|
throw new Error("applyDefaultEnvelope: authority \"binding\" requires an explicit binding flag");
|
|
65
84
|
}
|
|
66
|
-
return withOptionalFields(requested
|
|
85
|
+
return withOptionalFields(requested.kind === "valid" ? requested.authority : "informational", input);
|
|
67
86
|
}
|
|
68
87
|
|
|
69
88
|
export function parseSharedEnvelope(raw: unknown): SharedEnvelope {
|
|
@@ -71,8 +90,8 @@ export function parseSharedEnvelope(raw: unknown): SharedEnvelope {
|
|
|
71
90
|
return { authority: "informational" };
|
|
72
91
|
}
|
|
73
92
|
const record = raw as Record<string, unknown>;
|
|
74
|
-
const requested =
|
|
75
|
-
const authority = requested
|
|
93
|
+
const requested = readExactAuthority(record.authority);
|
|
94
|
+
const authority = requested.kind === "valid" ? requested.authority : "informational";
|
|
76
95
|
return withOptionalFields(authority, record);
|
|
77
96
|
}
|
|
78
97
|
|