OverviewFilesCommitsIssuesDocsReleasesPeers

knowledge-ratchet commits / 83a4b14

Fix slop vs signal — better skip patterns, split stop, add implicit approvals
- Skip patterns loaded from tuned-patterns.json (40+ patterns for terminal output, logs, system messages, error traces) - "stop" split: "stop + negative" = correction, bare "stop" = medium confidence - Implicit approvals: "yes", "continue", "try it", "ok do it", "let's go" - Removed bare "no" from corrections (false positives) - Learning rate in status bar: X% (corrections that led to clean turns) - All consumers read from shared tuned-patterns.json Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
83a4b14740dd2f32e4eecd1fc0ffb854b37aedb8
by plankatron <fleeky@gmail.com> · 2026-04-07T17:03:07.000Z

Changed files (4) +335 -22

data/tuned-patterns.json +254 -0
……@@ -0,0 +1,254 @@
1{
2 "generated": "2026-04-07T16:00:00.000Z",
3 "correction": {
4 "high": [
5 {
6 "id": "explicit-no",
7 "pattern": "\\b(wrong|not that|that's not|that is not|incorrect|stop doing)\\b",
8 "flags": "i",
9 "precision": 1,
10 "fires": 8,
11 "note": "Removed bare 'no' — too many false positives ('no rush', 'no problem'). Kept 'wrong', 'not that'."
12 },
13 {
14 "id": "no-as-rejection",
15 "pattern": "^\\s*no[,.]?\\s*$|\\bno[,.]\\s+(that|this|it|you|we|i)",
16 "flags": "i",
17 "precision": 0.95,
18 "note": "Bare 'no' only at start of line or followed by subject. Avoids 'no problem', 'no rush'."
19 },
20 {
21 "id": "repeating-self",
22 "pattern": "\\b(i said|i meant|i asked for|that's wrong|that is wrong)\\b",
23 "flags": "i",
24 "precision": 1,
25 "fires": 1
26 },
27 {
28 "id": "frustration-repeat",
29 "pattern": "\\b(again|already told you|how many times|we discussed this)\\b",
30 "flags": "i",
31 "precision": 1,
32 "fires": 3
33 },
34 {
35 "id": "stop-with-negative",
36 "pattern": "\\bstop\\b.{0,30}\\b(wrong|broke|fucking|what|no|don't|not|this is|you)\\b",
37 "flags": "i",
38 "precision": 0.95,
39 "note": "Stop + negative context = correction. Bare 'stop' without negative moved to medium."
40 },
41 {
42 "id": "prohibition",
43 "pattern": "\\b(don't ever|never do that|please don't|do not do)\\b",
44 "flags": "i",
45 "precision": 1,
46 "fires": 16,
47 "note": "Removed bare 'stop' and bare 'do not' — too many instruction false positives."
48 },
49 {
50 "id": "blame-question",
51 "pattern": "\\b(why did you|why are you|that broke|you broke|you just)\\b",
52 "flags": "i",
53 "precision": 1,
54 "fires": 3
55 },
56 {
57 "id": "revert-request",
58 "pattern": "\\b(revert|undo|put it back|roll back)\\b",
59 "flags": "i",
60 "precision": 0.5,
61 "fires": 2
62 },
63 {
64 "id": "giving-up",
65 "pattern": "\\b(let me (just )?do it|i'll (just )?do it|forget it|never\\s*mind)\\b",
66 "flags": "i",
67 "precision": 1
68 },
69 {
70 "id": "not-visible",
71 "pattern": "\\b(don't see|can't see|cannot see|not visible|invisible|not showing|not rendering)\\b",
72 "flags": "i",
73 "precision": 1,
74 "hits": 8
75 },
76 {
77 "id": "questioning-why",
78 "pattern": "\\b(why (is|are|does|did) (it|the|this))\\b",
79 "flags": "i",
80 "precision": 1,
81 "hits": 6
82 },
83 {
84 "id": "hesitation",
85 "pattern": "\\b(hmm+)\\b",
86 "flags": "i",
87 "precision": 1,
88 "hits": 6
89 },
90 {
91 "id": "same-result",
92 "pattern": "\\b(it is the same|it's the same|still the same|same (problem|issue|bug|error|result))\\b",
93 "flags": "i",
94 "precision": 1,
95 "hits": 5
96 },
97 {
98 "id": "still-broken",
99 "pattern": "\\b(still (flat|broken|wrong|missing|empty|invisible|not))\\b",
100 "flags": "i",
101 "precision": 1,
102 "hits": 3
103 },
104 {
105 "id": "runtime-issue",
106 "pattern": "\\b(crash|crashes|crashing|crashed)\\b",
107 "flags": "i",
108 "precision": 1,
109 "hits": 3
110 },
111 {
112 "id": "not-working",
113 "pattern": "\\b(not (working|rendering|updating|showing|displaying))\\b",
114 "flags": "i",
115 "precision": 1,
116 "hits": 3
117 },
118 {
119 "id": "wrong-action",
120 "pattern": "\\b(you flipped|you swapped|you mixed up|you confused)\\b",
121 "flags": "i",
122 "precision": 1,
123 "hits": 2
124 },
125 {
126 "id": "just-empty",
127 "pattern": "\\b(just (flat|empty|blank|black|white|nothing))\\b",
128 "flags": "i",
129 "precision": 1,
130 "hits": 2
131 },
132 {
133 "id": "completely-wrong",
134 "pattern": "\\b(completely wrong|totally wrong|absolutely wrong|so wrong|fucking wrong)\\b",
135 "flags": "i",
136 "precision": 1,
137 "note": "Strong negative — always a correction"
138 }
139 ],
140 "medium": [
141 {
142 "id": "bare-stop-redirect",
143 "pattern": "^\\s*stop\\b",
144 "flags": "i",
145 "precision": 0.5,
146 "note": "Bare 'stop' at start — could be correction or instruction. Medium confidence."
147 },
148 {
149 "id": "quality-pushback",
150 "pattern": "\\b(audit|think deeper|planning mode)\\b",
151 "flags": "i",
152 "precision": 0.78,
153 "hits": 25
154 },
155 {
156 "id": "visual-artifact",
157 "pattern": "\\b(artifact|artifacts|glitch|glitches)\\b",
158 "flags": "i",
159 "precision": 0.5,
160 "hits": 3
161 }
162 ],
163 "low": []
164 },
165 "approval": {
166 "high": [
167 {
168 "id": "strong-approval",
169 "pattern": "\\b(perfect|exactly|great|lgtm|looks good|nice work|nailed it)\\b",
170 "flags": "i"
171 },
172 {
173 "id": "confirmation",
174 "pattern": "\\b(that works|that's right|correct|good job|well done)\\b",
175 "flags": "i"
176 },
177 {
178 "id": "action-approval",
179 "pattern": "\\b(ship it|merge it|push it|deploy it|commit it)\\b",
180 "flags": "i"
181 },
182 {
183 "id": "thanks",
184 "pattern": "\\b(thanks|thank you)\\b",
185 "flags": "i"
186 },
187 {
188 "id": "implicit-yes",
189 "pattern": "^\\s*(yes|yep|yeah|yup|ok|okay)\\s*[,.]?\\s*$",
190 "flags": "i",
191 "note": "Bare affirmative at start of line — implicit approval"
192 },
193 {
194 "id": "yes-directive",
195 "pattern": "^\\s*(yes|ok|okay)\\b.{0,20}\\b(do it|go ahead|proceed|continue|please|commit|push)\\b",
196 "flags": "i",
197 "note": "Affirmative + action word = approval"
198 },
199 {
200 "id": "continue-approval",
201 "pattern": "^\\s*continue\\s*$",
202 "flags": "i",
203 "note": "Bare 'continue' = implicit approval of current direction"
204 },
205 {
206 "id": "try-it",
207 "pattern": "\\b(try (it|that|this)|let's try|go for it|let's do it|let's go)\\b",
208 "flags": "i",
209 "note": "Directing to try = approving the approach"
210 }
211 ]
212 },
213 "skip": [
214 "^!",
215 "^<command-name>",
216 "^<system-reminder>",
217 "^<task-notification>",
218 "^<local-command",
219 "^Base directory for this skill",
220 "^Implement the following plan",
221 "^This session is being continued",
222 "^Service Unavailable",
223 "^fleeky@\\w+",
224 "tool_use_id",
225 "tool_result",
226 "^Godot Engine v",
227 "^Vulkan \\d",
228 "^\\[Request interrupted",
229 "^\\[P2P\\]",
230 "^\\[GitSync\\]",
231 "^\\[Mirror\\]",
232 "^\\[OTA\\]",
233 "^\\[ANProto\\]",
234 "^\\[Deploy\\]",
235 "^\\[tid:",
236 "^remote:",
237 "^To /home/",
238 "^● User approved",
239 "^● UserPromptSubmit",
240 "^error: cannot lock ref",
241 "^\\s*\\{\\s*$",
242 "^\\s*\\}\\s*$",
243 "^\\s*\\[\\s*$",
244 "^\\$\\s",
245 "^\\d+\\.\\d+\\.\\d+",
246 "^node:",
247 "^Error:",
248 "^\\s*at\\s",
249 "^fatal:",
250 "^warning:",
251 "^hint:",
252 "RangeError|TypeError|SyntaxError|ReferenceError"
253 ]
254}
fuse-signals.js +13 -2
……@@ -151,7 +151,18 @@ const USER_PROVIDES_ANSWER_PATTERNS = [
151151 /```[\s\S]{20,}```/, // user pasting code blocks
152152]
153153
154const SKIP_PATTERNS = [
154// Load skip patterns from tuned config
155const _skipFromTuned = (() => {
156 if (fs.existsSync(TUNED_PATTERNS_FILE)) {
157 try {
158 const tuned = JSON.parse(fs.readFileSync(TUNED_PATTERNS_FILE, 'utf8'))
159 if (tuned.skip?.length > 0) return tuned.skip.map(p => new RegExp(p, 'i'))
160 } catch {}
161 }
162 return null
163})()
164
165const SKIP_PATTERNS = _skipFromTuned || [
155166 /^!/,
156167 /^<command-name>/,
157168 /^<system-reminder>/,
……@@ -161,7 +172,7 @@ const SKIP_PATTERNS = [
161172 /^Implement the following plan/,
162173 /^This session is being continued/,
163174 /^Service Unavailable/,
164 /^fleeky@\w+ /,
175 /^fleeky@\w+/,
165176 /tool_use_id/,
166177 /tool_result/,
167178 /^Godot Engine v/,
loop-intervention.js +34 -15
……@@ -20,23 +20,39 @@ const path = require('path')
2020const STATE_FILE = '/tmp/claude-session-score.json'
2121const RULES_FILE = path.join(__dirname, 'data', 'learned-rules.json')
2222const LOOPS_FILE = path.join(__dirname, 'data', 'loops.json')
23const TUNED_PATTERNS_FILE = path.join(__dirname, 'data', 'tuned-patterns.json')
2324
24const CORRECTION_PATTERNS = [
25 /\b(no[,.]|wrong|not that|that's not|incorrect|stop doing)\b/i,
25// Load tuned patterns — same source as realtime-score and fuse-signals
26function loadTunedPatterns () {
27 if (fs.existsSync(TUNED_PATTERNS_FILE)) {
28 try {
29 const tuned = JSON.parse(fs.readFileSync(TUNED_PATTERNS_FILE, 'utf8'))
30 const patterns = []
31 for (const tier of ['high', 'medium']) {
32 for (const p of (tuned.correction?.[tier] || [])) {
33 patterns.push(new RegExp(p.pattern, p.flags || 'i'))
34 }
35 }
36 const skip = (tuned.skip || []).map(p => new RegExp(p, 'i'))
37 if (patterns.length > 0) return { patterns, skip }
38 } catch {}
39 }
40 return null
41}
42
43const _tuned = loadTunedPatterns()
44
45const CORRECTION_PATTERNS = _tuned?.patterns || [
46 /\b(wrong|not that|that's not|incorrect|stop doing)\b/i,
2647 /\b(i said|i meant|i asked for|that's wrong)\b/i,
27 /\b(again|already told you|how many times|we discussed this)\b/i,
28 /\b(don't ever|never do that|stop|please don't|do not)\b/i,
29 /\b(why did you|why are you|that broke|you broke|you just)\b/i,
30 /\b(revert|undo|go back|roll back|put it back)\b/i,
31 /\b(let me (just |)do it|i'll (just |)do it|forget it|never\s*mind)\b/i,
32 // Tuned patterns
33 /\b(it is the same|it's the same|still the same|same (problem|issue|bug|error|result))\b/i,
34 /\b(still (flat|broken|wrong|missing|empty|invisible|not))\b/i,
35 /\b(don't see|can't see|cannot see|not visible|invisible|not showing|not rendering)\b/i,
36 /\b(crash|crashes|crashing|crashed)\b/i,
37 /\b(not (working|rendering|updating|showing|displaying))\b/i,
38 /\b(why (is|are|does|did) (it|the|this))\b/i,
39 /\b(hmm+)\b/i,
48 /\b(don't ever|never do that|please don't|do not do)\b/i,
49 /\b(why did you|why are you|that broke|you broke)\b/i,
50 /\b(revert|undo|put it back|roll back)\b/i,
51]
52
53const SKIP_PATTERNS = _tuned?.skip || [
54 /^!/, /^<command-name>/, /^<system-reminder>/, /^<task-notification>/,
55 /^fleeky@\w+/, /^Godot Engine/, /^\[Request interrupted/,
4056]
4157
4258async function main () {
……@@ -53,6 +69,9 @@ async function main () {
5369 try { state = JSON.parse(fs.readFileSync(STATE_FILE, 'utf8')) }
5470 catch { process.exit(0) }
5571
72 // Skip terminal output, logs, system messages
73 if (SKIP_PATTERNS.some(p => p.test(userText))) process.exit(0)
74
5675 // Check if THIS message is a correction
5776 const isCorrection = CORRECTION_PATTERNS.some(p => p.test(userText))
5877
realtime-score.js +34 -5
……@@ -62,7 +62,18 @@ const APPROVAL_PATTERNS = _tuned?.approval || [
6262 /\b(thanks|thank you)\b/i,
6363]
6464
65const SKIP_PATTERNS = [
65// Load skip patterns from tuned config, fall back to defaults
66const _skipFromConfig = (() => {
67 if (fs.existsSync(TUNED_PATTERNS_FILE)) {
68 try {
69 const tuned = JSON.parse(fs.readFileSync(TUNED_PATTERNS_FILE, 'utf8'))
70 if (tuned.skip?.length > 0) return tuned.skip.map(p => new RegExp(p, 'i'))
71 } catch {}
72 }
73 return null
74})()
75
76const SKIP_PATTERNS = _skipFromConfig || [
6677 /^!/,
6778 /^<command-name>/,
6879 /^<system-reminder>/,
……@@ -72,7 +83,7 @@ const SKIP_PATTERNS = [
7283 /^Implement the following plan/,
7384 /^This session is being continued/,
7485 /^Service Unavailable/,
75 /^fleeky@\w+ /,
86 /^fleeky@\w+/,
7687 /tool_use_id/,
7788 /tool_result/,
7889 /^Godot Engine v/,
……@@ -460,13 +471,31 @@ function handleStatus () {
460471 : state.trajectory === 'declining' ? '▼'
461472 : '▬'
462473
463 // Format: ▬ 0.72 │ 5 approved 2 corrected │ 34 tools │ ⟳LOOP
474 // Compute learning rate: what % of corrections led to clean turns?
475 const scores = state.turnScores || []
476 let corrLearned = 0
477 let corrFailed = 0
478 for (let i = 0; i < scores.length; i++) {
479 if (scores[i] === 0.2) {
480 const after = scores.slice(i + 1, i + 4)
481 if (after.includes(0.2)) corrFailed++
482 else corrLearned++
483 }
484 }
485 const totalCorr = corrLearned + corrFailed
486 const learningRate = totalCorr > 0 ? Math.round(corrLearned / totalCorr * 100) : null
487
488 // Format: ▬ 0.72 │ 5ok 2fix │ 34T │ 75% learning │ ⟳LOOP
464489 const parts = [
465490 `${arrow} ${state.score.toFixed(2)}`,
466 `${state.approvals} approved ${state.corrections} corrected`,
467 `${state.toolCalls} tools`,
491 `${state.approvals}ok ${state.corrections}fix`,
492 `${state.toolCalls}T`,
468493 ]
469494
495 if (learningRate !== null) {
496 parts.push(`${learningRate}% learning`)
497 }
498
470499 if (state._loopActive) {
471500 parts.push('⟳LOOP')
472501 }