gitmem-mcp 1.6.5 → 1.6.6

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/CHANGELOG.md CHANGED
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.6.6] - 2026-06-27
11
+
12
+ ### Changed
13
+ - **`recall` stubs low-confidence scars to cut wasted tokens**: scars scoring below the `0.55` similarity threshold (already flagged `[low confidence]`, ~66% N/A rate in that band) now render as a one-line stub — title, severity, score, short id, and the `[low confidence]` tag — instead of hydrating their full body (description, counter-arguments, applies-when, why-this-matters, action-protocol, self-check, related triples). High-confidence scars (≥ 0.55) are unchanged, and blocking-verification scars always render in full regardless of score. The `0.55` cutoff is now a single named constant (`LOW_CONFIDENCE_THRESHOLD`) shared by the tag and the stub so they can't drift apart. The scar's id stays visible, so an agent can still pull detail on demand. (GIT-49)
14
+
10
15
  ## [1.6.5] - 2026-06-27
11
16
 
12
17
  ### Fixed
@@ -15,6 +15,16 @@
15
15
  import type { KnowledgeTriple } from "../services/supabase-client.js";
16
16
  import { type ScarWithVariant } from "../services/variant-assignment.js";
17
17
  import type { Project, PerformanceData } from "../types/index.js";
18
+ /**
19
+ * Confidence cutoff for scar rendering.
20
+ *
21
+ * Matches below this similarity are flagged `[low confidence]` and, per the
22
+ * 1.5.0 UX-audit calibration, are N/A ~66% of the time. They pass the pro-tier
23
+ * 0.45 inclusion filter but are rendered as stubs (header only) rather than full
24
+ * bodies — the tag boundary and the stub boundary share this constant so they
25
+ * can never drift apart.
26
+ */
27
+ export declare const LOW_CONFIDENCE_THRESHOLD = 0.55;
18
28
  /**
19
29
  * Parameters for recall tool
20
30
  */
@@ -27,6 +27,16 @@ import { getSessionPath } from "../services/gitmem-dir.js";
27
27
  import { wrapDisplay, SEV, dimText, ANSI } from "../services/display-protocol.js";
28
28
  import { formatNudgeHeader } from "../services/nudge-variants.js";
29
29
  import { fetchDismissalCounts } from "../services/behavioral-decay.js";
30
+ /**
31
+ * Confidence cutoff for scar rendering.
32
+ *
33
+ * Matches below this similarity are flagged `[low confidence]` and, per the
34
+ * 1.5.0 UX-audit calibration, are N/A ~66% of the time. They pass the pro-tier
35
+ * 0.45 inclusion filter but are rendered as stubs (header only) rather than full
36
+ * bodies — the tag boundary and the stub boundary share this constant so they
37
+ * can never drift apart.
38
+ */
39
+ export const LOW_CONFIDENCE_THRESHOLD = 0.55;
30
40
  /**
31
41
  * Format scars into a readable response for Claude
32
42
  */
@@ -80,8 +90,8 @@ No past lessons match this plan closely enough. Scars accumulate as you work —
80
90
  for (const scar of scars) {
81
91
  const sev = SEV[scar.severity] || "[?]";
82
92
  const starterTag = scar.is_starter ? ` ${dimText("[starter]")}` : "";
83
- // Confidence tier: marginal matches (< 0.55) get flagged — 66% N/A rate in this range
84
- const confidenceTag = scar.similarity < 0.55 ? ` ${dimText("[low confidence]")}` : "";
93
+ // Confidence tier: marginal matches get flagged — 66% N/A rate below the threshold
94
+ const confidenceTag = scar.similarity < LOW_CONFIDENCE_THRESHOLD ? ` ${dimText("[low confidence]")}` : "";
85
95
  // Pro: decay tag for scars with reduced behavioral relevance
86
96
  const decayTag = hasProInsights() && scar.decay_multiplier !== undefined && scar.decay_multiplier < 0.8
87
97
  ? ` ${dimText(`[decay: ${Math.round(scar.decay_multiplier * 100)}%]`)}`
@@ -94,55 +104,61 @@ No past lessons match this plan closely enough. Scars accumulate as you work —
94
104
  lines.push(` _[dismissed ${counts.dismissed}/${counts.surfaced} times — re-evaluate whether this still applies]_`);
95
105
  }
96
106
  }
