@remnic/core 9.69.35 → 9.69.37
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 +12 -12
- package/dist/access-admin-ops-surface.js +35 -35
- package/dist/access-authorization-probe.d.ts +12 -12
- package/dist/access-authorization-probe.js +36 -36
- package/dist/access-boundary.d.ts +12 -12
- package/dist/access-boundary.js +35 -35
- package/dist/access-cli.js +116 -111
- 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 +12 -12
- package/dist/access-extraction-force-flush.js +35 -35
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-briefing.d.ts +12 -12
- package/dist/access-http-briefing.js +36 -36
- package/dist/access-http-lcm-compaction.d.ts +12 -12
- package/dist/access-http-lifecycle-flush.d.ts +12 -12
- package/dist/access-http-offline-stream.d.ts +12 -12
- package/dist/access-http-query.d.ts +2 -2
- package/dist/access-http-query.js +37 -37
- package/dist/access-http.d.ts +13 -13
- package/dist/access-http.js +55 -55
- package/dist/access-identity-continuity-surface.d.ts +10 -10
- package/dist/access-identity-continuity-surface.js +35 -35
- package/dist/access-lcm-surface.d.ts +12 -12
- package/dist/access-lcm-surface.js +35 -35
- package/dist/access-mcp.d.ts +12 -12
- package/dist/access-mcp.js +44 -44
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-D8qri11P.d.ts → access-namespace-preflight-CV5cHujx.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +35 -35
- package/dist/access-observe-transcript.d.ts +10 -10
- package/dist/access-observe-write-surface.d.ts +12 -12
- package/dist/access-observe-write-surface.js +35 -35
- package/dist/access-offline-manifest.d.ts +10 -10
- package/dist/access-offline-manifest.js +2 -2
- package/dist/access-operations-batch.js +38 -38
- package/dist/access-operations.d.ts +16 -16
- package/dist/access-operations.js +43 -43
- package/dist/access-recall-concurrency.d.ts +12 -12
- package/dist/access-recall-concurrency.js +35 -35
- package/dist/access-recall-response.d.ts +12 -12
- package/dist/access-recall-response.js +35 -35
- package/dist/access-recall-surface.d.ts +12 -12
- package/dist/access-recall-surface.js +35 -35
- package/dist/access-schema.d.ts +94 -94
- package/dist/access-schema.js +3 -3
- package/dist/{access-service-CKu5ixg9.d.ts → access-service-DwHC7lcV.d.ts} +71 -71
- package/dist/access-service-helpers.d.ts +12 -12
- package/dist/access-service.d.ts +12 -12
- package/dist/access-service.js +35 -35
- package/dist/access-surface-catalog.d.ts +12 -12
- package/dist/access-surface-catalog.js +37 -37
- 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 +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +4 -3
- package/dist/active-recall.js.map +1 -1
- package/dist/activity/digest.d.ts +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/ambient-provenance.d.ts +1 -1
- package/dist/artifact-search.d.ts +1 -1
- package/dist/{auto-sync-4YFATLFQ.js → auto-sync-FSRJDU63.js} +4 -4
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +10 -10
- package/dist/briefing-window.d.ts +2 -2
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +9 -9
- 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/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/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
- package/dist/{catalog-Bq1AxZwF.d.ts → catalog-Cl4H8N89.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +12 -12
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/causal-trajectory-graph.js +2 -2
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-RUXPVSML.js → chunk-2AR5JFD7.js} +2 -2
- package/dist/{chunk-YNN26CIZ.js → chunk-2JGGZICG.js} +2 -2
- package/dist/{chunk-A7GQBJP5.js → chunk-2L5FSNPC.js} +10 -10
- package/dist/{chunk-XPJNT6PI.js → chunk-2PUE5P7C.js} +7 -3
- package/dist/chunk-2PUE5P7C.js.map +1 -0
- package/dist/{chunk-27IOSH2W.js → chunk-375ARKRS.js} +32 -11
- package/dist/chunk-375ARKRS.js.map +1 -0
- package/dist/{chunk-ZTG4P7NZ.js → chunk-3IXB77DA.js} +67 -67
- package/dist/{chunk-WHHEPAO3.js → chunk-3K6UFW5B.js} +3 -3
- package/dist/{chunk-UBG4GAEP.js → chunk-3OHISDDW.js} +5 -1
- package/dist/chunk-3OHISDDW.js.map +1 -0
- package/dist/chunk-3SL52JKD.js +160 -0
- package/dist/chunk-3SL52JKD.js.map +1 -0
- package/dist/{chunk-EEBQFG5E.js → chunk-3YMDY3ZF.js} +10 -10
- package/dist/{chunk-5JG5EBVL.js → chunk-4DPDIOVA.js} +2 -2
- package/dist/{chunk-UDZYNIDJ.js → chunk-4WGAMREC.js} +2 -2
- package/dist/{chunk-HXSAWV3A.js → chunk-57GDHV2D.js} +3 -3
- package/dist/{chunk-Z7ACR6MJ.js → chunk-5LLQAUMI.js} +2 -2
- package/dist/{chunk-P3ONDDIJ.js → chunk-5SYI2F47.js} +2 -2
- package/dist/{chunk-DGS34QSY.js → chunk-6E5GYDIE.js} +2 -2
- package/dist/{chunk-J7PB5UQ4.js → chunk-6Z3WW2MW.js} +2 -2
- package/dist/{chunk-GLZH5VEN.js → chunk-76DRU7C4.js} +2 -2
- package/dist/{chunk-L2QLDZJC.js → chunk-7MJBKZPU.js} +2 -2
- package/dist/{chunk-Y63ZFP4X.js → chunk-7RKBPXY6.js} +2 -2
- package/dist/chunk-A6CXG5WI.js +51 -0
- package/dist/chunk-A6CXG5WI.js.map +1 -0
- package/dist/{chunk-JSRVXI6E.js → chunk-B2YKTE7P.js} +4 -4
- package/dist/{chunk-Z3O53WZR.js → chunk-BICNRVEC.js} +2 -2
- package/dist/{chunk-BNGHPYZU.js → chunk-BLHX5FQW.js} +2 -2
- package/dist/{chunk-7CBKAQIG.js → chunk-BOADKFN4.js} +28 -4
- package/dist/chunk-BOADKFN4.js.map +1 -0
- package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
- package/dist/{chunk-776GVKL7.js → chunk-CD3C4BJN.js} +2 -2
- package/dist/{chunk-LMCD5W5B.js → chunk-CIYUWSMZ.js} +2 -2
- package/dist/{chunk-YJ6VCDMZ.js → chunk-CQ7SSBO4.js} +2 -2
- package/dist/{chunk-CNV2A557.js → chunk-CYEMS2PG.js} +2 -2
- package/dist/{chunk-DVOBLPSQ.js → chunk-D2DIYEFW.js} +6 -6
- package/dist/chunk-D2DIYEFW.js.map +1 -0
- package/dist/{chunk-OQ7SSRXP.js → chunk-DOKKRZPH.js} +21 -17
- package/dist/chunk-DOKKRZPH.js.map +1 -0
- package/dist/{chunk-UYUCCQ46.js → chunk-DOQLHCSS.js} +2 -2
- package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
- package/dist/{chunk-RRZKTSFG.js → chunk-FCFAYMTU.js} +2 -2
- package/dist/{chunk-R4OCGPSH.js → chunk-FJMYMJLR.js} +2 -2
- package/dist/{chunk-TKFSXDOB.js → chunk-FLLORID2.js} +2 -2
- package/dist/{chunk-QATYVTP7.js → chunk-FPQDZCUX.js} +2 -2
- package/dist/{chunk-L2WQVSKP.js → chunk-G5MO3VQA.js} +2 -2
- package/dist/{chunk-LNDLXMH6.js → chunk-GDDSXVWR.js} +2 -2
- package/dist/{chunk-JZ2CHRLB.js → chunk-GHX5PNXW.js} +2 -2
- package/dist/{chunk-2BQ4ZIWC.js → chunk-GNR6YEWZ.js} +5 -5
- package/dist/{chunk-5FAGCOZD.js → chunk-GWK7FEUL.js} +4 -4
- package/dist/{chunk-SCXURCVT.js → chunk-GWQVMKUJ.js} +3 -3
- package/dist/{chunk-QBLDCI6E.js → chunk-HHDTBYDJ.js} +2 -2
- package/dist/{chunk-2YLMUME2.js → chunk-IQZ6ISFX.js} +2 -2
- package/dist/chunk-JE26AUX6.js +16 -0
- package/dist/chunk-JE26AUX6.js.map +1 -0
- package/dist/{chunk-AJTG3CP7.js → chunk-JHU4EYDV.js} +11 -1
- package/dist/chunk-JHU4EYDV.js.map +1 -0
- package/dist/{chunk-JHZCXUQI.js → chunk-JLXWRQNR.js} +33 -33
- package/dist/{chunk-FVJ4D6L7.js → chunk-JMPYZJQN.js} +1 -1
- package/dist/{chunk-HC4GFLMQ.js → chunk-JO5TQAKW.js} +3 -3
- package/dist/{chunk-ZBEGS7OB.js → chunk-JPKZTCWZ.js} +3 -3
- package/dist/{chunk-AZSKROVQ.js → chunk-JYR4LH76.js} +2 -2
- package/dist/{chunk-ECKG5WSI.js → chunk-JZYECQWN.js} +2 -2
- package/dist/{chunk-NPNSKE76.js → chunk-KTRXQQFN.js} +2 -2
- package/dist/{chunk-LEMD7WZJ.js → chunk-KUK56OPR.js} +62 -17
- package/dist/chunk-KUK56OPR.js.map +1 -0
- package/dist/{chunk-HUT2JR6I.js → chunk-L5OXE4PX.js} +2 -2
- package/dist/{chunk-B3O3IRZN.js → chunk-LMMQKZK3.js} +1 -1
- package/dist/{chunk-QURNMKME.js → chunk-LSDEIZ76.js} +2 -2
- package/dist/{chunk-XCOV45MO.js → chunk-MR6LQVZ5.js} +2 -2
- package/dist/chunk-OEBLZZKK.js +53 -0
- package/dist/chunk-OEBLZZKK.js.map +1 -0
- package/dist/{chunk-6J6K3STG.js → chunk-OTPXEE6W.js} +6 -6
- package/dist/{chunk-LYDJRF45.js → chunk-PNEDMJ53.js} +2 -2
- package/dist/{chunk-MPAJFFP3.js → chunk-PPTOAHTZ.js} +4 -4
- package/dist/{chunk-MPAJFFP3.js.map → chunk-PPTOAHTZ.js.map} +1 -1
- package/dist/{chunk-JRWW7GM6.js → chunk-Q6D7EUSQ.js} +7 -7
- package/dist/{chunk-VYXDUPYE.js → chunk-Q7JK6YEB.js} +2 -2
- package/dist/chunk-QJ2AX6DU.js +19 -0
- package/dist/chunk-QJ2AX6DU.js.map +1 -0
- package/dist/{chunk-4MDKNUV4.js → chunk-RN3MVLW3.js} +1 -1
- package/dist/chunk-RN3MVLW3.js.map +1 -0
- package/dist/{chunk-YXLUTALO.js → chunk-SAKA6PPL.js} +2 -2
- package/dist/{chunk-HWLIMQE2.js → chunk-SF6RFI5Z.js} +2 -2
- package/dist/{chunk-OS2AT2JU.js → chunk-SROIT6QY.js} +5 -5
- package/dist/{chunk-S5G2LAL7.js → chunk-SV4Z2S67.js} +4 -4
- package/dist/{chunk-DK4X5B6I.js → chunk-TFRDUD3M.js} +2 -2
- package/dist/{chunk-JR6H5CYS.js → chunk-TL7NLM2L.js} +2 -2
- package/dist/{chunk-NN4JEFON.js → chunk-TRU6JBOI.js} +2 -2
- package/dist/{chunk-PHP3MUGF.js → chunk-UYVXIY6C.js} +2 -2
- package/dist/{chunk-KQAFEZQX.js → chunk-VDX2J7OX.js} +2 -2
- package/dist/{chunk-ZHXSOMYH.js → chunk-VVX5PZFS.js} +2 -2
- package/dist/{chunk-BJETIR53.js → chunk-WS3WNLST.js} +3 -3
- package/dist/{chunk-3FJKJ5UZ.js → chunk-X7BCM2NA.js} +2 -2
- package/dist/{chunk-Q4AUIFUA.js → chunk-XAITGGX5.js} +4 -4
- package/dist/{chunk-WPDKBUWX.js → chunk-XCF3SFHD.js} +2 -2
- package/dist/{chunk-LO4UKPKX.js → chunk-YHU5XUF4.js} +2 -2
- package/dist/{chunk-F6IVBYFS.js → chunk-YIZ2EUUL.js} +51 -51
- package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
- package/dist/{chunk-5VAF4ID4.js → chunk-ZEPVWLCN.js} +9 -9
- package/dist/{cli-Bk7Ctql4.d.ts → cli-1mzd5TM4.d.ts} +5 -5
- package/dist/cli.d.ts +14 -14
- package/dist/cli.js +79 -78
- package/dist/coding/export-okf-codegraph.d.ts +1 -1
- package/dist/coding/export-okf-codegraph.js +8 -8
- package/dist/coding/pre-action-gate.d.ts +1 -1
- package/dist/coding/pre-action-gate.js +2 -2
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +9 -9
- 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 +4 -3
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +9 -9
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +9 -9
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/contradiction/index.d.ts +3 -3
- package/dist/converge-config.d.ts +1 -1
- package/dist/convergence-refresh.d.ts +2 -2
- package/dist/convergence-refresh.js +11 -11
- package/dist/conversation-index/backend.d.ts +1 -1
- 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 +11 -11
- package/dist/cross-lingual-recall.d.ts +1 -1
- package/dist/dashboard-runtime.js +2 -2
- package/dist/day-summary.d.ts +1 -1
- package/dist/deep-recall-http-glue.d.ts +12 -12
- package/dist/deep-recall-http-glue.js +4 -4
- package/dist/deep-recall-mcp-tools.d.ts +12 -12
- package/dist/deep-recall-policy-llm.d.ts +1 -1
- package/dist/deep-recall-seeds.d.ts +1 -1
- package/dist/deep-recall.js +2 -2
- package/dist/delinearize.d.ts +1 -1
- package/dist/dependency-propagation-config.d.ts +1 -1
- package/dist/{dependency-propagation-delivery-DLiAtj25.d.ts → dependency-propagation-delivery-Bua2ApHV.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-origin-fields.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +9 -9
- package/dist/entity-schema.d.ts +1 -1
- package/dist/episodic-context.d.ts +1 -1
- package/dist/eval-trajectory-contracts.d.ts +1 -1
- package/dist/eval-trajectory-store.d.ts +1 -1
- package/dist/eval-trajectory.d.ts +1 -1
- package/dist/explicit-capture.d.ts +10 -10
- package/dist/external-wiki-access.d.ts +12 -12
- package/dist/external-wiki-access.js +36 -36
- 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 +12 -12
- package/dist/extraction-error-classification.d.ts +1 -1
- package/dist/extraction-faithfulness.d.ts +1 -1
- 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-normalization.js +2 -2
- package/dist/extraction-prompt.d.ts +11 -2
- package/dist/extraction-prompt.js +7 -3
- package/dist/extraction-source-grounding-rules.d.ts +3 -2
- package/dist/extraction-source-grounding-rules.js +1 -1
- package/dist/extraction-source-grounding.d.ts +2 -2
- package/dist/extraction-source-grounding.js +2 -2
- package/dist/extraction-span-config.d.ts +15 -0
- package/dist/extraction-span-config.js +15 -0
- package/dist/extraction-span-materialize.d.ts +105 -0
- package/dist/extraction-span-materialize.js +30 -0
- package/dist/extraction-span-materialize.js.map +1 -0
- package/dist/extraction-span-slice.js +3 -12
- package/dist/extraction-span-slice.js.map +1 -1
- package/dist/extraction-span-source-hash.js +4 -46
- package/dist/extraction-span-source-hash.js.map +1 -1
- package/dist/extraction-span-validate.js +3 -15
- package/dist/extraction-span-validate.js.map +1 -1
- package/dist/extraction.d.ts +7 -1
- package/dist/extraction.js +20 -16
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{first-start-migration-L3UFX5CU.js → first-start-migration-GZ45G5FS.js} +4 -4
- package/dist/{generic-recall-paths-DbitKJI5.d.ts → generic-recall-paths-DJBADojG.d.ts} +1 -1
- package/dist/graph-append-error.d.ts +1 -1
- 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-decay-MKIRZ762.js → graph-edge-decay-ROSUPDX3.js} +5 -5
- package/dist/graph-edge-decay-ROSUPDX3.js.map +1 -0
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-jsonl.d.ts +1 -1
- package/dist/graph-jsonl.js +3 -3
- 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-snapshot.js +3 -3
- package/dist/graph.d.ts +1 -1
- package/dist/graph.js +2 -2
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/importers/index.d.ts +1 -1
- package/dist/importers/test-utils.d.ts +1 -1
- package/dist/in-flight-reads.d.ts +1 -1
- package/dist/{index-BINUgPFo.d.ts → index-Bsy8ygLL.d.ts} +2 -2
- package/dist/index.d.ts +700 -700
- package/dist/index.js +147 -142
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +4 -4
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +9 -9
- 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 +1 -1
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/location/index.d.ts +3 -3
- package/dist/location/index.js +11 -11
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +9 -9
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +9 -9
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +10 -10
- package/dist/{maintenance-ag1gYztC.d.ts → maintenance-DItyBwTC.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +12 -12
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-controller.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-subject-cli.d.ts +12 -12
- package/dist/memory-subject.d.ts +12 -12
- 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 +10 -10
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +5 -5
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +9 -9
- 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 +12 -12
- 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 +17 -17
- package/dist/{orchestrator-Cf3G-3Ed.d.ts → orchestrator-DBUX-aAM.d.ts} +9 -9
- package/dist/orchestrator.d.ts +10 -10
- package/dist/orchestrator.js +117 -112
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-AwB03fw_.d.ts → pipeline-BqgcOk1Z.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-BetSQn7q.d.ts → public-http-CqtZ5kv3.d.ts} +1 -1
- package/dist/{qmd-Bfaydrfm.d.ts → qmd-BD0ikV_Y.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-navigate-access.d.ts +1 -1
- package/dist/recall-navigate-access.js +2 -2
- package/dist/recall-navigate-disclosure.d.ts +1 -1
- package/dist/recall-navigate-disclosure.js +1 -1
- package/dist/recall-navigate.d.ts +1 -1
- package/dist/recall-navigate.js +2 -2
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state-view-admission.d.ts +2 -2
- 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 +11 -2
- package/dist/reconcile/manifest.js +5 -3
- 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 +5 -4
- 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/schemas.d.ts +386 -176
- package/dist/schemas.js +1 -1
- package/dist/{scope-profiles-nxTKvjE-.d.ts → scope-profiles-BIJMsd0B.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 +4 -4
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +10 -10
- 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-C83DVakV.d.ts → semantic-consolidation-D7sJocll.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +10 -10
- package/dist/semantic-rule-promotion.js +9 -9
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +9 -9
- package/dist/{service-q-xtOoAr.d.ts → service-fwgEngUj.d.ts} +2 -2
- 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 +7 -7
- package/dist/signal.d.ts +1 -1
- package/dist/source-agent-qualifier.d.ts +1 -1
- package/dist/source-agent-qualifier.js +12 -12
- package/dist/standup/build.js +9 -9
- package/dist/{storage-Ca0MbTfm.d.ts → storage-Cbll3-Tk.d.ts} +1 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +8 -8
- package/dist/subject-config.d.ts +1 -1
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/support-passport/index.d.ts +15 -15
- package/dist/support-passport/index.js +38 -38
- 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/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +2 -2
- package/dist/transfer/export-okf.d.ts +1 -1
- package/dist/transfer/export-okf.js +9 -9
- package/dist/transfer/types.d.ts +98 -98
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-yDgWDkrJ.d.ts → types-48sPkWB0.d.ts} +49 -10
- 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 +9 -9
- package/dist/who-knows-cli.d.ts +12 -12
- package/dist/who-knows-cli.js +10 -10
- package/dist/who-knows.d.ts +12 -12
- package/dist/who-knows.js +9 -9
- package/dist/write-envelope.d.ts +1 -1
- package/package.json +42 -2
- package/src/access-http.test.ts +43 -5
- package/src/access-http.ts +2 -0
- package/src/config.ts +2 -2
- package/src/extraction-prompt.ts +37 -3
- package/src/extraction-source-grounding-rules.ts +46 -9
- package/src/extraction-source-grounding.ts +2 -1
- package/src/extraction-span-config.ts +81 -0
- package/src/extraction-span-materialize.test.ts +376 -0
- package/src/extraction-span-materialize.ts +241 -0
- package/src/extraction.ts +70 -25
- package/src/reconcile/manifest.test.ts +11 -1
- package/src/reconcile/manifest.ts +12 -0
- package/src/schemas.ts +14 -0
- package/src/source-agent-qualifier.ts +5 -1
- package/src/testing/subjects/extraction-lifecycle.test.ts +27 -10
- package/src/types.ts +9 -9
- package/dist/chunk-27IOSH2W.js.map +0 -1
- package/dist/chunk-4MDKNUV4.js.map +0 -1
- package/dist/chunk-7CBKAQIG.js.map +0 -1
- package/dist/chunk-AJTG3CP7.js.map +0 -1
- package/dist/chunk-DVOBLPSQ.js.map +0 -1
- package/dist/chunk-LEMD7WZJ.js.map +0 -1
- package/dist/chunk-OQ7SSRXP.js.map +0 -1
- package/dist/chunk-UBG4GAEP.js.map +0 -1
- package/dist/chunk-XPJNT6PI.js.map +0 -1
- /package/dist/{auto-sync-4YFATLFQ.js.map → auto-sync-FSRJDU63.js.map} +0 -0
- /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-YO5QJ6L3.js.map} +0 -0
- /package/dist/{chunk-RUXPVSML.js.map → chunk-2AR5JFD7.js.map} +0 -0
- /package/dist/{chunk-YNN26CIZ.js.map → chunk-2JGGZICG.js.map} +0 -0
- /package/dist/{chunk-A7GQBJP5.js.map → chunk-2L5FSNPC.js.map} +0 -0
- /package/dist/{chunk-ZTG4P7NZ.js.map → chunk-3IXB77DA.js.map} +0 -0
- /package/dist/{chunk-WHHEPAO3.js.map → chunk-3K6UFW5B.js.map} +0 -0
- /package/dist/{chunk-EEBQFG5E.js.map → chunk-3YMDY3ZF.js.map} +0 -0
- /package/dist/{chunk-5JG5EBVL.js.map → chunk-4DPDIOVA.js.map} +0 -0
- /package/dist/{chunk-UDZYNIDJ.js.map → chunk-4WGAMREC.js.map} +0 -0
- /package/dist/{chunk-HXSAWV3A.js.map → chunk-57GDHV2D.js.map} +0 -0
- /package/dist/{chunk-Z7ACR6MJ.js.map → chunk-5LLQAUMI.js.map} +0 -0
- /package/dist/{chunk-P3ONDDIJ.js.map → chunk-5SYI2F47.js.map} +0 -0
- /package/dist/{chunk-DGS34QSY.js.map → chunk-6E5GYDIE.js.map} +0 -0
- /package/dist/{chunk-J7PB5UQ4.js.map → chunk-6Z3WW2MW.js.map} +0 -0
- /package/dist/{chunk-GLZH5VEN.js.map → chunk-76DRU7C4.js.map} +0 -0
- /package/dist/{chunk-L2QLDZJC.js.map → chunk-7MJBKZPU.js.map} +0 -0
- /package/dist/{chunk-Y63ZFP4X.js.map → chunk-7RKBPXY6.js.map} +0 -0
- /package/dist/{chunk-JSRVXI6E.js.map → chunk-B2YKTE7P.js.map} +0 -0
- /package/dist/{chunk-Z3O53WZR.js.map → chunk-BICNRVEC.js.map} +0 -0
- /package/dist/{chunk-BNGHPYZU.js.map → chunk-BLHX5FQW.js.map} +0 -0
- /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
- /package/dist/{chunk-776GVKL7.js.map → chunk-CD3C4BJN.js.map} +0 -0
- /package/dist/{chunk-LMCD5W5B.js.map → chunk-CIYUWSMZ.js.map} +0 -0
- /package/dist/{chunk-YJ6VCDMZ.js.map → chunk-CQ7SSBO4.js.map} +0 -0
- /package/dist/{chunk-CNV2A557.js.map → chunk-CYEMS2PG.js.map} +0 -0
- /package/dist/{chunk-UYUCCQ46.js.map → chunk-DOQLHCSS.js.map} +0 -0
- /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
- /package/dist/{chunk-RRZKTSFG.js.map → chunk-FCFAYMTU.js.map} +0 -0
- /package/dist/{chunk-R4OCGPSH.js.map → chunk-FJMYMJLR.js.map} +0 -0
- /package/dist/{chunk-TKFSXDOB.js.map → chunk-FLLORID2.js.map} +0 -0
- /package/dist/{chunk-QATYVTP7.js.map → chunk-FPQDZCUX.js.map} +0 -0
- /package/dist/{chunk-L2WQVSKP.js.map → chunk-G5MO3VQA.js.map} +0 -0
- /package/dist/{chunk-LNDLXMH6.js.map → chunk-GDDSXVWR.js.map} +0 -0
- /package/dist/{chunk-JZ2CHRLB.js.map → chunk-GHX5PNXW.js.map} +0 -0
- /package/dist/{chunk-2BQ4ZIWC.js.map → chunk-GNR6YEWZ.js.map} +0 -0
- /package/dist/{chunk-5FAGCOZD.js.map → chunk-GWK7FEUL.js.map} +0 -0
- /package/dist/{chunk-SCXURCVT.js.map → chunk-GWQVMKUJ.js.map} +0 -0
- /package/dist/{chunk-QBLDCI6E.js.map → chunk-HHDTBYDJ.js.map} +0 -0
- /package/dist/{chunk-2YLMUME2.js.map → chunk-IQZ6ISFX.js.map} +0 -0
- /package/dist/{chunk-JHZCXUQI.js.map → chunk-JLXWRQNR.js.map} +0 -0
- /package/dist/{chunk-FVJ4D6L7.js.map → chunk-JMPYZJQN.js.map} +0 -0
- /package/dist/{chunk-HC4GFLMQ.js.map → chunk-JO5TQAKW.js.map} +0 -0
- /package/dist/{chunk-ZBEGS7OB.js.map → chunk-JPKZTCWZ.js.map} +0 -0
- /package/dist/{chunk-AZSKROVQ.js.map → chunk-JYR4LH76.js.map} +0 -0
- /package/dist/{chunk-ECKG5WSI.js.map → chunk-JZYECQWN.js.map} +0 -0
- /package/dist/{chunk-NPNSKE76.js.map → chunk-KTRXQQFN.js.map} +0 -0
- /package/dist/{chunk-HUT2JR6I.js.map → chunk-L5OXE4PX.js.map} +0 -0
- /package/dist/{chunk-B3O3IRZN.js.map → chunk-LMMQKZK3.js.map} +0 -0
- /package/dist/{chunk-QURNMKME.js.map → chunk-LSDEIZ76.js.map} +0 -0
- /package/dist/{chunk-XCOV45MO.js.map → chunk-MR6LQVZ5.js.map} +0 -0
- /package/dist/{chunk-6J6K3STG.js.map → chunk-OTPXEE6W.js.map} +0 -0
- /package/dist/{chunk-LYDJRF45.js.map → chunk-PNEDMJ53.js.map} +0 -0
- /package/dist/{chunk-JRWW7GM6.js.map → chunk-Q6D7EUSQ.js.map} +0 -0
- /package/dist/{chunk-VYXDUPYE.js.map → chunk-Q7JK6YEB.js.map} +0 -0
- /package/dist/{chunk-YXLUTALO.js.map → chunk-SAKA6PPL.js.map} +0 -0
- /package/dist/{chunk-HWLIMQE2.js.map → chunk-SF6RFI5Z.js.map} +0 -0
- /package/dist/{chunk-OS2AT2JU.js.map → chunk-SROIT6QY.js.map} +0 -0
- /package/dist/{chunk-S5G2LAL7.js.map → chunk-SV4Z2S67.js.map} +0 -0
- /package/dist/{chunk-DK4X5B6I.js.map → chunk-TFRDUD3M.js.map} +0 -0
- /package/dist/{chunk-JR6H5CYS.js.map → chunk-TL7NLM2L.js.map} +0 -0
- /package/dist/{chunk-NN4JEFON.js.map → chunk-TRU6JBOI.js.map} +0 -0
- /package/dist/{chunk-PHP3MUGF.js.map → chunk-UYVXIY6C.js.map} +0 -0
- /package/dist/{chunk-KQAFEZQX.js.map → chunk-VDX2J7OX.js.map} +0 -0
- /package/dist/{chunk-ZHXSOMYH.js.map → chunk-VVX5PZFS.js.map} +0 -0
- /package/dist/{chunk-BJETIR53.js.map → chunk-WS3WNLST.js.map} +0 -0
- /package/dist/{chunk-3FJKJ5UZ.js.map → chunk-X7BCM2NA.js.map} +0 -0
- /package/dist/{chunk-Q4AUIFUA.js.map → chunk-XAITGGX5.js.map} +0 -0
- /package/dist/{chunk-WPDKBUWX.js.map → chunk-XCF3SFHD.js.map} +0 -0
- /package/dist/{chunk-LO4UKPKX.js.map → chunk-YHU5XUF4.js.map} +0 -0
- /package/dist/{chunk-F6IVBYFS.js.map → chunk-YIZ2EUUL.js.map} +0 -0
- /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
- /package/dist/{chunk-5VAF4ID4.js.map → chunk-ZEPVWLCN.js.map} +0 -0
- /package/dist/{graph-edge-decay-MKIRZ762.js.map → extraction-span-config.js.map} +0 -0
- /package/dist/{first-start-migration-L3UFX5CU.js.map → first-start-migration-GZ45G5FS.js.map} +0 -0
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
export interface ExtractionSourceGroundingOptions {
|
|
30
30
|
sourceGrounding: boolean;
|
|
31
31
|
anchorTemporalExpressions: boolean;
|
|
32
|
+
spanMode?: "off" | "shadow" | "on";
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
export function applyExtractionSourceGrounding(
|
|
@@ -60,6 +61,7 @@ export function applyExtractionSourceGrounding(
|
|
|
60
61
|
anchorSource(assertionSourceText),
|
|
61
62
|
anchoredRoleSources,
|
|
62
63
|
options.anchorTemporalExpressions ? anchorSource : undefined,
|
|
64
|
+
options.spanMode ?? "off",
|
|
63
65
|
);
|
|
64
66
|
}
|
|
65
67
|
|
|
@@ -653,18 +655,51 @@ function filterGroundedFact(
|
|
|
653
655
|
assertionSource: string | undefined,
|
|
654
656
|
roleAssertionSources: ExtractionGroundingRoleSources | undefined,
|
|
655
657
|
eventTimeNormalizer: ((eventTime: string) => string) | undefined,
|
|
658
|
+
spanMode: "off" | "shadow" | "on" = "off",
|
|
656
659
|
): ExtractionResult["facts"][number] | undefined {
|
|
657
|
-
|
|
660
|
+
// Span-materialized content (issue #2333) is "frame: verbatim slice". The
|
|
661
|
+
// frame is generated deixis, so full-content gating would drop a verbatim
|
|
662
|
+
// fact. Only on-mode facts whose content is that materialized shape may
|
|
663
|
+
// fall back to the slice. Shadow stays zero-diff with off.
|
|
664
|
+
const quote = typeof fact.quote === "string" ? fact.quote : "";
|
|
665
|
+
const materializedPrefix = quote.length > 0 && fact.content.endsWith(quote) && fact.content !== quote
|
|
666
|
+
? fact.content.slice(0, fact.content.length - quote.length)
|
|
667
|
+
: "";
|
|
668
|
+
const embeddedQuote =
|
|
669
|
+
spanMode === "on"
|
|
670
|
+
&& quote.trim().length > 0
|
|
671
|
+
&& (materializedPrefix.endsWith(": ") || /[:—-]\s$/.test(materializedPrefix))
|
|
672
|
+
? quote
|
|
673
|
+
: undefined;
|
|
674
|
+
const contentContext = selectGroundingContext(
|
|
658
675
|
fact.content,
|
|
659
676
|
resolveGroundingContext(fact.content, source, assertionSource, roleAssertionSources),
|
|
660
677
|
);
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
678
|
+
let gateContent = fact.content;
|
|
679
|
+
let factContext = contentContext;
|
|
680
|
+
if (
|
|
681
|
+
!isGroundedCandidate(
|
|
682
|
+
fact.content,
|
|
683
|
+
contentContext.source,
|
|
684
|
+
contentContext.assertionSource,
|
|
685
|
+
false,
|
|
686
|
+
contentContext.allowRoleNormalization,
|
|
687
|
+
)
|
|
688
|
+
) {
|
|
689
|
+
if (embeddedQuote === undefined) return undefined;
|
|
690
|
+
gateContent = embeddedQuote;
|
|
691
|
+
factContext = selectGroundingContext(
|
|
692
|
+
gateContent,
|
|
693
|
+
resolveGroundingContext(gateContent, source, assertionSource, roleAssertionSources),
|
|
694
|
+
);
|
|
695
|
+
if (!isGroundedCandidate(
|
|
696
|
+
gateContent,
|
|
697
|
+
factContext.source,
|
|
698
|
+
factContext.assertionSource,
|
|
699
|
+
false,
|
|
700
|
+
factContext.allowRoleNormalization,
|
|
701
|
+
)) return undefined;
|
|
702
|
+
}
|
|
668
703
|
const factEventTime = fact.eventTime;
|
|
669
704
|
const groundedFactEventTime = factEventTime === undefined
|
|
670
705
|
? undefined
|
|
@@ -672,7 +707,7 @@ function filterGroundedFact(
|
|
|
672
707
|
const factSupportingSentences = sourceSentences(factContext.assertionSource ?? factContext.source).filter(
|
|
673
708
|
(sentence) =>
|
|
674
709
|
isGroundedCandidate(
|
|
675
|
-
|
|
710
|
+
gateContent,
|
|
676
711
|
sentence,
|
|
677
712
|
undefined,
|
|
678
713
|
false,
|
|
@@ -1068,6 +1103,7 @@ export function filterExtractionResultBySource(
|
|
|
1068
1103
|
assertionSource?: string,
|
|
1069
1104
|
roleAssertionSources?: ExtractionGroundingRoleSources,
|
|
1070
1105
|
eventTimeNormalizer?: (eventTime: string) => string,
|
|
1106
|
+
spanMode: "off" | "shadow" | "on" = "off",
|
|
1071
1107
|
): ExtractionResult {
|
|
1072
1108
|
if (source.trim().length === 0) {
|
|
1073
1109
|
return {
|
|
@@ -1088,6 +1124,7 @@ export function filterExtractionResultBySource(
|
|
|
1088
1124
|
assertionSource,
|
|
1089
1125
|
roleAssertionSources,
|
|
1090
1126
|
eventTimeNormalizer,
|
|
1127
|
+
spanMode,
|
|
1091
1128
|
);
|
|
1092
1129
|
return grounded === undefined ? [] : [grounded];
|
|
1093
1130
|
});
|
|
@@ -99,6 +99,7 @@ export function filterExtractionResultBySource(
|
|
|
99
99
|
assertionSource?: string,
|
|
100
100
|
roleAssertionSources?: ExtractionGroundingRoleSources,
|
|
101
101
|
eventTimeNormalizer?: (eventTime: string) => string,
|
|
102
|
+
spanMode: "off" | "shadow" | "on" = "off",
|
|
102
103
|
): ExtractionResult {
|
|
103
|
-
return filterGroundingRules(result, source, assertionSource, roleAssertionSources, eventTimeNormalizer);
|
|
104
|
+
return filterGroundingRules(result, source, assertionSource, roleAssertionSources, eventTimeNormalizer, spanMode);
|
|
104
105
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Span-mode extraction config + fact span-ref types (issue #2333 Phase B,
|
|
3
|
+
* bench-gated). Sibling module so config.ts and types.ts stay under their
|
|
4
|
+
* structural ratchets (#1995); types.ts re-exports both.
|
|
5
|
+
*
|
|
6
|
+
* Default "off"; an unrecognized value is REJECTED, never defaulted
|
|
7
|
+
* (checklist #39) — silently ignoring it would run an unbenched extraction
|
|
8
|
+
* contract.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import { parseExtractionLivenessConfig } from "./extraction-liveness.js";
|
|
13
|
+
|
|
14
|
+
export interface ExtractionSpanConfig {
|
|
15
|
+
/**
|
|
16
|
+
* - "off" (default): extraction generates content as before.
|
|
17
|
+
* - "shadow": request spans AND content; materialize + compare + log
|
|
18
|
+
* agreement telemetry; persist the generated content (zero behavior
|
|
19
|
+
* change).
|
|
20
|
+
* - "on": persist materialized frame+span content, falling back per fact
|
|
21
|
+
* to generated content when the span fails validation.
|
|
22
|
+
*/
|
|
23
|
+
spanMode: "off" | "shadow" | "on";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ExtractedFactSpanRef {
|
|
27
|
+
/** Ordinal of the source turn in the extraction segment (0-based). */
|
|
28
|
+
sourceMessageIndex: number;
|
|
29
|
+
/** [charStart, charEnd) into the turn's exact in-memory text (UTF-16 code units). */
|
|
30
|
+
charStart: number;
|
|
31
|
+
charEnd: number;
|
|
32
|
+
/** ≤ 15 generated words making the span self-contained (resolves deixis). */
|
|
33
|
+
frame: string;
|
|
34
|
+
/** Optional prompt-source identity; when present it must match the captured stamp. */
|
|
35
|
+
sourceHash?: string;
|
|
36
|
+
sourceLength?: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const EXTRACTION_SPAN_MODES = ["off", "shadow", "on"] as const;
|
|
40
|
+
const extractionSpanBlockSchema = z.object({ spanMode: z.unknown().optional() }).strict();
|
|
41
|
+
|
|
42
|
+
/** Span + liveness fields for parseConfig. One spread keeps config.ts at the ratchet. */
|
|
43
|
+
export function parseExtractionFields(cfg: Record<string, unknown>) {
|
|
44
|
+
return {
|
|
45
|
+
extraction: parseExtractionSpanConfig(cfg.extraction),
|
|
46
|
+
extractionLiveness: parseExtractionLivenessConfig(cfg),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function parseExtractionSpanConfig(raw: unknown): ExtractionSpanConfig {
|
|
51
|
+
if (raw === undefined) {
|
|
52
|
+
return { spanMode: "off" };
|
|
53
|
+
}
|
|
54
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`extraction must be an object with optional spanMode (got ${JSON.stringify(raw)}). Omit the key for the default "off".`,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const block = raw as Record<string, unknown>;
|
|
60
|
+
const parsed = extractionSpanBlockSchema.safeParse(block);
|
|
61
|
+
if (!parsed.success) {
|
|
62
|
+
const unknownKeys = parsed.error.issues.flatMap((issue) =>
|
|
63
|
+
issue.code === "unrecognized_keys" ? issue.keys : []
|
|
64
|
+
);
|
|
65
|
+
throw new Error(
|
|
66
|
+
`extraction has unknown propert${unknownKeys.length === 1 ? "y" : "ies"}: ${unknownKeys.join(", ")}. Allowed: "spanMode".`,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const spanMode = block.spanMode;
|
|
70
|
+
if (spanMode === undefined) {
|
|
71
|
+
return { spanMode: "off" };
|
|
72
|
+
}
|
|
73
|
+
for (const mode of EXTRACTION_SPAN_MODES) {
|
|
74
|
+
if (spanMode === mode) {
|
|
75
|
+
return { spanMode: mode };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
throw new Error(
|
|
79
|
+
`extraction.spanMode must be one of "off", "shadow", "on" (got ${JSON.stringify(spanMode)}). Omit the key for the default "off".`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Span-mode materialization tests (issue #2333 Phase B).
|
|
3
|
+
*
|
|
4
|
+
* Covers the Phase B test contract: bounds off-by-one at both ends
|
|
5
|
+
* ([charStart, charEnd) end-exclusive), hash-mismatch (offset drift)
|
|
6
|
+
* rejection, per-fact fail-open, shadow-mode zero-diff vs "off", oversized
|
|
7
|
+
* span rejection, frame word-count limits, untrusted-span stripping in "off",
|
|
8
|
+
* and strict config enum handling.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import assert from "node:assert/strict";
|
|
12
|
+
import test from "node:test";
|
|
13
|
+
import { stampSpanSource } from "./extraction-span-source-hash.js";
|
|
14
|
+
import {
|
|
15
|
+
applyExtractionSpanMaterialization,
|
|
16
|
+
bindLocalExtractionPrompt,
|
|
17
|
+
buildSpanMaterializeTurns,
|
|
18
|
+
factCarriesSpan,
|
|
19
|
+
materializeFactSpan,
|
|
20
|
+
spanAgreesWithContent,
|
|
21
|
+
stripUntrustedFactSpans,
|
|
22
|
+
SPAN_MAX_SLICE_CHARS,
|
|
23
|
+
type SpanMaterializeTurn,
|
|
24
|
+
} from "./extraction-span-materialize.js";
|
|
25
|
+
import { renderExtractionConversation } from "./source-agent-qualifier.js";
|
|
26
|
+
import { parseConfig } from "./config.js";
|
|
27
|
+
import type { BufferTurn, ExtractedFact } from "./types.js";
|
|
28
|
+
import type { ExtractedFactSpanRef } from "./extraction-span-config.js";
|
|
29
|
+
|
|
30
|
+
const TURN_TEXT = "Maya moved to Seattle last spring for a new senior role.";
|
|
31
|
+
|
|
32
|
+
function turns(...texts: string[]): SpanMaterializeTurn[] {
|
|
33
|
+
return buildSpanMaterializeTurns(texts);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function fact(overrides: {
|
|
37
|
+
charStart: number;
|
|
38
|
+
charEnd: number;
|
|
39
|
+
frame?: string;
|
|
40
|
+
content?: string;
|
|
41
|
+
sourceMessageIndex?: number;
|
|
42
|
+
sourceHash?: string;
|
|
43
|
+
sourceLength?: number;
|
|
44
|
+
}): ExtractedFact {
|
|
45
|
+
const span: ExtractedFactSpanRef = {
|
|
46
|
+
sourceMessageIndex: overrides.sourceMessageIndex ?? 0,
|
|
47
|
+
charStart: overrides.charStart,
|
|
48
|
+
charEnd: overrides.charEnd,
|
|
49
|
+
frame: overrides.frame ?? "Maya's relocation",
|
|
50
|
+
...(overrides.sourceHash !== undefined && overrides.sourceLength !== undefined
|
|
51
|
+
? { sourceHash: overrides.sourceHash, sourceLength: overrides.sourceLength }
|
|
52
|
+
: {}),
|
|
53
|
+
};
|
|
54
|
+
return {
|
|
55
|
+
category: "fact",
|
|
56
|
+
content: overrides.content ?? "Maya moved to Seattle last spring for a new senior role.",
|
|
57
|
+
confidence: 0.9,
|
|
58
|
+
tags: ["relocation"],
|
|
59
|
+
span,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
test("on-mode materializes frame + verbatim slice and sets the grounding quote", () => {
|
|
64
|
+
const start = TURN_TEXT.indexOf("Seattle");
|
|
65
|
+
const result = materializeFactSpan(
|
|
66
|
+
fact({ charStart: start, charEnd: start + "Seattle".length }),
|
|
67
|
+
turns(TURN_TEXT),
|
|
68
|
+
"on",
|
|
69
|
+
);
|
|
70
|
+
assert.equal(result.outcome, "span");
|
|
71
|
+
assert.equal(result.fact.content, "Maya's relocation: Seattle");
|
|
72
|
+
assert.equal(result.fact.quote, "Seattle");
|
|
73
|
+
assert.equal(result.fact.span, undefined, "offsets die at materialization");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("[charStart, charEnd) is end-exclusive — off-by-one at both ends", () => {
|
|
77
|
+
const start = TURN_TEXT.indexOf("Seattle");
|
|
78
|
+
const messages = turns(TURN_TEXT);
|
|
79
|
+
const inner = materializeFactSpan(fact({ charStart: start + 1, charEnd: start + 6 }), messages, "on");
|
|
80
|
+
assert.equal(inner.fact.quote, "eattl");
|
|
81
|
+
const lastChar = materializeFactSpan(
|
|
82
|
+
fact({ charStart: TURN_TEXT.length - 1, charEnd: TURN_TEXT.length }),
|
|
83
|
+
messages,
|
|
84
|
+
"on",
|
|
85
|
+
);
|
|
86
|
+
assert.equal(lastChar.outcome, "span");
|
|
87
|
+
assert.equal(lastChar.fact.quote, ".");
|
|
88
|
+
assert.equal(
|
|
89
|
+
materializeFactSpan(fact({ charStart: 0, charEnd: TURN_TEXT.length + 1 }), messages, "on").outcome,
|
|
90
|
+
"fallback",
|
|
91
|
+
);
|
|
92
|
+
assert.equal(
|
|
93
|
+
materializeFactSpan(fact({ charStart: -1, charEnd: 4 }), messages, "on").outcome,
|
|
94
|
+
"fallback",
|
|
95
|
+
);
|
|
96
|
+
assert.equal(
|
|
97
|
+
materializeFactSpan(fact({ charStart: 5, charEnd: 5 }), messages, "on").outcome,
|
|
98
|
+
"fallback",
|
|
99
|
+
);
|
|
100
|
+
assert.equal(
|
|
101
|
+
materializeFactSpan(fact({ charStart: 9, charEnd: 4 }), messages, "on").outcome,
|
|
102
|
+
"fallback",
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("offset drift (turn text changed after stamping) is rejected", () => {
|
|
107
|
+
// The stamp was computed over the exact double-spaced string the model saw;
|
|
108
|
+
// the turn text here has been renormalized — verify must fail.
|
|
109
|
+
const drifted: SpanMaterializeTurn[] = [
|
|
110
|
+
{ text: "Maya moved to Seattle.", stamp: stampSpanSource("Maya moved to Seattle.") },
|
|
111
|
+
];
|
|
112
|
+
assert.notEqual(drifted[0].stamp.hash, stampSpanSource(drifted[0].text).hash);
|
|
113
|
+
const result = materializeFactSpan(fact({ charStart: 0, charEnd: 4 }), drifted, "on");
|
|
114
|
+
assert.equal(result.outcome, "fallback");
|
|
115
|
+
assert.equal(result.fact.content, "Maya moved to Seattle last spring for a new senior role.");
|
|
116
|
+
assert.equal(result.fact.span, undefined);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("oversized slice (>400 chars) is rejected; exactly 400 passes", () => {
|
|
120
|
+
const long = "a".repeat(600);
|
|
121
|
+
const messages = turns(long);
|
|
122
|
+
assert.equal(
|
|
123
|
+
materializeFactSpan(fact({ charStart: 0, charEnd: SPAN_MAX_SLICE_CHARS + 1 }), messages, "on").outcome,
|
|
124
|
+
"fallback",
|
|
125
|
+
);
|
|
126
|
+
assert.equal(
|
|
127
|
+
materializeFactSpan(fact({ charStart: 0, charEnd: SPAN_MAX_SLICE_CHARS }), messages, "on").outcome,
|
|
128
|
+
"span",
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("whitespace-only slice and frame word-count limits are rejected", () => {
|
|
133
|
+
const messages = turns("word1 word2 word3");
|
|
134
|
+
const words = (count: number) => Array.from({ length: count }, (_, i) => `w${i}`).join(" ");
|
|
135
|
+
assert.equal(
|
|
136
|
+
materializeFactSpan(fact({ charStart: 5, charEnd: 7 }), messages, "on").outcome,
|
|
137
|
+
"fallback",
|
|
138
|
+
);
|
|
139
|
+
assert.equal(
|
|
140
|
+
materializeFactSpan(fact({ charStart: 0, charEnd: 5, frame: words(15) }), messages, "on").outcome,
|
|
141
|
+
"span",
|
|
142
|
+
);
|
|
143
|
+
assert.equal(
|
|
144
|
+
materializeFactSpan(fact({ charStart: 0, charEnd: 5, frame: " " }), messages, "on").outcome,
|
|
145
|
+
"fallback",
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("per-fact fail-open: one invalid span among three persists all three", () => {
|
|
150
|
+
const messages = turns(TURN_TEXT);
|
|
151
|
+
const seattle = TURN_TEXT.indexOf("Seattle");
|
|
152
|
+
const facts = [
|
|
153
|
+
fact({ charStart: seattle, charEnd: seattle + 7, content: "fallback A" }),
|
|
154
|
+
fact({ charStart: 0, charEnd: TURN_TEXT.length + 5, content: "fallback B" }),
|
|
155
|
+
fact({ charStart: 0, charEnd: 4, content: "fallback C" }),
|
|
156
|
+
];
|
|
157
|
+
const outcomes = facts.map((f) => materializeFactSpan(f, messages, "on"));
|
|
158
|
+
assert.deepEqual(
|
|
159
|
+
outcomes.map((o) => o.outcome),
|
|
160
|
+
["span", "fallback", "span"],
|
|
161
|
+
);
|
|
162
|
+
for (const outcome of outcomes) {
|
|
163
|
+
assert.ok(outcome.fact.content.length > 0);
|
|
164
|
+
assert.equal(outcome.fact.span, undefined);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test("shadow mode is zero-diff: byte-identical facts vs the same input", () => {
|
|
169
|
+
const messages = turns(TURN_TEXT);
|
|
170
|
+
const seattle = TURN_TEXT.indexOf("Seattle");
|
|
171
|
+
const spanFact = fact({ charStart: seattle, charEnd: seattle + 7, content: "generated restatement" });
|
|
172
|
+
const shadow = materializeFactSpan(spanFact, messages, "shadow");
|
|
173
|
+
assert.equal(shadow.outcome, "span");
|
|
174
|
+
assert.equal(shadow.fact.content, "generated restatement", "shadow persists generated content");
|
|
175
|
+
assert.ok(!("quote" in shadow.fact), "shadow does not touch the grounding quote");
|
|
176
|
+
assert.equal(shadow.fact.span, undefined);
|
|
177
|
+
// Zero-diff vs "off": the persisted fact is byte-identical to simply
|
|
178
|
+
// stripping the span — same content, same fields, nothing added.
|
|
179
|
+
const stripped = stripUntrustedFactSpans([spanFact])[0];
|
|
180
|
+
assert.deepEqual(shadow.fact, stripped);
|
|
181
|
+
// And the comparison materialization is still produced for telemetry.
|
|
182
|
+
assert.equal(shadow.materialized, "Maya's relocation: Seattle");
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("shadow agreement predicate: exact or containment", () => {
|
|
186
|
+
assert.equal(spanAgreesWithContent("a: b c", "b c"), true);
|
|
187
|
+
assert.equal(spanAgreesWithContent("b c", "a: b c"), true);
|
|
188
|
+
assert.equal(spanAgreesWithContent("a: b c", "a: b c"), true);
|
|
189
|
+
assert.equal(spanAgreesWithContent("a: b c", "z z z"), false);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test("stray span in off-mode is stripped untrusted; factCarriesSpan detects spans", () => {
|
|
193
|
+
const messages = turns(TURN_TEXT);
|
|
194
|
+
const stray = fact({ charStart: 0, charEnd: 900, content: "kept" });
|
|
195
|
+
assert.ok(factCarriesSpan(stray));
|
|
196
|
+
const strippedFacts = stripUntrustedFactSpans([stray]);
|
|
197
|
+
assert.equal(strippedFacts[0].span, undefined);
|
|
198
|
+
assert.equal(strippedFacts[0].content, "kept");
|
|
199
|
+
assert.ok(!factCarriesSpan(strippedFacts[0]));
|
|
200
|
+
// materializeFactSpan in off mode never validates — callers strip instead;
|
|
201
|
+
// a fallback here still must not lose content.
|
|
202
|
+
const result = materializeFactSpan(stray, messages, "off");
|
|
203
|
+
assert.equal(result.fact.content, "kept");
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("config: extraction.spanMode default off, valid values accepted, unknown rejected", () => {
|
|
207
|
+
assert.equal(parseConfig({}).extraction.spanMode, "off");
|
|
208
|
+
assert.equal(parseConfig({}).extractionLiveness.enabled, true);
|
|
209
|
+
assert.equal(parseConfig({ extractionLiveness: { enabled: false } }).extractionLiveness.enabled, false);
|
|
210
|
+
assert.equal(parseConfig({ extraction: { spanMode: "shadow" } }).extraction.spanMode, "shadow");
|
|
211
|
+
assert.equal(parseConfig({ extraction: { spanMode: "on" } }).extraction.spanMode, "on");
|
|
212
|
+
assert.equal(parseConfig({ extraction: {} }).extraction.spanMode, "off");
|
|
213
|
+
assert.throws(
|
|
214
|
+
() => parseConfig({ extraction: { spanMode: "sometimes" } }),
|
|
215
|
+
/extraction\.spanMode must be one of "off", "shadow", "on"/,
|
|
216
|
+
);
|
|
217
|
+
assert.throws(
|
|
218
|
+
() => parseConfig({ extraction: { spanMode: 1 } }),
|
|
219
|
+
/extraction\.spanMode must be one of "off", "shadow", "on"/,
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test("config: extraction block must be an object, not an array or scalar", () => {
|
|
224
|
+
assert.throws(() => parseConfig({ extraction: [] }), /extraction must be an object/);
|
|
225
|
+
assert.throws(() => parseConfig({ extraction: "on" }), /extraction must be an object/);
|
|
226
|
+
assert.throws(() => parseConfig({ extraction: null }), /extraction must be an object/);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test("config: unknown extraction keys including spanMode typos are rejected", () => {
|
|
230
|
+
assert.throws(
|
|
231
|
+
() => parseConfig({ extraction: { spanMdoe: "on" } }),
|
|
232
|
+
/extraction has unknown property: spanMdoe/,
|
|
233
|
+
);
|
|
234
|
+
assert.throws(
|
|
235
|
+
() => parseConfig({ extraction: { spanMode: "on", extra: true } }),
|
|
236
|
+
/extraction has unknown property: extra/,
|
|
237
|
+
);
|
|
238
|
+
assert.equal(parseConfig({ extraction: { spanMode: "on" } }).extraction.spanMode, "on");
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test("applyExtractionSpanMaterialization uses captured prompt stamps, not a restamp", () => {
|
|
242
|
+
const generated = "Maya moved to Seattle last spring for a new senior role.";
|
|
243
|
+
const result = {
|
|
244
|
+
facts: [fact({ charStart: 0, charEnd: 4, content: generated })],
|
|
245
|
+
entities: [],
|
|
246
|
+
questions: [],
|
|
247
|
+
profileUpdates: [],
|
|
248
|
+
};
|
|
249
|
+
const captured = buildSpanMaterializeTurns([TURN_TEXT]);
|
|
250
|
+
const ok = applyExtractionSpanMaterialization(result, captured, "on");
|
|
251
|
+
assert.equal(ok.facts[0]?.content, "Maya's relocation: Maya");
|
|
252
|
+
|
|
253
|
+
const drifted = [{ text: TURN_TEXT, stamp: stampSpanSource("different prompt text") }];
|
|
254
|
+
const fallback = applyExtractionSpanMaterialization(result, drifted, "on");
|
|
255
|
+
assert.equal(fallback.facts[0]?.content, generated);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test("span sourceHash/sourceLength must match the captured prompt stamp", () => {
|
|
259
|
+
const captured = buildSpanMaterializeTurns([TURN_TEXT]);
|
|
260
|
+
const stamp = captured[0]?.stamp;
|
|
261
|
+
assert.ok(stamp);
|
|
262
|
+
const matching = materializeFactSpan(
|
|
263
|
+
fact({ charStart: 0, charEnd: 4, sourceHash: stamp.hash, sourceLength: stamp.length }),
|
|
264
|
+
captured,
|
|
265
|
+
"on",
|
|
266
|
+
);
|
|
267
|
+
assert.equal(matching.outcome, "span");
|
|
268
|
+
const mismatched = materializeFactSpan(
|
|
269
|
+
fact({ charStart: 0, charEnd: 4, sourceHash: "0".repeat(64), sourceLength: stamp.length }),
|
|
270
|
+
captured,
|
|
271
|
+
"on",
|
|
272
|
+
);
|
|
273
|
+
assert.equal(mismatched.outcome, "fallback");
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
test("local prompt bind stamps the truncated visible prefix, not the unseen suffix", () => {
|
|
277
|
+
const visible = "Maya moved to Seattle last spring";
|
|
278
|
+
const unseen = " for a new senior role. UNSEEN_SUFFIX";
|
|
279
|
+
const content = `${visible}${unseen}`;
|
|
280
|
+
const turns: BufferTurn[] = [{ role: "user", content, timestamp: "2026-05-21T00:00:00.000Z" }];
|
|
281
|
+
const { conversation, renderedConversation } = renderExtractionConversation(turns, undefined);
|
|
282
|
+
const cut = conversation.indexOf(unseen);
|
|
283
|
+
assert.ok(cut > 0);
|
|
284
|
+
const bound = bindLocalExtractionPrompt(conversation, turns, cut, renderedConversation);
|
|
285
|
+
assert.match(bound.promptConversation, /\[truncated\]$/);
|
|
286
|
+
assert.equal(bound.spanTurns[0]?.text, visible);
|
|
287
|
+
assert.equal(bound.spanTurns[0]?.stamp.length, visible.length);
|
|
288
|
+
assert.notEqual(bound.spanTurns[0]?.stamp.hash, stampSpanSource(content).hash);
|
|
289
|
+
|
|
290
|
+
const leakStart = content.indexOf("UNSEEN_SUFFIX");
|
|
291
|
+
const againstFull = materializeFactSpan(
|
|
292
|
+
fact({ charStart: leakStart, charEnd: content.length, content: "kept-frame" }),
|
|
293
|
+
buildSpanMaterializeTurns([content]),
|
|
294
|
+
"on",
|
|
295
|
+
);
|
|
296
|
+
assert.equal(againstFull.outcome, "span");
|
|
297
|
+
assert.match(againstFull.fact.content ?? "", /UNSEEN_SUFFIX/);
|
|
298
|
+
|
|
299
|
+
const againstBound = materializeFactSpan(
|
|
300
|
+
fact({ charStart: leakStart, charEnd: content.length, content: "kept-frame" }),
|
|
301
|
+
bound.spanTurns,
|
|
302
|
+
"on",
|
|
303
|
+
);
|
|
304
|
+
assert.equal(againstBound.outcome, "fallback");
|
|
305
|
+
assert.equal(againstBound.fact.content, "kept-frame");
|
|
306
|
+
|
|
307
|
+
const visibleOk = materializeFactSpan(
|
|
308
|
+
fact({
|
|
309
|
+
charStart: 0,
|
|
310
|
+
charEnd: visible.length,
|
|
311
|
+
content: "kept-frame",
|
|
312
|
+
sourceHash: bound.spanTurns[0]?.stamp.hash,
|
|
313
|
+
sourceLength: bound.spanTurns[0]?.stamp.length,
|
|
314
|
+
}),
|
|
315
|
+
bound.spanTurns,
|
|
316
|
+
"on",
|
|
317
|
+
);
|
|
318
|
+
assert.equal(visibleOk.outcome, "span");
|
|
319
|
+
assert.equal(visibleOk.fact.quote, visible);
|
|
320
|
+
const fullStamp = stampSpanSource(content);
|
|
321
|
+
const wrongHash = materializeFactSpan(
|
|
322
|
+
fact({
|
|
323
|
+
charStart: 0,
|
|
324
|
+
charEnd: visible.length,
|
|
325
|
+
content: "kept-frame",
|
|
326
|
+
sourceHash: fullStamp.hash,
|
|
327
|
+
sourceLength: fullStamp.length,
|
|
328
|
+
}),
|
|
329
|
+
bound.spanTurns,
|
|
330
|
+
"on",
|
|
331
|
+
);
|
|
332
|
+
assert.equal(wrongHash.outcome, "fallback");
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
test("on-mode facts that omit span are dropped instead of persisting the frame", () => {
|
|
336
|
+
const generated = {
|
|
337
|
+
facts: [
|
|
338
|
+
{
|
|
339
|
+
category: "fact" as const,
|
|
340
|
+
content: "Maya's relocation",
|
|
341
|
+
confidence: 0.9,
|
|
342
|
+
tags: ["relocation"],
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
entities: [],
|
|
346
|
+
questions: [],
|
|
347
|
+
profileUpdates: [],
|
|
348
|
+
};
|
|
349
|
+
const on = applyExtractionSpanMaterialization(generated, turns(TURN_TEXT), "on");
|
|
350
|
+
assert.equal(on.facts.length, 0);
|
|
351
|
+
const shadow = applyExtractionSpanMaterialization(generated, turns(TURN_TEXT), "shadow");
|
|
352
|
+
assert.equal(shadow.facts[0]?.content, "Maya's relocation");
|
|
353
|
+
const off = applyExtractionSpanMaterialization(generated, turns(TURN_TEXT), "off");
|
|
354
|
+
assert.equal(off.facts[0]?.content, "Maya's relocation");
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test("on-mode mixed batch keeps validated spans and drops omitted spans", () => {
|
|
358
|
+
const seattle = TURN_TEXT.indexOf("Seattle");
|
|
359
|
+
const result = {
|
|
360
|
+
facts: [
|
|
361
|
+
fact({ charStart: seattle, charEnd: seattle + 7 }),
|
|
362
|
+
{
|
|
363
|
+
category: "fact" as const,
|
|
364
|
+
content: "Maya's relocation",
|
|
365
|
+
confidence: 0.9,
|
|
366
|
+
tags: [],
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
entities: [],
|
|
370
|
+
questions: [],
|
|
371
|
+
profileUpdates: [],
|
|
372
|
+
};
|
|
373
|
+
const on = applyExtractionSpanMaterialization(result, turns(TURN_TEXT), "on");
|
|
374
|
+
assert.equal(on.facts.length, 1);
|
|
375
|
+
assert.equal(on.facts[0]?.content, "Maya's relocation: Seattle");
|
|
376
|
+
});
|