specmem-hardwicksoftware 3.7.34 → 3.7.35
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/watcher/index.js +37 -2
- package/package.json +1 -1
- package/specmem/supervisord.conf +1 -1
package/dist/watcher/index.js
CHANGED
|
@@ -31,6 +31,12 @@ export class WatcherManager {
|
|
|
31
31
|
syncTimeout = null;
|
|
32
32
|
lastLowScoreResyncAt = 0;
|
|
33
33
|
lastLowScoreResyncScore = null; // track score at last resync to detect drops
|
|
34
|
+
// Drift-resync plateau detection: stop resyncing if score isn't improving
|
|
35
|
+
lastDriftResyncAt = 0;
|
|
36
|
+
lastDriftResyncScore = null;
|
|
37
|
+
driftResyncNoImprovementCount = 0; // consecutive resyncs that didn't improve score
|
|
38
|
+
static DRIFT_RESYNC_MAX_NO_IMPROVEMENT = 2; // after 2 consecutive no-improvement resyncs, accept plateau
|
|
39
|
+
static DRIFT_RESYNC_COOLDOWN_MS = 15 * 60 * 1000; // 15 min cooldown between drift resyncs
|
|
34
40
|
constructor(config) {
|
|
35
41
|
// Create handler first - it's the core component
|
|
36
42
|
this.handler = new AutoUpdateTheMemories(config.handler);
|
|
@@ -126,7 +132,7 @@ export class WatcherManager {
|
|
|
126
132
|
const LOW_SCORE_THRESHOLD = parseFloat(process.env['SPECMEM_LOW_SCORE_THRESHOLD'] || '0.85');
|
|
127
133
|
const LOW_SCORE_DROP_THRESHOLD = parseFloat(process.env['SPECMEM_LOW_SCORE_DROP_THRESHOLD'] || '0.10');
|
|
128
134
|
const LOW_SCORE_DEBOUNCE_MS = parseInt(process.env['SPECMEM_LOW_SCORE_DEBOUNCE_MS'] || String(15 * 60 * 1000), 10);
|
|
129
|
-
if (report.syncScore
|
|
135
|
+
if (report.syncScore <= LOW_SCORE_THRESHOLD) {
|
|
130
136
|
// First time seeing low score — always resync
|
|
131
137
|
// After that, only resync if score dropped by >=10% from the post-resync score
|
|
132
138
|
const scoreDrop = this.lastLowScoreResyncScore !== null
|
|
@@ -163,8 +169,21 @@ export class WatcherManager {
|
|
|
163
169
|
missingFromMcp: report.missingFromMcp.length,
|
|
164
170
|
contentMismatch: report.contentMismatch.length
|
|
165
171
|
}, 'drift detected during periodic check');
|
|
166
|
-
// Auto-resync when drift is detected
|
|
172
|
+
// Auto-resync when drift is detected — with plateau detection + cooldown
|
|
167
173
|
if (report.missingFromMcp.length > 0 || report.contentMismatch.length > 0) {
|
|
174
|
+
// Plateau guard: if we've resynced N times without improvement, accept the score
|
|
175
|
+
if (this.driftResyncNoImprovementCount >= WatcherManager.DRIFT_RESYNC_MAX_NO_IMPROVEMENT) {
|
|
176
|
+
logger.info({ syncScore: report.syncScore, noImprovementCount: this.driftResyncNoImprovementCount }, 'drift-resync plateau reached — score is stable, accepting current sync level');
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
// Cooldown guard: don't resync more than once per 15 min via drift path
|
|
180
|
+
const now = Date.now();
|
|
181
|
+
const driftCooldownRemaining = WatcherManager.DRIFT_RESYNC_COOLDOWN_MS - (now - this.lastDriftResyncAt);
|
|
182
|
+
if (driftCooldownRemaining > 0) {
|
|
183
|
+
logger.debug({ syncScore: report.syncScore, cooldownRemainingSec: Math.round(driftCooldownRemaining / 1000) }, 'drift-resync on cooldown — skipping');
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
this.lastDriftResyncAt = now;
|
|
168
187
|
logger.info('periodic check triggering auto-resync...');
|
|
169
188
|
const resyncResult = await this.syncChecker.resyncEverythingFrFr();
|
|
170
189
|
logger.info({
|
|
@@ -175,6 +194,16 @@ export class WatcherManager {
|
|
|
175
194
|
// Update score after resync
|
|
176
195
|
const postReport = await this.syncChecker.checkSync();
|
|
177
196
|
await this.writeSyncScore(postReport.syncScore);
|
|
197
|
+
// Plateau detection: did this resync actually improve the score?
|
|
198
|
+
const improvement = postReport.syncScore - (this.lastDriftResyncScore ?? 0);
|
|
199
|
+
if (improvement < 0.01) { // less than 1% improvement = no meaningful change
|
|
200
|
+
this.driftResyncNoImprovementCount++;
|
|
201
|
+
logger.warn({ syncScore: postReport.syncScore, previousScore: this.lastDriftResyncScore, noImprovementCount: this.driftResyncNoImprovementCount, maxAllowed: WatcherManager.DRIFT_RESYNC_MAX_NO_IMPROVEMENT }, 'drift-resync did not improve score — tracking plateau');
|
|
202
|
+
} else {
|
|
203
|
+
// Score improved — reset plateau counter
|
|
204
|
+
this.driftResyncNoImprovementCount = 0;
|
|
205
|
+
}
|
|
206
|
+
this.lastDriftResyncScore = postReport.syncScore;
|
|
178
207
|
}
|
|
179
208
|
}
|
|
180
209
|
}
|
|
@@ -307,6 +336,12 @@ export class WatcherManager {
|
|
|
307
336
|
* resync - manually trigger full resync
|
|
308
337
|
*/
|
|
309
338
|
async resync() {
|
|
339
|
+
// Manual resync resets all plateau/cooldown state so it always runs fresh
|
|
340
|
+
this.driftResyncNoImprovementCount = 0;
|
|
341
|
+
this.lastDriftResyncAt = 0;
|
|
342
|
+
this.lastDriftResyncScore = null;
|
|
343
|
+
this.lastLowScoreResyncScore = null;
|
|
344
|
+
this.lastLowScoreResyncAt = 0;
|
|
310
345
|
return await this.syncChecker.resyncEverythingFrFr();
|
|
311
346
|
}
|
|
312
347
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specmem-hardwicksoftware",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.35",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Your Claude Code sessions don't have to start from scratch anymore — SpecMem gives your AI real memory. It won't forget your conversations, your code, or your architecture decisions between sessions. That's the whole point. Semantic code indexing that actually works: TypeScript, JavaScript, Python, Go, Rust, Java, Kotlin, C, C++, HTML and more. It doesn't just track functions — it gets classes, methods, fields, constants, enums, macros, imports, structs, the whole codebase graph. There's chat memory too, powered by pgvector embeddings. You've also got token compression, team coordination, multi-agent comms, and file watching built in. 74+ MCP tools. Runs on PostgreSQL + Docker. It's kind of a big deal. justcalljon.pro",
|
|
6
6
|
"main": "dist/index.js",
|
package/specmem/supervisord.conf
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
; ============================================
|
|
2
2
|
; SPECMEM BRAIN CONTAINER - DYNAMIC SUPERVISORD CONFIG
|
|
3
|
-
; Generated by specmem-init at 2026-02-26T20:
|
|
3
|
+
; Generated by specmem-init at 2026-02-26T20:34:50.062Z
|
|
4
4
|
; Thread counts from model-config.json resourcePool
|
|
5
5
|
; ============================================
|
|
6
6
|
|