You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -324,6 +346,10 @@ export ANTHROPIC_BASE_URL=http://127.0.0.1:7432 # point Claude Code at it
324
346
325
347
10.**Graceful shutdown.** The daemon catches SIGINT/SIGTERM, stops the steward, stops the HTTP server, then cancels context. The order matters.
326
348
349
+
11.**Content score pre-gate does NOT feed rejection store.** Exchanges filtered by the content score gate are NOT added to the rejection store — only QuickFilter and synthesizer rejections feed back. This prevents a positive feedback loop where the scorer would amplify its own noise signal.
350
+
351
+
12.**Top-K noise scoring, not averaging.** The ContentScorer uses the top-3 most similar noise prototypes, not the average of all. When the rejection store grows to 150+ entries, averaging would converge to a constant, destroying discriminative power.
Copy file name to clipboardExpand all lines: CLAUDE.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -58,3 +58,5 @@ When you store a new memory that's similar (but not identical) to an existing so
58
58
## Adaptive quality learning
59
59
60
60
The system tracks which memories get retrieved and how often. While in "learning mode" (< 50 retrieval events), it keeps everything. Use `quality_stats` to check the current learning status. Over time, memories that are never retrieved will score lower, helping the system learn what's worth keeping.
61
+
62
+
The system also learns what **noise** looks like. Exchanges rejected by the pre-filter or synthesizer are accumulated in a ring buffer. Every 25 rejections, the assistant texts are re-embedded as noise prototypes and hot-swapped into the content scorer. This means the system adapts to your team's specific noise patterns — the more it sees procedural chatter, the better it gets at filtering it before spending an LLM call.
Every AI response is captured asynchronously (zero latency impact), broken into meaningful pieces, scrubbed of secrets (API keys, tokens, passwords — 13 detection patterns), deduplicated, and stored in the shared database.
73
+
Every AI response is captured asynchronously (zero latency impact), passed through a multi-stage quality filter (length gate, adaptive content scoring, LLM synthesis gate), scrubbed of secrets (API keys, tokens, passwords — 13 detection patterns), deduplicated, and stored in the shared database. The system learns what noise looks like from rejected exchanges, improving filtering accuracy over time.
Copy file name to clipboardExpand all lines: docs/INTERNALS.md
+10-4Lines changed: 10 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -880,10 +880,12 @@ When LLM synthesis is enabled, the proxy does more than raw capture:
880
880
881
881
**Per-exchange (`ingest()`):**
882
882
1. Extract the last user message from the request
883
-
2.**Pre-filter:**`QuickFilter()` checks if both user and assistant messages are procedural → reject immediately
884
-
3.**LLM quality gate:**`SynthesizeQA()` asks the model to distill or return `"SKIP"` → reject if no durable value
885
-
4.**Store:** Distilled entry goes through `ProcessDirect()` (no chunking, already formatted)
886
-
5.**Fallback:** If no synthesizer, store raw Q&A pair
883
+
2.**Pre-filter:**`QuickFilter()` checks if both user and assistant messages are procedural → reject immediately (feeds rejection store)
884
+
3.**Length gate:** Responses shorter than `ingest_min_len` (default 80 chars) are skipped — no LLM call
885
+
4.**Content score gate:** Raw assistant text is embedded and scored against noise prototypes via `PreScore()`. Below `content_score_pre_gate` (default 0.35) → skipped. Does NOT feed rejection store (prevents positive feedback loop)
886
+
5.**LLM quality gate:**`SynthesizeQA()` asks the model to distill or return `"SKIP"` → reject if no durable value (feeds rejection store)
887
+
6.**Store:** Distilled entry goes through `ProcessDirect()` (no chunking, already formatted)
888
+
7.**Fallback:** If no synthesizer, store raw Q&A pair
887
889
888
890
**Session synthesis:**
889
891
- Fired at 3 complete Q&A pairs, then every 5 pairs after
@@ -990,6 +992,10 @@ Created automatically on first run with sensible defaults. All pipeline threshol
990
992
|`sessionSynthesisInterval`| 5 | proxy/anthropic.go | Pairs between subsequent summaries |
0 commit comments