@remnic/core 10.0.65 → 10.0.67
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.js +16 -16
- package/dist/access-authorization-probe.js +17 -17
- package/dist/access-boundary.js +16 -16
- package/dist/access-cli.js +61 -61
- package/dist/access-extraction-force-flush.js +16 -16
- package/dist/access-http-briefing.js +17 -17
- package/dist/access-http-query.js +18 -18
- package/dist/access-http.js +33 -33
- package/dist/access-identity-continuity-surface.js +16 -16
- package/dist/access-lcm-surface.js +16 -16
- package/dist/access-mcp.js +26 -26
- package/dist/access-namespace-preflight.js +16 -16
- package/dist/access-observe-write-surface.js +16 -16
- package/dist/access-operations-batch.js +17 -17
- package/dist/access-operations.js +24 -24
- package/dist/access-recall-concurrency.js +16 -16
- package/dist/access-recall-diagnostics.js +2 -2
- package/dist/access-recall-response.js +16 -16
- package/dist/access-recall-surface.js +16 -16
- package/dist/access-service.js +16 -16
- package/dist/access-surface-catalog.js +18 -18
- package/dist/active-recall.js +3 -3
- package/dist/briefing.js +3 -3
- package/dist/buffer.js +2 -2
- package/dist/causal-consolidation.js +4 -4
- package/dist/{chunk-KISOMGY2.js → chunk-3RHU5MD7.js} +2 -2
- package/dist/{chunk-3LSTL6EY.js → chunk-4MPAKYZU.js} +2 -2
- package/dist/{chunk-OVL5AD3N.js → chunk-4NV7O76Q.js} +2 -2
- package/dist/{chunk-BH7NVSEC.js → chunk-4SOWMA55.js} +3 -3
- package/dist/{chunk-GROHOWR5.js → chunk-5MGKGEL7.js} +2 -2
- package/dist/{chunk-ZPLQ27MY.js → chunk-5UM4H64E.js} +2 -2
- package/dist/{chunk-2DNFRLLL.js → chunk-5Y6VA6X2.js} +2 -2
- package/dist/{chunk-GRAUQXQB.js → chunk-6WKWL53V.js} +13 -13
- package/dist/{chunk-HOR4RMUM.js → chunk-75DCOS6I.js} +24 -24
- package/dist/{chunk-25QK3LR2.js → chunk-7O2MC42R.js} +2 -2
- package/dist/{chunk-7ETWIBTO.js → chunk-ADYP7HXE.js} +3 -3
- package/dist/{chunk-FUDKGJDN.js → chunk-AVGDYYMA.js} +2 -2
- package/dist/{chunk-ECF627KC.js → chunk-AYJQ644F.js} +2 -2
- package/dist/{chunk-T22FBDG3.js → chunk-B3MWELZ3.js} +2 -2
- package/dist/{chunk-DRTSPRWL.js → chunk-B4DXREWC.js} +2 -2
- package/dist/{chunk-5UEGL5BF.js → chunk-CI3MAAIY.js} +2 -2
- package/dist/{chunk-7JYK7NNY.js → chunk-CTH2CQCB.js} +2 -2
- package/dist/{chunk-UVHXLVFJ.js → chunk-EURPSF4Y.js} +2 -2
- package/dist/{chunk-VPEA63FC.js → chunk-EWJZZDRG.js} +2 -2
- package/dist/{chunk-BOZQAUAJ.js → chunk-EXQJMFRF.js} +2 -2
- package/dist/{chunk-UH6ROXFJ.js → chunk-GGD2YDS6.js} +2 -2
- package/dist/{chunk-5JABRT5G.js → chunk-GHHQLSSY.js} +3 -3
- package/dist/{chunk-N4T5FW6U.js → chunk-GJ4HU6LK.js} +2 -2
- package/dist/{chunk-HRRAOTOQ.js → chunk-H5DIRCZP.js} +12 -12
- package/dist/{chunk-434E4BTO.js → chunk-HH73M65H.js} +3 -3
- package/dist/{chunk-LIGZO7XN.js → chunk-HPB5TF55.js} +2 -2
- package/dist/{chunk-E4QIX2OB.js → chunk-IAGVM7EY.js} +2 -2
- package/dist/{chunk-YJQJRXUI.js → chunk-IG3EZ3TF.js} +2 -2
- package/dist/{chunk-KNMSD2MQ.js → chunk-IVUVQPTQ.js} +2 -2
- package/dist/{chunk-XOFIJGB2.js → chunk-IZBIDPMY.js} +2 -2
- package/dist/{chunk-HFEGRMFG.js → chunk-JLGBJ4AX.js} +7 -7
- package/dist/{chunk-BBHKN2CN.js → chunk-JLMOH5JA.js} +2 -2
- package/dist/{chunk-TPCRDPUY.js → chunk-KZSGBWOJ.js} +2 -2
- package/dist/{chunk-SHHZWSSE.js → chunk-KZZ5EZ7O.js} +2 -2
- package/dist/{chunk-2ZSRACNK.js → chunk-LFYEQK45.js} +682 -549
- package/dist/chunk-LFYEQK45.js.map +1 -0
- package/dist/{chunk-FKGLJJVS.js → chunk-LN4X2NDA.js} +2 -2
- package/dist/{chunk-5ZHFPUBC.js → chunk-MOIJWWNA.js} +8 -8
- package/dist/{chunk-KO224R36.js → chunk-NCZGGGWI.js} +2 -2
- package/dist/{chunk-XVQVF2TK.js → chunk-NHWDTOBN.js} +269 -230
- package/dist/chunk-NHWDTOBN.js.map +1 -0
- package/dist/{chunk-7ZTGMEXF.js → chunk-O5ZINWW3.js} +2 -2
- package/dist/{chunk-WWH7GJ42.js → chunk-OCK4D5PC.js} +2 -2
- package/dist/{chunk-G6L3REL3.js → chunk-OPFVXM2D.js} +2 -2
- package/dist/{chunk-FR7PK7ED.js → chunk-P4TV3TQ2.js} +2 -2
- package/dist/{chunk-P2EM5LKH.js → chunk-PMDOGXA2.js} +2 -2
- package/dist/{chunk-NM2II57L.js → chunk-PRKNAIGZ.js} +2 -1
- package/dist/chunk-PRKNAIGZ.js.map +1 -0
- package/dist/{chunk-MRF5V5CD.js → chunk-QGFR73SN.js} +2 -2
- package/dist/{chunk-6D3IWYNY.js → chunk-R2BIVU2Z.js} +354 -292
- package/dist/chunk-R2BIVU2Z.js.map +1 -0
- package/dist/{chunk-HG3CG557.js → chunk-RLVI2M5Q.js} +2 -2
- package/dist/{chunk-HHL4MX3W.js → chunk-SXTVZ6JL.js} +2 -2
- package/dist/{chunk-CLSKGTAT.js → chunk-TECK5IVY.js} +2 -2
- package/dist/{chunk-SNS3DWG6.js → chunk-TVE7W67N.js} +2 -2
- package/dist/{chunk-KYSSUY66.js → chunk-U2CAGMUD.js} +2 -2
- package/dist/{chunk-XLCEFUAU.js → chunk-UVVFPCPX.js} +2 -2
- package/dist/{chunk-KQJUEQ2E.js → chunk-UW6LBFYN.js} +5 -5
- package/dist/{chunk-SEA56G6S.js → chunk-V4XE263I.js} +1 -1
- package/dist/chunk-V4XE263I.js.map +1 -0
- package/dist/{chunk-JL5HXL25.js → chunk-V6SBA5O7.js} +3 -3
- package/dist/{chunk-R7WYAXPO.js → chunk-VHSQU3RO.js} +81 -42
- package/dist/chunk-VHSQU3RO.js.map +1 -0
- package/dist/{chunk-B7VD36TI.js → chunk-WHROVQ5Q.js} +3 -3
- package/dist/{chunk-LDHR465K.js → chunk-Y3XPSGNF.js} +2 -2
- package/dist/{chunk-JPY3RMG2.js → chunk-ZORS5BG5.js} +4 -4
- package/dist/{chunk-KXY4HW2Y.js → chunk-ZXF3O7P4.js} +2 -2
- package/dist/cli.js +47 -47
- package/dist/coding/export-okf-codegraph.js +2 -2
- package/dist/compounding/engine.js +4 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -3
- package/dist/connectors/codex-materialize-runner.js +3 -3
- package/dist/connectors/index.js +3 -3
- package/dist/convergence-refresh.js +5 -5
- package/dist/corpus-watermark.js +5 -5
- package/dist/entity-retrieval.js +3 -3
- package/dist/external-wiki-access.js +17 -17
- package/dist/extraction.js +6 -6
- package/dist/harmonic-retrieval.js +3 -3
- package/dist/index.js +61 -61
- package/dist/location/index.js +5 -5
- package/dist/maintenance/memory-governance.js +3 -3
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
- package/dist/maintenance/rebuild-memory-projection-runner.js +5 -5
- package/dist/maintenance/rebuild-memory-projection.js +4 -4
- package/dist/memory-browse-operations.js +17 -17
- package/dist/namespaces/migrate.js +4 -4
- package/dist/namespaces/storage.js +3 -3
- package/dist/operator-doctor-corpus.js +6 -6
- package/dist/operator-toolkit.js +12 -12
- package/dist/orchestration/buffer-drain-runner.js +61 -61
- package/dist/orchestration/consolidation-run.d.ts.map +1 -1
- package/dist/orchestration/extraction-drain.d.ts +4 -4
- package/dist/orchestration/extraction-drain.d.ts.map +1 -1
- package/dist/orchestration/extraction-persist-deps.d.ts +0 -2
- package/dist/orchestration/extraction-persist-deps.d.ts.map +1 -1
- package/dist/orchestration/extraction-persist.d.ts +10 -4
- package/dist/orchestration/extraction-persist.d.ts.map +1 -1
- package/dist/orchestration/extraction-queue-coordinator.d.ts +67 -33
- package/dist/orchestration/extraction-queue-coordinator.d.ts.map +1 -1
- package/dist/orchestration/extraction-run-helpers.d.ts +3 -2
- package/dist/orchestration/extraction-run-helpers.d.ts.map +1 -1
- package/dist/orchestration/extraction-run.d.ts +4 -14
- package/dist/orchestration/extraction-run.d.ts.map +1 -1
- package/dist/orchestration/fact-dedup-window.d.ts +49 -0
- package/dist/orchestration/fact-dedup-window.d.ts.map +1 -0
- package/dist/orchestration/maintenance.js +13 -13
- package/dist/orchestration/provider-breaker.d.ts +58 -0
- package/dist/orchestration/provider-breaker.d.ts.map +1 -0
- package/dist/orchestrator.d.ts +2 -17
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +61 -61
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-navigate-access.js +2 -2
- package/dist/recall-navigate-disclosure.js +2 -2
- package/dist/recall-navigate.js +2 -2
- package/dist/recall-navigation-operations.js +17 -17
- package/dist/recall-navigation.js +16 -16
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.js +2 -2
- package/dist/resume-bundles.js +4 -4
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.js +3 -3
- package/dist/source-agent-qualifier.js +5 -5
- package/dist/standup/build.js +3 -3
- package/dist/storage/profile-mutation.d.ts +25 -0
- package/dist/storage/profile-mutation.d.ts.map +1 -0
- package/dist/storage.d.ts +4 -6
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +2 -2
- package/dist/support-passport/index.js +19 -19
- package/dist/threading.d.ts +21 -4
- package/dist/threading.d.ts.map +1 -1
- package/dist/threading.js +1 -1
- package/dist/transfer/export-okf.js +3 -3
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/verified-recall.js +3 -3
- package/dist/who-knows-cli.js +4 -4
- package/dist/who-knows.js +3 -3
- package/package.json +2 -2
- package/src/access-observe-replay-durability.test.ts +1 -1
- package/src/buffer-drain-handover.test.ts +3 -3
- package/src/buffer-drop-extraction-chunk.test.ts +0 -1
- package/src/config.test.ts +12 -0
- package/src/config.ts +2 -0
- package/src/connector-provenance-lifecycle.test.ts +5 -8
- package/src/fact-dedup-window.test.ts +116 -0
- package/src/faithfulness-graph-guard.test.ts +11 -6
- package/src/harmonic-construction.test.ts +16 -10
- package/src/orchestration/consolidation-profile-race.test.ts +178 -0
- package/src/orchestration/consolidation-run.ts +19 -7
- package/src/orchestration/extraction-drain.ts +10 -3
- package/src/orchestration/extraction-persist-deps.ts +0 -2
- package/src/orchestration/extraction-persist.ts +159 -148
- package/src/orchestration/extraction-queue-coordinator.ts +167 -56
- package/src/orchestration/extraction-run-helpers.ts +5 -4
- package/src/orchestration/extraction-run.test.ts +1 -2
- package/src/orchestration/extraction-run.ts +56 -99
- package/src/orchestration/fact-dedup-window.ts +122 -0
- package/src/orchestration/provider-breaker.test.ts +89 -0
- package/src/orchestration/provider-breaker.ts +158 -0
- package/src/orchestration/turn-ingestion.ts +5 -5
- package/src/orchestrator-extraction-queue.test.ts +179 -8
- package/src/orchestrator.ts +7 -23
- package/src/storage/profile-mutation.ts +119 -0
- package/src/storage-append-profile.test.ts +114 -0
- package/src/storage.ts +17 -48
- package/src/testing/orchestrator-lite.ts +1 -1
- package/src/threading.test.ts +153 -0
- package/src/threading.ts +95 -45
- package/src/types.ts +2 -0
- package/dist/chunk-2ZSRACNK.js.map +0 -1
- package/dist/chunk-6D3IWYNY.js.map +0 -1
- package/dist/chunk-NM2II57L.js.map +0 -1
- package/dist/chunk-R7WYAXPO.js.map +0 -1
- package/dist/chunk-SEA56G6S.js.map +0 -1
- package/dist/chunk-XVQVF2TK.js.map +0 -1
- /package/dist/{chunk-KISOMGY2.js.map → chunk-3RHU5MD7.js.map} +0 -0
- /package/dist/{chunk-3LSTL6EY.js.map → chunk-4MPAKYZU.js.map} +0 -0
- /package/dist/{chunk-OVL5AD3N.js.map → chunk-4NV7O76Q.js.map} +0 -0
- /package/dist/{chunk-BH7NVSEC.js.map → chunk-4SOWMA55.js.map} +0 -0
- /package/dist/{chunk-GROHOWR5.js.map → chunk-5MGKGEL7.js.map} +0 -0
- /package/dist/{chunk-ZPLQ27MY.js.map → chunk-5UM4H64E.js.map} +0 -0
- /package/dist/{chunk-2DNFRLLL.js.map → chunk-5Y6VA6X2.js.map} +0 -0
- /package/dist/{chunk-GRAUQXQB.js.map → chunk-6WKWL53V.js.map} +0 -0
- /package/dist/{chunk-HOR4RMUM.js.map → chunk-75DCOS6I.js.map} +0 -0
- /package/dist/{chunk-25QK3LR2.js.map → chunk-7O2MC42R.js.map} +0 -0
- /package/dist/{chunk-7ETWIBTO.js.map → chunk-ADYP7HXE.js.map} +0 -0
- /package/dist/{chunk-FUDKGJDN.js.map → chunk-AVGDYYMA.js.map} +0 -0
- /package/dist/{chunk-ECF627KC.js.map → chunk-AYJQ644F.js.map} +0 -0
- /package/dist/{chunk-T22FBDG3.js.map → chunk-B3MWELZ3.js.map} +0 -0
- /package/dist/{chunk-DRTSPRWL.js.map → chunk-B4DXREWC.js.map} +0 -0
- /package/dist/{chunk-5UEGL5BF.js.map → chunk-CI3MAAIY.js.map} +0 -0
- /package/dist/{chunk-7JYK7NNY.js.map → chunk-CTH2CQCB.js.map} +0 -0
- /package/dist/{chunk-UVHXLVFJ.js.map → chunk-EURPSF4Y.js.map} +0 -0
- /package/dist/{chunk-VPEA63FC.js.map → chunk-EWJZZDRG.js.map} +0 -0
- /package/dist/{chunk-BOZQAUAJ.js.map → chunk-EXQJMFRF.js.map} +0 -0
- /package/dist/{chunk-UH6ROXFJ.js.map → chunk-GGD2YDS6.js.map} +0 -0
- /package/dist/{chunk-5JABRT5G.js.map → chunk-GHHQLSSY.js.map} +0 -0
- /package/dist/{chunk-N4T5FW6U.js.map → chunk-GJ4HU6LK.js.map} +0 -0
- /package/dist/{chunk-HRRAOTOQ.js.map → chunk-H5DIRCZP.js.map} +0 -0
- /package/dist/{chunk-434E4BTO.js.map → chunk-HH73M65H.js.map} +0 -0
- /package/dist/{chunk-LIGZO7XN.js.map → chunk-HPB5TF55.js.map} +0 -0
- /package/dist/{chunk-E4QIX2OB.js.map → chunk-IAGVM7EY.js.map} +0 -0
- /package/dist/{chunk-YJQJRXUI.js.map → chunk-IG3EZ3TF.js.map} +0 -0
- /package/dist/{chunk-KNMSD2MQ.js.map → chunk-IVUVQPTQ.js.map} +0 -0
- /package/dist/{chunk-XOFIJGB2.js.map → chunk-IZBIDPMY.js.map} +0 -0
- /package/dist/{chunk-HFEGRMFG.js.map → chunk-JLGBJ4AX.js.map} +0 -0
- /package/dist/{chunk-BBHKN2CN.js.map → chunk-JLMOH5JA.js.map} +0 -0
- /package/dist/{chunk-TPCRDPUY.js.map → chunk-KZSGBWOJ.js.map} +0 -0
- /package/dist/{chunk-SHHZWSSE.js.map → chunk-KZZ5EZ7O.js.map} +0 -0
- /package/dist/{chunk-FKGLJJVS.js.map → chunk-LN4X2NDA.js.map} +0 -0
- /package/dist/{chunk-5ZHFPUBC.js.map → chunk-MOIJWWNA.js.map} +0 -0
- /package/dist/{chunk-KO224R36.js.map → chunk-NCZGGGWI.js.map} +0 -0
- /package/dist/{chunk-7ZTGMEXF.js.map → chunk-O5ZINWW3.js.map} +0 -0
- /package/dist/{chunk-WWH7GJ42.js.map → chunk-OCK4D5PC.js.map} +0 -0
- /package/dist/{chunk-G6L3REL3.js.map → chunk-OPFVXM2D.js.map} +0 -0
- /package/dist/{chunk-FR7PK7ED.js.map → chunk-P4TV3TQ2.js.map} +0 -0
- /package/dist/{chunk-P2EM5LKH.js.map → chunk-PMDOGXA2.js.map} +0 -0
- /package/dist/{chunk-MRF5V5CD.js.map → chunk-QGFR73SN.js.map} +0 -0
- /package/dist/{chunk-HG3CG557.js.map → chunk-RLVI2M5Q.js.map} +0 -0
- /package/dist/{chunk-HHL4MX3W.js.map → chunk-SXTVZ6JL.js.map} +0 -0
- /package/dist/{chunk-CLSKGTAT.js.map → chunk-TECK5IVY.js.map} +0 -0
- /package/dist/{chunk-SNS3DWG6.js.map → chunk-TVE7W67N.js.map} +0 -0
- /package/dist/{chunk-KYSSUY66.js.map → chunk-U2CAGMUD.js.map} +0 -0
- /package/dist/{chunk-XLCEFUAU.js.map → chunk-UVVFPCPX.js.map} +0 -0
- /package/dist/{chunk-KQJUEQ2E.js.map → chunk-UW6LBFYN.js.map} +0 -0
- /package/dist/{chunk-JL5HXL25.js.map → chunk-V6SBA5O7.js.map} +0 -0
- /package/dist/{chunk-B7VD36TI.js.map → chunk-WHROVQ5Q.js.map} +0 -0
- /package/dist/{chunk-LDHR465K.js.map → chunk-Y3XPSGNF.js.map} +0 -0
- /package/dist/{chunk-JPY3RMG2.js.map → chunk-ZORS5BG5.js.map} +0 -0
- /package/dist/{chunk-KXY4HW2Y.js.map → chunk-ZXF3O7P4.js.map} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { classifyExtractionOrigin, type ExtractionSourceContext } from "./extraction-origin-context.js";
|
|
2
|
+
import { confirmActiveFactDuplicate, persistUnderFactDedupWindow } from "./fact-dedup-window.js";
|
|
2
3
|
import { evaluateInjectionScreen, screenEntityForIndex, screenPersistStrings } from "./extraction-injection-gate.js";
|
|
3
4
|
/**
|
|
4
5
|
* Extraction persistence coordinator (issue #1526, seam 16).
|
|
@@ -127,6 +128,16 @@ import {
|
|
|
127
128
|
normalizeStoredHashSource as normalizeStoredHashSourceContent,
|
|
128
129
|
} from "./extraction-persist-citation.js";
|
|
129
130
|
|
|
131
|
+
/** One extraction run's persist outcome: per-run values, no shared side channels (#1526). */
|
|
132
|
+
export interface ExtractionPersistResult {
|
|
133
|
+
persistedIds: string[];
|
|
134
|
+
memoryPathById: Map<string, string>;
|
|
135
|
+
/** Facts the judge deferred — drives this run's buffer retention (#562). */
|
|
136
|
+
deferredCount: number;
|
|
137
|
+
/** Persisted pending_review ids, excluded from the thread episode set (#1635). */
|
|
138
|
+
pendingReviewIds: string[];
|
|
139
|
+
}
|
|
140
|
+
|
|
130
141
|
export class ExtractionPersistCoordinator {
|
|
131
142
|
constructor(
|
|
132
143
|
private readonly deps: ExtractionPersistDeps,
|
|
@@ -149,7 +160,7 @@ export class ExtractionPersistCoordinator {
|
|
|
149
160
|
sourceText?: string,
|
|
150
161
|
graphCaps: GraphConstructionCapabilitySet = resolveGraphConstructionCapabilities(this.deps.config),
|
|
151
162
|
lifecycleCaps: MemoryLifecycleCapabilitySet = resolveMemoryLifecycleCapabilities(this.deps.config),
|
|
152
|
-
): Promise<
|
|
163
|
+
): Promise<ExtractionPersistResult> {
|
|
153
164
|
const citationEnabled = resolvePipelineProcessingCapabilities(this.deps.config).inlineSourceAttribution === true;
|
|
154
165
|
const citationTemplate = this.deps.config.inlineSourceAttributionFormat;
|
|
155
166
|
const factDedupEnabled = resolveRecallAuxiliaryCapabilities(this.deps.config).factDeduplication;
|
|
@@ -190,6 +201,10 @@ export class ExtractionPersistCoordinator {
|
|
|
190
201
|
validAt && validAt.length > 0 ? validAt : new Date().toISOString();
|
|
191
202
|
// #1635: pending_review persisted ids, excluded from the thread episode set below.
|
|
192
203
|
const pendingReviewPersistedIds: string[] = [];
|
|
204
|
+
// This run's judge-deferred count, returned to the caller (issue #562 PR 2)
|
|
205
|
+
// instead of shared side-channel state, so concurrent extractions cannot
|
|
206
|
+
// read each other's retention decision.
|
|
207
|
+
let deferredCount = 0;
|
|
193
208
|
const persistedIdsByStorage = new Map<string, { storage: StorageManager; ids: string[] }>();
|
|
194
209
|
const trackPersistedId = (
|
|
195
210
|
targetStorage: StorageManager,
|
|
@@ -1071,7 +1086,7 @@ export class ExtractionPersistCoordinator {
|
|
|
1071
1086
|
"persistExtraction: result or result.facts is invalid, skipping",
|
|
1072
1087
|
{ resultType: typeof result, factsType: typeof result?.facts },
|
|
1073
1088
|
);
|
|
1074
|
-
return { persistedIds, memoryPathById };
|
|
1089
|
+
return { persistedIds, memoryPathById, deferredCount, pendingReviewIds: pendingReviewPersistedIds };
|
|
1075
1090
|
}
|
|
1076
1091
|
|
|
1077
1092
|
// Chunking config from plugin settings
|
|
@@ -1243,10 +1258,6 @@ export class ExtractionPersistCoordinator {
|
|
|
1243
1258
|
// be persisted, not the raw extraction-time category.
|
|
1244
1259
|
let judgeVerdictsByFactIndex: Map<number, import("../extraction-judge.js").JudgeVerdict> | null = null;
|
|
1245
1260
|
let judgeGatedCount = 0;
|
|
1246
|
-
// Reset the side-channel defer count at the start of every
|
|
1247
|
-
// persistExtraction call so stale state from a prior call cannot leak
|
|
1248
|
-
// into the caller's buffer-retention decision.
|
|
1249
|
-
this.deps.setLastPersistExtractionDeferredCount(0);
|
|
1250
1261
|
if (lifecycleCaps.extractionJudge) {
|
|
1251
1262
|
// #1669 P1 + #1713 Item 1: pre-filter redacted facts from judge candidates
|
|
1252
1263
|
// so never-store content is not persisted as judge training data.
|
|
@@ -1433,7 +1444,7 @@ export class ExtractionPersistCoordinator {
|
|
|
1433
1444
|
);
|
|
1434
1445
|
// Expose defer count to the caller (issue #562 PR 2) so it can decide
|
|
1435
1446
|
// whether to retain buffer turns for the next extraction pass.
|
|
1436
|
-
|
|
1447
|
+
deferredCount = judgeResult.deferred;
|
|
1437
1448
|
} catch (err) {
|
|
1438
1449
|
// Fail-open: if the entire judge pipeline errors, proceed without filtering
|
|
1439
1450
|
log.warn(
|
|
@@ -1653,148 +1664,123 @@ export class ExtractionPersistCoordinator {
|
|
|
1653
1664
|
fact.tags,
|
|
1654
1665
|
);
|
|
1655
1666
|
let exactDuplicate = false;
|
|
1656
|
-
let needsCorpusConfirm = false;
|
|
1657
1667
|
try {
|
|
1658
1668
|
exactDuplicate = await this.deps.hasContentHashDedup(targetStorage, contentHashDedupKey);
|
|
1659
|
-
if (factDedupEnabled && !exactDuplicate) {
|
|
1660
|
-
// Fact dedup disabled → skip the authority check AND (via the guarded
|
|
1661
|
-
// corpus block below) corpus confirmation, so a disabled deployment
|
|
1662
|
-
// never suppresses a write via dedup (PR #2016 thread SD-nH). Enabled:
|
|
1663
|
-
// a MISS is trustworthy only against an AUTHORITATIVE index — re-check.
|
|
1664
|
-
if (await targetStorage.isFactContentHashAuthoritative()) {
|
|
1665
|
-
exactDuplicate = await this.deps.hasContentHashDedup(targetStorage, contentHashDedupKey);
|
|
1666
|
-
} else {
|
|
1667
|
-
needsCorpusConfirm = true;
|
|
1668
|
-
}
|
|
1669
|
-
}
|
|
1670
1669
|
} catch (err) {
|
|
1671
|
-
// Dedup lookup failed (e.g. the authoritative rebuild could not run).
|
|
1672
|
-
//
|
|
1673
|
-
|
|
1670
|
+
// Dedup lookup failed (e.g. the authoritative rebuild could not run).
|
|
1671
|
+
// When dedup is enabled the confirm below still scans the corpus; when
|
|
1672
|
+
// it is disabled, never suppress a write via dedup (PR #2016 SD-nH).
|
|
1673
|
+
exactDuplicate = false;
|
|
1674
1674
|
log.warn(
|
|
1675
1675
|
`content-hash dedup lookup unavailable for storage ${targetStorage.dir}; confirming against corpus: ${err}`,
|
|
1676
1676
|
);
|
|
1677
1677
|
}
|
|
1678
|
-
//
|
|
1679
|
-
//
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
const matchesActiveDuplicate = (m: MemoryFile): boolean => {
|
|
1697
|
-
if (m.frontmatter.category !== writeCategory) return false;
|
|
1698
|
-
if ((m.frontmatter.status ?? "active") !== "active") return false;
|
|
1699
|
-
// Thread 5 (QPDE5): for procedures the hash is keyed on the full
|
|
1700
|
-
// body (title + steps via buildProcedurePersistBody), so compare
|
|
1701
|
-
// against contentHashDedupKey — not canonicalContentForHash which
|
|
1702
|
-
// is the title only. Thread 3 (QO42V): facts with
|
|
1703
|
-
// structuredAttributes get an appended [Attributes: ...] suffix in
|
|
1704
|
-
// the stored body that the hash key lacks; strip it before
|
|
1705
|
-
// comparing so same-connector enriched facts dedup correctly.
|
|
1706
|
-
if (normalizeStoredHashSource(stripAttributesSuffix(m.content ?? "")) !==
|
|
1707
|
-
ContentHashIndex.normalizeContent(contentHashDedupKey)) return false;
|
|
1708
|
-
return (m.frontmatter.sourceConnector?.trim() || undefined) === nc;
|
|
1709
|
-
};
|
|
1710
|
-
exactDuplicate =
|
|
1711
|
-
hotMems.some(matchesActiveDuplicate) || coldMems.some(matchesActiveDuplicate);
|
|
1712
|
-
} catch (err) {
|
|
1713
|
-
log.warn(
|
|
1714
|
-
`connector-aware dedup scan failed for storage ${targetStorage.dir}; writing fail-open: ${err instanceof Error ? err.message : String(err)}`,
|
|
1715
|
-
);
|
|
1716
|
-
exactDuplicate = false;
|
|
1717
|
-
}
|
|
1678
|
+
// Shared confirm options for the persist-time check and the write-window
|
|
1679
|
+
// race recheck below.
|
|
1680
|
+
const raceDedupOpts = (key: string) => ({
|
|
1681
|
+
category: writeCategory,
|
|
1682
|
+
contentHashDedupKey: key,
|
|
1683
|
+
connector: sourceContext?.sourceConnector?.trim() || undefined,
|
|
1684
|
+
citationEnabled,
|
|
1685
|
+
citationTemplate,
|
|
1686
|
+
});
|
|
1687
|
+
// Fact dedup disabled → skip the authority check AND the corpus
|
|
1688
|
+
// confirmation, so a disabled deployment never suppresses a write via
|
|
1689
|
+
// dedup (PR #2016 thread SD-nH).
|
|
1690
|
+
if (factDedupEnabled) {
|
|
1691
|
+
exactDuplicate = await confirmActiveFactDuplicate(
|
|
1692
|
+
{ hasContentHashDedup: (storage, key) => this.deps.hasContentHashDedup(storage, key) },
|
|
1693
|
+
targetStorage,
|
|
1694
|
+
raceDedupOpts(contentHashDedupKey),
|
|
1695
|
+
);
|
|
1718
1696
|
}
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
//
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1697
|
+
// PR #2016/#3231: finalize committed writes before a fail-closed
|
|
1698
|
+
// window throw propagates (PRRT_kwDORJXyws6zxG6H).
|
|
1699
|
+
const finalizeOnWindowFailure = async (err: Error): Promise<never> => {
|
|
1700
|
+
await finalizeCommittedWrites(true).catch((finalizeErr) =>
|
|
1701
|
+
log.warn(`committed-write finalization after fact-dedup window failure failed: ${finalizeErr}`),
|
|
1702
|
+
);
|
|
1703
|
+
throw err;
|
|
1704
|
+
};
|
|
1705
|
+
const raceRecheck = (storage: StorageManager, key: string) => () => {
|
|
1706
|
+
// Gates mirror the persist-time suppression gates (PR #2016 SD-nH; #1645 quarantine).
|
|
1707
|
+
if (!factDedupEnabled || injectionScreenStatus === "pending_review") return Promise.resolve(false);
|
|
1708
|
+
return confirmActiveFactDuplicate(
|
|
1709
|
+
{ hasContentHashDedup: (s, k) => this.deps.hasContentHashDedup(s, k) },
|
|
1710
|
+
storage,
|
|
1711
|
+
raceDedupOpts(key),
|
|
1712
|
+
);
|
|
1713
|
+
};
|
|
1714
|
+
// #1671/#1707 — backfill bi-temporal bounds onto the surviving copy
|
|
1715
|
+
// when a duplicate short-circuits: persist-time hit OR raced duplicate
|
|
1716
|
+
// suppressed in the window (codex P2, PRRT_kwDORJXyws6zxlor). Facts
|
|
1717
|
+
// only (#1707 t3); a corrected start bound counts (t2). Skipped when a
|
|
1718
|
+
// downstream gate would reject the candidate — a non-durable candidate
|
|
1719
|
+
// must not expire an active fact (faithfulness, requireSpans, judge,
|
|
1720
|
+
// #372 importance).
|
|
1721
|
+
const backfillDuplicateTemporalBounds = async () => {
|
|
1722
|
+
if (!(biTemporal && writeCategory === "fact" && (biTemporal.validUntil || biTemporal.validFrom))) return;
|
|
1723
|
+
const fr = faithfulnessResultsByFactIndex?.get(factLoopIndex);
|
|
1724
|
+
const faithfulnessWouldPending =
|
|
1725
|
+
faithfulnessMode === "enforce" &&
|
|
1726
|
+
fr?.ok === true &&
|
|
1727
|
+
(fr.verdict === "unsupported" || fr.verdict === "contradicted");
|
|
1728
|
+
const requireSpansWouldPending =
|
|
1729
|
+
this.deps.config.provenance?.requireSpans === true &&
|
|
1730
|
+
fact.requireSpansPending === true;
|
|
1731
|
+
const judgeVerdict = judgeVerdictsByFactIndex?.get(factLoopIndex);
|
|
1732
|
+
const judgeWouldGate =
|
|
1733
|
+
!this.deps.config.extractionJudgeShadow &&
|
|
1734
|
+
judgeVerdict !== undefined &&
|
|
1735
|
+
!judgeVerdict.durable;
|
|
1736
|
+
// Importance gate (cursor PRRT_OvKnS): below-threshold duplicates
|
|
1737
|
+
// would never persist (#372) and carry no judge verdict (the
|
|
1738
|
+
// pre-filter skips them), so they must not expire an active fact.
|
|
1735
1739
|
if (
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1740
|
+
!isAboveImportanceThreshold(importance.level, this.deps.config.extractionMinImportanceLevel) ||
|
|
1741
|
+
faithfulnessWouldPending ||
|
|
1742
|
+
requireSpansWouldPending ||
|
|
1743
|
+
judgeWouldGate
|
|
1739
1744
|
) {
|
|
1740
|
-
|
|
1741
|
-
const faithfulnessWouldPending =
|
|
1742
|
-
faithfulnessMode === "enforce" &&
|
|
1743
|
-
fr?.ok === true &&
|
|
1744
|
-
(fr.verdict === "unsupported" || fr.verdict === "contradicted");
|
|
1745
|
-
const requireSpansWouldPending =
|
|
1746
|
-
this.deps.config.provenance?.requireSpans === true &&
|
|
1747
|
-
fact.requireSpansPending === true;
|
|
1748
|
-
const judgeVerdict = judgeVerdictsByFactIndex?.get(factLoopIndex);
|
|
1749
|
-
const judgeWouldGate =
|
|
1750
|
-
!this.deps.config.extractionJudgeShadow &&
|
|
1751
|
-
judgeVerdict !== undefined &&
|
|
1752
|
-
!judgeVerdict.durable;
|
|
1753
|
-
// Importance gate (cursor PRRT_OvKnS): below-threshold duplicates
|
|
1754
|
-
// would never persist (#372) and carry no judge verdict (the
|
|
1755
|
-
// pre-filter skips them), so they must not expire an active fact.
|
|
1756
|
-
if (
|
|
1757
|
-
isAboveImportanceThreshold(importance.level, this.deps.config.extractionMinImportanceLevel) &&
|
|
1758
|
-
!faithfulnessWouldPending &&
|
|
1759
|
-
!requireSpansWouldPending &&
|
|
1760
|
-
!judgeWouldGate
|
|
1761
|
-
) {
|
|
1762
|
-
await this.deps.backfillTemporalBoundsOnDedupHit(
|
|
1763
|
-
targetStorage,
|
|
1764
|
-
contentHashDedupKey,
|
|
1765
|
-
{
|
|
1766
|
-
invalidAt: biTemporal.validUntil,
|
|
1767
|
-
// #1707 thread 2 — carry the corrected start bound too.
|
|
1768
|
-
validFrom: biTemporal.validFrom,
|
|
1769
|
-
observedAt: biTemporal.observedAt,
|
|
1770
|
-
eventTimeSource: biTemporal.eventTimeSource,
|
|
1771
|
-
},
|
|
1772
|
-
fact.entityRef,
|
|
1773
|
-
sourceContext?.sourceConnector,
|
|
1774
|
-
);
|
|
1775
|
-
// #1707 thread 1 — the source branch short-circuits (`continue`
|
|
1776
|
-
// below) before the promotion dedup paths run, so promoted
|
|
1777
|
-
// shared/profile copies written before the source fact carried
|
|
1778
|
-
// resolved bounds stay stale and cross-namespace recall surfaces
|
|
1779
|
-
// an expired fact. Backfill the promotion targets too (fail-open,
|
|
1780
|
-
// backfill-only — never writes a new promoted copy).
|
|
1781
|
-
await backfillTemporalBoundsOnPromotionCopies({
|
|
1782
|
-
sourceStorage: targetStorage,
|
|
1783
|
-
content: fact.content,
|
|
1784
|
-
category: writeCategory,
|
|
1785
|
-
confidence: fact.confidence,
|
|
1786
|
-
entityRef: fact.entityRef,
|
|
1787
|
-
structuredAttributes: fact.structuredAttributes,
|
|
1788
|
-
sourceConnector: sourceContext?.sourceConnector,
|
|
1789
|
-
bounds: {
|
|
1790
|
-
invalidAt: biTemporal.validUntil,
|
|
1791
|
-
validFrom: biTemporal.validFrom,
|
|
1792
|
-
observedAt: biTemporal.observedAt,
|
|
1793
|
-
eventTimeSource: biTemporal.eventTimeSource,
|
|
1794
|
-
},
|
|
1795
|
-
});
|
|
1796
|
-
}
|
|
1745
|
+
return;
|
|
1797
1746
|
}
|
|
1747
|
+
await this.deps.backfillTemporalBoundsOnDedupHit(
|
|
1748
|
+
targetStorage,
|
|
1749
|
+
contentHashDedupKey,
|
|
1750
|
+
{
|
|
1751
|
+
invalidAt: biTemporal.validUntil,
|
|
1752
|
+
// #1707 thread 2 — carry the corrected start bound too.
|
|
1753
|
+
validFrom: biTemporal.validFrom,
|
|
1754
|
+
observedAt: biTemporal.observedAt,
|
|
1755
|
+
eventTimeSource: biTemporal.eventTimeSource,
|
|
1756
|
+
},
|
|
1757
|
+
fact.entityRef,
|
|
1758
|
+
sourceContext?.sourceConnector,
|
|
1759
|
+
);
|
|
1760
|
+
// #1707 thread 1 — a short-circuited source branch never reaches the
|
|
1761
|
+
// promotion dedup paths, so promoted shared/profile copies written
|
|
1762
|
+
// before the source fact carried resolved bounds stay stale and
|
|
1763
|
+
// cross-namespace recall surfaces an expired fact. Backfill the
|
|
1764
|
+
// promotion targets too (fail-open, backfill-only — never writes a
|
|
1765
|
+
// new promoted copy).
|
|
1766
|
+
await backfillTemporalBoundsOnPromotionCopies({
|
|
1767
|
+
sourceStorage: targetStorage,
|
|
1768
|
+
content: fact.content,
|
|
1769
|
+
category: writeCategory,
|
|
1770
|
+
confidence: fact.confidence,
|
|
1771
|
+
entityRef: fact.entityRef,
|
|
1772
|
+
structuredAttributes: fact.structuredAttributes,
|
|
1773
|
+
sourceConnector: sourceContext?.sourceConnector,
|
|
1774
|
+
bounds: {
|
|
1775
|
+
invalidAt: biTemporal.validUntil,
|
|
1776
|
+
validFrom: biTemporal.validFrom,
|
|
1777
|
+
observedAt: biTemporal.observedAt,
|
|
1778
|
+
eventTimeSource: biTemporal.eventTimeSource,
|
|
1779
|
+
},
|
|
1780
|
+
});
|
|
1781
|
+
};
|
|
1782
|
+
if (exactDuplicate && injectionScreenStatus !== "pending_review") {
|
|
1783
|
+
await backfillDuplicateTemporalBounds();
|
|
1798
1784
|
log.debug(
|
|
1799
1785
|
`dedup: skipping duplicate fact "${fact.content.slice(0, 60)}…" in storage ${targetStorage.dir}`,
|
|
1800
1786
|
);
|
|
@@ -2188,7 +2174,11 @@ export class ExtractionPersistCoordinator {
|
|
|
2188
2174
|
},
|
|
2189
2175
|
{ source: extractionWriteSource },
|
|
2190
2176
|
);
|
|
2191
|
-
const
|
|
2177
|
+
const parentWriteOutcome = await persistUnderFactDedupWindow(
|
|
2178
|
+
targetStorage.dir,
|
|
2179
|
+
raceRecheck(targetStorage, contentHashDedupKey),
|
|
2180
|
+
async () =>
|
|
2181
|
+
targetStorage.writeSealedMemory(parentWriteEnvelope, {
|
|
2192
2182
|
importance,
|
|
2193
2183
|
supersedes,
|
|
2194
2184
|
links: links.length > 0 ? links : undefined,
|
|
@@ -2208,7 +2198,16 @@ export class ExtractionPersistCoordinator {
|
|
|
2208
2198
|
// durable parent .md; flush the hash now so a throw can't strand it (dup).
|
|
2209
2199
|
deferHashIndexSave: false,
|
|
2210
2200
|
...(factToolScoped ? { toolScoped: true as const } : {}),
|
|
2211
|
-
|
|
2201
|
+
}),
|
|
2202
|
+
).catch(finalizeOnWindowFailure);
|
|
2203
|
+
if (parentWriteOutcome.suppressed) {
|
|
2204
|
+
// Codex P2: backfill bounds onto the winning copy first.
|
|
2205
|
+
await backfillDuplicateTemporalBounds();
|
|
2206
|
+
log.info(`dedup: raced duplicate suppressed in fact-dedup window (chunked parent) for storage ${targetStorage.dir}`);
|
|
2207
|
+
dedupedCount++;
|
|
2208
|
+
continue;
|
|
2209
|
+
}
|
|
2210
|
+
const parentWrite = parentWriteOutcome.result;
|
|
2212
2211
|
const parentId = parentWrite.id;
|
|
2213
2212
|
// #1645: surface the tombstone block and gate active post-write paths
|
|
2214
2213
|
const tombstoneBlocked = parentWrite.tombstoneBlocked;
|
|
@@ -2579,7 +2578,11 @@ export class ExtractionPersistCoordinator {
|
|
|
2579
2578
|
},
|
|
2580
2579
|
{ source: extractionWriteSource },
|
|
2581
2580
|
);
|
|
2582
|
-
const
|
|
2581
|
+
const factWriteOutcome = await persistUnderFactDedupWindow(
|
|
2582
|
+
targetStorage.dir,
|
|
2583
|
+
raceRecheck(targetStorage, contentHashDedupKey),
|
|
2584
|
+
async () =>
|
|
2585
|
+
targetStorage.writeSealedMemory(factWriteEnvelope, {
|
|
2583
2586
|
importance,
|
|
2584
2587
|
supersedes,
|
|
2585
2588
|
links: links.length > 0 ? links : undefined,
|
|
@@ -2597,11 +2600,21 @@ export class ExtractionPersistCoordinator {
|
|
|
2597
2600
|
// through to frontmatter so they survive end-to-end.
|
|
2598
2601
|
...(fact.sources && fact.sources.length > 0 ? { sources: fact.sources } : {}),
|
|
2599
2602
|
...(fact.provenance ? { provenance: fact.provenance } : {}),
|
|
2600
|
-
// #
|
|
2601
|
-
//
|
|
2602
|
-
|
|
2603
|
+
// PR #2016: never defer inside the commit window (chunked-path
|
|
2604
|
+
// rule): a peer loading an authoritative index after the release
|
|
2605
|
+
// must see this hash, or its recheck misses and duplicates it.
|
|
2606
|
+
deferHashIndexSave: false,
|
|
2603
2607
|
...(factToolScoped ? { toolScoped: true as const } : {}),
|
|
2604
|
-
|
|
2608
|
+
}),
|
|
2609
|
+
).catch(finalizeOnWindowFailure);
|
|
2610
|
+
if (factWriteOutcome.suppressed) {
|
|
2611
|
+
// Codex P2: backfill bounds onto the window's winning copy first.
|
|
2612
|
+
await backfillDuplicateTemporalBounds();
|
|
2613
|
+
log.info(`dedup: raced duplicate suppressed in fact-dedup window for storage ${targetStorage.dir}`);
|
|
2614
|
+
dedupedCount++;
|
|
2615
|
+
continue;
|
|
2616
|
+
}
|
|
2617
|
+
const factWrite = factWriteOutcome.result;
|
|
2605
2618
|
const memoryId = factWrite.id;
|
|
2606
2619
|
// #1645: surface the tombstone block; gate active post-write paths like #1576
|
|
2607
2620
|
// so a blocked fact creates no active shared copy / supersession / graph entry.
|
|
@@ -2978,9 +2991,7 @@ export class ExtractionPersistCoordinator {
|
|
|
2978
2991
|
`persisted: ${facts.length - dedupedCount - importanceGatedCount - judgeGatedCount - redactionGatedCount - semanticMergedCount} facts${dedupSuffix}${gatedSuffix}${judgeSuffix}${redactionSuffix}, ${entities.length} entities, ${questions.length} questions, ${profileUpdates.length} profile updates`,
|
|
2979
2992
|
);
|
|
2980
2993
|
|
|
2981
|
-
// #1635: surface pending_review ids so the thread episode set excludes them.
|
|
2982
|
-
this.deps.setLastPersistExtractionPendingReviewIds(pendingReviewPersistedIds);
|
|
2983
2994
|
// Return the persisted fact IDs for threading
|
|
2984
|
-
return { persistedIds, memoryPathById };
|
|
2995
|
+
return { persistedIds, memoryPathById, deferredCount, pendingReviewIds: pendingReviewPersistedIds };
|
|
2985
2996
|
}
|
|
2986
2997
|
}
|