97
- // Use variant enforcement text if available (blind to variant name)
98
- if (scar.variant_info?.has_variants && scar.variant_info.variant) {
99
- const variantText = formatVariantEnforcement(scar.variant_info.variant, scar.title);
100
- lines.push(variantText);
101
- }
102
- else {
103
- // Legacy path: use original scar description
104
- lines.push(scar.description);
105
- }
106
- if (scar.counter_arguments.length > 0) {
107
- lines.push("");
108
- lines.push("*You might think:*");
109
- for (const counter of scar.counter_arguments.slice(0, 2)) {
110
- lines.push(` - ${counter}`);
107
+ // Stub low-confidence scars: render header only, skip the heavy body.
108
+ // ~66% of sub-threshold matches are N/A, so their full bodies are wasted
109
+ // tokens. Blocking-verification scars always render full regardless of score.
110
+ const isStub = scar.similarity < LOW_CONFIDENCE_THRESHOLD && !scar.required_verification?.blocking;
111
+ if (!isStub) {
112
+ // Use variant enforcement text if available (blind to variant name)
113
+ if (scar.variant_info?.has_variants && scar.variant_info.variant) {
114
+ const variantText = formatVariantEnforcement(scar.variant_info.variant, scar.title);
115
+ lines.push(variantText);
111
116
  }
112
- }
113
- if (scar.applies_when.length > 0) {
114
- lines.push("");
115
- lines.push("*Applies when:* " + scar.applies_when.slice(0, 3).join(", "));
116
- }
117
- // Render LLM-cooperative enforcement fields
118
- if (scar.why_this_matters) {
119
- lines.push("");
120
- lines.push(`**Why this matters:** ${scar.why_this_matters}`);
121
- }
122
- if (scar.action_protocol && scar.action_protocol.length > 0) {
123
- lines.push("");
124
- lines.push("**Action Protocol:**");
125
- scar.action_protocol.forEach((step, i) => {
126
- lines.push(` ${i + 1}. ${step}`);
127
- });
128
- }
129
- if (scar.self_check_criteria && scar.self_check_criteria.length > 0) {
130
- lines.push("");
131
- lines.push("**Self-Check:**");
132
- for (const criterion of scar.self_check_criteria) {
133
- lines.push(` - [ ] ${criterion}`);
117
+ else {
118
+ // Legacy path: use original scar description
119
+ lines.push(scar.description);
134
120
  }
135
- }
136
- // Render related knowledge triples
137
- if (scar.related_triples && scar.related_triples.length > 0) {
138
- lines.push("");
139
- lines.push("*Related knowledge:*");
140
- for (const triple of scar.related_triples) {
141
- lines.push(` - ${triple.subject} **${triple.predicate}** ${triple.object}`);
121
+ if (scar.counter_arguments.length > 0) {
122
+ lines.push("");
123
+ lines.push("*You might think:*");
124
+ for (const counter of scar.counter_arguments.slice(0, 2)) {
125
+ lines.push(` - ${counter}`);
126
+ }
127
+ }
128
+ if (scar.applies_when.length > 0) {
129
+ lines.push("");
130
+ lines.push("*Applies when:* " + scar.applies_when.slice(0, 3).join(", "));
131
+ }
132
+ // Render LLM-cooperative enforcement fields
133
+ if (scar.why_this_matters) {
134
+ lines.push("");
135
+ lines.push(`**Why this matters:** ${scar.why_this_matters}`);
136
+ }
137
+ if (scar.action_protocol && scar.action_protocol.length > 0) {
138
+ lines.push("");
139
+ lines.push("**Action Protocol:**");
140
+ scar.action_protocol.forEach((step, i) => {
141
+ lines.push(` ${i + 1}. ${step}`);
142
+ });
143
+ }
144
+ if (scar.self_check_criteria && scar.self_check_criteria.length > 0) {
145
+ lines.push("");
146
+ lines.push("**Self-Check:**");
147
+ for (const criterion of scar.self_check_criteria) {
148
+ lines.push(` - [ ] ${criterion}`);
149
+ }
150
+ }
151
+ // Render related knowledge triples
152
+ if (scar.related_triples && scar.related_triples.length > 0) {
153
+ lines.push("");
154
+ lines.push("*Related knowledge:*");
155
+ for (const triple of scar.related_triples) {
156
+ lines.push(` - ${triple.subject} **${triple.predicate}** ${triple.object}`);
157
+ }
158
+ }
159
+ if (scar.source_issue) {
160
+ lines.push(`*Source:* ${scar.source_issue}`);
142
161
  }
143
- }
144
- if (scar.source_issue) {
145
- lines.push(`*Source:* ${scar.source_issue}`);
146
162
  }
147
163
  lines.push("");
148
164
  lines.push("---");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitmem-mcp",
3
- "version": "1.6.5",
3
+ "version": "1.6.6",
4
4
  "mcpName": "io.github.gitmem-dev/gitmem",
5
5
  "description": "Persistent learning memory for AI coding agents. Memory that compounds.",
6
6
  "type": "module",