@cachly-dev/mcp-server 0.10.129 → 0.10.131
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/README.md +2 -2
- package/dist/index.js +1 -7
- package/dist/packages/telegram-notify/client.js +2 -75
- package/dist/src/ambient-cli.js +7 -253
- package/dist/src/ambient-deps.js +1 -55
- package/dist/src/ambient-hooks.js +5 -278
- package/dist/src/ambient-ledger.js +6 -95
- package/dist/src/ambient-memory.js +1 -67
- package/dist/src/ambient-recall.js +1 -221
- package/dist/src/aussetzer.js +1 -225
- package/dist/src/auth.js +9 -140
- package/dist/src/autor-abzeichen.js +1 -56
- package/dist/src/autor.js +1 -136
- package/dist/src/bauabdruck.js +1 -93
- package/dist/src/bedeutung.js +2 -323
- package/dist/src/bench/cachly-bench.js +4 -249
- package/dist/src/bench/external-corpus.js +4 -135
- package/dist/src/bench/fixtures.js +1 -225
- package/dist/src/brain-export.js +16 -119
- package/dist/src/brain-watch-hook.js +8 -86
- package/dist/src/cachly-url.js +1 -21
- package/dist/src/ckg.js +1 -108
- package/dist/src/cls-hook.js +8 -94
- package/dist/src/confidence.js +1 -50
- package/dist/src/credentials.js +1 -85
- package/dist/src/deutsch.js +1 -223
- package/dist/src/doctor.js +2 -248
- package/dist/src/editor.js +1 -63
- package/dist/src/eingaenge-nachruesten.js +1 -290
- package/dist/src/eingaenge.js +2 -260
- package/dist/src/embeddings.js +13 -223
- package/dist/src/feldreparatur.js +3 -113
- package/dist/src/first-contact.js +4 -108
- package/dist/src/first-recall-proof.js +4 -41
- package/dist/src/funnel-milestones.js +2 -48
- package/dist/src/geliefert.js +1 -114
- package/dist/src/handlers/advanced.js +38 -537
- package/dist/src/handlers/brain.js +69 -4397
- package/dist/src/handlers/cache.js +59 -638
- package/dist/src/handlers/context.js +17 -182
- package/dist/src/handlers/fedbrain.js +40 -1436
- package/dist/src/handlers/instances.js +16 -201
- package/dist/src/handlers/roadmap.js +13 -175
- package/dist/src/handlers/share.js +19 -530
- package/dist/src/handlers/syndicate.js +38 -904
- package/dist/src/handlers/team.js +89 -1865
- package/dist/src/handlers/viz.js +3 -148
- package/dist/src/index.js +321 -4281
- package/dist/src/interferenz.js +1 -141
- package/dist/src/kostprobe.js +7 -125
- package/dist/src/lesson-preview.js +2 -133
- package/dist/src/namespace.js +1 -128
- package/dist/src/notifier.js +1 -6
- package/dist/src/rangfolge-stellschrauben.js +1 -0
- package/dist/src/rangfolge.js +1 -249
- package/dist/src/raumkorrektur.js +1 -197
- package/dist/src/recall-tiefe.js +1 -42
- package/dist/src/rerank.js +1 -154
- package/dist/src/resonanz.js +1 -140
- package/dist/src/search.js +1 -2104
- package/dist/src/seltenheitsbestand.js +1 -92
- package/dist/src/speicherlage.js +1 -84
- package/dist/src/spuren.js +1 -150
- package/dist/src/starter-corpus.js +1 -165
- package/dist/src/telemetry-types.js +0 -13
- package/dist/src/tools.js +10 -2465
- package/dist/src/toolspecs.js +1 -121
- package/dist/src/upgrade-nudge.js +1 -29
- package/dist/src/utils.js +1 -89
- package/dist/src/versuch.js +1 -264
- package/dist/src/vorspann.js +1 -146
- package/dist/src/wartung/vektoren-verdichten.js +1 -200
- package/dist/src/werkzeug-nutzung.js +1 -72
- package/dist/src/wertbeitrag.js +1 -203
- package/dist/src/wirkungsspur.js +1 -0
- package/glama.json +1 -1
- package/package.json +8 -7
- package/server.json +3 -3
- package/dist/index.d.ts +0 -1
- package/dist/index.js.map +0 -1
- package/dist/packages/telegram-notify/client.d.ts +0 -19
- package/dist/packages/telegram-notify/client.js.map +0 -1
- package/dist/src/ambient-cli.d.ts +0 -101
- package/dist/src/ambient-cli.js.map +0 -1
- package/dist/src/ambient-deps.d.ts +0 -26
- package/dist/src/ambient-deps.js.map +0 -1
- package/dist/src/ambient-hooks.d.ts +0 -137
- package/dist/src/ambient-hooks.js.map +0 -1
- package/dist/src/ambient-ledger.d.ts +0 -19
- package/dist/src/ambient-ledger.js.map +0 -1
- package/dist/src/ambient-memory.d.ts +0 -12
- package/dist/src/ambient-memory.js.map +0 -1
- package/dist/src/ambient-recall.d.ts +0 -127
- package/dist/src/ambient-recall.js.map +0 -1
- package/dist/src/aussetzer.d.ts +0 -156
- package/dist/src/aussetzer.js.map +0 -1
- package/dist/src/auth.d.ts +0 -43
- package/dist/src/auth.js.map +0 -1
- package/dist/src/autor-abzeichen.d.ts +0 -41
- package/dist/src/autor-abzeichen.js.map +0 -1
- package/dist/src/autor.d.ts +0 -101
- package/dist/src/autor.js.map +0 -1
- package/dist/src/bauabdruck-daten.generiert.json +0 -5
- package/dist/src/bauabdruck.d.ts +0 -38
- package/dist/src/bauabdruck.js.map +0 -1
- package/dist/src/bedeutung.d.ts +0 -168
- package/dist/src/bedeutung.js.map +0 -1
- package/dist/src/bench/cachly-bench.d.ts +0 -61
- package/dist/src/bench/cachly-bench.js.map +0 -1
- package/dist/src/bench/external-corpus.d.ts +0 -44
- package/dist/src/bench/external-corpus.js.map +0 -1
- package/dist/src/bench/fixtures.d.ts +0 -37
- package/dist/src/bench/fixtures.js.map +0 -1
- package/dist/src/brain-export.d.ts +0 -64
- package/dist/src/brain-export.js.map +0 -1
- package/dist/src/brain-watch-hook.d.ts +0 -21
- package/dist/src/brain-watch-hook.js.map +0 -1
- package/dist/src/cachly-url.d.ts +0 -68
- package/dist/src/cachly-url.js.map +0 -1
- package/dist/src/ckg.d.ts +0 -54
- package/dist/src/ckg.js.map +0 -1
- package/dist/src/cls-hook.d.ts +0 -15
- package/dist/src/cls-hook.js.map +0 -1
- package/dist/src/confidence.d.ts +0 -19
- package/dist/src/confidence.js.map +0 -1
- package/dist/src/credentials.d.ts +0 -37
- package/dist/src/credentials.js.map +0 -1
- package/dist/src/deutsch.d.ts +0 -98
- package/dist/src/deutsch.js.map +0 -1
- package/dist/src/doctor.d.ts +0 -47
- package/dist/src/doctor.js.map +0 -1
- package/dist/src/editor.d.ts +0 -9
- package/dist/src/editor.js.map +0 -1
- package/dist/src/eingaenge-nachruesten.d.ts +0 -41
- package/dist/src/eingaenge-nachruesten.js.map +0 -1
- package/dist/src/eingaenge.d.ts +0 -159
- package/dist/src/eingaenge.js.map +0 -1
- package/dist/src/embeddings.d.ts +0 -48
- package/dist/src/embeddings.js.map +0 -1
- package/dist/src/feldreparatur.d.ts +0 -58
- package/dist/src/feldreparatur.js.map +0 -1
- package/dist/src/first-contact.d.ts +0 -56
- package/dist/src/first-contact.js.map +0 -1
- package/dist/src/first-recall-proof.d.ts +0 -19
- package/dist/src/first-recall-proof.js.map +0 -1
- package/dist/src/funnel-milestones.d.ts +0 -5
- package/dist/src/funnel-milestones.js.map +0 -1
- package/dist/src/geliefert.d.ts +0 -63
- package/dist/src/geliefert.js.map +0 -1
- package/dist/src/handlers/advanced.d.ts +0 -6
- package/dist/src/handlers/advanced.js.map +0 -1
- package/dist/src/handlers/brain.d.ts +0 -41
- package/dist/src/handlers/brain.js.map +0 -1
- package/dist/src/handlers/cache.d.ts +0 -6
- package/dist/src/handlers/cache.js.map +0 -1
- package/dist/src/handlers/context.d.ts +0 -6
- package/dist/src/handlers/context.js.map +0 -1
- package/dist/src/handlers/fedbrain.d.ts +0 -18
- package/dist/src/handlers/fedbrain.js.map +0 -1
- package/dist/src/handlers/instances.d.ts +0 -33
- package/dist/src/handlers/instances.js.map +0 -1
- package/dist/src/handlers/roadmap.d.ts +0 -6
- package/dist/src/handlers/roadmap.js.map +0 -1
- package/dist/src/handlers/share.d.ts +0 -8
- package/dist/src/handlers/share.js.map +0 -1
- package/dist/src/handlers/syndicate.d.ts +0 -6
- package/dist/src/handlers/syndicate.js.map +0 -1
- package/dist/src/handlers/team.d.ts +0 -45
- package/dist/src/handlers/team.js.map +0 -1
- package/dist/src/handlers/viz.d.ts +0 -6
- package/dist/src/handlers/viz.js.map +0 -1
- package/dist/src/index.d.ts +0 -93
- package/dist/src/index.js.map +0 -1
- package/dist/src/interferenz.d.ts +0 -111
- package/dist/src/interferenz.js.map +0 -1
- package/dist/src/kostprobe.d.ts +0 -25
- package/dist/src/kostprobe.js.map +0 -1
- package/dist/src/lesson-preview.d.ts +0 -81
- package/dist/src/lesson-preview.js.map +0 -1
- package/dist/src/namespace.d.ts +0 -20
- package/dist/src/namespace.js.map +0 -1
- package/dist/src/notifier.d.ts +0 -5
- package/dist/src/notifier.js.map +0 -1
- package/dist/src/rangfolge.d.ts +0 -205
- package/dist/src/rangfolge.js.map +0 -1
- package/dist/src/raumkorrektur.d.ts +0 -100
- package/dist/src/raumkorrektur.js.map +0 -1
- package/dist/src/recall-tiefe.d.ts +0 -48
- package/dist/src/recall-tiefe.js.map +0 -1
- package/dist/src/rerank.d.ts +0 -48
- package/dist/src/rerank.js.map +0 -1
- package/dist/src/resonanz.d.ts +0 -85
- package/dist/src/resonanz.js.map +0 -1
- package/dist/src/search.d.ts +0 -153
- package/dist/src/search.js.map +0 -1
- package/dist/src/seltenheitsbestand.d.ts +0 -53
- package/dist/src/seltenheitsbestand.js.map +0 -1
- package/dist/src/speicherlage.d.ts +0 -51
- package/dist/src/speicherlage.js.map +0 -1
- package/dist/src/spuren.d.ts +0 -97
- package/dist/src/spuren.js.map +0 -1
- package/dist/src/starter-corpus.d.ts +0 -28
- package/dist/src/starter-corpus.js.map +0 -1
- package/dist/src/telemetry-types.d.ts +0 -87
- package/dist/src/telemetry-types.js.map +0 -1
- package/dist/src/tools.d.ts +0 -2933
- package/dist/src/tools.js.map +0 -1
- package/dist/src/toolspecs.d.ts +0 -43
- package/dist/src/toolspecs.js.map +0 -1
- package/dist/src/upgrade-nudge.d.ts +0 -15
- package/dist/src/upgrade-nudge.js.map +0 -1
- package/dist/src/utils.d.ts +0 -34
- package/dist/src/utils.js.map +0 -1
- package/dist/src/versuch.d.ts +0 -187
- package/dist/src/versuch.js.map +0 -1
- package/dist/src/vorspann.d.ts +0 -73
- package/dist/src/vorspann.js.map +0 -1
- package/dist/src/wartung/vektoren-verdichten.d.ts +0 -50
- package/dist/src/wartung/vektoren-verdichten.js.map +0 -1
- package/dist/src/werkzeug-nutzung.d.ts +0 -62
- package/dist/src/werkzeug-nutzung.js.map +0 -1
- package/dist/src/wertbeitrag.d.ts +0 -148
- package/dist/src/wertbeitrag.js.map +0 -1
|
@@ -1,92 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Die Seltenheit der Wörter im Bestand — einmal gelesen, dann stehend.
|
|
3
|
-
*
|
|
4
|
-
* ── Warum es das gibt ───────────────────────────────────────────────────────
|
|
5
|
-
*
|
|
6
|
-
* `bewerteTopf` (src/rangfolge.ts) gewichtet die Seltenheits-Deckung mit 1,3 —
|
|
7
|
-
* dem höchsten Gewicht von allen. Sie zu rechnen verlangt die Wortstatistik
|
|
8
|
-
* über den GANZEN Bestand, nicht nur über die Kandidaten.
|
|
9
|
-
*
|
|
10
|
-
* Diese Statistik bei jeder Frage neu aufzubauen wäre genau der Fehler, den
|
|
11
|
-
* der Wortabgleich heute macht: gemessen am 19.08.2026 baut er seinen Index
|
|
12
|
-
* bei JEDER Frage neu, 1,6 ms je Lektion — bei 2000 Lektionen 3,2 Sekunden,
|
|
13
|
-
* womit das 3-Sekunden-Budget der automatischen Einblendung reißt.
|
|
14
|
-
*
|
|
15
|
-
* Also dasselbe Muster wie `Vektorbestand`: einmal laden, eine Minute lang
|
|
16
|
-
* gültig, danach nachladen. Ein voller Lesevorgang je Minute statt einer je
|
|
17
|
-
* Frage.
|
|
18
|
-
*
|
|
19
|
-
* ── Was hier NICHT passiert ─────────────────────────────────────────────────
|
|
20
|
-
*
|
|
21
|
-
* Es wird keine zweite Zerlegung gebaut. `inhaltsWoerter` und `grobStamm`
|
|
22
|
-
* kommen aus rangfolge.ts — dieselben Funktionen, die auch der Sortierer
|
|
23
|
-
* benutzt. Zwei Zerlegungen desselben Textes wären zwei Wahrheiten, und die
|
|
24
|
-
* Deckung würde gegen eine Statistik gerechnet, die anders zählt als sie.
|
|
25
|
-
*/
|
|
26
|
-
import { Seltenheit } from './rangfolge.js';
|
|
27
|
-
const LEKTION_PRAEFIX = 'cachly:lesson:best:';
|
|
28
|
-
/** Der Text einer Lektion, so wie ihn auch der Messstand bildet. */
|
|
29
|
-
export function lektionsText(l) {
|
|
30
|
-
const s = (v) => (typeof v === 'string' ? v : '');
|
|
31
|
-
return [s(l.topic), s(l.what_worked), s(l.what_failed)].filter(Boolean).join(' ');
|
|
32
|
-
}
|
|
33
|
-
export class Seltenheitsbestand {
|
|
34
|
-
frischeMs;
|
|
35
|
-
seltenheit = null;
|
|
36
|
-
texte = new Map();
|
|
37
|
-
geladen = 0;
|
|
38
|
-
constructor(frischeMs = 60_000) {
|
|
39
|
-
this.frischeMs = frischeMs;
|
|
40
|
-
}
|
|
41
|
-
get groesse() { return this.texte.size; }
|
|
42
|
-
/** Der Wortschatz einer Lektion, oder ein leerer Text, wenn sie fehlt. */
|
|
43
|
-
textVon(topic) { return this.texte.get(topic) ?? ''; }
|
|
44
|
-
/**
|
|
45
|
-
* Alle Themen des Bestands.
|
|
46
|
-
*
|
|
47
|
-
* Wird für die Vorauswahl gebraucht: sie muss über ALLE Lektionen laufen,
|
|
48
|
-
* nicht nur über die, die zufällig einen bestimmten Vektor haben. Genau
|
|
49
|
-
* daran ist der erste Verdrahtungsversuch am 20.08.2026 gescheitert — die
|
|
50
|
-
* Vorauswahl lief nur über die 399 Lektionen mit Fehlertext, und die
|
|
51
|
-
* restlichen 108 konnten nicht mehr gefunden werden (Trefferlage 90 % auf
|
|
52
|
-
* 70 % gefallen).
|
|
53
|
-
*/
|
|
54
|
-
themen() { return this.texte.keys(); }
|
|
55
|
-
/** Die Statistik selbst. `null`, solange nie geladen wurde. */
|
|
56
|
-
get statistik() { return this.seltenheit; }
|
|
57
|
-
async aktualisiere(redis, jetzt = Date.now()) {
|
|
58
|
-
if (this.seltenheit && jetzt - this.geladen < this.frischeMs)
|
|
59
|
-
return;
|
|
60
|
-
const schluessel = [];
|
|
61
|
-
let cursor = '0';
|
|
62
|
-
do {
|
|
63
|
-
const [next, gefunden] = await redis.scan(cursor, 'MATCH', `${LEKTION_PRAEFIX}*`, 'COUNT', 500);
|
|
64
|
-
cursor = next;
|
|
65
|
-
schluessel.push(...gefunden);
|
|
66
|
-
} while (cursor !== '0');
|
|
67
|
-
if (schluessel.length === 0)
|
|
68
|
-
return; // Lieber die alte Statistik als gar keine.
|
|
69
|
-
const texte = new Map();
|
|
70
|
-
for (let i = 0; i < schluessel.length; i += 100) {
|
|
71
|
-
const block = schluessel.slice(i, i + 100);
|
|
72
|
-
const werte = await redis.mget(...block);
|
|
73
|
-
for (const [j, roh] of werte.entries()) {
|
|
74
|
-
if (!roh)
|
|
75
|
-
continue;
|
|
76
|
-
try {
|
|
77
|
-
const o = JSON.parse(roh);
|
|
78
|
-
const topic = typeof o.topic === 'string' && o.topic
|
|
79
|
-
? o.topic
|
|
80
|
-
: block[j].slice(LEKTION_PRAEFIX.length);
|
|
81
|
-
if (topic)
|
|
82
|
-
texte.set(topic, lektionsText(o));
|
|
83
|
-
}
|
|
84
|
-
catch { /* eine kaputte Zeile ist ein Thema fuer doctor, nicht fuer den Recall */ }
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
this.texte = texte;
|
|
88
|
-
this.seltenheit = new Seltenheit([...texte.values()]);
|
|
89
|
-
this.geladen = jetzt;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
//# sourceMappingURL=seltenheitsbestand.js.map
|
|
1
|
+
import{Seltenheit as p}from"./rangfolge.js";const f="cachly:lesson:best:";function w(n){const t=s=>typeof s=="string"?s:"";return[t(n.topic),t(n.what_worked),t(n.what_failed)].filter(Boolean).join(" ")}class d{frischeMs;seltenheit=null;texte=new Map;geladen=0;constructor(t=6e4){this.frischeMs=t}get groesse(){return this.texte.size}textVon(t){return this.texte.get(t)??""}themen(){return this.texte.keys()}get statistik(){return this.seltenheit}async aktualisiere(t,s=Date.now()){if(this.seltenheit&&s-this.geladen<this.frischeMs)return;const i=[];let c="0";do{const[e,o]=await t.scan(c,"MATCH",`${f}*`,"COUNT",500);c=e,i.push(...o)}while(c!=="0");if(i.length===0)return;const h=new Map;for(let e=0;e<i.length;e+=100){const o=i.slice(e,e+100),u=await t.mget(...o);for(const[g,l]of u.entries())if(l)try{const r=JSON.parse(l),a=typeof r.topic=="string"&&r.topic?r.topic:o[g].slice(f.length);a&&h.set(a,w(r))}catch{}}this.texte=h,this.seltenheit=new p([...h.values()]),this.geladen=s}}export{d as Seltenheitsbestand,w as lektionsText};
|
package/dist/src/speicherlage.js
CHANGED
|
@@ -1,84 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Was tut der Speicher WIRKLICH — nicht, was für ihn vorgesehen war.
|
|
3
|
-
*
|
|
4
|
-
* ── Warum es das gibt ───────────────────────────────────────────────────────
|
|
5
|
-
*
|
|
6
|
-
* Am 20.08.2026 stand ein Bestand bei 23,6 MB von 25 MB Tarifgrenze und lief
|
|
7
|
-
* dabei auf der Räumungsregel `allkeys-lru`. Diese Regel löscht bei Platzmangel
|
|
8
|
-
* die am längsten ungenutzte Lektion — ohne Meldung, ohne Fehler, ohne Spur.
|
|
9
|
-
* Genau die alten, selten gebrauchten Lektionen sind aber oft die wertvollen.
|
|
10
|
-
*
|
|
11
|
-
* Das Ärgerliche daran: der Code war seit April richtig. `evictionPolicy` gibt
|
|
12
|
-
* für jeden Tarif `volatile-lru` zurück, und ein Test bewacht das seither. Die
|
|
13
|
-
* laufende Instanz hatte trotzdem `allkeys-lru`, weil ein Container den
|
|
14
|
-
* Startbefehl behält, mit dem er erzeugt wurde. Eine Regeländerung im Code
|
|
15
|
-
* erreicht bestehende Instanzen NICHT.
|
|
16
|
-
*
|
|
17
|
-
* Ein Test beweist die Absicht. Diese Prüfung misst den Zustand. Das ist nicht
|
|
18
|
-
* dieselbe Frage, und die zweite hat monatelang niemand gestellt.
|
|
19
|
-
*
|
|
20
|
-
* ── Warum "nicht gemessen" ein eigenes Urteil ist ──────────────────────────
|
|
21
|
-
*
|
|
22
|
-
* `CONFIG GET` ist auf manchen verwalteten Speichern gesperrt. Wer das als
|
|
23
|
-
* "in Ordnung" verbucht, baut genau den Fehler wieder ein: Stille als grün.
|
|
24
|
-
* Deshalb hat diese Prüfung drei Ausgänge, nicht zwei — gut, Hinweis, und
|
|
25
|
-
* "konnte nicht nachsehen".
|
|
26
|
-
*/
|
|
27
|
-
/** Anteil der Belegung, 0 bis 1. `null`, wenn es keine Grenze gibt oder nichts ablesbar ist. */
|
|
28
|
-
export function anteil(l) {
|
|
29
|
-
if (l.benutzt === null || l.grenze === null || l.grenze <= 0)
|
|
30
|
-
return null;
|
|
31
|
-
return l.benutzt / l.grenze;
|
|
32
|
-
}
|
|
33
|
-
const mb = (b) => `${(b / 1024 / 1024).toFixed(1)} MB`;
|
|
34
|
-
/**
|
|
35
|
-
* Das Urteil über eine Speicherlage.
|
|
36
|
-
*
|
|
37
|
-
* Die Reihenfolge ist Absicht: die stille Löschung steht vor der Füllung. Eine
|
|
38
|
-
* halbvolle Instanz, die still löscht, ist gefährlicher als eine volle, die
|
|
39
|
-
* laut scheitert.
|
|
40
|
-
*/
|
|
41
|
-
export function beurteileSpeicher(l) {
|
|
42
|
-
const aus = [];
|
|
43
|
-
if (l.richtlinie === null) {
|
|
44
|
-
aus.push({
|
|
45
|
-
art: 'ungemessen',
|
|
46
|
-
text: 'Raeumungsregel nicht ablesbar (CONFIG GET gesperrt) — unbekannt, ob dieser Speicher bei Platzmangel still loescht.',
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
else if (l.richtlinie.startsWith('allkeys')) {
|
|
50
|
-
aus.push({
|
|
51
|
-
art: 'fehler',
|
|
52
|
-
text: `Raeumungsregel ist \`${l.richtlinie}\`: bei Platzmangel wird die am laengsten ungenutzte Lektion GELOESCHT, ohne Meldung. Ein Gedaechtnis darf nicht raeumen wie ein Zwischenspeicher. Richtig waere \`volatile-lru\` (raeumt nur, was ohnehin ablaeuft) oder \`noeviction\` (scheitert laut).`,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
else if (l.richtlinie === 'volatile-lru' || l.richtlinie === 'noeviction') {
|
|
56
|
-
aus.push({ art: 'gut', text: `Raeumungsregel \`${l.richtlinie}\` — Lektionen ohne Ablaufdatum sind sicher.` });
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
aus.push({ art: 'hinweis', text: `Raeumungsregel \`${l.richtlinie}\` — ungeprueft fuer diesen Zweck.` });
|
|
60
|
-
}
|
|
61
|
-
const a = anteil(l);
|
|
62
|
-
if (l.benutzt === null) {
|
|
63
|
-
aus.push({ art: 'ungemessen', text: 'Belegung nicht ablesbar.' });
|
|
64
|
-
}
|
|
65
|
-
else if (a === null) {
|
|
66
|
-
aus.push({ art: 'hinweis', text: `${mb(l.benutzt)} belegt, keine Obergrenze gesetzt — dieser Speicher waechst, bis der Rechner voll ist.` });
|
|
67
|
-
}
|
|
68
|
-
else if (a >= 0.9) {
|
|
69
|
-
aus.push({ art: 'fehler', text: `${mb(l.benutzt)} von ${mb(l.grenze)} belegt (${Math.round(a * 100)} %). Die naechsten Lektionen scheitern bald.` });
|
|
70
|
-
}
|
|
71
|
-
else if (a >= 0.75) {
|
|
72
|
-
aus.push({ art: 'hinweis', text: `${mb(l.benutzt)} von ${mb(l.grenze)} belegt (${Math.round(a * 100)} %).` });
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
aus.push({ art: 'gut', text: `${mb(l.benutzt)} von ${mb(l.grenze)} belegt (${Math.round(a * 100)} %).` });
|
|
76
|
-
}
|
|
77
|
-
return aus;
|
|
78
|
-
}
|
|
79
|
-
/** Eine Zahl aus einem INFO-Block, z. B. `used_memory`. `null`, wenn sie fehlt. */
|
|
80
|
-
export function zahlAusInfo(info, name) {
|
|
81
|
-
const t = new RegExp(`^${name}:(\\d+)`, 'm').exec(info);
|
|
82
|
-
return t ? Number(t[1]) : null;
|
|
83
|
-
}
|
|
84
|
-
//# sourceMappingURL=speicherlage.js.map
|
|
1
|
+
function r(e){return e.benutzt===null||e.grenze===null||e.grenze<=0?null:e.benutzt/e.grenze}const i=e=>`${(e/1024/1024).toFixed(1)} MB`;function u(e){const t=[];e.richtlinie===null?t.push({art:"ungemessen",text:"Raeumungsregel nicht ablesbar (CONFIG GET gesperrt) \u2014 unbekannt, ob dieser Speicher bei Platzmangel still loescht."}):e.richtlinie.startsWith("allkeys")?t.push({art:"fehler",text:`Raeumungsregel ist \`${e.richtlinie}\`: bei Platzmangel wird die am laengsten ungenutzte Lektion GELOESCHT, ohne Meldung. Ein Gedaechtnis darf nicht raeumen wie ein Zwischenspeicher. Richtig waere \`volatile-lru\` (raeumt nur, was ohnehin ablaeuft) oder \`noeviction\` (scheitert laut).`}):e.richtlinie==="volatile-lru"||e.richtlinie==="noeviction"?t.push({art:"gut",text:`Raeumungsregel \`${e.richtlinie}\` \u2014 Lektionen ohne Ablaufdatum sind sicher.`}):t.push({art:"hinweis",text:`Raeumungsregel \`${e.richtlinie}\` \u2014 ungeprueft fuer diesen Zweck.`});const n=r(e);return e.benutzt===null?t.push({art:"ungemessen",text:"Belegung nicht ablesbar."}):n===null?t.push({art:"hinweis",text:`${i(e.benutzt)} belegt, keine Obergrenze gesetzt \u2014 dieser Speicher waechst, bis der Rechner voll ist.`}):n>=.9?t.push({art:"fehler",text:`${i(e.benutzt)} von ${i(e.grenze)} belegt (${Math.round(n*100)} %). Die naechsten Lektionen scheitern bald.`}):n>=.75?t.push({art:"hinweis",text:`${i(e.benutzt)} von ${i(e.grenze)} belegt (${Math.round(n*100)} %).`}):t.push({art:"gut",text:`${i(e.benutzt)} von ${i(e.grenze)} belegt (${Math.round(n*100)} %).`}),t}function s(e,t){const n=new RegExp(`^${t}:(\\d+)`,"m").exec(e);return n?Number(n[1]):null}export{r as anteil,u as beurteileSpeicher,s as zahlAusInfo};
|
package/dist/src/spuren.js
CHANGED
|
@@ -1,150 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Trampelpfade: das System lernt die Fragen, mit denen man es wirklich sucht.
|
|
3
|
-
*
|
|
4
|
-
* ── Der Gedanke ─────────────────────────────────────────────────────────────
|
|
5
|
-
*
|
|
6
|
-
* Ein Immunsystem hält Andockstellen vorrätig — und nach jeder überstandenen
|
|
7
|
-
* Infektion bleiben Gedächtniszellen zurück, die genau diesen Erreger beim
|
|
8
|
-
* nächsten Mal sofort greifen. Die Andockstellen sind gebaut (`eingaenge.ts`,
|
|
9
|
-
* die Fehlertexte). Das hier sind die Gedächtniszellen.
|
|
10
|
-
*
|
|
11
|
-
* Wenn eine Frage eine Lektion findet, ist diese Frage ein bewiesener Weg zu
|
|
12
|
-
* ihr. Sie wird als eigener Eingang gespeichert — beim nächsten Mal ist der
|
|
13
|
-
* Weg breiter.
|
|
14
|
-
*
|
|
15
|
-
* ── Warum erst beim ZWEITEN Mal ─────────────────────────────────────────────
|
|
16
|
-
*
|
|
17
|
-
* Der Bauplan wollte den Eingang speichern, sobald eine Lektion „benutzt oder
|
|
18
|
-
* bestätigt" wurde. Dieses Signal gibt es nicht: der Server sieht, was er
|
|
19
|
-
* ausgeliefert hat, nicht was jemand damit gemacht hat. Es zu erfinden wäre
|
|
20
|
-
* eine Zahl ohne Deckung.
|
|
21
|
-
*
|
|
22
|
-
* Also das, was ein Trampelpfad wirklich ist: **Wiederholung.** Ein einzelnes
|
|
23
|
-
* Durchqueren macht keinen Weg. Führt dieselbe Frage ZWEIMAL zu derselben
|
|
24
|
-
* Lektion, ist sie ein Pfad — und braucht dafür keine Bestätigung von außen,
|
|
25
|
-
* sondern nur Geduld.
|
|
26
|
-
*
|
|
27
|
-
* ── Was das kann, und was ausdrücklich nicht ────────────────────────────────
|
|
28
|
-
*
|
|
29
|
-
* ES HILFT: einer Frage, die die Lektion heute auf Platz 3 findet, morgen auf
|
|
30
|
-
* Platz 1. Genau das ist der gemessene Engpass — 37 richtige Antworten liegen
|
|
31
|
-
* im Topf und werden nicht gezeigt (`.agent/cachly/tor0-tor1-ergebnis.md`).
|
|
32
|
-
*
|
|
33
|
-
* ES HILFT NICHT: einer Frage, die die Lektion gar nicht findet. Die wird nie
|
|
34
|
-
* aufgezeichnet, weil sie nie ankam. Dieser blinde Fleck ist der Grund, warum
|
|
35
|
-
* die Fehlertext-Eingänge daneben bestehen bleiben — sie wirken ohne Nutzung.
|
|
36
|
-
*/
|
|
37
|
-
import { packe } from './bedeutung.js';
|
|
38
|
-
import { EINGANG_PRAEFIX } from './eingaenge.js';
|
|
39
|
-
/** Wo die noch unbewiesenen Spuren liegen: Frage → wie oft sie hierher führte. */
|
|
40
|
-
export const SPUR_PRAEFIX = 'cachly:lesson:spur:';
|
|
41
|
-
/**
|
|
42
|
-
* Wo die bewiesenen Pfade liegen — als eigener Hash, NICHT im Eingangs-Hash.
|
|
43
|
-
*
|
|
44
|
-
* Grund: `schreibeEingaenge` löscht seinen Hash vor jedem Schreiben, damit die
|
|
45
|
-
* Fehlertexte einer alten Fassung nicht neben denen der neuen stehen bleiben.
|
|
46
|
-
* Lägen die gelernten Fragen dort, würde jedes erneute Lernen der Lektion die
|
|
47
|
-
* gesammelte Erfahrung wegwerfen — ein Gedächtnis, das beim Dazulernen
|
|
48
|
-
* vergisst.
|
|
49
|
-
*/
|
|
50
|
-
export const PFAD_PRAEFIX = 'cachly:lesson:pfad:';
|
|
51
|
-
/** Ab wie vielen Malen eine Frage als Pfad gilt. Einmal ist Zufall. */
|
|
52
|
-
export const PFAD_SCHWELLE = 2;
|
|
53
|
-
/** Höchstens so viele gelernte Fragen je Lektion. Der schwächste weicht. */
|
|
54
|
-
export const PFAD_KAPPE = 8;
|
|
55
|
-
/** Nur Fragen dieser Länge werden aufgezeichnet. */
|
|
56
|
-
const MIN_LAENGE = 8;
|
|
57
|
-
const MAX_LAENGE = 200;
|
|
58
|
-
/**
|
|
59
|
-
* Zwei Fragen, die sich nur in Zeichensetzung und Grossschreibung
|
|
60
|
-
* unterscheiden, sind derselbe Weg.
|
|
61
|
-
*
|
|
62
|
-
* Bewusst KEIN Stammformen-Verfahren: am 19.08.2026 gemessen kostete
|
|
63
|
-
* Stammbildung drei Punkte Findequote. Hier geht es ausserdem um Gleichheit,
|
|
64
|
-
* nicht um Ähnlichkeit — wer „docker startet nicht" und „Docker startet
|
|
65
|
-
* nicht!" trennt, zählt zweimal halb statt einmal ganz.
|
|
66
|
-
*/
|
|
67
|
-
export function spurSchluessel(frage) {
|
|
68
|
-
return frage
|
|
69
|
-
.toLowerCase()
|
|
70
|
-
.replace(/[^\p{L}\p{N}\s]/gu, ' ')
|
|
71
|
-
.replace(/\s+/g, ' ')
|
|
72
|
-
.trim()
|
|
73
|
-
.slice(0, MAX_LAENGE);
|
|
74
|
-
}
|
|
75
|
-
/** Taugt diese Frage überhaupt als Pfad? */
|
|
76
|
-
export function taugtAlsSpur(frage) {
|
|
77
|
-
const k = spurSchluessel(frage);
|
|
78
|
-
// Eine Frage aus einem einzigen Wort ist kein Weg, sondern ein Stichwort —
|
|
79
|
-
// sie würde jede Lektion an sich ziehen, die dieses Wort enthält.
|
|
80
|
-
return k.length >= MIN_LAENGE && k.split(' ').length >= 2;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Welche Fragen sollen ihre Kappe überleben?
|
|
84
|
-
*
|
|
85
|
-
* Absteigend nach Häufigkeit; bei Gleichstand gewinnt die kürzere. Eine kurze
|
|
86
|
-
* Frage, die genauso oft hierher führte, ist die allgemeinere — sie fängt mehr
|
|
87
|
-
* Formulierungen als ihre lange Schwester.
|
|
88
|
-
*/
|
|
89
|
-
export function behalte(pfade, kappe = PFAD_KAPPE) {
|
|
90
|
-
return pfade
|
|
91
|
-
.slice()
|
|
92
|
-
.sort((a, b) => b.anzahl - a.anzahl || a.frage.length - b.frage.length)
|
|
93
|
-
.slice(0, kappe);
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Zeichnet auf, dass diese Frage zu diesen Lektionen geführt hat, und macht
|
|
97
|
-
* aus einer Spur einen Pfad, sobald sie sich wiederholt.
|
|
98
|
-
*
|
|
99
|
-
* Bewusst KEIN await beim Aufrufer nötig: wer sucht, soll nicht warten, bis
|
|
100
|
-
* das Gedächtnis nachgeführt ist. Fällt es aus, ist die Suche trotzdem
|
|
101
|
-
* beantwortet — der Pfad entsteht dann eben beim nächsten Mal.
|
|
102
|
-
*
|
|
103
|
-
* @returns wie viele Fragen zu Pfaden befördert wurden
|
|
104
|
-
*/
|
|
105
|
-
export async function spurLegen(redis, frage, themen, einbetten) {
|
|
106
|
-
if (!taugtAlsSpur(frage) || themen.length === 0)
|
|
107
|
-
return 0;
|
|
108
|
-
const schluessel = spurSchluessel(frage);
|
|
109
|
-
let befoerdert = 0;
|
|
110
|
-
for (const topic of themen) {
|
|
111
|
-
const spurKey = `${SPUR_PRAEFIX}${topic}`;
|
|
112
|
-
const pfadKey = `${PFAD_PRAEFIX}${topic}`;
|
|
113
|
-
// Schon ein Pfad? Dann nur mitzaehlen, nicht noch einmal einbetten.
|
|
114
|
-
const istPfad = await redis.hexists(pfadKey, schluessel);
|
|
115
|
-
const anzahl = await redis.hincrby(spurKey, schluessel, 1);
|
|
116
|
-
if (istPfad || anzahl < PFAD_SCHWELLE)
|
|
117
|
-
continue;
|
|
118
|
-
// Eingebettet wird die FRAGE, wiedererkannt wird der Schluessel.
|
|
119
|
-
//
|
|
120
|
-
// Zwei verschiedene Aufgaben: der Schluessel muss "Docker startet nicht!"
|
|
121
|
-
// und "docker startet nicht" als denselben Weg erkennen — dafuer ist er
|
|
122
|
-
// kleingeschrieben und ohne Zeichensetzung. Fuer die Bedeutung ist genau
|
|
123
|
-
// das ein Verlust: im Deutschen traegt die Grossschreibung, ob "Sein" ein
|
|
124
|
-
// Hauptwort ist. Also wird der Originalwortlaut eingebettet.
|
|
125
|
-
const v = await einbetten(frage.trim().slice(0, MAX_LAENGE));
|
|
126
|
-
if (!v?.length)
|
|
127
|
-
continue;
|
|
128
|
-
await redis.hset(pfadKey, schluessel, packe(v));
|
|
129
|
-
befoerdert++;
|
|
130
|
-
// Kappe durchsetzen: der am seltensten begangene Pfad weicht.
|
|
131
|
-
const alle = await redis.hkeys(pfadKey);
|
|
132
|
-
if (alle.length > PFAD_KAPPE) {
|
|
133
|
-
const zaehler = await redis.hgetall(spurKey);
|
|
134
|
-
const mitAnzahl = alle.map((f) => ({ frage: f, anzahl: Number(zaehler[f] ?? 0) }));
|
|
135
|
-
const bleiben = new Set(behalte(mitAnzahl).map((x) => x.frage));
|
|
136
|
-
const raus = alle.filter((f) => !bleiben.has(f));
|
|
137
|
-
if (raus.length)
|
|
138
|
-
await redis.hdel(pfadKey, ...raus);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return befoerdert;
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Was `Eingangsbestand` laden muss: beide Hashes.
|
|
145
|
-
*
|
|
146
|
-
* Steht hier und nicht in eingaenge.ts, damit die Reihenfolge der Module
|
|
147
|
-
* eindeutig bleibt — spuren kennt eingaenge, nicht umgekehrt.
|
|
148
|
-
*/
|
|
149
|
-
export const EINGANGS_PRAEFIXE = [EINGANG_PRAEFIX, PFAD_PRAEFIX];
|
|
150
|
-
//# sourceMappingURL=spuren.js.map
|
|
1
|
+
import{packe as _}from"./bedeutung.js";import{EINGANG_PRAEFIX as y}from"./eingaenge.js";const F="cachly:lesson:spur:",f="cachly:lesson:pfad:",I=2,g=8,L=8,A=200;function E(t){return t.toLowerCase().replace(/[^\p{L}\p{N}\s]/gu," ").replace(/\s+/g," ").trim().slice(0,A)}function z(t){const e=E(t);return e.length>=L&&e.split(" ").length>=2}function G(t,e=g){return t.slice().sort((o,s)=>s.anzahl-o.anzahl||o.frage.length-s.frage.length).slice(0,e)}async function R(t,e,o,s){if(!z(e)||o.length===0)return 0;const c=E(e);let r=0;for(const i of o){const p=`${F}${i}`,a=`${f}${i}`,P=await t.hexists(a,c),x=await t.hincrby(p,c,1);if(P||x<I)continue;const h=await s(e.trim().slice(0,A));if(!h?.length)continue;await t.hset(a,c,_(h)),r++;const l=await t.hkeys(a);if(l.length>g){const m=await t.hgetall(p),w=l.map(n=>({frage:n,anzahl:Number(m[n]??0)})),N=new Set(G(w).map(n=>n.frage)),u=l.filter(n=>!N.has(n));u.length&&await t.hdel(a,...u)}}return r}const X=[y,f];export{X as EINGANGS_PRAEFIXE,g as PFAD_KAPPE,f as PFAD_PRAEFIX,I as PFAD_SCHWELLE,F as SPUR_PRAEFIX,G as behalte,R as spurLegen,E as spurSchluessel,z as taugtAlsSpur};
|
|
@@ -1,165 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Curated starter corpus — universal, high-value engineering lessons.
|
|
3
|
-
*
|
|
4
|
-
* Loaded on demand via `brain_seed_starter` (or offered in the empty-brain
|
|
5
|
-
* session_start welcome). The goal is to drop **time-to-first-recall** below
|
|
6
|
-
* two minutes: a brand-new Brain (fresh repo, shallow clone, no fix-commits in
|
|
7
|
-
* git history) would otherwise return nothing on the user's first query.
|
|
8
|
-
*
|
|
9
|
-
* Every lesson here is:
|
|
10
|
-
* - stack-agnostic or broadly applicable (no project-specific paths)
|
|
11
|
-
* - a real, common failure mode with a proven fix
|
|
12
|
-
* - free of secrets / PII
|
|
13
|
-
* - tagged `source: 'starter'` so it can be identified, filtered, or removed
|
|
14
|
-
*
|
|
15
|
-
* These ship inside the package — no network call needed to seed.
|
|
16
|
-
*/
|
|
17
|
-
export const STARTER_CORPUS = [
|
|
18
|
-
{
|
|
19
|
-
topic: 'docker:layer-cache',
|
|
20
|
-
outcome: 'success',
|
|
21
|
-
what_worked: 'Copy package manifests (package.json/lock, go.mod, requirements.txt) and install deps BEFORE copying the rest of the source. Dependency layers then stay cached across code-only changes.',
|
|
22
|
-
what_failed: 'Build re-downloads all dependencies on every code change because `COPY . .` came before the install step, busting the cache.',
|
|
23
|
-
ctx: 'Slow Docker builds in CI — every commit reinstalls dependencies even when only app code changed.',
|
|
24
|
-
tags: ['docker', 'ci', 'build', 'cache', 'performance'],
|
|
25
|
-
confidence: 0.9,
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
topic: 'git:force-push-safety',
|
|
29
|
-
outcome: 'success',
|
|
30
|
-
what_worked: 'Use `git push --force-with-lease` instead of `--force`. It refuses to overwrite if the remote moved since your last fetch, protecting teammates\' commits.',
|
|
31
|
-
what_failed: 'A plain `git push --force` silently clobbered a colleague\'s commits that had landed after the last local fetch.',
|
|
32
|
-
ctx: 'Rebasing a shared feature branch and force-pushing the result.',
|
|
33
|
-
tags: ['git', 'rebase', 'collaboration', 'safety'],
|
|
34
|
-
confidence: 0.92,
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
topic: 'ci:flaky-tests-timing',
|
|
38
|
-
outcome: 'success',
|
|
39
|
-
what_worked: 'Pin time and randomness: use fake/frozen timers (e.g. vi.useFakeTimers, freezegun) and a fixed RNG seed. Replace arbitrary sleeps with explicit awaits on a condition.',
|
|
40
|
-
what_failed: 'Tests passed locally but failed ~10% of the time in CI due to real wall-clock timing and unseeded random data.',
|
|
41
|
-
ctx: 'Intermittent CI failures that disappear on re-run — classic flaky test.',
|
|
42
|
-
tags: ['ci', 'testing', 'flaky', 'timers', 'determinism'],
|
|
43
|
-
confidence: 0.85,
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
topic: 'node:esm-cjs-interop',
|
|
47
|
-
outcome: 'success',
|
|
48
|
-
what_worked: 'Set `"type": "module"` in package.json for ESM, use explicit `.js` extensions in relative imports, and `import { createRequire }` if you must load a CJS-only module.',
|
|
49
|
-
what_failed: '"ReferenceError: exports is not defined" / "Cannot use import statement outside a module" after mixing ESM and CommonJS.',
|
|
50
|
-
ctx: 'Migrating a Node project to ES modules or adding an ESM-only dependency.',
|
|
51
|
-
tags: ['node', 'esm', 'commonjs', 'modules', 'typescript'],
|
|
52
|
-
confidence: 0.85,
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
topic: 'jwt:clock-skew',
|
|
56
|
-
outcome: 'success',
|
|
57
|
-
what_worked: 'Allow a small leeway (30–60s) when validating `exp`/`nbf` claims, and keep server clocks synced with NTP. Most JWT libraries accept a `clockTolerance` option.',
|
|
58
|
-
what_failed: 'Valid tokens were rejected as expired because the auth server and API server clocks differed by a few seconds.',
|
|
59
|
-
ctx: 'Intermittent 401s right around token expiry across multiple services.',
|
|
60
|
-
tags: ['jwt', 'auth', 'clock', 'security', 'tokens'],
|
|
61
|
-
confidence: 0.88,
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
topic: 'postgres:migration-lock',
|
|
65
|
-
outcome: 'success',
|
|
66
|
-
what_worked: 'Set a short `lock_timeout` before DDL and add indexes with `CREATE INDEX CONCURRENTLY`. This avoids a migration blocking on a long-held table lock and stalling the whole deploy.',
|
|
67
|
-
what_failed: 'A migration hung indefinitely waiting for an ACCESS EXCLUSIVE lock while a long-running query held the table, blocking the deploy.',
|
|
68
|
-
ctx: 'Production deploy froze during a schema migration under live traffic.',
|
|
69
|
-
tags: ['postgres', 'database', 'migration', 'deploy', 'locking'],
|
|
70
|
-
confidence: 0.87,
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
topic: 'redis:eviction-policy',
|
|
74
|
-
outcome: 'success',
|
|
75
|
-
what_worked: 'Set `maxmemory` and an explicit `maxmemory-policy` (e.g. `allkeys-lru` for a cache, `noeviction` for a datastore). Always set TTLs on cache keys.',
|
|
76
|
-
what_failed: 'Redis silently evicted keys (or OOM-errored on writes) because no maxmemory policy was configured and keys never expired.',
|
|
77
|
-
ctx: 'Cache hit-rate cratered / writes started failing as Redis filled up.',
|
|
78
|
-
tags: ['redis', 'cache', 'memory', 'eviction', 'ttl'],
|
|
79
|
-
confidence: 0.86,
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
topic: 'k8s:oom-limits',
|
|
83
|
-
outcome: 'success',
|
|
84
|
-
what_worked: 'Set both memory `requests` and `limits` on every container. For JVM/Node, also cap the runtime heap below the container limit so the GC reclaims before the kernel OOM-kills.',
|
|
85
|
-
what_failed: 'Pods were OOMKilled (exit 137) and restarted in a loop because no memory limit was set and the node was overcommitted.',
|
|
86
|
-
ctx: 'Pod restarting repeatedly with OOMKilled status in kubectl describe.',
|
|
87
|
-
tags: ['kubernetes', 'oom', 'memory', 'limits', 'infra'],
|
|
88
|
-
confidence: 0.85,
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
topic: 'cors:preflight',
|
|
92
|
-
outcome: 'success',
|
|
93
|
-
what_worked: 'Handle the OPTIONS preflight explicitly and return the right Access-Control-Allow-{Origin,Methods,Headers}. For credentialed requests, echo a specific origin (never `*`) and set Allow-Credentials: true.',
|
|
94
|
-
what_failed: 'Browser blocked requests with "No \'Access-Control-Allow-Origin\' header" — the server never answered the preflight OPTIONS request.',
|
|
95
|
-
ctx: 'Frontend on a different origin gets CORS errors only in the browser (curl works fine).',
|
|
96
|
-
tags: ['cors', 'http', 'api', 'browser', 'preflight'],
|
|
97
|
-
confidence: 0.84,
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
topic: 'env:dotenv-precedence',
|
|
101
|
-
outcome: 'success',
|
|
102
|
-
what_worked: 'Know the precedence: real environment variables (and Docker `-e`/compose `environment`) override a `.env` file. Most loaders will NOT overwrite an already-set var. Audit with a startup log of effective config.',
|
|
103
|
-
what_failed: 'A value in `.env` was silently ignored in the container because an environment variable of the same name was already set by Docker.',
|
|
104
|
-
ctx: 'Config works locally but the container picks up the wrong value.',
|
|
105
|
-
tags: ['env', 'dotenv', 'docker', 'config'],
|
|
106
|
-
confidence: 0.83,
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
topic: 'async:unhandled-rejection',
|
|
110
|
-
outcome: 'success',
|
|
111
|
-
what_worked: 'Await or `.catch()` every promise. Add a process-level `unhandledRejection` handler that logs and exits non-zero, so a dropped rejection is loud, not silent.',
|
|
112
|
-
what_failed: 'A fire-and-forget promise rejected, the error vanished, and the process kept running in a broken state with no log.',
|
|
113
|
-
ctx: 'Mysterious missing data / silent failures with no stack trace in a Node service.',
|
|
114
|
-
tags: ['async', 'node', 'promises', 'error-handling'],
|
|
115
|
-
confidence: 0.84,
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
topic: 'sql:n-plus-one',
|
|
119
|
-
outcome: 'success',
|
|
120
|
-
what_worked: 'Eager-load related rows in one query (JOIN or the ORM\'s include/preload/select_related) instead of looping and querying per row. Verify with query logging or an APM trace.',
|
|
121
|
-
what_failed: 'An endpoint issued one query per item in a list (N+1), making latency scale linearly with result count.',
|
|
122
|
-
ctx: 'List endpoint gets slow as data grows; DB shows a flood of near-identical small queries.',
|
|
123
|
-
tags: ['sql', 'database', 'orm', 'performance', 'n+1'],
|
|
124
|
-
confidence: 0.86,
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
topic: 'http:retry-idempotency',
|
|
128
|
-
outcome: 'success',
|
|
129
|
-
what_worked: 'Only auto-retry idempotent requests (GET/PUT/DELETE) or POSTs guarded by an idempotency key. Use exponential backoff with jitter and a cap on attempts.',
|
|
130
|
-
what_failed: 'A retried POST created duplicate records because the first request actually succeeded but the response was lost.',
|
|
131
|
-
ctx: 'Duplicate charges / duplicate rows after adding naive retry logic to an HTTP client.',
|
|
132
|
-
tags: ['http', 'retry', 'idempotency', 'reliability', 'backoff'],
|
|
133
|
-
confidence: 0.85,
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
topic: 'cache:stampede',
|
|
137
|
-
outcome: 'success',
|
|
138
|
-
what_worked: 'Prevent thundering-herd recomputation on cache expiry with a short lock (single-flight) or early-recompute-with-jitter so only one request rebuilds the value while others serve the stale one.',
|
|
139
|
-
what_failed: 'When a hot cache key expired, hundreds of concurrent requests all missed and hammered the database simultaneously.',
|
|
140
|
-
ctx: 'Periodic DB load spikes that line up exactly with cache TTL expiry.',
|
|
141
|
-
tags: ['cache', 'stampede', 'performance', 'concurrency', 'redis'],
|
|
142
|
-
confidence: 0.83,
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
topic: 'security:no-secrets-in-logs',
|
|
146
|
-
outcome: 'success',
|
|
147
|
-
what_worked: 'Redact tokens, passwords, and full auth headers before logging. Log a token\'s prefix + length, never the value. Add a log scrubber/filter so it cannot regress.',
|
|
148
|
-
what_failed: 'A bearer token was written to application logs and ended up in the log aggregator, where it was searchable by anyone with log access.',
|
|
149
|
-
ctx: 'Security review found credentials in centralized logs.',
|
|
150
|
-
tags: ['security', 'logging', 'secrets', 'pii', 'compliance'],
|
|
151
|
-
confidence: 0.9,
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
topic: 'tls:cert-expiry',
|
|
155
|
-
outcome: 'success',
|
|
156
|
-
what_worked: 'Automate renewal (ACME/cert-manager) and alert at least 14 days before expiry. Monitor the leaf AND intermediate chain — clients fail if the chain is incomplete even when the leaf is valid.',
|
|
157
|
-
what_failed: 'A production outage hit when a TLS certificate silently expired over a weekend with no alerting in place.',
|
|
158
|
-
ctx: 'Sudden "certificate has expired" errors from clients; site unreachable over HTTPS.',
|
|
159
|
-
tags: ['tls', 'ssl', 'certificates', 'monitoring', 'infra'],
|
|
160
|
-
confidence: 0.88,
|
|
161
|
-
},
|
|
162
|
-
];
|
|
163
|
-
/** Stable count for changelog / docs. */
|
|
164
|
-
export const STARTER_CORPUS_SIZE = STARTER_CORPUS.length;
|
|
165
|
-
//# sourceMappingURL=starter-corpus.js.map
|
|
1
|
+
const e=[{topic:"docker:layer-cache",outcome:"success",what_worked:"Copy package manifests (package.json/lock, go.mod, requirements.txt) and install deps BEFORE copying the rest of the source. Dependency layers then stay cached across code-only changes.",what_failed:"Build re-downloads all dependencies on every code change because `COPY . .` came before the install step, busting the cache.",ctx:"Slow Docker builds in CI \u2014 every commit reinstalls dependencies even when only app code changed.",tags:["docker","ci","build","cache","performance"],confidence:.9},{topic:"git:force-push-safety",outcome:"success",what_worked:"Use `git push --force-with-lease` instead of `--force`. It refuses to overwrite if the remote moved since your last fetch, protecting teammates' commits.",what_failed:"A plain `git push --force` silently clobbered a colleague's commits that had landed after the last local fetch.",ctx:"Rebasing a shared feature branch and force-pushing the result.",tags:["git","rebase","collaboration","safety"],confidence:.92},{topic:"ci:flaky-tests-timing",outcome:"success",what_worked:"Pin time and randomness: use fake/frozen timers (e.g. vi.useFakeTimers, freezegun) and a fixed RNG seed. Replace arbitrary sleeps with explicit awaits on a condition.",what_failed:"Tests passed locally but failed ~10% of the time in CI due to real wall-clock timing and unseeded random data.",ctx:"Intermittent CI failures that disappear on re-run \u2014 classic flaky test.",tags:["ci","testing","flaky","timers","determinism"],confidence:.85},{topic:"node:esm-cjs-interop",outcome:"success",what_worked:'Set `"type": "module"` in package.json for ESM, use explicit `.js` extensions in relative imports, and `import { createRequire }` if you must load a CJS-only module.',what_failed:'"ReferenceError: exports is not defined" / "Cannot use import statement outside a module" after mixing ESM and CommonJS.',ctx:"Migrating a Node project to ES modules or adding an ESM-only dependency.",tags:["node","esm","commonjs","modules","typescript"],confidence:.85},{topic:"jwt:clock-skew",outcome:"success",what_worked:"Allow a small leeway (30\u201360s) when validating `exp`/`nbf` claims, and keep server clocks synced with NTP. Most JWT libraries accept a `clockTolerance` option.",what_failed:"Valid tokens were rejected as expired because the auth server and API server clocks differed by a few seconds.",ctx:"Intermittent 401s right around token expiry across multiple services.",tags:["jwt","auth","clock","security","tokens"],confidence:.88},{topic:"postgres:migration-lock",outcome:"success",what_worked:"Set a short `lock_timeout` before DDL and add indexes with `CREATE INDEX CONCURRENTLY`. This avoids a migration blocking on a long-held table lock and stalling the whole deploy.",what_failed:"A migration hung indefinitely waiting for an ACCESS EXCLUSIVE lock while a long-running query held the table, blocking the deploy.",ctx:"Production deploy froze during a schema migration under live traffic.",tags:["postgres","database","migration","deploy","locking"],confidence:.87},{topic:"redis:eviction-policy",outcome:"success",what_worked:"Set `maxmemory` and an explicit `maxmemory-policy` (e.g. `allkeys-lru` for a cache, `noeviction` for a datastore). Always set TTLs on cache keys.",what_failed:"Redis silently evicted keys (or OOM-errored on writes) because no maxmemory policy was configured and keys never expired.",ctx:"Cache hit-rate cratered / writes started failing as Redis filled up.",tags:["redis","cache","memory","eviction","ttl"],confidence:.86},{topic:"k8s:oom-limits",outcome:"success",what_worked:"Set both memory `requests` and `limits` on every container. For JVM/Node, also cap the runtime heap below the container limit so the GC reclaims before the kernel OOM-kills.",what_failed:"Pods were OOMKilled (exit 137) and restarted in a loop because no memory limit was set and the node was overcommitted.",ctx:"Pod restarting repeatedly with OOMKilled status in kubectl describe.",tags:["kubernetes","oom","memory","limits","infra"],confidence:.85},{topic:"cors:preflight",outcome:"success",what_worked:"Handle the OPTIONS preflight explicitly and return the right Access-Control-Allow-{Origin,Methods,Headers}. For credentialed requests, echo a specific origin (never `*`) and set Allow-Credentials: true.",what_failed:`Browser blocked requests with "No 'Access-Control-Allow-Origin' header" \u2014 the server never answered the preflight OPTIONS request.`,ctx:"Frontend on a different origin gets CORS errors only in the browser (curl works fine).",tags:["cors","http","api","browser","preflight"],confidence:.84},{topic:"env:dotenv-precedence",outcome:"success",what_worked:"Know the precedence: real environment variables (and Docker `-e`/compose `environment`) override a `.env` file. Most loaders will NOT overwrite an already-set var. Audit with a startup log of effective config.",what_failed:"A value in `.env` was silently ignored in the container because an environment variable of the same name was already set by Docker.",ctx:"Config works locally but the container picks up the wrong value.",tags:["env","dotenv","docker","config"],confidence:.83},{topic:"async:unhandled-rejection",outcome:"success",what_worked:"Await or `.catch()` every promise. Add a process-level `unhandledRejection` handler that logs and exits non-zero, so a dropped rejection is loud, not silent.",what_failed:"A fire-and-forget promise rejected, the error vanished, and the process kept running in a broken state with no log.",ctx:"Mysterious missing data / silent failures with no stack trace in a Node service.",tags:["async","node","promises","error-handling"],confidence:.84},{topic:"sql:n-plus-one",outcome:"success",what_worked:"Eager-load related rows in one query (JOIN or the ORM's include/preload/select_related) instead of looping and querying per row. Verify with query logging or an APM trace.",what_failed:"An endpoint issued one query per item in a list (N+1), making latency scale linearly with result count.",ctx:"List endpoint gets slow as data grows; DB shows a flood of near-identical small queries.",tags:["sql","database","orm","performance","n+1"],confidence:.86},{topic:"http:retry-idempotency",outcome:"success",what_worked:"Only auto-retry idempotent requests (GET/PUT/DELETE) or POSTs guarded by an idempotency key. Use exponential backoff with jitter and a cap on attempts.",what_failed:"A retried POST created duplicate records because the first request actually succeeded but the response was lost.",ctx:"Duplicate charges / duplicate rows after adding naive retry logic to an HTTP client.",tags:["http","retry","idempotency","reliability","backoff"],confidence:.85},{topic:"cache:stampede",outcome:"success",what_worked:"Prevent thundering-herd recomputation on cache expiry with a short lock (single-flight) or early-recompute-with-jitter so only one request rebuilds the value while others serve the stale one.",what_failed:"When a hot cache key expired, hundreds of concurrent requests all missed and hammered the database simultaneously.",ctx:"Periodic DB load spikes that line up exactly with cache TTL expiry.",tags:["cache","stampede","performance","concurrency","redis"],confidence:.83},{topic:"security:no-secrets-in-logs",outcome:"success",what_worked:"Redact tokens, passwords, and full auth headers before logging. Log a token's prefix + length, never the value. Add a log scrubber/filter so it cannot regress.",what_failed:"A bearer token was written to application logs and ended up in the log aggregator, where it was searchable by anyone with log access.",ctx:"Security review found credentials in centralized logs.",tags:["security","logging","secrets","pii","compliance"],confidence:.9},{topic:"tls:cert-expiry",outcome:"success",what_worked:"Automate renewal (ACME/cert-manager) and alert at least 14 days before expiry. Monitor the leaf AND intermediate chain \u2014 clients fail if the chain is incomplete even when the leaf is valid.",what_failed:"A production outage hit when a TLS certificate silently expired over a weekend with no alerting in place.",ctx:'Sudden "certificate has expired" errors from clients; site unreachable over HTTPS.',tags:["tls","ssl","certificates","monitoring","infra"],confidence:.88}],t=e.length;export{e as STARTER_CORPUS,t as STARTER_CORPUS_SIZE};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canonical types for the cachly telemetry event stream.
|
|
3
|
-
*
|
|
4
|
-
* These types form the contract between:
|
|
5
|
-
* - cachly-mcp (emitter) → POST /api/v1/telemetry/mcp
|
|
6
|
-
* - cachly API (receiver) → resolves api_key → {org_id, user_id}, queues enriched event
|
|
7
|
-
* - cachly-insights ingest (consumer) ← reads enriched events from the resolved queue
|
|
8
|
-
*
|
|
9
|
-
* The ingest worker MUST NOT see raw JWTs or api_keys. Resolution happens
|
|
10
|
-
* exclusively inside the cachly API trust boundary before events reach the queue.
|
|
11
|
-
*/
|
|
12
|
-
export {};
|
|
13
|
-
//# sourceMappingURL=telemetry-types.js.map
|