@remnic/core 9.65.2 → 9.65.3
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 +44 -44
- package/dist/access-admin-ops-surface.js +14 -14
- package/dist/access-authorization-probe.d.ts +38 -38
- package/dist/access-authorization-probe.js +15 -15
- package/dist/access-boundary.d.ts +40 -40
- package/dist/access-boundary.js +14 -14
- package/dist/access-cli.js +52 -52
- package/dist/access-coding-context-resolution.d.ts +3 -1
- package/dist/access-extraction-force-flush.d.ts +25 -25
- package/dist/access-extraction-force-flush.js +14 -14
- package/dist/access-health-types.d.ts +3 -1
- package/dist/access-http-lcm-compaction.d.ts +39 -39
- package/dist/access-http-lifecycle-flush.d.ts +39 -39
- package/dist/access-http-offline-stream.d.ts +25 -25
- package/dist/access-http-query.d.ts +4 -2
- package/dist/access-http-query.js +16 -16
- package/dist/access-http.d.ts +51 -44
- package/dist/access-http.js +30 -30
- package/dist/access-identity-continuity-surface.d.ts +12 -12
- package/dist/access-identity-continuity-surface.js +14 -14
- package/dist/access-lcm-surface.d.ts +27 -27
- package/dist/access-lcm-surface.js +14 -14
- package/dist/access-mcp-admin-tools.d.ts +9 -1
- package/dist/access-mcp-admin-tools.js +3 -1
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.d.ts +39 -39
- package/dist/access-mcp.js +24 -24
- package/dist/access-memory-search-fanout.d.ts +4 -2
- package/dist/{access-namespace-preflight-Dhvcl-T0.d.ts → access-namespace-preflight-B7Usyz-K.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +5 -3
- package/dist/access-namespace-preflight.js +14 -14
- package/dist/access-observe-write-surface.d.ts +39 -39
- package/dist/access-observe-write-surface.js +14 -14
- package/dist/access-offline-manifest.d.ts +12 -12
- package/dist/access-operations-batch.js +18 -18
- package/dist/access-operations.d.ts +40 -40
- package/dist/access-operations.js +21 -21
- package/dist/access-recall-concurrency.d.ts +40 -40
- package/dist/access-recall-concurrency.js +14 -14
- package/dist/access-recall-response.d.ts +24 -24
- package/dist/access-recall-response.js +14 -14
- package/dist/access-recall-surface.d.ts +24 -24
- package/dist/access-recall-surface.js +14 -14
- package/dist/access-schema.d.ts +45 -45
- package/dist/{access-service-Bke1alZO.d.ts → access-service-DkaIG3n8.d.ts} +219 -75
- package/dist/access-service-helpers.d.ts +40 -40
- package/dist/access-service.d.ts +47 -47
- package/dist/access-service.js +14 -14
- package/dist/access-surface-catalog.d.ts +40 -40
- package/dist/access-surface-catalog.js +20 -16
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/access-wearables-meetings-surface.d.ts +5 -3
- package/dist/action-confidence.d.ts +3 -1
- package/dist/active-memory-bridge.d.ts +3 -1
- package/dist/active-recall.d.ts +3 -1
- package/dist/active-recall.js +6 -1
- package/dist/active-recall.js.map +1 -1
- package/dist/ambient-provenance.d.ts +3 -1
- package/dist/artifact-search.d.ts +3 -1
- package/dist/behavior-learner.d.ts +3 -1
- package/dist/behavior-signals.d.ts +3 -1
- package/dist/bootstrap.d.ts +12 -12
- package/dist/briefing-window.d.ts +4 -2
- package/dist/briefing.d.ts +4 -2
- package/dist/briefing.js +3 -3
- package/dist/buffer-surprise-report.d.ts +3 -1
- package/dist/buffer-turn-helpers.d.ts +3 -1
- package/dist/buffer.d.ts +4 -2
- package/dist/bulk-import/index.d.ts +5 -3
- package/dist/calibration.d.ts +3 -1
- package/dist/capabilities.d.ts +3 -1
- package/dist/{catalog-DV6qnbr7.d.ts → catalog-CX2BZEJh.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +3 -1
- package/dist/causal-consolidation.js +7 -7
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-R7JAM2XF.js → chunk-2VXWFYJE.js} +3 -3
- package/dist/{chunk-UXO5IMBK.js → chunk-4XDGYCZI.js} +2 -2
- package/dist/{chunk-OTHZWLUD.js → chunk-57HVIG5U.js} +2 -2
- package/dist/{chunk-EILZG5VC.js → chunk-6TAX66IA.js} +2 -2
- package/dist/{chunk-NKKD4ZAU.js → chunk-6VALIZKG.js} +2 -2
- package/dist/{chunk-BWLRUMOG.js → chunk-76PL4XLG.js} +435 -1
- package/dist/chunk-76PL4XLG.js.map +1 -0
- package/dist/{chunk-2E36UXVW.js → chunk-7KFIMGMP.js} +2 -2
- package/dist/{chunk-LGO6A7GJ.js → chunk-7QOO4LGC.js} +28 -28
- package/dist/{chunk-TBOJ76ER.js → chunk-AB3A7EFH.js} +18 -2
- package/dist/{chunk-TBOJ76ER.js.map → chunk-AB3A7EFH.js.map} +1 -1
- package/dist/{chunk-DZUJ46DO.js → chunk-AUO2LJ3K.js} +2 -2
- package/dist/{chunk-ZO6AXLEH.js → chunk-AYDDB3XI.js} +2 -2
- package/dist/{chunk-NTWN6HB2.js → chunk-AYYGRVRP.js} +2 -2
- package/dist/{chunk-7YQ4IYS2.js → chunk-AZAA5DNP.js} +2 -2
- package/dist/{chunk-4KYOLI6M.js → chunk-BKYPJUQL.js} +120 -14
- package/dist/chunk-BKYPJUQL.js.map +1 -0
- package/dist/{chunk-Z7PBQPJ4.js → chunk-BQUEAVNW.js} +2 -2
- package/dist/{chunk-35NN3ZFA.js → chunk-CTVWELNK.js} +21 -3
- package/dist/chunk-CTVWELNK.js.map +1 -0
- package/dist/{chunk-5YQ63T4B.js → chunk-D27J626P.js} +2 -2
- package/dist/{chunk-LZH5FR2W.js → chunk-DHTQP334.js} +2 -2
- package/dist/{chunk-Y7DK7HHJ.js → chunk-E4MVQQVX.js} +2 -2
- package/dist/{chunk-JYYBA7TF.js → chunk-EIVIB73I.js} +2 -2
- package/dist/{chunk-S2DPMJXH.js → chunk-EV3YFLCB.js} +2 -2
- package/dist/{chunk-TZNQUNKL.js → chunk-FC7TIRFS.js} +15 -1
- package/dist/chunk-FC7TIRFS.js.map +1 -0
- package/dist/{chunk-3I7ASZN3.js → chunk-G57LQRP6.js} +2 -2
- package/dist/{chunk-UIN2BWDD.js → chunk-GN55KU2P.js} +2 -2
- package/dist/{chunk-PE255F4T.js → chunk-GUXS322H.js} +2 -2
- package/dist/{chunk-V3MXUL3D.js → chunk-H5FW4S5Q.js} +319 -643
- package/dist/chunk-H5FW4S5Q.js.map +1 -0
- package/dist/chunk-I32NKXE2.js +879 -0
- package/dist/chunk-I32NKXE2.js.map +1 -0
- package/dist/{chunk-YB42WZCY.js → chunk-IQSC3V2E.js} +2 -2
- package/dist/{chunk-MN4KB2A4.js → chunk-MBDJJTAT.js} +3 -3
- package/dist/{chunk-SQI57UCJ.js → chunk-MRTUN665.js} +2 -2
- package/dist/{chunk-SBDCZ2AX.js → chunk-NXKJHSDN.js} +1 -1
- package/dist/chunk-NXKJHSDN.js.map +1 -0
- package/dist/{chunk-SPUJNJJC.js → chunk-NZWEEALH.js} +2 -2
- package/dist/{chunk-2XDWWPTN.js → chunk-OJD4WS2E.js} +2 -2
- package/dist/{chunk-ZWXJBFZU.js → chunk-OLWTCWQ2.js} +8 -8
- package/dist/{chunk-XRYZRW54.js → chunk-P4DHENRE.js} +2 -2
- package/dist/{chunk-J275IYMG.js → chunk-PAYGC3BD.js} +29 -2
- package/dist/chunk-PAYGC3BD.js.map +1 -0
- package/dist/{chunk-IID2CMUU.js → chunk-PDVQ5JU3.js} +2 -2
- package/dist/{chunk-7BY7V4YX.js → chunk-Q4WONDMJ.js} +4 -3
- package/dist/{chunk-7BY7V4YX.js.map → chunk-Q4WONDMJ.js.map} +1 -1
- package/dist/{chunk-5NM4OH4P.js → chunk-QFMO32TO.js} +3 -3
- package/dist/{chunk-SIHSCCUQ.js → chunk-QXIQPCCN.js} +1 -1
- package/dist/{chunk-2YI72KM3.js → chunk-R47WINCY.js} +2 -2
- package/dist/{chunk-ZQHI2BZB.js → chunk-RK4WXUI2.js} +2 -2
- package/dist/{chunk-QOS5LBZN.js → chunk-S7Q5CM7E.js} +2 -2
- package/dist/{chunk-GDFVPUJ5.js → chunk-TDKSCV62.js} +2 -2
- package/dist/{chunk-OCZIYAE5.js → chunk-TYUS5TLG.js} +3 -3
- package/dist/{chunk-GNCCUR6K.js → chunk-URHCUXKI.js} +2 -2
- package/dist/{chunk-TF77C7SV.js → chunk-VA5KMSAE.js} +7 -5
- package/dist/chunk-VA5KMSAE.js.map +1 -0
- package/dist/{chunk-SB7D4BT7.js → chunk-WN5FSGLE.js} +1545 -105
- package/dist/chunk-WN5FSGLE.js.map +1 -0
- package/dist/{chunk-YLDXWCZP.js → chunk-YF6UHWOV.js} +14 -9
- package/dist/chunk-YF6UHWOV.js.map +1 -0
- package/dist/{chunk-CT56C22C.js → chunk-Z4RPXHJH.js} +4 -4
- package/dist/{cli-cShQ13XG.d.ts → cli-ChKeYMZv.d.ts} +5 -5
- package/dist/cli.d.ts +25 -25
- package/dist/cli.js +44 -43
- package/dist/coding/pre-action-gate.d.ts +2 -60
- package/dist/compounding/engine.d.ts +4 -2
- package/dist/compounding/engine.js +3 -3
- package/dist/compounding/preference-consolidator.d.ts +3 -1
- package/dist/compression-optimizer.d.ts +3 -1
- package/dist/config.d.ts +3 -1
- package/dist/config.js +6 -1
- package/dist/connectors/codex-materialize-runner.d.ts +3 -1
- package/dist/connectors/codex-materialize-runner.js +3 -3
- package/dist/connectors/codex-materialize.d.ts +3 -1
- package/dist/connectors/index.d.ts +3 -1
- package/dist/connectors/index.js +3 -3
- package/dist/consolidation-provenance-check.d.ts +4 -2
- package/dist/consolidation-undo.d.ts +4 -2
- package/dist/contradiction/index.d.ts +10 -270
- package/dist/contradiction/index.js +11 -6
- package/dist/{contradiction-review-QKJH5DKD.js → contradiction-review-WRVLRWHS.js} +6 -2
- package/dist/{contradiction-scan-VOTQRRSX.js → contradiction-scan-AKUWPX5N.js} +5 -3
- package/dist/converge-config.d.ts +3 -1
- package/dist/convergence-refresh.d.ts +4 -2
- package/dist/convergence-refresh.js +5 -5
- package/dist/conversation-index/backend.d.ts +3 -1
- package/dist/conversation-index/chunker.d.ts +3 -1
- package/dist/conversation-index/faiss-adapter.d.ts +3 -1
- package/dist/conversation-index/indexer.d.ts +3 -1
- package/dist/conversation-index/search.d.ts +3 -1
- package/dist/corpus-watermark.d.ts +3 -1
- package/dist/corpus-watermark.js +5 -5
- package/dist/cross-lingual-recall.d.ts +3 -1
- package/dist/day-summary.d.ts +3 -1
- package/dist/delinearize.d.ts +3 -1
- package/dist/dependency-propagation-config.d.ts +3 -1
- package/dist/{dependency-propagation-delivery-CsGg-VwS.d.ts → dependency-propagation-delivery-B8ZMBBCY.d.ts} +1 -1
- package/dist/direct-answer-wiring.d.ts +3 -1
- package/dist/direct-answer.d.ts +3 -1
- package/dist/embedding-fallback.d.ts +3 -1
- package/dist/enrichment/index.d.ts +3 -1
- package/dist/entity-origin-fields.d.ts +3 -1
- package/dist/entity-retrieval.d.ts +4 -2
- package/dist/entity-retrieval.js +3 -3
- package/dist/entity-schema.d.ts +3 -1
- package/dist/episodic-context.d.ts +3 -1
- package/dist/explicit-capture.d.ts +12 -12
- package/dist/external-wiki-access.d.ts +40 -40
- package/dist/external-wiki-access.js +15 -15
- package/dist/external-wiki-collection-registration.d.ts +3 -1
- package/dist/external-wiki-collection.d.ts +3 -1
- package/dist/external-wiki-mcp-tools.d.ts +40 -40
- package/dist/extraction-error-classification.d.ts +3 -1
- package/dist/extraction-faithfulness.d.ts +3 -1
- package/dist/extraction-judge-telemetry.d.ts +3 -1
- package/dist/extraction-judge-training.d.ts +3 -1
- package/dist/extraction-judge.d.ts +3 -1
- package/dist/extraction-liveness.d.ts +3 -1
- package/dist/extraction-normalization.d.ts +3 -1
- package/dist/extraction-prompt.d.ts +3 -1
- package/dist/extraction-source-grounding-rules.d.ts +3 -1
- package/dist/extraction-source-grounding.d.ts +3 -1
- package/dist/extraction.d.ts +3 -1
- package/dist/extraction.js +3 -3
- package/dist/fallback-llm.d.ts +3 -1
- package/dist/graph-dashboard-diff.d.ts +3 -1
- package/dist/graph-dashboard-key.d.ts +3 -1
- package/dist/graph-dashboard-parser.d.ts +3 -1
- package/dist/graph-edge-reinforcement.d.ts +3 -1
- package/dist/graph-path-reconstruction.d.ts +3 -1
- package/dist/graph-path-scoring.d.ts +3 -1
- package/dist/graph-snapshot.d.ts +3 -1
- package/dist/graph.d.ts +3 -1
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/importance.d.ts +3 -1
- package/dist/importers/index.d.ts +3 -1
- package/dist/in-flight-reads.d.ts +3 -1
- package/dist/index-CexDrJzC.d.ts +284 -0
- package/dist/index.d.ts +251 -29
- package/dist/index.js +129 -75
- package/dist/intent.d.ts +3 -1
- package/dist/lcm/engine.d.ts +3 -1
- package/dist/lcm/index.d.ts +3 -1
- package/dist/lcm/tools.d.ts +3 -1
- package/dist/lifecycle.d.ts +3 -1
- package/dist/live-connectors-runner.d.ts +3 -1
- package/dist/local-llm.d.ts +3 -1
- package/dist/local-model-endpoint.d.ts +3 -1
- package/dist/maintenance/memory-governance.d.ts +3 -1
- package/dist/maintenance/memory-governance.js +3 -3
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +4 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
- package/dist/maintenance/rebuild-memory-projection.d.ts +4 -2
- package/dist/maintenance/rebuild-memory-projection.js +4 -4
- package/dist/{maintenance-jhMpeGne.d.ts → maintenance-nkdtSrVr.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +37 -37
- package/dist/memory-action-policy.d.ts +3 -1
- package/dist/memory-cache.d.ts +3 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +3 -1
- package/dist/memory-projection-store.d.ts +3 -1
- package/dist/memory-provenance.d.ts +3 -1
- package/dist/memory-snapshot.d.ts +3 -1
- package/dist/memory-subject-cli.d.ts +40 -40
- package/dist/memory-subject.d.ts +42 -42
- package/dist/memory-worth-outcomes.d.ts +4 -2
- package/dist/models-json.d.ts +3 -1
- package/dist/namespaces/migrate.d.ts +5 -3
- package/dist/namespaces/migrate.js +4 -4
- package/dist/namespaces/principal.d.ts +3 -1
- package/dist/namespaces/search.d.ts +3 -1
- package/dist/namespaces/storage.d.ts +5 -3
- package/dist/namespaces/storage.js +3 -3
- package/dist/native-knowledge.d.ts +3 -1
- package/dist/offline-sync-impression-drain.d.ts +3 -1
- package/dist/operator-doctor-corpus.d.ts +3 -1
- package/dist/operator-doctor-corpus.js +6 -6
- package/dist/operator-doctor-replica.d.ts +3 -1
- package/dist/operator-toolkit.d.ts +5 -3
- package/dist/operator-toolkit.js +15 -12
- package/dist/orchestration/compression-guideline-coordinator.d.ts +4 -2
- package/dist/orchestration/maintenance.d.ts +6 -4
- package/dist/orchestration/maintenance.js +9 -9
- package/dist/{orchestrator-DyGUC7re.d.ts → orchestrator-Bvq1-RQs.d.ts} +23 -9
- package/dist/orchestrator.d.ts +12 -12
- package/dist/orchestrator.js +52 -52
- package/dist/patterns-cli.d.ts +3 -1
- package/dist/{pipeline-C25Oxtp1.d.ts → pipeline-C8vfIiTX.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +3 -1
- package/dist/proactive-contention.d.ts +3 -1
- package/dist/provenance.d.ts +3 -1
- package/dist/{public-http-CMe7NQzj.d.ts → public-http-Cy0aYbys.d.ts} +1 -1
- package/dist/{qmd-DkDVCbgF.d.ts → qmd-B9p1SZTZ.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +4 -2
- package/dist/qmd-recall-cache.d.ts +3 -1
- package/dist/qmd.d.ts +4 -2
- package/dist/recall-concurrency-config.d.ts +3 -1
- package/dist/recall-disclosure-escalation.d.ts +3 -1
- package/dist/recall-explain-renderer.d.ts +3 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +3 -1
- package/dist/recall-planner-llm.d.ts +3 -1
- package/dist/recall-state.d.ts +3 -1
- package/dist/recall-tag-filter.d.ts +3 -1
- package/dist/recall-timings.d.ts +3 -1
- package/dist/recall-xray-cli.d.ts +3 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +3 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +3 -1
- package/dist/recall-xray.js +2 -2
- package/dist/reconcile/cursor.d.ts +3 -1
- package/dist/reconcile/manifest.d.ts +3 -1
- package/dist/reconcile/plan.d.ts +3 -1
- package/dist/replay/normalizers/chatgpt.d.ts +3 -1
- package/dist/replay/normalizers/claude.d.ts +3 -1
- package/dist/replay/normalizers/openclaw.d.ts +3 -1
- package/dist/replay/normalizers/shared.d.ts +3 -1
- package/dist/replay/runner.d.ts +3 -1
- package/dist/replay/types.d.ts +3 -1
- package/dist/replica-divergence.d.ts +3 -1
- package/dist/replica-peers-config.d.ts +3 -1
- package/dist/{resolution-MFY72STR.js → resolution-4552BNRV.js} +13 -3
- package/dist/resolve-auth-token.d.ts +3 -1
- package/dist/resume-bundles.js +4 -2
- package/dist/retrieval-agents.d.ts +4 -2
- package/dist/retrieval-tiers.d.ts +3 -1
- package/dist/routing/engine.d.ts +3 -1
- package/dist/routing/store.d.ts +3 -1
- package/dist/salvage-envelope.d.ts +3 -1
- package/dist/schemas.d.ts +44 -44
- package/dist/{scope-profiles-B9xMoFO-.d.ts → scope-profiles-DLrRxFWR.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +3 -1
- package/dist/search/factory.d.ts +3 -1
- package/dist/search/index.d.ts +3 -1
- package/dist/search/lancedb-backend.d.ts +3 -1
- package/dist/search/meilisearch-backend.d.ts +3 -1
- package/dist/search/noop-backend.d.ts +3 -1
- package/dist/search/orama-backend.d.ts +3 -1
- package/dist/search/port.d.ts +3 -1
- package/dist/search/remote-backend.d.ts +3 -1
- package/dist/{semantic-TddhF0y7.d.ts → semantic-BalR6EXU.d.ts} +1 -1
- package/dist/{semantic-consolidation-C4uykW84.d.ts → semantic-consolidation-DlN6xe20.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +4 -2
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.d.ts +3 -1
- package/dist/semantic-rule-verifier.js +3 -3
- package/dist/{service-DCZDZNcV.d.ts → service-GkYyVfm9.d.ts} +2 -2
- package/dist/session-observer-bands.d.ts +3 -1
- package/dist/session-observer-state.d.ts +3 -1
- package/dist/shared-context/manager.d.ts +3 -1
- package/dist/signal.d.ts +3 -1
- package/dist/source-agent-qualifier.d.ts +3 -1
- package/dist/source-agent-qualifier.js +3 -3
- package/dist/{storage-CcKmEjL8.d.ts → storage-BIDzuKIn.d.ts} +1 -1
- package/dist/storage.d.ts +4 -2
- package/dist/storage.js +2 -2
- package/dist/subject-config.d.ts +3 -1
- package/dist/summarizer.d.ts +3 -1
- package/dist/summary-snapshot.d.ts +3 -1
- package/dist/support-passport/index.d.ts +43 -43
- package/dist/support-passport/index.js +17 -17
- package/dist/temporal-supersession.d.ts +4 -2
- package/dist/temporal-timeline-recall.d.ts +3 -1
- package/dist/temporal-validity.d.ts +3 -1
- package/dist/threading.d.ts +3 -1
- package/dist/tier-migration.d.ts +4 -2
- package/dist/tier-routing.d.ts +3 -1
- package/dist/topics.d.ts +3 -1
- package/dist/transcript.d.ts +3 -1
- package/dist/transfer/types.d.ts +20 -20
- package/dist/trust-score-stage.d.ts +3 -1
- package/dist/trust-score.d.ts +3 -1
- package/dist/{types-Pi0lfaEt.d.ts → types-BxAcOl5Q.d.ts} +323 -4
- package/dist/types.d.ts +3 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +3 -1
- package/dist/verified-recall.js +3 -3
- package/dist/who-knows-cli.d.ts +40 -40
- package/dist/who-knows-cli.js +4 -4
- package/dist/who-knows.d.ts +42 -42
- package/dist/who-knows.js +3 -3
- package/dist/write-envelope.d.ts +3 -1
- package/package.json +2 -2
- package/src/access-boundary.ts +4 -0
- package/src/access-http.ts +6 -5
- package/src/access-mcp-admin-tools.ts +24 -0
- package/src/access-mcp-output-schemas.ts +14 -0
- package/src/access-mcp.ts +2 -2
- package/src/access-operations-batch.ts +5 -0
- package/src/access-service.ts +27 -0
- package/src/access-surface-catalog.test.ts +24 -0
- package/src/access-surface-catalog.ts +4 -0
- package/src/coding/action-gate.test.ts +341 -0
- package/src/coding/action-gate.ts +556 -0
- package/src/config.ts +5 -0
- package/src/contradiction/contradiction-review.ts +50 -4
- package/src/contradiction/contradiction-scan.ts +14 -3
- package/src/contradiction/resolution.ts +50 -2
- package/src/index.ts +4 -3
- package/src/orchestration/recall-rerank-coordinator.ts +123 -4
- package/src/orchestration/recall-result-formatter.ts +6 -2
- package/src/orchestration/recall-search-pipeline.ts +14 -1
- package/src/preferences/drift-config.ts +118 -0
- package/src/preferences/drift-recall.ts +133 -0
- package/src/preferences/drift-types.ts +87 -0
- package/src/preferences/index.ts +12 -0
- package/src/preferences/preference-drift.test.ts +690 -0
- package/src/preferences/preference-drift.ts +724 -0
- package/src/review/review-deck-access.test.ts +325 -0
- package/src/review/review-deck-http-base.ts +133 -0
- package/src/review/review-deck-mutation.test.ts +417 -0
- package/src/review/review-deck-mutation.ts +677 -0
- package/src/review/review-deck-snapshot.ts +196 -0
- package/src/review/review-deck-surface.ts +117 -0
- package/src/review/review-deck.test.ts +347 -0
- package/src/review/review-deck.ts +311 -0
- package/src/storage.ts +4 -6
- package/src/types.ts +7 -3
- package/dist/chunk-35NN3ZFA.js.map +0 -1
- package/dist/chunk-4KYOLI6M.js.map +0 -1
- package/dist/chunk-BWLRUMOG.js.map +0 -1
- package/dist/chunk-J275IYMG.js.map +0 -1
- package/dist/chunk-SB7D4BT7.js.map +0 -1
- package/dist/chunk-SBDCZ2AX.js.map +0 -1
- package/dist/chunk-TF77C7SV.js.map +0 -1
- package/dist/chunk-TZNQUNKL.js.map +0 -1
- package/dist/chunk-V3MXUL3D.js.map +0 -1
- package/dist/chunk-XCTXS7VY.js +0 -402
- package/dist/chunk-XCTXS7VY.js.map +0 -1
- package/dist/chunk-YLDXWCZP.js.map +0 -1
- /package/dist/{chunk-R7JAM2XF.js.map → chunk-2VXWFYJE.js.map} +0 -0
- /package/dist/{chunk-UXO5IMBK.js.map → chunk-4XDGYCZI.js.map} +0 -0
- /package/dist/{chunk-OTHZWLUD.js.map → chunk-57HVIG5U.js.map} +0 -0
- /package/dist/{chunk-EILZG5VC.js.map → chunk-6TAX66IA.js.map} +0 -0
- /package/dist/{chunk-NKKD4ZAU.js.map → chunk-6VALIZKG.js.map} +0 -0
- /package/dist/{chunk-2E36UXVW.js.map → chunk-7KFIMGMP.js.map} +0 -0
- /package/dist/{chunk-LGO6A7GJ.js.map → chunk-7QOO4LGC.js.map} +0 -0
- /package/dist/{chunk-DZUJ46DO.js.map → chunk-AUO2LJ3K.js.map} +0 -0
- /package/dist/{chunk-ZO6AXLEH.js.map → chunk-AYDDB3XI.js.map} +0 -0
- /package/dist/{chunk-NTWN6HB2.js.map → chunk-AYYGRVRP.js.map} +0 -0
- /package/dist/{chunk-7YQ4IYS2.js.map → chunk-AZAA5DNP.js.map} +0 -0
- /package/dist/{chunk-Z7PBQPJ4.js.map → chunk-BQUEAVNW.js.map} +0 -0
- /package/dist/{chunk-5YQ63T4B.js.map → chunk-D27J626P.js.map} +0 -0
- /package/dist/{chunk-LZH5FR2W.js.map → chunk-DHTQP334.js.map} +0 -0
- /package/dist/{chunk-Y7DK7HHJ.js.map → chunk-E4MVQQVX.js.map} +0 -0
- /package/dist/{chunk-JYYBA7TF.js.map → chunk-EIVIB73I.js.map} +0 -0
- /package/dist/{chunk-S2DPMJXH.js.map → chunk-EV3YFLCB.js.map} +0 -0
- /package/dist/{chunk-3I7ASZN3.js.map → chunk-G57LQRP6.js.map} +0 -0
- /package/dist/{chunk-UIN2BWDD.js.map → chunk-GN55KU2P.js.map} +0 -0
- /package/dist/{chunk-PE255F4T.js.map → chunk-GUXS322H.js.map} +0 -0
- /package/dist/{chunk-YB42WZCY.js.map → chunk-IQSC3V2E.js.map} +0 -0
- /package/dist/{chunk-MN4KB2A4.js.map → chunk-MBDJJTAT.js.map} +0 -0
- /package/dist/{chunk-SQI57UCJ.js.map → chunk-MRTUN665.js.map} +0 -0
- /package/dist/{chunk-SPUJNJJC.js.map → chunk-NZWEEALH.js.map} +0 -0
- /package/dist/{chunk-2XDWWPTN.js.map → chunk-OJD4WS2E.js.map} +0 -0
- /package/dist/{chunk-ZWXJBFZU.js.map → chunk-OLWTCWQ2.js.map} +0 -0
- /package/dist/{chunk-XRYZRW54.js.map → chunk-P4DHENRE.js.map} +0 -0
- /package/dist/{chunk-IID2CMUU.js.map → chunk-PDVQ5JU3.js.map} +0 -0
- /package/dist/{chunk-5NM4OH4P.js.map → chunk-QFMO32TO.js.map} +0 -0
- /package/dist/{chunk-SIHSCCUQ.js.map → chunk-QXIQPCCN.js.map} +0 -0
- /package/dist/{chunk-2YI72KM3.js.map → chunk-R47WINCY.js.map} +0 -0
- /package/dist/{chunk-ZQHI2BZB.js.map → chunk-RK4WXUI2.js.map} +0 -0
- /package/dist/{chunk-QOS5LBZN.js.map → chunk-S7Q5CM7E.js.map} +0 -0
- /package/dist/{chunk-GDFVPUJ5.js.map → chunk-TDKSCV62.js.map} +0 -0
- /package/dist/{chunk-OCZIYAE5.js.map → chunk-TYUS5TLG.js.map} +0 -0
- /package/dist/{chunk-GNCCUR6K.js.map → chunk-URHCUXKI.js.map} +0 -0
- /package/dist/{chunk-CT56C22C.js.map → chunk-Z4RPXHJH.js.map} +0 -0
- /package/dist/{contradiction-review-QKJH5DKD.js.map → contradiction-review-WRVLRWHS.js.map} +0 -0
- /package/dist/{contradiction-scan-VOTQRRSX.js.map → contradiction-scan-AKUWPX5N.js.map} +0 -0
- /package/dist/{resolution-MFY72STR.js.map → resolution-4552BNRV.js.map} +0 -0
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action-site failure gate (issue #2382, slice 1 — core contract).
|
|
3
|
+
*
|
|
4
|
+
* The H6 study (#1963) measured that a failure memory delivered in the prompt
|
|
5
|
+
* preamble barely changes behaviour, while the same memory delivered at the
|
|
6
|
+
* moment the agent proposes the matched action removes the repeated failure.
|
|
7
|
+
* This module productionises that delivery point: `ActionGateService` wraps the
|
|
8
|
+
* experimental `PreActionFailureGate` primitive, adds failure-class memory
|
|
9
|
+
* candidates, a per-turn budget, cross-channel suppression, and telemetry.
|
|
10
|
+
*
|
|
11
|
+
* Scope, per the study's honest limit: the gate removes a known failure mode.
|
|
12
|
+
* It does not improve task completion. It is advisory only — it never blocks an
|
|
13
|
+
* action, never outruns its deadline, and fails open on every error path.
|
|
14
|
+
*/
|
|
15
|
+
import type { ActionIntent, ActionStrategyId } from "../causal-trajectory.js";
|
|
16
|
+
import { coerceBool, coerceNumber } from "../connectors/coerce.js";
|
|
17
|
+
import type { CodingContext, MemoryFile } from "../types.js";
|
|
18
|
+
import {
|
|
19
|
+
PRE_ACTION_GATE_DEFAULT_TIMEOUT_MS,
|
|
20
|
+
type PreActionFailureGate,
|
|
21
|
+
normalizeActionIntent,
|
|
22
|
+
sanitizePayloadString,
|
|
23
|
+
} from "./pre-action-gate.js";
|
|
24
|
+
|
|
25
|
+
export const ACTION_GATE_DEFAULT_MAX_ADVISORIES_PER_TURN = 3;
|
|
26
|
+
/** Bound on a single advisory payload, above the primitive's citation bound. */
|
|
27
|
+
const MAX_ADVISORY_CHARS = 400;
|
|
28
|
+
/** Bounded lexical matching: terms considered from one proposed action. */
|
|
29
|
+
const MAX_ACTION_TERMS = 24;
|
|
30
|
+
const MIN_TERM_CHARS = 3;
|
|
31
|
+
/** Fraction of action terms a failure memory must mention to be a candidate. */
|
|
32
|
+
const MIN_TERM_OVERLAP_RATIO = 0.6;
|
|
33
|
+
/** Sessions tracked for suppression before the oldest is evicted. */
|
|
34
|
+
const MAX_TRACKED_SESSIONS = 200;
|
|
35
|
+
/** Memory ids remembered per session for cross-channel suppression. */
|
|
36
|
+
const MAX_TRACKED_IDS_PER_SESSION = 200;
|
|
37
|
+
|
|
38
|
+
export interface ActionGateConfig {
|
|
39
|
+
/**
|
|
40
|
+
* Master gate. Default `false`: when disabled no lookup, no matching, and no
|
|
41
|
+
* suppression bookkeeping runs on any path.
|
|
42
|
+
*/
|
|
43
|
+
enabled: boolean;
|
|
44
|
+
/** Hard latency cap for a whole gate evaluation. Overrun fails open. */
|
|
45
|
+
timeoutMs: number;
|
|
46
|
+
/** Advisories injected per turn. `0` disables injection and all lookups. */
|
|
47
|
+
maxAdvisoriesPerTurn: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const ACTION_GATE_DEFAULTS: ActionGateConfig = {
|
|
51
|
+
enabled: false,
|
|
52
|
+
timeoutMs: PRE_ACTION_GATE_DEFAULT_TIMEOUT_MS,
|
|
53
|
+
maxAdvisoriesPerTurn: ACTION_GATE_DEFAULT_MAX_ADVISORIES_PER_TURN,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export function parseActionGateConfig(raw: unknown): ActionGateConfig {
|
|
57
|
+
if (raw !== undefined && (raw === null || typeof raw !== "object" || Array.isArray(raw))) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`actionGate must be an object (got ${JSON.stringify(raw)}). Use actionGate: { enabled: true } to opt in.`
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
const block = (raw ?? {}) as Record<string, unknown>;
|
|
63
|
+
const rawEnabled = block.enabled;
|
|
64
|
+
let enabled = ACTION_GATE_DEFAULTS.enabled;
|
|
65
|
+
if (rawEnabled !== undefined) {
|
|
66
|
+
const coerced = coerceBool(rawEnabled);
|
|
67
|
+
if (coerced === undefined) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`actionGate.enabled must be a boolean or one of "true"/"false"/"1"/"0"/"yes"/"no"/"on"/"off" (got ${JSON.stringify(rawEnabled)}).`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
enabled = coerced;
|
|
73
|
+
}
|
|
74
|
+
const rawTimeout = coerceNumber(block.timeoutMs);
|
|
75
|
+
const timeoutMs =
|
|
76
|
+
rawTimeout !== undefined && Number.isFinite(rawTimeout)
|
|
77
|
+
? Math.min(5000, Math.max(1, Math.floor(rawTimeout)))
|
|
78
|
+
: ACTION_GATE_DEFAULTS.timeoutMs;
|
|
79
|
+
const rawMax = coerceNumber(block.maxAdvisoriesPerTurn);
|
|
80
|
+
// Zero-limit semantics are a compatibility contract: `0` stays `0`.
|
|
81
|
+
const maxAdvisoriesPerTurn =
|
|
82
|
+
rawMax !== undefined && Number.isFinite(rawMax)
|
|
83
|
+
? Math.min(20, Math.max(0, Math.floor(rawMax)))
|
|
84
|
+
: ACTION_GATE_DEFAULTS.maxAdvisoriesPerTurn;
|
|
85
|
+
return { enabled, timeoutMs, maxAdvisoriesPerTurn };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export type ActionGateStatus = "DISABLED" | "NO_MATCH" | "MATCH_WARN" | "ERROR_FAIL_OPEN";
|
|
89
|
+
|
|
90
|
+
export interface ActionGateRequest {
|
|
91
|
+
sessionKey: string;
|
|
92
|
+
/** Turn identity: the per-turn budget and dedupe reset when this changes. */
|
|
93
|
+
turnId: string;
|
|
94
|
+
strategyId: ActionStrategyId;
|
|
95
|
+
intent: ActionIntent;
|
|
96
|
+
codingContext: CodingContext;
|
|
97
|
+
/** Memory directory ALREADY resolved for the caller's readable namespace. */
|
|
98
|
+
memoryDir: string;
|
|
99
|
+
/** Resolved readable namespace, passed verbatim to candidate sources. */
|
|
100
|
+
namespace?: string;
|
|
101
|
+
causalTrajectoryStoreDir?: string;
|
|
102
|
+
signal?: AbortSignal;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface ActionGateAdvisory {
|
|
106
|
+
/** Trajectory id or memory id — the unit of dedupe and suppression. */
|
|
107
|
+
memoryId: string;
|
|
108
|
+
sourceId: string;
|
|
109
|
+
text: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface ActionGateDecision {
|
|
113
|
+
status: ActionGateStatus;
|
|
114
|
+
advisories: ActionGateAdvisory[];
|
|
115
|
+
/** Candidates withheld: already delivered this turn/session, or over budget. */
|
|
116
|
+
suppressedIds: string[];
|
|
117
|
+
/** Source failures, kept distinct from "no candidates" (rule 22). */
|
|
118
|
+
degradations: string[];
|
|
119
|
+
fingerprint?: string;
|
|
120
|
+
reason?: string;
|
|
121
|
+
latencyMs: number;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface ActionGateCandidate {
|
|
125
|
+
memoryId: string;
|
|
126
|
+
advisoryText: string;
|
|
127
|
+
/** Deterministic ranking key; higher wins, ties break on `memoryId`. */
|
|
128
|
+
score?: number;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface ActionGateCandidateQuery {
|
|
132
|
+
sessionKey: string;
|
|
133
|
+
fingerprint: string;
|
|
134
|
+
/** Normalized, deduplicated lexical terms describing the proposed action. */
|
|
135
|
+
actionTerms: string[];
|
|
136
|
+
strategyId: ActionStrategyId;
|
|
137
|
+
intent: ActionIntent;
|
|
138
|
+
codingContext: CodingContext;
|
|
139
|
+
memoryDir: string;
|
|
140
|
+
namespace?: string;
|
|
141
|
+
causalTrajectoryStoreDir?: string;
|
|
142
|
+
signal?: AbortSignal;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export type ActionGateSourceResult = { ok: true; candidates: ActionGateCandidate[] } | { ok: false; reason: string };
|
|
146
|
+
|
|
147
|
+
export interface ActionGateCandidateSource {
|
|
148
|
+
readonly id: string;
|
|
149
|
+
find(query: ActionGateCandidateQuery): Promise<ActionGateSourceResult>;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface ActionGateAuditRecord {
|
|
153
|
+
ts: string;
|
|
154
|
+
sessionKey: string;
|
|
155
|
+
turnId: string;
|
|
156
|
+
status: ActionGateStatus;
|
|
157
|
+
latencyMs: number;
|
|
158
|
+
fingerprint?: string;
|
|
159
|
+
deliveredIds: string[];
|
|
160
|
+
suppressedIds: string[];
|
|
161
|
+
degradations: string[];
|
|
162
|
+
reason?: string;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export type ActionGateAuditSink = (record: ActionGateAuditRecord) => void | Promise<void>;
|
|
166
|
+
|
|
167
|
+
export interface ActionGateServiceDependencies {
|
|
168
|
+
sources?: ActionGateCandidateSource[];
|
|
169
|
+
audit?: ActionGateAuditSink;
|
|
170
|
+
clock?: () => number;
|
|
171
|
+
now?: () => Date;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Deterministic, local term extraction from a proposed action. No LLM and no
|
|
176
|
+
* I/O: this runs in the hot path ahead of the tool call.
|
|
177
|
+
*/
|
|
178
|
+
export function actionTermsFor(intent: ActionIntent): string[] {
|
|
179
|
+
const raw =
|
|
180
|
+
intent.kind === "command"
|
|
181
|
+
? [intent.command, ...(intent.args ?? [])]
|
|
182
|
+
: [intent.filePath, intent.editKind, intent.symbol ?? "", intent.range ?? ""];
|
|
183
|
+
const terms: string[] = [];
|
|
184
|
+
const seen = new Set<string>();
|
|
185
|
+
for (const piece of raw) {
|
|
186
|
+
for (const token of sanitizePayloadString(piece ?? "")
|
|
187
|
+
.toLowerCase()
|
|
188
|
+
.split(/[^a-z0-9._-]+/)) {
|
|
189
|
+
const term = token.replace(/^[._-]+|[._-]+$/g, "");
|
|
190
|
+
if (term.length < MIN_TERM_CHARS || seen.has(term)) continue;
|
|
191
|
+
seen.add(term);
|
|
192
|
+
terms.push(term);
|
|
193
|
+
if (terms.length >= MAX_ACTION_TERMS) return terms;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return terms;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Failure-class markers on stored memories, read from frontmatter only so the
|
|
201
|
+
* decision stays deterministic: explicit corrections, procedures flagged for
|
|
202
|
+
* repair by library maintenance, and memories whose recorded outcomes are
|
|
203
|
+
* failure-dominant.
|
|
204
|
+
*/
|
|
205
|
+
export function isFailureClassMemory(memory: MemoryFile): boolean {
|
|
206
|
+
const fm = memory.frontmatter;
|
|
207
|
+
if (fm.status !== undefined && fm.status !== "active") return false;
|
|
208
|
+
if (fm.category === "correction") return true;
|
|
209
|
+
if (fm.structuredAttributes?.needsRepair === "true") return true;
|
|
210
|
+
const failures = typeof fm.mw_fail === "number" ? fm.mw_fail : 0;
|
|
211
|
+
const successes = typeof fm.mw_success === "number" ? fm.mw_success : 0;
|
|
212
|
+
return failures > 0 && failures > successes;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export interface FailureMemorySourceDependencies {
|
|
216
|
+
/**
|
|
217
|
+
* Namespace-scoped listing of candidate memories. Callers wire this to a
|
|
218
|
+
* storage read for the SAME namespace the gate request resolved, so a
|
|
219
|
+
* principal can never receive another principal's advisories.
|
|
220
|
+
*/
|
|
221
|
+
listMemories: (options: {
|
|
222
|
+
namespace?: string;
|
|
223
|
+
memoryDir: string;
|
|
224
|
+
signal?: AbortSignal;
|
|
225
|
+
}) => Promise<MemoryFile[]>;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Failure-class memory candidates, matched by bounded lexical overlap against
|
|
230
|
+
* the proposed action's terms. Deterministic and local by construction.
|
|
231
|
+
*/
|
|
232
|
+
export function createFailureMemoryCandidateSource(deps: FailureMemorySourceDependencies): ActionGateCandidateSource {
|
|
233
|
+
return {
|
|
234
|
+
id: "failure-memory",
|
|
235
|
+
async find(query) {
|
|
236
|
+
if (query.actionTerms.length === 0) return { ok: true, candidates: [] };
|
|
237
|
+
let memories: MemoryFile[];
|
|
238
|
+
try {
|
|
239
|
+
memories = await deps.listMemories({
|
|
240
|
+
namespace: query.namespace,
|
|
241
|
+
memoryDir: query.memoryDir,
|
|
242
|
+
signal: query.signal,
|
|
243
|
+
});
|
|
244
|
+
} catch (error) {
|
|
245
|
+
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
246
|
+
}
|
|
247
|
+
const required = Math.max(1, Math.ceil(query.actionTerms.length * MIN_TERM_OVERLAP_RATIO));
|
|
248
|
+
const candidates: ActionGateCandidate[] = [];
|
|
249
|
+
for (const memory of memories) {
|
|
250
|
+
if (!isFailureClassMemory(memory)) continue;
|
|
251
|
+
const haystack = `${memory.content} ${(memory.frontmatter.tags ?? []).join(" ")}`.toLowerCase();
|
|
252
|
+
let hits = 0;
|
|
253
|
+
for (const term of query.actionTerms) if (haystack.includes(term)) hits += 1;
|
|
254
|
+
if (hits < required) continue;
|
|
255
|
+
candidates.push({
|
|
256
|
+
memoryId: memory.frontmatter.id,
|
|
257
|
+
score: hits,
|
|
258
|
+
advisoryText: `[ActionGate] A stored failure memory matches this action: "${memory.content}".`,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
candidates.sort((left, right) => {
|
|
262
|
+
const byScore = (right.score ?? 0) - (left.score ?? 0);
|
|
263
|
+
return byScore !== 0 ? byScore : left.memoryId.localeCompare(right.memoryId);
|
|
264
|
+
});
|
|
265
|
+
return { ok: true, candidates };
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Candidate source over recorded causal-trajectory failures, delegating the
|
|
272
|
+
* fingerprint match to the existing `PreActionFailureGate` primitive.
|
|
273
|
+
*/
|
|
274
|
+
export function createTrajectoryCandidateSource(gate: PreActionFailureGate): ActionGateCandidateSource {
|
|
275
|
+
return {
|
|
276
|
+
id: "causal-trajectory",
|
|
277
|
+
async find(query) {
|
|
278
|
+
const result = await gate.evaluate({
|
|
279
|
+
sessionKey: query.sessionKey,
|
|
280
|
+
strategyId: query.strategyId,
|
|
281
|
+
intent: query.intent,
|
|
282
|
+
codingContext: query.codingContext,
|
|
283
|
+
memoryDir: query.memoryDir,
|
|
284
|
+
causalTrajectoryStoreDir: query.causalTrajectoryStoreDir,
|
|
285
|
+
signal: query.signal,
|
|
286
|
+
});
|
|
287
|
+
if (result.status === "ERROR_FAIL_OPEN") {
|
|
288
|
+
return { ok: false, reason: result.reason ?? "pre-action gate failed open" };
|
|
289
|
+
}
|
|
290
|
+
if (result.status !== "MATCH_WARN" || !result.matchedTrajectoryId || !result.advisoryText) {
|
|
291
|
+
return { ok: true, candidates: [] };
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
ok: true,
|
|
295
|
+
candidates: [
|
|
296
|
+
{
|
|
297
|
+
memoryId: result.matchedTrajectoryId,
|
|
298
|
+
// Trajectory matches are exact fingerprint hits: rank above lexical ones.
|
|
299
|
+
score: Number.MAX_SAFE_INTEGER,
|
|
300
|
+
advisoryText: result.advisoryText,
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
};
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
interface SessionSuppression {
|
|
309
|
+
turnId: string;
|
|
310
|
+
/** Ids the gate delivered during `turnId`. */
|
|
311
|
+
deliveredThisTurn: Set<string>;
|
|
312
|
+
/** Ids the gate delivered anywhere in the session; turn-start must skip them. */
|
|
313
|
+
deliveredByGate: Set<string>;
|
|
314
|
+
/** Ids turn-start injection already delivered; the gate must skip them. */
|
|
315
|
+
deliveredByTurnStart: Set<string>;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Advisory gate evaluated immediately before an agent action.
|
|
320
|
+
*
|
|
321
|
+
* Delivery is bounded three ways: a hard deadline, `maxAdvisoriesPerTurn`, and
|
|
322
|
+
* dedupe per memory per turn. Cross-channel suppression keeps one memory from
|
|
323
|
+
* arriving twice in a session — once here and once from turn-start recall.
|
|
324
|
+
*/
|
|
325
|
+
export class ActionGateService {
|
|
326
|
+
private readonly config: ActionGateConfig;
|
|
327
|
+
private readonly sources: ActionGateCandidateSource[];
|
|
328
|
+
private readonly audit?: ActionGateAuditSink;
|
|
329
|
+
private readonly clock: () => number;
|
|
330
|
+
private readonly now: () => Date;
|
|
331
|
+
private readonly sessions = new Map<string, SessionSuppression>();
|
|
332
|
+
|
|
333
|
+
constructor(config: ActionGateConfig, deps: ActionGateServiceDependencies = {}) {
|
|
334
|
+
this.config = config;
|
|
335
|
+
this.sources = deps.sources ?? [];
|
|
336
|
+
this.audit = deps.audit;
|
|
337
|
+
this.clock = deps.clock ?? Date.now;
|
|
338
|
+
this.now = deps.now ?? (() => new Date());
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Memory ids the gate already delivered in this session. Turn-start recall
|
|
343
|
+
* filters these out before its own cap, honouring the filter-then-cap order.
|
|
344
|
+
*/
|
|
345
|
+
public suppressedForTurnStart(sessionKey: string): string[] {
|
|
346
|
+
if (!this.config.enabled) return [];
|
|
347
|
+
return [...(this.sessions.get(sessionKey)?.deliveredByGate ?? [])];
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/** Record ids turn-start recall injected, so the gate will not repeat them. */
|
|
351
|
+
public noteTurnStartDelivery(sessionKey: string, memoryIds: readonly string[]): void {
|
|
352
|
+
if (!this.config.enabled || memoryIds.length === 0) return;
|
|
353
|
+
const state = this.sessionState(sessionKey, undefined);
|
|
354
|
+
for (const id of memoryIds) this.addTracked(state.deliveredByTurnStart, id);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
public resetSession(sessionKey: string): void {
|
|
358
|
+
this.sessions.delete(sessionKey);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
async evaluate(request: ActionGateRequest): Promise<ActionGateDecision> {
|
|
362
|
+
const startedAt = this.clock();
|
|
363
|
+
if (!this.config.enabled) {
|
|
364
|
+
return {
|
|
365
|
+
status: "DISABLED",
|
|
366
|
+
advisories: [],
|
|
367
|
+
suppressedIds: [],
|
|
368
|
+
degradations: [],
|
|
369
|
+
reason: "actionGate.enabled is false",
|
|
370
|
+
latencyMs: 0,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
if (this.config.maxAdvisoriesPerTurn === 0) {
|
|
374
|
+
return this.finish(request, startedAt, {
|
|
375
|
+
status: "DISABLED",
|
|
376
|
+
advisories: [],
|
|
377
|
+
suppressedIds: [],
|
|
378
|
+
degradations: [],
|
|
379
|
+
reason: "actionGate.maxAdvisoriesPerTurn is 0",
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
let fingerprint: string;
|
|
384
|
+
try {
|
|
385
|
+
fingerprint = normalizeActionIntent(request.intent, request.strategyId, request.codingContext).fingerprint;
|
|
386
|
+
} catch (error) {
|
|
387
|
+
return this.finish(request, startedAt, {
|
|
388
|
+
status: "ERROR_FAIL_OPEN",
|
|
389
|
+
advisories: [],
|
|
390
|
+
suppressedIds: [],
|
|
391
|
+
degradations: [],
|
|
392
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const deadline = startedAt + this.config.timeoutMs;
|
|
397
|
+
const collected = await this.collect(request, fingerprint, deadline);
|
|
398
|
+
const state = this.sessionState(request.sessionKey, request.turnId);
|
|
399
|
+
const advisories: ActionGateAdvisory[] = [];
|
|
400
|
+
const suppressedIds: string[] = [];
|
|
401
|
+
for (const { sourceId, candidate } of collected.candidates) {
|
|
402
|
+
if (state.deliveredThisTurn.has(candidate.memoryId) || state.deliveredByTurnStart.has(candidate.memoryId)) {
|
|
403
|
+
suppressedIds.push(candidate.memoryId);
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (advisories.length >= this.config.maxAdvisoriesPerTurn) {
|
|
407
|
+
suppressedIds.push(candidate.memoryId);
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
advisories.push({
|
|
411
|
+
memoryId: candidate.memoryId,
|
|
412
|
+
sourceId,
|
|
413
|
+
text: sanitizePayloadString(candidate.advisoryText).replace(/\s+/g, " ").slice(0, MAX_ADVISORY_CHARS),
|
|
414
|
+
});
|
|
415
|
+
this.addTracked(state.deliveredThisTurn, candidate.memoryId);
|
|
416
|
+
this.addTracked(state.deliveredByGate, candidate.memoryId);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const status: ActionGateStatus =
|
|
420
|
+
advisories.length > 0 ? "MATCH_WARN" : collected.degradations.length > 0 ? "ERROR_FAIL_OPEN" : "NO_MATCH";
|
|
421
|
+
return this.finish(request, startedAt, {
|
|
422
|
+
status,
|
|
423
|
+
advisories,
|
|
424
|
+
suppressedIds,
|
|
425
|
+
degradations: collected.degradations,
|
|
426
|
+
fingerprint,
|
|
427
|
+
reason: status === "ERROR_FAIL_OPEN" ? collected.degradations[0] : undefined,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
private async collect(
|
|
432
|
+
request: ActionGateRequest,
|
|
433
|
+
fingerprint: string,
|
|
434
|
+
deadline: number
|
|
435
|
+
): Promise<{
|
|
436
|
+
candidates: Array<{ sourceId: string; candidate: ActionGateCandidate }>;
|
|
437
|
+
degradations: string[];
|
|
438
|
+
}> {
|
|
439
|
+
if (this.sources.length === 0) return { candidates: [], degradations: [] };
|
|
440
|
+
const timeoutAbort = new AbortController();
|
|
441
|
+
const signal = request.signal
|
|
442
|
+
? AbortSignal.any([request.signal, timeoutAbort.signal])
|
|
443
|
+
: timeoutAbort.signal;
|
|
444
|
+
const query: ActionGateCandidateQuery = {
|
|
445
|
+
sessionKey: request.sessionKey,
|
|
446
|
+
fingerprint,
|
|
447
|
+
actionTerms: actionTermsFor(request.intent),
|
|
448
|
+
strategyId: request.strategyId,
|
|
449
|
+
intent: request.intent,
|
|
450
|
+
codingContext: request.codingContext,
|
|
451
|
+
memoryDir: request.memoryDir,
|
|
452
|
+
namespace: request.namespace,
|
|
453
|
+
causalTrajectoryStoreDir: request.causalTrajectoryStoreDir,
|
|
454
|
+
signal,
|
|
455
|
+
};
|
|
456
|
+
const remaining = Math.max(1, deadline - this.clock());
|
|
457
|
+
let onTimeout!: (value: ActionGateSourceResult) => void;
|
|
458
|
+
const timeoutResult = new Promise<ActionGateSourceResult>((resolve) => {
|
|
459
|
+
onTimeout = resolve;
|
|
460
|
+
});
|
|
461
|
+
const timer = setTimeout(() => {
|
|
462
|
+
timeoutAbort.abort();
|
|
463
|
+
onTimeout({ ok: false, reason: `action gate timed out after ${this.config.timeoutMs}ms` });
|
|
464
|
+
}, remaining);
|
|
465
|
+
try {
|
|
466
|
+
const settled = await Promise.all(
|
|
467
|
+
this.sources.map(async (source) => {
|
|
468
|
+
let result: ActionGateSourceResult;
|
|
469
|
+
try {
|
|
470
|
+
result = await Promise.race([source.find(query), timeoutResult]);
|
|
471
|
+
} catch (error) {
|
|
472
|
+
result = { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
473
|
+
}
|
|
474
|
+
return { source, result };
|
|
475
|
+
})
|
|
476
|
+
);
|
|
477
|
+
const candidates: Array<{ sourceId: string; candidate: ActionGateCandidate }> = [];
|
|
478
|
+
const degradations: string[] = [];
|
|
479
|
+
for (const { source, result } of settled) {
|
|
480
|
+
if (!result.ok) {
|
|
481
|
+
degradations.push(`${source.id}: ${result.reason}`);
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
for (const candidate of result.candidates) candidates.push({ sourceId: source.id, candidate });
|
|
485
|
+
}
|
|
486
|
+
candidates.sort((left, right) => {
|
|
487
|
+
const byScore = (right.candidate.score ?? 0) - (left.candidate.score ?? 0);
|
|
488
|
+
if (byScore !== 0) return byScore;
|
|
489
|
+
const bySource = left.sourceId.localeCompare(right.sourceId);
|
|
490
|
+
return bySource !== 0 ? bySource : left.candidate.memoryId.localeCompare(right.candidate.memoryId);
|
|
491
|
+
});
|
|
492
|
+
return { candidates, degradations };
|
|
493
|
+
} finally {
|
|
494
|
+
clearTimeout(timer);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
private finish(
|
|
499
|
+
request: ActionGateRequest,
|
|
500
|
+
startedAt: number,
|
|
501
|
+
decision: Omit<ActionGateDecision, "latencyMs">
|
|
502
|
+
): ActionGateDecision {
|
|
503
|
+
const latencyMs = Math.max(0, this.clock() - startedAt);
|
|
504
|
+
const result: ActionGateDecision = { ...decision, latencyMs };
|
|
505
|
+
if (this.audit) {
|
|
506
|
+
const record: ActionGateAuditRecord = {
|
|
507
|
+
ts: this.now().toISOString(),
|
|
508
|
+
sessionKey: request.sessionKey,
|
|
509
|
+
turnId: request.turnId,
|
|
510
|
+
status: result.status,
|
|
511
|
+
latencyMs,
|
|
512
|
+
fingerprint: result.fingerprint,
|
|
513
|
+
deliveredIds: result.advisories.map((advisory) => advisory.memoryId),
|
|
514
|
+
suppressedIds: result.suppressedIds,
|
|
515
|
+
degradations: result.degradations,
|
|
516
|
+
reason: result.reason,
|
|
517
|
+
};
|
|
518
|
+
// Telemetry must never break the action it observes.
|
|
519
|
+
void Promise.resolve()
|
|
520
|
+
.then(() => this.audit?.(record))
|
|
521
|
+
.catch(() => undefined);
|
|
522
|
+
}
|
|
523
|
+
return result;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
private sessionState(sessionKey: string, turnId: string | undefined): SessionSuppression {
|
|
527
|
+
let state = this.sessions.get(sessionKey);
|
|
528
|
+
if (!state) {
|
|
529
|
+
if (this.sessions.size >= MAX_TRACKED_SESSIONS) {
|
|
530
|
+
const oldest = this.sessions.keys().next().value;
|
|
531
|
+
if (oldest !== undefined) this.sessions.delete(oldest);
|
|
532
|
+
}
|
|
533
|
+
state = {
|
|
534
|
+
turnId: turnId ?? "",
|
|
535
|
+
deliveredThisTurn: new Set(),
|
|
536
|
+
deliveredByGate: new Set(),
|
|
537
|
+
deliveredByTurnStart: new Set(),
|
|
538
|
+
};
|
|
539
|
+
this.sessions.set(sessionKey, state);
|
|
540
|
+
}
|
|
541
|
+
if (turnId !== undefined && state.turnId !== turnId) {
|
|
542
|
+
state.turnId = turnId;
|
|
543
|
+
state.deliveredThisTurn.clear();
|
|
544
|
+
}
|
|
545
|
+
return state;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
private addTracked(set: Set<string>, value: string): void {
|
|
549
|
+
if (set.has(value)) return;
|
|
550
|
+
if (set.size >= MAX_TRACKED_IDS_PER_SESSION) {
|
|
551
|
+
const oldest = set.values().next().value;
|
|
552
|
+
if (oldest !== undefined) set.delete(oldest);
|
|
553
|
+
}
|
|
554
|
+
set.add(value);
|
|
555
|
+
}
|
|
556
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -43,6 +43,7 @@ import { parseExtractionLivenessConfig } from "./extraction-liveness.js";
|
|
|
43
43
|
import { parseReplicaPeersConfig } from "./replica-peers-config.js";
|
|
44
44
|
import { parseDependencyPropagationConfig } from "./dependency-propagation-config.js";
|
|
45
45
|
import { parseProceduralMaintenanceConfig } from "./procedural/maintenance-config.js";
|
|
46
|
+
import { parseDriftDetectionConfig } from "./preferences/drift-config.js";
|
|
46
47
|
import {
|
|
47
48
|
parseContradictionLocalizationConfig,
|
|
48
49
|
parseContradictionScanConfig,
|
|
@@ -68,6 +69,7 @@ import { parseLocationConfig } from "./location/config.js";
|
|
|
68
69
|
import { parseOkfConfig } from "./okf/config.js";
|
|
69
70
|
import { parseBoundedJsonlStateConfig } from "./bounded-jsonl-state.js";
|
|
70
71
|
import { parseCodingKnowledgeConfig } from "./coding/coding-knowledge-config.js";
|
|
72
|
+
import { parseActionGateConfig } from "./coding/action-gate.js";
|
|
71
73
|
import { parseChatConfig } from "./chat/chat-config.js";
|
|
72
74
|
import { parseSupportPassportConfig } from "./support-passport/config.js";
|
|
73
75
|
import { parseCorrectionIntentConfig, parseFaithfulnessGateConfig } from "./faithfulness-config.js";
|
|
@@ -1789,6 +1791,8 @@ export function parseConfig(
|
|
|
1789
1791
|
contradictionAutoResolve: cfg.contradictionAutoResolve !== false,
|
|
1790
1792
|
// Contradiction Scan cron (issue #520)
|
|
1791
1793
|
contradictionScan: parseContradictionScanConfig(cfg.contradictionScan),
|
|
1794
|
+
// Preference drift detection (issue #2371)
|
|
1795
|
+
driftDetection: parseDriftDetectionConfig(cfg.driftDetection),
|
|
1792
1796
|
dependencyPropagation: parseDependencyPropagationConfig(cfg),
|
|
1793
1797
|
// Temporal Supersession (issue #375)
|
|
1794
1798
|
temporalSupersessionEnabled: cfg.temporalSupersessionEnabled !== false, // On by default
|
|
@@ -2329,6 +2333,7 @@ export function parseConfig(
|
|
|
2329
2333
|
bridgeMode: cfg.bridgeMode === undefined ? "embedded" : String(cfg.bridgeMode),
|
|
2330
2334
|
codexCompat,
|
|
2331
2335
|
codingKnowledge: parseCodingKnowledgeConfig(cfg.codingKnowledge),
|
|
2336
|
+
actionGate: parseActionGateConfig(cfg.actionGate),
|
|
2332
2337
|
chat: parseChatConfig(cfg.chat),
|
|
2333
2338
|
supportPassport: parseSupportPassportConfig(cfg.supportPassport),
|
|
2334
2339
|
hourlySummariesEnabled: cfg.hourlySummariesEnabled !== false, // default: true
|
|
@@ -17,9 +17,31 @@ import type { ContradictionVerdict } from "./contradiction-judge.js";
|
|
|
17
17
|
|
|
18
18
|
// ── Types ──────────────────────────────────────────────────────────────────────
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Resolution verbs. The first five are contradiction-pair verbs; the last
|
|
22
|
+
* three resolve a `kind: "preference-drift"` item (issue #2371). Verb validity
|
|
23
|
+
* is per-kind — `executeResolution` rejects a cross-kind verb — but the stored
|
|
24
|
+
* union is shared so one review queue, one `review_resolve` surface, and one
|
|
25
|
+
* resolution record serve both item kinds.
|
|
26
|
+
*/
|
|
27
|
+
export type ResolutionVerb =
|
|
28
|
+
| "keep-a"
|
|
29
|
+
| "keep-b"
|
|
30
|
+
| "merge"
|
|
31
|
+
| "both-valid"
|
|
32
|
+
| "needs-more-context"
|
|
33
|
+
| "keep"
|
|
34
|
+
| "supersede"
|
|
35
|
+
| "archive";
|
|
36
|
+
|
|
37
|
+
/** Review-item kind. Absent on every pair written before issue #2371. */
|
|
38
|
+
export type ReviewItemKind = "contradiction" | "preference-drift";
|
|
39
|
+
|
|
40
|
+
/** Verbs valid for a `kind: "preference-drift"` item. */
|
|
41
|
+
export const PREFERENCE_DRIFT_VERBS: readonly ResolutionVerb[] = ["keep", "supersede", "archive"];
|
|
42
|
+
|
|
43
|
+
/** Verbs valid for a contradiction pair. */
|
|
44
|
+
export const CONTRADICTION_VERBS: readonly ResolutionVerb[] = [
|
|
23
45
|
"keep-a",
|
|
24
46
|
"keep-b",
|
|
25
47
|
"merge",
|
|
@@ -27,11 +49,23 @@ const VALID_RESOLUTION_VERBS: readonly ResolutionVerb[] = [
|
|
|
27
49
|
"needs-more-context",
|
|
28
50
|
];
|
|
29
51
|
|
|
52
|
+
const VALID_RESOLUTION_VERBS: readonly ResolutionVerb[] = [
|
|
53
|
+
...CONTRADICTION_VERBS,
|
|
54
|
+
...PREFERENCE_DRIFT_VERBS,
|
|
55
|
+
];
|
|
56
|
+
|
|
30
57
|
export interface ContradictionPair {
|
|
31
58
|
/** Deterministic pair ID: sha256(sorted(memoryIdA, memoryIdB) plus namespace when scoped). */
|
|
32
59
|
pairId: string;
|
|
33
60
|
/** Memory IDs (sorted). */
|
|
34
61
|
memoryIds: [string, string];
|
|
62
|
+
/**
|
|
63
|
+
* Item kind (issue #2371). Absent on every pair written before drift
|
|
64
|
+
* detection existed, which reads as `"contradiction"`. A
|
|
65
|
+
* `"preference-drift"` item pairs the aging preference (first id) with the
|
|
66
|
+
* recent evidence that pointed away from it (second id).
|
|
67
|
+
*/
|
|
68
|
+
kind?: ReviewItemKind;
|
|
35
69
|
/** Judge verdict. */
|
|
36
70
|
verdict: ContradictionVerdict;
|
|
37
71
|
/** Judge rationale. */
|
|
@@ -85,8 +119,20 @@ export function isDefaultReviewNamespace(
|
|
|
85
119
|
return !requested || requested === defaultNamespace || resolvedNamespace === defaultNamespace;
|
|
86
120
|
}
|
|
87
121
|
|
|
122
|
+
const TERMINAL_RESOLUTIONS: Partial<Record<ResolutionVerb, true>> = {
|
|
123
|
+
"keep-a": true,
|
|
124
|
+
"keep-b": true,
|
|
125
|
+
merge: true,
|
|
126
|
+
// Every preference-drift verb is terminal: the user has answered the "is
|
|
127
|
+
// this preference still true?" question, so the item must leave the
|
|
128
|
+
// unresolved queue and never be re-proposed by a later scan (issue #2371).
|
|
129
|
+
keep: true,
|
|
130
|
+
supersede: true,
|
|
131
|
+
archive: true,
|
|
132
|
+
};
|
|
133
|
+
|
|
88
134
|
function isTerminalResolution(resolution: ResolutionVerb | undefined): boolean {
|
|
89
|
-
return resolution
|
|
135
|
+
return resolution !== undefined && TERMINAL_RESOLUTIONS[resolution] === true;
|
|
90
136
|
}
|
|
91
137
|
|
|
92
138
|
function preservesDirectResolution(resolution: ResolutionVerb | undefined): boolean {
|
|
@@ -380,8 +380,16 @@ function normalizeScanNamespace(namespace: string | undefined): string | undefin
|
|
|
380
380
|
return trimmed ? trimmed : undefined;
|
|
381
381
|
}
|
|
382
382
|
|
|
383
|
-
|
|
384
|
-
|
|
383
|
+
/**
|
|
384
|
+
* Resolve the namespace-scoped storage a scan must read and write through.
|
|
385
|
+
*
|
|
386
|
+
* Exported and narrowed to the fields it actually reads so sibling scans
|
|
387
|
+
* (preference drift, issue #2371) share ONE namespace resolver rather than
|
|
388
|
+
* re-deriving the read/write namespace independently — the divergence the
|
|
389
|
+
* namespace/ACL scenario matrix in AGENTS.md exists to prevent.
|
|
390
|
+
*/
|
|
391
|
+
export async function resolveScanStorage(
|
|
392
|
+
deps: Pick<ScanDependencies, "config" | "storage" | "storageForNamespace">,
|
|
385
393
|
namespace: string | undefined,
|
|
386
394
|
): Promise<ScanStorageResolution> {
|
|
387
395
|
if (!resolveNamespaceCapabilities(deps.config).namespaces) {
|
|
@@ -427,7 +435,10 @@ function isStorageManagerLike(value: unknown): value is StorageManager {
|
|
|
427
435
|
return typeof candidate.readAllMemories === "function";
|
|
428
436
|
}
|
|
429
437
|
|
|
430
|
-
function fallbackResolvedNamespace(
|
|
438
|
+
function fallbackResolvedNamespace(
|
|
439
|
+
deps: Pick<ScanDependencies, "config">,
|
|
440
|
+
namespace: string | undefined,
|
|
441
|
+
): string | undefined {
|
|
431
442
|
if (namespace) return namespace;
|
|
432
443
|
return resolveNamespaceCapabilities(deps.config).namespaces ? deps.config.defaultNamespace : undefined;
|
|
433
444
|
}
|