@cachly-dev/mcp-server 0.10.62 → 0.10.65

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.
@@ -23,10 +23,14 @@ export interface BenchMetrics {
23
23
  ndcgAt5: number;
24
24
  }
25
25
  export interface BenchResult {
26
+ /** Flat-file memory simulation: naive term-overlap, no IDF, no quality signal. */
27
+ flatfile: BenchMetrics;
26
28
  baseline: BenchMetrics;
27
29
  cachly: BenchMetrics;
28
- /** Relative lift per metric, e.g. { mrr: 0.23 } = +23%. */
30
+ /** Relative lift of cachly vs the BM25 baseline. */
29
31
  lift: BenchMetrics;
32
+ /** Relative lift of cachly vs a flat-file memory (the head-to-head that matters). */
33
+ liftVsFlatfile: BenchMetrics;
30
34
  queryCount: number;
31
35
  corpusSize: number;
32
36
  }
@@ -85,6 +85,32 @@ function ndcgAtK(ranked, relevant, k) {
85
85
  }
86
86
  return idcg === 0 ? 0 : dcg / idcg;
87
87
  }
88
+ /**
89
+ * Simulates how a flat-file memory (e.g. an LLM reading a `/memories` directory)
90
+ * actually surfaces knowledge: it has NO ranking engine. Practical retrieval is
91
+ * naive lexical overlap — count how many distinct query terms appear in the file's
92
+ * text — with NO inverse-document-frequency, NO length normalization, and crucially
93
+ * NO quality signal (a proven fix and a failed attempt are just text). Ties break by
94
+ * recency, mimicking "most recently edited note first". This is a fair, and honestly
95
+ * weaker, stand-in for "Claude reads its own memory files".
96
+ */
97
+ function flatFileRank(lessons, query) {
98
+ const qTerms = new Set(query.toLowerCase().replace(/[^a-z0-9\s]/g, ' ').split(/\s+/).filter(t => t.length >= 3));
99
+ const scored = lessons.map(l => {
100
+ const blob = [l.topic, l.what_worked, l.what_failed ?? '', l.context ?? '', (l.tags ?? []).join(' ')]
101
+ .join(' ').toLowerCase();
102
+ let overlap = 0;
103
+ for (const t of qTerms)
104
+ if (blob.includes(t))
105
+ overlap++;
106
+ const recency = l.ts ? new Date(l.ts).getTime() : 0;
107
+ return { topic: l.topic, overlap, recency };
108
+ });
109
+ return scored
110
+ .filter(s => s.overlap > 0)
111
+ .sort((a, b) => (b.overlap - a.overlap) || (b.recency - a.recency))
112
+ .map(s => s.topic);
113
+ }
88
114
  const matchTopic = (m) => m.key.replace(LESSON_PREFIX, '');
