@remnic/core 9.3.629 → 9.3.631
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-cli.js +15 -13
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +5 -4
- package/dist/access-http.js +7 -6
- package/dist/access-mcp.d.ts +5 -4
- package/dist/access-mcp.js +6 -5
- package/dist/{access-service-BdThkfIE.d.ts → access-service-C9_EpVHd.d.ts} +2 -2
- package/dist/access-service.d.ts +5 -4
- package/dist/access-service.js +5 -4
- 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 +1 -1
- package/dist/auto-sync-RFADEHIQ.js +75 -0
- package/dist/auto-sync-RFADEHIQ.js.map +1 -0
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +4 -3
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +3 -2
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/calibration.d.ts +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +4 -3
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/{chunk-532VCWYW.js → chunk-242XFZ36.js} +2 -2
- package/dist/{chunk-XXO5TI3B.js → chunk-32U3N7H5.js} +3 -3
- package/dist/{chunk-KB4MFBF5.js → chunk-3RDYU3JS.js} +3 -3
- package/dist/{chunk-57QXN2CS.js → chunk-4S3N6HFG.js} +2 -2
- package/dist/{chunk-OLNNOHBC.js → chunk-5PT5I6JQ.js} +20 -14
- package/dist/{chunk-OLNNOHBC.js.map → chunk-5PT5I6JQ.js.map} +1 -1
- package/dist/{chunk-GE7Q7KXP.js → chunk-7A2QKUUA.js} +2 -2
- package/dist/{chunk-KKTXCFD7.js → chunk-7H5WCPBS.js} +95 -11
- package/dist/{chunk-KKTXCFD7.js.map → chunk-7H5WCPBS.js.map} +1 -1
- package/dist/{chunk-3MNBW7R7.js → chunk-C4KKM62E.js} +2 -2
- package/dist/{chunk-NKCW223V.js → chunk-CMN5AWAZ.js} +2 -2
- package/dist/{chunk-JXHMAQYT.js → chunk-DOBJH4I6.js} +4 -4
- package/dist/{chunk-TZDSNIRO.js → chunk-IFVFQRZ2.js} +5 -5
- package/dist/{chunk-LQYTQCXM.js → chunk-JCLECECB.js} +2 -2
- package/dist/chunk-KVDUDYEN.js +1164 -0
- package/dist/chunk-KVDUDYEN.js.map +1 -0
- package/dist/{chunk-QDV6VAD4.js → chunk-LEG7XWS2.js} +2 -2
- package/dist/chunk-M7XQSUBB.js +280 -0
- package/dist/chunk-M7XQSUBB.js.map +1 -0
- package/dist/{chunk-N5RGXWLQ.js → chunk-PUEAEQSN.js} +2 -2
- package/dist/{chunk-UGHUNQ74.js → chunk-QYGIQ5NM.js} +212 -417
- package/dist/chunk-QYGIQ5NM.js.map +1 -0
- package/dist/{chunk-JKCDQBDW.js → chunk-UXFOGILU.js} +2 -2
- package/dist/{chunk-MVQN73GT.js → chunk-VTR3MNYF.js} +2 -2
- package/dist/{chunk-KVFYTRMV.js → chunk-W25I7G6U.js} +2 -2
- package/dist/{chunk-3GLCUPXP.js → chunk-WLZBVYC6.js} +192 -889
- package/dist/chunk-WLZBVYC6.js.map +1 -0
- package/dist/{chunk-3R2UZV3U.js → chunk-X7EJF46S.js} +2 -2
- package/dist/{chunk-54KDA6UK.js → chunk-XG4NAWAV.js} +3 -3
- package/dist/{chunk-P2D2MM47.js → chunk-YROCXMCK.js} +2 -2
- package/dist/{cli-DAsHklrf.d.ts → cli-CuVEQWKr.d.ts} +3 -3
- package/dist/cli.d.ts +6 -5
- package/dist/cli.js +18 -17
- package/dist/compounding/engine.d.ts +1 -1
- package/dist/compounding/engine.js +3 -2
- 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 +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +3 -2
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +3 -2
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/contradiction/index.js +4 -4
- 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/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +3 -2
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +4 -3
- 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.d.ts +1 -1
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +49 -45
- package/dist/index.js.map +1 -1
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/index.d.ts +1 -1
- 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/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +3 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -2
- package/dist/maintenance/rebuild-memory-projection.js +4 -3
- package/dist/mcp-memory-inspector-app.d.ts +5 -4
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +1 -1
- package/dist/namespaces/migrate.js +4 -3
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/storage.d.ts +1 -1
- package/dist/namespaces/storage.js +3 -2
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +7 -6
- package/dist/{orchestrator-BexeSJ2j.d.ts → orchestrator-CoqytbK_.d.ts} +102 -10
- package/dist/orchestrator.d.ts +4 -3
- package/dist/orchestrator.js +12 -10
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.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-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +2 -2
- package/dist/retrieval-agents.d.ts +1 -1
- 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/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/index.d.ts +1 -1
- 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-PwkzNfdK.d.ts → semantic-consolidation-BPs6BURk.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +4 -3
- package/dist/semantic-rule-promotion.js +3 -2
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +3 -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 +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/storage.d.ts +38 -2
- package/dist/storage.js +6 -3
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.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 +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/{types-BCF2wqKa.d.ts → types-CpMPD8xl.d.ts} +59 -11
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +3 -2
- package/package.json +1 -1
- package/src/orchestrator.ts +74 -0
- package/src/storage.ts +100 -0
- package/src/wearables/auto-sync.test.ts +181 -0
- package/src/wearables/auto-sync.ts +129 -0
- package/src/wearables/cli.ts +6 -0
- package/src/wearables/config.test.ts +90 -11
- package/src/wearables/config.ts +113 -11
- package/src/wearables/memory-gen.test.ts +416 -1
- package/src/wearables/memory-gen.ts +381 -23
- package/src/wearables/pipeline.test.ts +396 -5
- package/src/wearables/pipeline.ts +174 -22
- package/src/wearables/service.test.ts +172 -0
- package/src/wearables/service.ts +84 -3
- package/src/wearables/storage-io.test.ts +81 -0
- package/src/wearables/trust.test.ts +123 -0
- package/src/wearables/trust.ts +168 -0
- package/src/wearables/types.ts +57 -9
- package/dist/chunk-3GLCUPXP.js.map +0 -1
- package/dist/chunk-UGHUNQ74.js.map +0 -1
- /package/dist/{chunk-532VCWYW.js.map → chunk-242XFZ36.js.map} +0 -0
- /package/dist/{chunk-XXO5TI3B.js.map → chunk-32U3N7H5.js.map} +0 -0
- /package/dist/{chunk-KB4MFBF5.js.map → chunk-3RDYU3JS.js.map} +0 -0
- /package/dist/{chunk-57QXN2CS.js.map → chunk-4S3N6HFG.js.map} +0 -0
- /package/dist/{chunk-GE7Q7KXP.js.map → chunk-7A2QKUUA.js.map} +0 -0
- /package/dist/{chunk-3MNBW7R7.js.map → chunk-C4KKM62E.js.map} +0 -0
- /package/dist/{chunk-NKCW223V.js.map → chunk-CMN5AWAZ.js.map} +0 -0
- /package/dist/{chunk-JXHMAQYT.js.map → chunk-DOBJH4I6.js.map} +0 -0
- /package/dist/{chunk-TZDSNIRO.js.map → chunk-IFVFQRZ2.js.map} +0 -0
- /package/dist/{chunk-LQYTQCXM.js.map → chunk-JCLECECB.js.map} +0 -0
- /package/dist/{chunk-QDV6VAD4.js.map → chunk-LEG7XWS2.js.map} +0 -0
- /package/dist/{chunk-N5RGXWLQ.js.map → chunk-PUEAEQSN.js.map} +0 -0
- /package/dist/{chunk-JKCDQBDW.js.map → chunk-UXFOGILU.js.map} +0 -0
- /package/dist/{chunk-MVQN73GT.js.map → chunk-VTR3MNYF.js.map} +0 -0
- /package/dist/{chunk-KVFYTRMV.js.map → chunk-W25I7G6U.js.map} +0 -0
- /package/dist/{chunk-3R2UZV3U.js.map → chunk-X7EJF46S.js.map} +0 -0
- /package/dist/{chunk-54KDA6UK.js.map → chunk-XG4NAWAV.js.map} +0 -0
- /package/dist/{chunk-P2D2MM47.js.map → chunk-YROCXMCK.js.map} +0 -0
|
@@ -90,6 +90,87 @@ test("transcript files never surface from readAllMemories", async () => {
|
|
|
90
90
|
}
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
+
test("promoteWearableMemory flips status, merges evidence, and updates confidence", async () => {
|
|
94
|
+
const { storage, dir } = makeStorage();
|
|
95
|
+
try {
|
|
96
|
+
const id = await storage.writeMemory("fact", "Launch moved to September twelfth.", {
|
|
97
|
+
confidence: 0.6,
|
|
98
|
+
source: "wearable:limitless",
|
|
99
|
+
status: "pending_review",
|
|
100
|
+
structuredAttributes: { wearableSource: "limitless", trustScore: "0.600" },
|
|
101
|
+
});
|
|
102
|
+
const promoted = await storage.promoteWearableMemory(
|
|
103
|
+
id,
|
|
104
|
+
{ trustScore: "0.750", trustDecision: "promoted-by-corroboration" },
|
|
105
|
+
0.75,
|
|
106
|
+
);
|
|
107
|
+
assert.equal(promoted, true);
|
|
108
|
+
const memory = (await storage.readAllMemories()).find(
|
|
109
|
+
(entry) => entry.frontmatter.id === id,
|
|
110
|
+
);
|
|
111
|
+
assert.ok(memory);
|
|
112
|
+
assert.equal(memory.frontmatter.status, "active");
|
|
113
|
+
assert.equal(memory.frontmatter.confidence, 0.75);
|
|
114
|
+
assert.equal(memory.frontmatter.structuredAttributes?.trustScore, "0.750");
|
|
115
|
+
assert.equal(
|
|
116
|
+
memory.frontmatter.structuredAttributes?.trustDecision,
|
|
117
|
+
"promoted-by-corroboration",
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
// Already-active rows are not re-promoted (operator decisions win).
|
|
121
|
+
assert.equal(await storage.promoteWearableMemory(id, {}, 0.9), false);
|
|
122
|
+
assert.equal(await storage.promoteWearableMemory("missing-id", {}), false);
|
|
123
|
+
|
|
124
|
+
const found = await storage.findWearableMemoryByContent(
|
|
125
|
+
"Launch moved to September twelfth.",
|
|
126
|
+
);
|
|
127
|
+
assert.equal(found?.id, id);
|
|
128
|
+
} finally {
|
|
129
|
+
rmSync(dir, { recursive: true, force: true });
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("demoteWearableMemory rejects only pending rows and merges evidence", async () => {
|
|
134
|
+
const { storage, dir } = makeStorage();
|
|
135
|
+
try {
|
|
136
|
+
const id = await storage.writeMemory("fact", "Vendor call moved the launch again.", {
|
|
137
|
+
confidence: 0.5,
|
|
138
|
+
source: "wearable:limitless",
|
|
139
|
+
status: "pending_review",
|
|
140
|
+
structuredAttributes: { wearableSource: "limitless", trustScore: "0.500" },
|
|
141
|
+
});
|
|
142
|
+
const demoted = await storage.demoteWearableMemory(id, {
|
|
143
|
+
trustScore: "0.310",
|
|
144
|
+
trustDecision: "demoted-by-rejection",
|
|
145
|
+
judgeVerdict: "reject",
|
|
146
|
+
});
|
|
147
|
+
assert.equal(demoted, true);
|
|
148
|
+
const memory = (await storage.readAllMemories()).find(
|
|
149
|
+
(entry) => entry.frontmatter.id === id,
|
|
150
|
+
);
|
|
151
|
+
assert.ok(memory);
|
|
152
|
+
assert.equal(memory.frontmatter.status, "rejected");
|
|
153
|
+
assert.equal(memory.frontmatter.structuredAttributes?.trustDecision, "demoted-by-rejection");
|
|
154
|
+
assert.equal(memory.frontmatter.structuredAttributes?.wearableSource, "limitless");
|
|
155
|
+
|
|
156
|
+
// Rejected rows are terminal for the wearable pipeline: no
|
|
157
|
+
// re-demote, no promote (operator surfaces own them from here).
|
|
158
|
+
assert.equal(await storage.demoteWearableMemory(id, {}), false);
|
|
159
|
+
assert.equal(await storage.promoteWearableMemory(id, {}, 0.9), false);
|
|
160
|
+
assert.equal(await storage.demoteWearableMemory("missing-id", {}), false);
|
|
161
|
+
|
|
162
|
+
// Active rows are never auto-demoted.
|
|
163
|
+
const activeId = await storage.writeMemory("fact", "Approved active row.", {
|
|
164
|
+
confidence: 0.9,
|
|
165
|
+
source: "wearable:limitless",
|
|
166
|
+
status: "active",
|
|
167
|
+
});
|
|
168
|
+
assert.equal(await storage.demoteWearableMemory(activeId, {}), false);
|
|
169
|
+
} finally {
|
|
170
|
+
rmSync(dir, { recursive: true, force: true });
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
93
174
|
test("non-transcript files in the wearables tree are ignored by listing", async () => {
|
|
94
175
|
const { storage, dir } = makeStorage();
|
|
95
176
|
try {
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
computeTrustScore,
|
|
6
|
+
decideSmart,
|
|
7
|
+
findCorroboration,
|
|
8
|
+
tokenizeDayBody,
|
|
9
|
+
TRUST_CROSS_SOURCE_BOOST,
|
|
10
|
+
TRUST_JUDGE_ACCEPT_BOOST,
|
|
11
|
+
TRUST_SUPPORTING_MEMORY_BOOST,
|
|
12
|
+
} from "./trust.js";
|
|
13
|
+
|
|
14
|
+
const NO_EVIDENCE = { corroboratedBySources: [] };
|
|
15
|
+
|
|
16
|
+
test("trust = confidence x sourceTrust, clamped to [0,1]", () => {
|
|
17
|
+
assert.ok(
|
|
18
|
+
Math.abs(
|
|
19
|
+
computeTrustScore({ extractionConfidence: 0.9, sourceTrust: 0.8, evidence: NO_EVIDENCE }) -
|
|
20
|
+
0.72,
|
|
21
|
+
) < 1e-9,
|
|
22
|
+
);
|
|
23
|
+
// Missing confidence defaults to 0.7.
|
|
24
|
+
assert.equal(
|
|
25
|
+
computeTrustScore({ extractionConfidence: undefined, sourceTrust: 1, evidence: NO_EVIDENCE }),
|
|
26
|
+
0.7,
|
|
27
|
+
);
|
|
28
|
+
// Boosts never push past 1.
|
|
29
|
+
assert.equal(
|
|
30
|
+
computeTrustScore({
|
|
31
|
+
extractionConfidence: 1,
|
|
32
|
+
sourceTrust: 1,
|
|
33
|
+
judgeVerdict: "accept",
|
|
34
|
+
evidence: { corroboratedBySources: ["bee"], supportingMemoryId: "m1" },
|
|
35
|
+
}),
|
|
36
|
+
1,
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("judge accept and corroboration boosts stack as documented", () => {
|
|
41
|
+
const base = computeTrustScore({
|
|
42
|
+
extractionConfidence: 0.5,
|
|
43
|
+
sourceTrust: 0.8,
|
|
44
|
+
evidence: NO_EVIDENCE,
|
|
45
|
+
});
|
|
46
|
+
const judged = computeTrustScore({
|
|
47
|
+
extractionConfidence: 0.5,
|
|
48
|
+
sourceTrust: 0.8,
|
|
49
|
+
judgeVerdict: "accept",
|
|
50
|
+
evidence: NO_EVIDENCE,
|
|
51
|
+
});
|
|
52
|
+
const corroborated = computeTrustScore({
|
|
53
|
+
extractionConfidence: 0.5,
|
|
54
|
+
sourceTrust: 0.8,
|
|
55
|
+
judgeVerdict: "accept",
|
|
56
|
+
evidence: { corroboratedBySources: ["omi"], supportingMemoryId: "m1" },
|
|
57
|
+
});
|
|
58
|
+
assert.ok(Math.abs(judged - base - TRUST_JUDGE_ACCEPT_BOOST) < 1e-9);
|
|
59
|
+
assert.ok(
|
|
60
|
+
Math.abs(
|
|
61
|
+
corroborated -
|
|
62
|
+
judged -
|
|
63
|
+
TRUST_CROSS_SOURCE_BOOST -
|
|
64
|
+
TRUST_SUPPORTING_MEMORY_BOOST,
|
|
65
|
+
) < 1e-9,
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("decideSmart: judge verdicts short-circuit; trust bands otherwise", () => {
|
|
70
|
+
const thresholds = { autoApproveTrust: 0.7, reviewTrust: 0.45 };
|
|
71
|
+
assert.equal(decideSmart(0.99, "reject", thresholds).outcome, "drop");
|
|
72
|
+
assert.equal(decideSmart(0.99, "defer", thresholds).outcome, "review");
|
|
73
|
+
assert.equal(decideSmart(0.7, "accept", thresholds).outcome, "active");
|
|
74
|
+
assert.equal(decideSmart(0.7, undefined, thresholds).outcome, "active");
|
|
75
|
+
assert.equal(decideSmart(0.5, undefined, thresholds).outcome, "review");
|
|
76
|
+
assert.equal(decideSmart(0.2, undefined, thresholds).outcome, "drop");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("cross-source corroboration requires high token coverage", () => {
|
|
80
|
+
const beeDay = tokenizeDayBody(
|
|
81
|
+
"We agreed the product launch moves to September twelfth after the vendor call.",
|
|
82
|
+
);
|
|
83
|
+
const context = {
|
|
84
|
+
otherSourceDayTokens: new Map([["bee", beeDay]]),
|
|
85
|
+
existingMemories: [],
|
|
86
|
+
};
|
|
87
|
+
const corroborated = findCorroboration(
|
|
88
|
+
"Launch moved to September twelfth after vendor call.",
|
|
89
|
+
context,
|
|
90
|
+
);
|
|
91
|
+
assert.deepEqual(corroborated.corroboratedBySources, ["bee"]);
|
|
92
|
+
|
|
93
|
+
const unrelated = findCorroboration(
|
|
94
|
+
"Dentist appointment is on Thursday afternoon downtown.",
|
|
95
|
+
context,
|
|
96
|
+
);
|
|
97
|
+
assert.deepEqual(unrelated.corroboratedBySources, []);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("existing-memory support sets supportingMemoryId", () => {
|
|
101
|
+
const context = {
|
|
102
|
+
otherSourceDayTokens: new Map<string, Set<string>>(),
|
|
103
|
+
existingMemories: [
|
|
104
|
+
{ id: "fact-1", content: "User prefers the aisle seat on long flights." },
|
|
105
|
+
{ id: "fact-2", content: "The launch moved to September twelfth, vendor informed." },
|
|
106
|
+
],
|
|
107
|
+
};
|
|
108
|
+
const supported = findCorroboration(
|
|
109
|
+
"Launch moved to September twelfth and the vendor was informed.",
|
|
110
|
+
context,
|
|
111
|
+
);
|
|
112
|
+
assert.equal(supported.supportingMemoryId, "fact-2");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("very short facts never corroborate (too little signal)", () => {
|
|
116
|
+
const context = {
|
|
117
|
+
otherSourceDayTokens: new Map([["bee", tokenizeDayBody("yes ok sure fine")]]),
|
|
118
|
+
existingMemories: [{ id: "m", content: "yes ok sure fine" }],
|
|
119
|
+
};
|
|
120
|
+
const evidence = findCorroboration("yes ok", context);
|
|
121
|
+
assert.deepEqual(evidence.corroboratedBySources, []);
|
|
122
|
+
assert.equal(evidence.supportingMemoryId, undefined);
|
|
123
|
+
});
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wearable memory trust scoring — the "smart" memoryMode engine.
|
|
3
|
+
*
|
|
4
|
+
* Grounded in how production memory systems handle noisy ingest:
|
|
5
|
+
*
|
|
6
|
+
* - **LLM-as-judge gating** (Remnic's own extraction judge,
|
|
7
|
+
* `judgeFactDurability`): an LLM verdict on durability decides
|
|
8
|
+
* accept / defer / reject before anything persists.
|
|
9
|
+
* - **Provenance priors**: each source carries a configurable trust
|
|
10
|
+
* prior (`sourceTrust`) — a noisy ASR channel contributes less
|
|
11
|
+
* confidence than a clean one (provenance-weighted fusion).
|
|
12
|
+
* - **Corroboration**: independent agreement raises trust. A fact
|
|
13
|
+
* supported by a second wearable that recorded the same day, or by
|
|
14
|
+
* an existing active memory, is far less likely to be an ASR
|
|
15
|
+
* artifact (ensemble agreement / self-consistency).
|
|
16
|
+
*
|
|
17
|
+
* The combined score maps to a three-way decision:
|
|
18
|
+
*
|
|
19
|
+
* trust >= autoApproveTrust -> written ACTIVE
|
|
20
|
+
* trust >= reviewTrust -> written pending_review
|
|
21
|
+
* below -> dropped
|
|
22
|
+
*
|
|
23
|
+
* with the judge able to short-circuit (reject -> drop,
|
|
24
|
+
* defer -> pending_review regardless of score). The score, verdict,
|
|
25
|
+
* and corroboration evidence persist on the memory (confidence +
|
|
26
|
+
* structuredAttributes + verificationState), so Remnic's existing
|
|
27
|
+
* trust machinery — memory-worth outcome counters, pattern
|
|
28
|
+
* reinforcement, temporal supersession, contradiction scans — keeps
|
|
29
|
+
* calibrating these memories after they land.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import {
|
|
33
|
+
countRecallTokenOverlap,
|
|
34
|
+
normalizeRecallTokens,
|
|
35
|
+
} from "../recall-tokenization.js";
|
|
36
|
+
|
|
37
|
+
/** Judge adjustments and corroboration boosts (documented, fixed). */
|
|
38
|
+
export const TRUST_JUDGE_ACCEPT_BOOST = 0.15;
|
|
39
|
+
export const TRUST_CROSS_SOURCE_BOOST = 0.15;
|
|
40
|
+
export const TRUST_SUPPORTING_MEMORY_BOOST = 0.1;
|
|
41
|
+
|
|
42
|
+
/** Minimum distinct tokens before similarity is meaningful. */
|
|
43
|
+
const MIN_FACT_TOKENS = 4;
|
|
44
|
+
/** Fact-token coverage required to call a day-text corroborating. */
|
|
45
|
+
const CROSS_SOURCE_COVERAGE = 0.6;
|
|
46
|
+
/** Fact-token coverage required to call an existing memory supporting. */
|
|
47
|
+
const MEMORY_SUPPORT_COVERAGE = 0.7;
|
|
48
|
+
/** Bound on existing memories scanned per fact batch. */
|
|
49
|
+
const MAX_MEMORIES_SCANNED = 5_000;
|
|
50
|
+
|
|
51
|
+
export interface TrustEvidence {
|
|
52
|
+
/** Other-source ids whose same-day content corroborates the fact. */
|
|
53
|
+
corroboratedBySources: string[];
|
|
54
|
+
/** Id of an existing active memory whose content supports the fact. */
|
|
55
|
+
supportingMemoryId?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface TrustScoreInput {
|
|
59
|
+
/** Extraction confidence for the fact (defaults to 0.7 when absent). */
|
|
60
|
+
extractionConfidence: number | undefined;
|
|
61
|
+
/** Per-source trust prior from config (0..1). */
|
|
62
|
+
sourceTrust: number;
|
|
63
|
+
/** Judge verdict kind when a judge ran; undefined when unavailable. */
|
|
64
|
+
judgeVerdict?: "accept" | "reject" | "defer";
|
|
65
|
+
evidence: TrustEvidence;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function computeTrustScore(input: TrustScoreInput): number {
|
|
69
|
+
const confidence =
|
|
70
|
+
typeof input.extractionConfidence === "number" &&
|
|
71
|
+
Number.isFinite(input.extractionConfidence)
|
|
72
|
+
? Math.min(1, Math.max(0, input.extractionConfidence))
|
|
73
|
+
: 0.7;
|
|
74
|
+
let trust = confidence * Math.min(1, Math.max(0, input.sourceTrust));
|
|
75
|
+
if (input.judgeVerdict === "accept") trust += TRUST_JUDGE_ACCEPT_BOOST;
|
|
76
|
+
if (input.evidence.corroboratedBySources.length > 0) {
|
|
77
|
+
trust += TRUST_CROSS_SOURCE_BOOST;
|
|
78
|
+
}
|
|
79
|
+
if (input.evidence.supportingMemoryId !== undefined) {
|
|
80
|
+
trust += TRUST_SUPPORTING_MEMORY_BOOST;
|
|
81
|
+
}
|
|
82
|
+
return Math.min(1, Math.max(0, trust));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface CorroborationContext {
|
|
86
|
+
/**
|
|
87
|
+
* Same-day transcript bodies from OTHER sources, keyed by source id.
|
|
88
|
+
* Pre-tokenized once per sync (day bodies are large).
|
|
89
|
+
*/
|
|
90
|
+
otherSourceDayTokens: Map<string, Set<string>>;
|
|
91
|
+
/** Existing active memories: id + content. */
|
|
92
|
+
existingMemories: Array<{ id: string; content: string }>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Tokenize a day body once for repeated per-fact coverage checks. */
|
|
96
|
+
export function tokenizeDayBody(body: string): Set<string> {
|
|
97
|
+
return new Set(normalizeRecallTokens(body));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Find corroborating evidence for one fact. Deterministic and local:
|
|
102
|
+
* token-coverage similarity via the shared recall tokenizer — no LLM
|
|
103
|
+
* cost on the corroboration path.
|
|
104
|
+
*/
|
|
105
|
+
export function findCorroboration(
|
|
106
|
+
factText: string,
|
|
107
|
+
context: CorroborationContext,
|
|
108
|
+
): TrustEvidence {
|
|
109
|
+
const factTokens = normalizeRecallTokens(factText);
|
|
110
|
+
const evidence: TrustEvidence = { corroboratedBySources: [] };
|
|
111
|
+
if (factTokens.length < MIN_FACT_TOKENS) return evidence;
|
|
112
|
+
const factTokenSet = new Set(factTokens);
|
|
113
|
+
|
|
114
|
+
for (const [sourceId, dayTokens] of context.otherSourceDayTokens) {
|
|
115
|
+
let matches = 0;
|
|
116
|
+
for (const token of factTokenSet) {
|
|
117
|
+
if (dayTokens.has(token)) matches += 1;
|
|
118
|
+
}
|
|
119
|
+
if (matches / factTokenSet.size >= CROSS_SOURCE_COVERAGE) {
|
|
120
|
+
evidence.corroboratedBySources.push(sourceId);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
evidence.corroboratedBySources.sort();
|
|
124
|
+
|
|
125
|
+
let scanned = 0;
|
|
126
|
+
for (const memory of context.existingMemories) {
|
|
127
|
+
if (scanned >= MAX_MEMORIES_SCANNED) break;
|
|
128
|
+
scanned += 1;
|
|
129
|
+
const matches = countRecallTokenOverlap(factTokenSet, memory.content);
|
|
130
|
+
if (matches / factTokenSet.size >= MEMORY_SUPPORT_COVERAGE) {
|
|
131
|
+
evidence.supportingMemoryId = memory.id;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return evidence;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface SmartDecision {
|
|
139
|
+
outcome: "active" | "review" | "drop";
|
|
140
|
+
reason:
|
|
141
|
+
| "judge-rejected"
|
|
142
|
+
| "judge-deferred"
|
|
143
|
+
| "auto-approved"
|
|
144
|
+
| "queued-for-review"
|
|
145
|
+
| "below-trust";
|
|
146
|
+
trust: number;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Map judge verdict + trust score to the smart-mode decision. */
|
|
150
|
+
export function decideSmart(
|
|
151
|
+
trust: number,
|
|
152
|
+
judgeVerdict: "accept" | "reject" | "defer" | undefined,
|
|
153
|
+
thresholds: { autoApproveTrust: number; reviewTrust: number },
|
|
154
|
+
): SmartDecision {
|
|
155
|
+
if (judgeVerdict === "reject") {
|
|
156
|
+
return { outcome: "drop", reason: "judge-rejected", trust };
|
|
157
|
+
}
|
|
158
|
+
if (judgeVerdict === "defer") {
|
|
159
|
+
return { outcome: "review", reason: "judge-deferred", trust };
|
|
160
|
+
}
|
|
161
|
+
if (trust >= thresholds.autoApproveTrust) {
|
|
162
|
+
return { outcome: "active", reason: "auto-approved", trust };
|
|
163
|
+
}
|
|
164
|
+
if (trust >= thresholds.reviewTrust) {
|
|
165
|
+
return { outcome: "review", reason: "queued-for-review", trust };
|
|
166
|
+
}
|
|
167
|
+
return { outcome: "drop", reason: "below-trust", trust };
|
|
168
|
+
}
|
package/src/wearables/types.ts
CHANGED
|
@@ -143,32 +143,59 @@ export interface WearableSourceSettings {
|
|
|
143
143
|
userId?: string;
|
|
144
144
|
/**
|
|
145
145
|
* Memory creation mode (trust gate):
|
|
146
|
+
* - "smart": DEFAULT. Fully automated trust pipeline: the
|
|
147
|
+
* extraction judge (LLM-as-judge) plus a per-source
|
|
148
|
+
* trust prior, cross-device corroboration, and
|
|
149
|
+
* existing-memory support combine into a trust score.
|
|
150
|
+
* High-trust facts are written active; borderline facts
|
|
151
|
+
* go to the review queue; low-trust/judge-rejected
|
|
152
|
+
* facts are dropped. See wearables/trust.ts.
|
|
146
153
|
* - "off": transcripts only; never create memories.
|
|
147
|
-
* - "review":
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
* - "auto":
|
|
151
|
-
*
|
|
154
|
+
* - "review": every extracted candidate is written
|
|
155
|
+
* "pending_review" — nothing enters active recall
|
|
156
|
+
* without operator approval.
|
|
157
|
+
* - "auto": deterministic gates only; survivors written active
|
|
158
|
+
* (no judge, no trust scoring).
|
|
152
159
|
*/
|
|
153
160
|
memoryMode: WearableMemoryMode;
|
|
161
|
+
/**
|
|
162
|
+
* Trust prior for this source's transcription quality (0..1).
|
|
163
|
+
* Multiplies extraction confidence in smart mode — lower it for a
|
|
164
|
+
* device that mis-transcribes often. Default 0.8.
|
|
165
|
+
*/
|
|
166
|
+
sourceTrust: number;
|
|
167
|
+
/** Smart mode: trust at/above which facts are written active. */
|
|
168
|
+
autoApproveTrust: number;
|
|
169
|
+
/**
|
|
170
|
+
* Smart mode: trust at/above which borderline facts are queued for
|
|
171
|
+
* review instead of dropped. Must be below autoApproveTrust.
|
|
172
|
+
*/
|
|
173
|
+
reviewTrust: number;
|
|
154
174
|
/** Drop extracted facts below this confidence (0–1). */
|
|
155
175
|
minConfidence: number;
|
|
156
176
|
/** Drop extracted facts scored below this importance level. */
|
|
157
177
|
minImportance: ImportanceLevel;
|
|
158
178
|
/**
|
|
159
|
-
* Cap on memories created per source per day. 0
|
|
179
|
+
* Cap on memories created per source per day. 0 (the default)
|
|
180
|
+
* disables the cap — the smart trust pipeline is the quality gate,
|
|
181
|
+
* and a count cap would drop real memories on busy days.
|
|
160
182
|
*/
|
|
161
183
|
maxMemoriesPerDay: number;
|
|
162
184
|
/**
|
|
163
185
|
* Import provider-extracted memories (Bee facts / Omi memories).
|
|
164
|
-
* "
|
|
186
|
+
* - "smart": DEFAULT. Same trust pipeline as transcript facts
|
|
187
|
+
* (judge + trust prior + corroboration) with a slightly reduced
|
|
188
|
+
* prior — provider extraction quality is outside Remnic's
|
|
189
|
+
* control.
|
|
190
|
+
* - "review": always pending_review.
|
|
191
|
+
* - "off": skip.
|
|
165
192
|
*/
|
|
166
|
-
importNativeMemories: "off" | "review";
|
|
193
|
+
importNativeMemories: "off" | "review" | "smart";
|
|
167
194
|
/** Transcript cleanup toggles. */
|
|
168
195
|
cleanup: WearableCleanupSettings;
|
|
169
196
|
}
|
|
170
197
|
|
|
171
|
-
export type WearableMemoryMode = "off" | "review" | "auto";
|
|
198
|
+
export type WearableMemoryMode = "off" | "review" | "auto" | "smart";
|
|
172
199
|
|
|
173
200
|
export interface WearableCleanupSettings {
|
|
174
201
|
/** Merge consecutive segments from the same speaker. */
|
|
@@ -225,6 +252,23 @@ export interface WearablesConfig {
|
|
|
225
252
|
* Default false.
|
|
226
253
|
*/
|
|
227
254
|
digestEnabled: boolean;
|
|
255
|
+
/**
|
|
256
|
+
* Periodically refresh transcripts in-process (long-lived hosts).
|
|
257
|
+
* Every tick re-syncs `autoSyncDays` ending today — existing day
|
|
258
|
+
* files included, so the current day keeps growing while the
|
|
259
|
+
* wearable records. Default true.
|
|
260
|
+
*/
|
|
261
|
+
autoSyncEnabled: boolean;
|
|
262
|
+
/** Minutes between auto-sync ticks (1-1440). Default 15. */
|
|
263
|
+
autoSyncIntervalMinutes: number;
|
|
264
|
+
/** Rolling window (days ending today) per tick (1-90). Default 2. */
|
|
265
|
+
autoSyncDays: number;
|
|
266
|
+
/**
|
|
267
|
+
* Once-per-local-day deep pass window (days, 0-90) picking up late
|
|
268
|
+
* uploads and provider re-processing. 0 disables; otherwise must be
|
|
269
|
+
* >= autoSyncDays. Default 7.
|
|
270
|
+
*/
|
|
271
|
+
autoSyncDeepDays: number;
|
|
228
272
|
/** Correction rules from config (merged with CLI-managed rules). */
|
|
229
273
|
corrections: WearableCorrectionRule[];
|
|
230
274
|
/** Per-source settings, keyed by connector id. */
|
|
@@ -244,6 +288,10 @@ export interface WearableSyncSummary {
|
|
|
244
288
|
/** Day files written (skipped-unchanged days are not listed). */
|
|
245
289
|
transcriptsWritten: string[];
|
|
246
290
|
memoriesCreated: number;
|
|
291
|
+
/** Earlier borderline writes promoted to active by new evidence. */
|
|
292
|
+
memoriesPromoted: number;
|
|
293
|
+
/** Earlier pending writes retired by a fresh judge-reject verdict. */
|
|
294
|
+
memoriesDemoted: number;
|
|
247
295
|
memoriesSkipped: number;
|
|
248
296
|
nativeMemoriesImported: number;
|
|
249
297
|
/** Non-fatal warnings surfaced to the operator. */
|