89
115
  function mean(xs) {
90
116
  return xs.length === 0 ? 0 : xs.reduce((a, b) => a + b, 0) / xs.length;
@@ -110,48 +136,63 @@ function scoreRanking(ranked, relevant) {
110
136
  /** Run the benchmark over the fixture corpus. Pure-ish: no network, no real Redis. */
111
137
  export async function runBenchmark() {
112
138
  const redis = indexCorpus(BENCH_LESSONS);
139
+ const flatfileRows = [];
113
140
  const baselineRows = [];
114
141
  const cachlyRows = [];
115
142
  for (const q of BENCH_QUERIES) {
116
143
  const relevant = new Set(q.relevant);
117
- // Same candidate set for both rankers — isolates the ranking contribution.
144
+ // BM25 baseline + cachly share the same candidate set — isolates ranking quality.
118
145
  const matches = await keywordSearch(redis, [`${LESSON_PREFIX}*`], q.query, 10);
119
146
  const baselineRanked = matches.map(matchTopic);
120
147
  const cachlyRanked = rerankByQuality(matches).map(matchTopic);
148
+ // Flat-file memory sees the whole corpus but has no ranking engine.
149
+ const flatfileRanked = flatFileRank(BENCH_LESSONS, q.query);
150
+ flatfileRows.push(scoreRanking(flatfileRanked, relevant));
121
151
  baselineRows.push(scoreRanking(baselineRanked, relevant));
122
152
  cachlyRows.push(scoreRanking(cachlyRanked, relevant));
123
153
  }
154
+ const flatfile = aggregate(flatfileRows);
124
155
  const baseline = aggregate(baselineRows);
125
156
  const cachly = aggregate(cachlyRows);
126
157
  const liftOf = (b, c) => (b === 0 ? (c > 0 ? 1 : 0) : (c - b) / b);
127
- const lift = {
128
- precisionAt1: liftOf(baseline.precisionAt1, cachly.precisionAt1),
129
- precisionAt3: liftOf(baseline.precisionAt3, cachly.precisionAt3),
130
- recallAt3: liftOf(baseline.recallAt3, cachly.recallAt3),
131
- mrr: liftOf(baseline.mrr, cachly.mrr),
132
- ndcgAt5: liftOf(baseline.ndcgAt5, cachly.ndcgAt5),
158
+ const liftBetween = (from) => ({
159
+ precisionAt1: liftOf(from.precisionAt1, cachly.precisionAt1),
160
+ precisionAt3: liftOf(from.precisionAt3, cachly.precisionAt3),
161
+ recallAt3: liftOf(from.recallAt3, cachly.recallAt3),
162
+ mrr: liftOf(from.mrr, cachly.mrr),
163
+ ndcgAt5: liftOf(from.ndcgAt5, cachly.ndcgAt5),
164
+ });
165
+ return {
166
+ flatfile, baseline, cachly,
167
+ lift: liftBetween(baseline),
168
+ liftVsFlatfile: liftBetween(flatfile),
169
+ queryCount: BENCH_QUERIES.length,
170
+ corpusSize: BENCH_LESSONS.length,
133
171
  };
134
- return { baseline, cachly, lift, queryCount: BENCH_QUERIES.length, corpusSize: BENCH_LESSONS.length };
135
172
  }
136
173
  // ── Reporting ──────────────────────────────────────────────────────────────────
137
174
  const pct = (x) => `${(x * 100).toFixed(1)}%`;
138
175
  const signedPct = (x) => `${x >= 0 ? '+' : ''}${(x * 100).toFixed(1)}%`;
139
176
  export function formatReport(r) {
140
- const row = (label, b, c, l) => ` ${label.padEnd(14)} ${pct(b).padStart(8)} → ${pct(c).padStart(8)} ${signedPct(l).padStart(8)}`;
177
+ const row = (label, f, b, c, lf) => ` ${label.padEnd(12)} ${pct(f).padStart(8)} ${pct(b).padStart(8)} ${pct(c).padStart(8)} ${signedPct(lf).padStart(8)}`;
141
178
  return [
142
179
  '',
143
- '🧠 Cachly-Bench — recall quality (BM25 baseline vs quality-aware rerank)',
144
- '────────────────────────────────────────────────────────────────────────',
180
+ '🧠 Cachly-Bench — recall quality head-to-head',
181
+ '──────────────────────────────────────────────────────────────────────────',
145
182
  ` corpus: ${r.corpusSize} lessons · queries: ${r.queryCount}`,
183
+ ' flat-file = naive term-overlap, no quality signal (≈ LLM reading memory files)',
184
+ ' baseline = raw BM25+ keyword ranking',
185
+ ' cachly = BM25+ followed by quality-aware reranking',
146
186
  '',
147
- ` ${'metric'.padEnd(14)} ${'baseline'.padStart(8)} ${'cachly'.padStart(8)} ${'lift'.padStart(8)}`,
148
- row('Precision@1', r.baseline.precisionAt1, r.cachly.precisionAt1, r.lift.precisionAt1),
149
- row('Precision@3', r.baseline.precisionAt3, r.cachly.precisionAt3, r.lift.precisionAt3),
150
- row('Recall@3', r.baseline.recallAt3, r.cachly.recallAt3, r.lift.recallAt3),
151
- row('MRR', r.baseline.mrr, r.cachly.mrr, r.lift.mrr),
152
- row('nDCG@5', r.baseline.ndcgAt5, r.cachly.ndcgAt5, r.lift.ndcgAt5),
153
- '────────────────────────────────────────────────────────────────────────',
154
- ` Headline: MRR ${signedPct(r.lift.mrr)} · Precision@1 ${signedPct(r.lift.precisionAt1)}`,
187
+ ` ${'metric'.padEnd(12)} ${'flatfile'.padStart(8)} ${'baseline'.padStart(8)} ${'cachly'.padStart(8)} ${'vs flat'.padStart(8)}`,
188
+ row('Precision@1', r.flatfile.precisionAt1, r.baseline.precisionAt1, r.cachly.precisionAt1, r.liftVsFlatfile.precisionAt1),
189
+ row('Precision@3', r.flatfile.precisionAt3, r.baseline.precisionAt3, r.cachly.precisionAt3, r.liftVsFlatfile.precisionAt3),
190
+ row('Recall@3', r.flatfile.recallAt3, r.baseline.recallAt3, r.cachly.recallAt3, r.liftVsFlatfile.recallAt3),
191
+ row('MRR', r.flatfile.mrr, r.baseline.mrr, r.cachly.mrr, r.liftVsFlatfile.mrr),
192
+ row('nDCG@5', r.flatfile.ndcgAt5, r.baseline.ndcgAt5, r.cachly.ndcgAt5, r.liftVsFlatfile.ndcgAt5),
193
+ '──────────────────────────────────────────────────────────────────────────',
194
+ ` vs BM25 baseline : MRR ${signedPct(r.lift.mrr)} · Precision@1 ${signedPct(r.lift.precisionAt1)}`,
195
+ ` vs flat-file mem : MRR ${signedPct(r.liftVsFlatfile.mrr)} · Precision@1 ${signedPct(r.liftVsFlatfile.precisionAt1)}`,
155
196
  '',
156
197
  ].join('\n');
157
198
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cachly-bench.js","sourceRoot":"","sources":["../../../src/bench/cachly-bench.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cachly-bench.js","sourceRoot":"","sources":["../../../src/bench/cachly-bench.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,19 @@
1
1
  import { execSync } from 'node:child_process';
2
2
  import { calculateConfidence, confidenceBadge, STRUCTURED_TEMPLATES, CONFIDENCE_WARN_VALUE, CONFIDENCE_STALE_VALUE, CONFIDENCE_WARN_DAYS } from '../confidence.js';
3
3
  import { ckgSlug, extractProblemConcept, ckgUpsertNode, ckgUpdateEdge, ckgUpsertPersonNode, ckgUpsertFileNode } from '../ckg.js';
4
- import { safeJsonParse } from '../utils.js';
4
+ import { safeJsonParse, scanKeys } from '../utils.js';
5
5
  import { keywordSearch, tokenize, splitMultiQuery, levenshtein, indexVocab as _indexVocab } from '../search.js';
6
6
  import { rerankByQuality } from '../rerank.js';
7
7
  import { computeEmbedding, hasEmbedProvider } from '../embeddings.js';
8
8
  // ── Changelog (shown once per version in session_start) ──────────────────────
9
- const MCP_VERSION = '0.10.62';
9
+ const MCP_VERSION = '0.10.65';
10
10
  const WHATS_NEW = {
11
+ '0.10.64': [
12
+ `📈 **The three decisive metrics, now measurable**`,
13
+ ` ⏱️ \`brain_metrics()\` — time-to-first-recall, recall-lift, team-knowledge-reuse in one view`,
14
+ ` 👥 Cross-author reuse tracked: recall a teammate's lesson → counted + surfaced inline`,
15
+ ` 🛡️ Stability: scans now capped + timed out (a huge keyspace can't hang the agent)`,
16
+ ],
11
17
  '0.10.61': [
12
18
  `🎯 **Phase 3C: 100 MCP tools milestone — zero-setup knowledge graph**`,
13
19
  ` 🔄 \`brain_from_git\` now auto-builds Person+File nodes from git history (zero setup!)`,
@@ -69,7 +75,7 @@ export const BRAIN_TOOL_NAMES = new Set([
69
75
  'learn_from_attempts', 'recall_best_solution', 'smart_recall',
70
76
  'session_start', 'session_end', 'session_ping', 'session_handoff', 'auto_learn_session',
71
77
  'brain_who_knows', 'brain_file_map', 'team_expertise_map',
72
- 'skill_gaps', 'brain_coverage',
78
+ 'skill_gaps', 'brain_coverage', 'brain_metrics',
73
79
  ]);
74
80
  export async function handleBrainTool(name, args, getConnection, apiFetch) {
75
81
  switch (name) {
@@ -201,6 +207,9 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
201
207
  version: 3,
202
208
  };
203
209
  const lesson = JSON.stringify(lessonObj);
210
+ // Metric 1 (time-to-first-recall): mark the moment the Brain first gained
211
+ // knowledge. SET NX so only the very first learn wins. Fire-and-forget.
212
+ redis.set(`cachly:stats:born_at:${instance_id}`, ts, 'EX', 365 * 86400, 'NX').catch(() => { });
204
213
  // Always append to the history list (audit log); keep last 100 entries, 90-day TTL
205
214
  const listKey = `cachly:lessons:${topic}`;
206
215
  await redis.rpush(listKey, lesson);
@@ -510,7 +519,7 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
510
519
  return `🔍 **Partial matches for \`${topic}\`:**\n\n${results.join('\n\n')}`;
511
520
  }
512
521
  case 'smart_recall': {
513
- const { instance_id, query, threshold = 0.78, } = args;
522
+ const { instance_id, query, threshold = 0.78, author: requester = '', } = args;
514
523
  const redis = await getConnection(instance_id);
515
524
  // ── Layer 1: Keyword search across ALL brain data (always works, no embedding) ──
516
525
  const rawMatches = await keywordSearch(redis, ['cachly:ctx:*', 'cachly:lesson:best:*', 'cachly:idx:*'], query, 10);
@@ -519,6 +528,7 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
519
528
  const kwMatches = rerankByQuality(rawMatches);
520
529
  const savedHere = [];
521
530
  const lessonMatches = kwMatches.filter(m => m.key.startsWith('cachly:lesson:best:'));
531
+ let crossAuthorThisCall = 0;
522
532
  for (const m of lessonMatches.slice(0, 5)) {
523
533
  const existing = await redis.get(m.key).catch(() => null);
524
534
  if (existing) {
@@ -529,6 +539,15 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
529
539
  const sev = lesson.severity;
530
540
  const savedMins = sev === 'critical' ? 240 : sev === 'major' ? 60 : 30;
531
541
  redis.incrbyfloat(`cachly:stats:time_saved_mins:${instance_id}`, savedMins).catch(() => { });
542
+ // Metric 3 (team-knowledge-reuse): a recall of a lesson authored by
543
+ // someone OTHER than the requester is cross-author reuse — the value
544
+ // only cachly delivers. Track total proven recalls + cross-author ones.
545
+ redis.incr(`cachly:stats:recalls_total:${instance_id}`).catch(() => { });
546
+ if (lesson.author && requester && lesson.author !== requester) {
547
+ crossAuthorThisCall++;
548
+ redis.incr(`cachly:stats:cross_author_recalls:${instance_id}`).catch(() => { });
549
+ redis.sadd(`cachly:stats:reuse_pairs:${instance_id}`, `${requester}<-${lesson.author}`).catch(() => { });
550
+ }
532
551
  // Surface banner for proven successes (recall_count >= 1 means it's been validated)
533
552
  if (lesson.outcome === 'success' && (lesson.recall_count ?? 0) >= 1) {
534
553
  savedHere.push({
@@ -541,6 +560,11 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
541
560
  }
542
561
  }
543
562
  }
563
+ // Metric 1 (time-to-first-recall): stamp the first time recall returned a
564
+ // proven lesson. SET NX so only the first successful recall wins.
565
+ if (savedHere.length > 0) {
566
+ redis.set(`cachly:stats:first_recall_at:${instance_id}`, new Date().toISOString(), 'EX', 365 * 86400, 'NX').catch(() => { });
567
+ }
544
568
  // ── Layer 2: Semantic search (parallel, optional) ────────────────────────
545
569
  const inst = await apiFetch(`/api/v1/instances/${instance_id}`).catch(() => null);
546
570
  const semHits = [];
@@ -666,6 +690,9 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
666
690
  if (topLesson) {
667
691
  lines.push(`> 💡 **Brain saved you ~${topLesson.savedMins}m here** — ${topLesson.severity} issue from \`${topLesson.topic}\` recalled ${topLesson.recall_count}× proven\n`);
668
692
  }
693
+ if (crossAuthorThisCall > 0) {
694
+ lines.push(`> 👥 **Team knowledge reuse** — ${crossAuthorThisCall} of these lesson${crossAuthorThisCall !== 1 ? 's were' : ' was'} written by a teammate. This is the value only a shared brain delivers.\n`);
695
+ }
669
696
  // Show sub-query info if multi-topic was detected
670
697
  const subQueries = splitMultiQuery(query);
671
698
  if (subQueries.length > 1) {
@@ -2011,14 +2038,8 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
2011
2038
  }
2012
2039
  // Also: exact file_paths match via lesson scan
2013
2040
  if (relatedLessons.length < 2) {
2014
- const scanKeys = [];
2015
- const stream = redis.scanStream({ match: 'cachly:lesson:best:*', count: 200 });
2016
- await new Promise((res, rej) => {
2017
- stream.on('data', (b) => scanKeys.push(...b));
2018
- stream.on('end', res);
2019
- stream.on('error', rej);
2020
- });
2021
- for (const k of scanKeys.slice(0, 300)) {
2041
+ const allLessonKeys = await scanKeys(redis, 'cachly:lesson:best:*', { max: 1500 });
2042
+ for (const k of allLessonKeys.slice(0, 300)) {
2022
2043
  const raw = await redis.get(k);
2023
2044
  if (!raw)
2024
2045
  continue;
@@ -2053,14 +2074,8 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
2053
2074
  case 'team_expertise_map': {
2054
2075
  const { instance_id, top_n = 20, } = args;
2055
2076
  const redis = await getConnection(instance_id);
2056
- // Scan all person nodes
2057
- const personKeys = [];
2058
- const pStream = redis.scanStream({ match: 'cachly:ckg:node:person:*', count: 200 });
2059
- await new Promise((res, rej) => {
2060
- pStream.on('data', (b) => personKeys.push(...b));
2061
- pStream.on('end', res);
2062
- pStream.on('error', rej);
2063
- });
2077
+ // Scan all person nodes (capped + timed out so a huge keyspace can't hang the agent)
2078
+ const personKeys = await scanKeys(redis, 'cachly:ckg:node:person:*', { max: 2000 });
2064
2079
  if (personKeys.length === 0) {
2065
2080
  return [
2066
2081
  `## 🗺️ Team Expertise Map`,
@@ -2121,14 +2136,8 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
2121
2136
  case 'skill_gaps': {
2122
2137
  const { instance_id, min_failures = 1, } = args;
2123
2138
  const redis = await getConnection(instance_id);
2124
- // Scan all best lessons
2125
- const lessonKeys = [];
2126
- const lStream = redis.scanStream({ match: 'cachly:lesson:best:*', count: 500 });
2127
- await new Promise((res, rej) => {
2128
- lStream.on('data', (b) => lessonKeys.push(...b));
2129
- lStream.on('end', res);
2130
- lStream.on('error', rej);
2131
- });
2139
+ // Scan all best lessons (capped + timed out)
2140
+ const lessonKeys = await scanKeys(redis, 'cachly:lesson:best:*', { max: 3000 });
2132
2141
  const domainMap = new Map();
2133
2142
  let totalAttributed = 0;
2134
2143
  let totalPrivate = 0;
@@ -2169,14 +2178,6 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
2169
2178
  });
2170
2179
  }
2171
2180
  }
2172
- // Check for domains with person nodes but no lessons (contributors without lessons)
2173
- const personKeys = [];
2174
- const pStream = redis.scanStream({ match: 'cachly:ckg:node:person:*', count: 200 });
2175
- await new Promise((res, rej) => {
2176
- pStream.on('data', (b) => personKeys.push(...b));
2177
- pStream.on('end', res);
2178
- pStream.on('error', rej);
2179
- });
2180
2181
  const lines = [
2181
2182
  `## 🔍 Skill Gaps — Knowledge Blind Spots`,
2182
2183
  ``,
@@ -2209,30 +2210,12 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
2209
2210
  case 'brain_coverage': {
2210
2211
  const { instance_id, repo_path = '.', } = args;
2211
2212
  const redis = await getConnection(instance_id);
2212
- // Count lessons
2213
- const lessonKeys = [];
2214
- const lStream = redis.scanStream({ match: 'cachly:lesson:best:*', count: 500 });
2215
- await new Promise((res, rej) => {
2216
- lStream.on('data', (b) => lessonKeys.push(...b));
2217
- lStream.on('end', res);
2218
- lStream.on('error', rej);
2219
- });
2220
- // Count person nodes
2221
- const personKeys = [];
2222
- const pStream = redis.scanStream({ match: 'cachly:ckg:node:person:*', count: 200 });
2223
- await new Promise((res, rej) => {
2224
- pStream.on('data', (b) => personKeys.push(...b));
2225
- pStream.on('end', res);
2226
- pStream.on('error', rej);
2227
- });
2228
- // Count file nodes in CKG
2229
- const fileKeys = [];
2230
- const fStream = redis.scanStream({ match: 'cachly:ckg:node:file:*', count: 500 });
2231
- await new Promise((res, rej) => {
2232
- fStream.on('data', (b) => fileKeys.push(...b));
2233
- fStream.on('end', res);
2234
- fStream.on('error', rej);
2235
- });
2213
+ // Count lessons, person + file nodes (each capped + timed out, gathered in parallel)
2214
+ const [lessonKeys, personKeys, fileKeys] = await Promise.all([
2215
+ scanKeys(redis, 'cachly:lesson:best:*', { max: 5000 }),
2216
+ scanKeys(redis, 'cachly:ckg:node:person:*', { max: 2000 }),
2217
+ scanKeys(redis, 'cachly:ckg:node:file:*', { max: 5000 }),
2218
+ ]);
2236
2219
  // Get git file count for comparison (optional — non-critical if not a git repo)
2237
2220
  let gitFileCount = 0;
2238
2221
  let _gitFileCountLabel = 'n/a';
@@ -2298,6 +2281,69 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
2298
2281
  `_Boost score: run \`brain_from_git\` · add \`author\` to \`learn_from_attempts\` · fix gaps with \`skill_gaps\`_`,
2299
2282
  ].join('\n');
2300
2283
  }
2284
+ // ── brain_metrics ─────────────────────────────────────────────────────────
2285
+ // The three decisive metrics (PROGRESS.md §3 / VISION_10X.md §4):
2286
+ // 1. Time-to-first-recall — onboarding friction
2287
+ // 2. Recall-lift — the moat proof (vs. raw BM25)
2288
+ // 3. Team-knowledge-reuse — the value only a shared brain delivers
2289
+ case 'brain_metrics': {
2290
+ const { instance_id } = args;
2291
+ const redis = await getConnection(instance_id);
2292
+ const [bornAt, firstRecallAt, recallsTotalRaw, crossAuthorRaw, timeSavedRaw, reusePairs] = await Promise.all([
2293
+ redis.get(`cachly:stats:born_at:${instance_id}`).catch(() => null),
2294
+ redis.get(`cachly:stats:first_recall_at:${instance_id}`).catch(() => null),
2295
+ redis.get(`cachly:stats:recalls_total:${instance_id}`).catch(() => null),
2296
+ redis.get(`cachly:stats:cross_author_recalls:${instance_id}`).catch(() => null),
2297
+ redis.get(`cachly:stats:time_saved_mins:${instance_id}`).catch(() => null),
2298
+ redis.smembers(`cachly:stats:reuse_pairs:${instance_id}`).catch(() => []),
2299
+ ]);
2300
+ // ── Metric 1: Time-to-first-recall ──────────────────────────────────────
2301
+ let ttfrLine;
2302
+ if (bornAt && firstRecallAt) {
2303
+ const ms = new Date(firstRecallAt).getTime() - new Date(bornAt).getTime();
2304
+ const mins = Math.max(0, Math.round(ms / 60000));
2305
+ const human = mins < 1 ? '<1 min' : mins < 60 ? `${mins} min` : `${(mins / 60).toFixed(1)} h`;
2306
+ const target = ms <= 2 * 60000 ? '🟢 under 2 min target' : ms <= 60 * 60000 ? '🟡 over 2 min' : '🔴 over 1 h';
2307
+ ttfrLine = `**${human}** from first lesson → first proven recall · ${target}`;
2308
+ }
2309
+ else if (bornAt && !firstRecallAt) {
2310
+ ttfrLine = `🟡 Brain has knowledge but no proven recall yet — try \`smart_recall\``;
2311
+ }
2312
+ else {
2313
+ ttfrLine = `⚪ Not enough data yet — store a lesson, then recall it`;
2314
+ }
2315
+ // ── Metric 2: Recall-lift (the moat proof) ──────────────────────────────
2316
+ // Published headline from Cachly-Bench (CI-defended in rerank.test.ts).
2317
+ const recallLiftLine = `**+22.2 % Precision@1**, **+10.9 % MRR**, **+8.1 % nDCG@5** vs. raw BM25`;
2318
+ // ── Metric 3: Team-knowledge-reuse ──────────────────────────────────────
2319
+ const recallsTotal = Number(recallsTotalRaw ?? 0);
2320
+ const crossAuthor = Number(crossAuthorRaw ?? 0);
2321
+ const reusePct = recallsTotal > 0 ? Math.round((crossAuthor / recallsTotal) * 100) : 0;
2322
+ const reuseTarget = reusePct >= 30 ? '🟢 above 30 % target' : recallsTotal === 0 ? '⚪ no recalls yet' : '🟡 below 30 % target';
2323
+ const timeSaved = Math.round(Number(timeSavedRaw ?? 0));
2324
+ const timeSavedHuman = timeSaved < 60 ? `${timeSaved} min` : `${(timeSaved / 60).toFixed(1)} h`;
2325
+ const lines = [
2326
+ `## 📈 Brain Metrics — the three that decide everything`,
2327
+ ``,
2328
+ `### 1. Time-to-first-recall _(onboarding friction)_`,
2329
+ ttfrLine,
2330
+ ``,
2331
+ `### 2. Recall-lift _(the moat proof)_`,
2332
+ recallLiftLine,
2333
+ `_Reproduce: \`npm run bench\` · CI-defended in \`rerank.test.ts\` · details in BENCH.md_`,
2334
+ ``,
2335
+ `### 3. Team-knowledge-reuse _(the value only a shared brain delivers)_`,
2336
+ `**${reusePct}%** of proven recalls used a teammate's lesson (${crossAuthor}/${recallsTotal}) · ${reuseTarget}`,
2337
+ reusePairs.length > 0 ? `**${reusePairs.length}** distinct reuse relationship${reusePairs.length !== 1 ? 's' : ''} across the team` : '',
2338
+ ``,
2339
+ `---`,
2340
+ `⏱️ **${timeSavedHuman}** total saved not re-researching known fixes.`,
2341
+ recallsTotal === 0
2342
+ ? `_Tip: pass \`author="your-handle"\` to \`smart_recall\` so cross-author reuse can be tracked._`
2343
+ : `_These numbers compound: every learned lesson and every teammate raises all three._`,
2344
+ ].filter(Boolean);
2345
+ return lines.join('\n');
2346
+ }
2301
2347
  // ── sync_file_changes ─────────────────────────────────────────────────────
2302
2348
  default:
2303
2349
  return null;