@a13xu/lucid 1.1.0 → 1.9.0
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/LICENSE +21 -21
- package/README.md +221 -99
- package/build/config.d.ts +37 -0
- package/build/config.js +45 -0
- package/build/database.d.ts +54 -0
- package/build/database.js +175 -62
- package/build/guardian/checklist.js +66 -66
- package/build/guardian/coding-analyzer.d.ts +11 -0
- package/build/guardian/coding-analyzer.js +393 -0
- package/build/guardian/coding-rules.d.ts +1 -0
- package/build/guardian/coding-rules.js +97 -0
- package/build/index.js +241 -2
- package/build/indexer/ast.d.ts +9 -0
- package/build/indexer/ast.js +158 -0
- package/build/indexer/file.d.ts +15 -0
- package/build/indexer/file.js +100 -0
- package/build/indexer/project.d.ts +8 -0
- package/build/indexer/project.js +320 -0
- package/build/memory/experience.d.ts +11 -0
- package/build/memory/experience.js +85 -0
- package/build/retrieval/context.d.ts +29 -0
- package/build/retrieval/context.js +219 -0
- package/build/retrieval/qdrant.d.ts +16 -0
- package/build/retrieval/qdrant.js +135 -0
- package/build/retrieval/tfidf.d.ts +14 -0
- package/build/retrieval/tfidf.js +64 -0
- package/build/security/alerts.d.ts +44 -0
- package/build/security/alerts.js +228 -0
- package/build/security/env.d.ts +24 -0
- package/build/security/env.js +85 -0
- package/build/security/guard.d.ts +35 -0
- package/build/security/guard.js +133 -0
- package/build/security/ratelimit.d.ts +34 -0
- package/build/security/ratelimit.js +105 -0
- package/build/security/smtp.d.ts +26 -0
- package/build/security/smtp.js +125 -0
- package/build/security/ssrf.d.ts +18 -0
- package/build/security/ssrf.js +109 -0
- package/build/security/waf.d.ts +33 -0
- package/build/security/waf.js +174 -0
- package/build/store/content.d.ts +3 -0
- package/build/store/content.js +11 -0
- package/build/tools/coding-guard.d.ts +24 -0
- package/build/tools/coding-guard.js +82 -0
- package/build/tools/context.d.ts +39 -0
- package/build/tools/context.js +105 -0
- package/build/tools/grep.d.ts +17 -0
- package/build/tools/grep.js +65 -0
- package/build/tools/init.d.ts +51 -0
- package/build/tools/init.js +212 -0
- package/build/tools/remember.d.ts +4 -4
- package/build/tools/reward.d.ts +29 -0
- package/build/tools/reward.js +154 -0
- package/build/tools/sync.d.ts +18 -0
- package/build/tools/sync.js +76 -0
- package/package.json +55 -48
package/build/database.js
CHANGED
|
@@ -30,85 +30,198 @@ export function initDatabase() {
|
|
|
30
30
|
return db;
|
|
31
31
|
}
|
|
32
32
|
function createSchema(db) {
|
|
33
|
-
db.exec(`
|
|
34
|
-
CREATE TABLE IF NOT EXISTS entities (
|
|
35
|
-
id INTEGER PRIMARY KEY,
|
|
36
|
-
name TEXT NOT NULL UNIQUE COLLATE NOCASE,
|
|
37
|
-
type TEXT NOT NULL,
|
|
38
|
-
observations TEXT NOT NULL DEFAULT '[]',
|
|
39
|
-
created_at INTEGER DEFAULT (unixepoch()),
|
|
40
|
-
updated_at INTEGER DEFAULT (unixepoch())
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
CREATE TABLE IF NOT EXISTS relations (
|
|
44
|
-
id INTEGER PRIMARY KEY,
|
|
45
|
-
from_entity INTEGER NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
|
|
46
|
-
to_entity INTEGER NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
|
|
47
|
-
relation_type TEXT NOT NULL,
|
|
48
|
-
created_at INTEGER DEFAULT (unixepoch()),
|
|
49
|
-
UNIQUE(from_entity, to_entity, relation_type)
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
|
|
53
|
-
name,
|
|
54
|
-
type,
|
|
55
|
-
observations,
|
|
56
|
-
content='entities',
|
|
57
|
-
content_rowid='id',
|
|
58
|
-
tokenize='porter unicode61'
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
CREATE TRIGGER IF NOT EXISTS entities_ai AFTER INSERT ON entities BEGIN
|
|
62
|
-
INSERT INTO entities_fts(rowid, name, type, observations)
|
|
63
|
-
VALUES (new.id, new.name, new.type, new.observations);
|
|
64
|
-
END;
|
|
65
|
-
|
|
66
|
-
CREATE TRIGGER IF NOT EXISTS entities_au AFTER UPDATE ON entities BEGIN
|
|
67
|
-
INSERT INTO entities_fts(entities_fts, rowid, name, type, observations)
|
|
68
|
-
VALUES('delete', old.id, old.name, old.type, old.observations);
|
|
69
|
-
INSERT INTO entities_fts(rowid, name, type, observations)
|
|
70
|
-
VALUES (new.id, new.name, new.type, new.observations);
|
|
71
|
-
END;
|
|
72
|
-
|
|
73
|
-
CREATE TRIGGER IF NOT EXISTS entities_ad AFTER DELETE ON entities BEGIN
|
|
74
|
-
INSERT INTO entities_fts(entities_fts, rowid, name, type, observations)
|
|
75
|
-
VALUES('delete', old.id, old.name, old.type, old.observations);
|
|
76
|
-
END;
|
|
77
|
-
|
|
78
|
-
CREATE INDEX IF NOT EXISTS idx_relations_from ON relations(from_entity);
|
|
79
|
-
CREATE INDEX IF NOT EXISTS idx_relations_to ON relations(to_entity);
|
|
80
|
-
CREATE INDEX IF NOT EXISTS idx_entities_type ON entities(type);
|
|
33
|
+
db.exec(`
|
|
34
|
+
CREATE TABLE IF NOT EXISTS entities (
|
|
35
|
+
id INTEGER PRIMARY KEY,
|
|
36
|
+
name TEXT NOT NULL UNIQUE COLLATE NOCASE,
|
|
37
|
+
type TEXT NOT NULL,
|
|
38
|
+
observations TEXT NOT NULL DEFAULT '[]',
|
|
39
|
+
created_at INTEGER DEFAULT (unixepoch()),
|
|
40
|
+
updated_at INTEGER DEFAULT (unixepoch())
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
CREATE TABLE IF NOT EXISTS relations (
|
|
44
|
+
id INTEGER PRIMARY KEY,
|
|
45
|
+
from_entity INTEGER NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
|
|
46
|
+
to_entity INTEGER NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
|
|
47
|
+
relation_type TEXT NOT NULL,
|
|
48
|
+
created_at INTEGER DEFAULT (unixepoch()),
|
|
49
|
+
UNIQUE(from_entity, to_entity, relation_type)
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
|
|
53
|
+
name,
|
|
54
|
+
type,
|
|
55
|
+
observations,
|
|
56
|
+
content='entities',
|
|
57
|
+
content_rowid='id',
|
|
58
|
+
tokenize='porter unicode61'
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
CREATE TRIGGER IF NOT EXISTS entities_ai AFTER INSERT ON entities BEGIN
|
|
62
|
+
INSERT INTO entities_fts(rowid, name, type, observations)
|
|
63
|
+
VALUES (new.id, new.name, new.type, new.observations);
|
|
64
|
+
END;
|
|
65
|
+
|
|
66
|
+
CREATE TRIGGER IF NOT EXISTS entities_au AFTER UPDATE ON entities BEGIN
|
|
67
|
+
INSERT INTO entities_fts(entities_fts, rowid, name, type, observations)
|
|
68
|
+
VALUES('delete', old.id, old.name, old.type, old.observations);
|
|
69
|
+
INSERT INTO entities_fts(rowid, name, type, observations)
|
|
70
|
+
VALUES (new.id, new.name, new.type, new.observations);
|
|
71
|
+
END;
|
|
72
|
+
|
|
73
|
+
CREATE TRIGGER IF NOT EXISTS entities_ad AFTER DELETE ON entities BEGIN
|
|
74
|
+
INSERT INTO entities_fts(entities_fts, rowid, name, type, observations)
|
|
75
|
+
VALUES('delete', old.id, old.name, old.type, old.observations);
|
|
76
|
+
END;
|
|
77
|
+
|
|
78
|
+
CREATE INDEX IF NOT EXISTS idx_relations_from ON relations(from_entity);
|
|
79
|
+
CREATE INDEX IF NOT EXISTS idx_relations_to ON relations(to_entity);
|
|
80
|
+
CREATE INDEX IF NOT EXISTS idx_entities_type ON entities(type);
|
|
81
|
+
|
|
82
|
+
-- Conținut sursă comprimat (zlib deflate nivel 9)
|
|
83
|
+
CREATE TABLE IF NOT EXISTS file_contents (
|
|
84
|
+
id INTEGER PRIMARY KEY,
|
|
85
|
+
filepath TEXT NOT NULL UNIQUE,
|
|
86
|
+
content BLOB NOT NULL,
|
|
87
|
+
content_hash TEXT NOT NULL,
|
|
88
|
+
original_size INTEGER NOT NULL,
|
|
89
|
+
compressed_size INTEGER NOT NULL,
|
|
90
|
+
language TEXT NOT NULL DEFAULT 'generic',
|
|
91
|
+
indexed_at INTEGER DEFAULT (unixepoch())
|
|
92
|
+
);
|
|
93
|
+
CREATE INDEX IF NOT EXISTS idx_fc_filepath ON file_contents(filepath);
|
|
94
|
+
CREATE INDEX IF NOT EXISTS idx_fc_hash ON file_contents(content_hash);
|
|
95
|
+
CREATE INDEX IF NOT EXISTS idx_fc_indexed ON file_contents(indexed_at);
|
|
96
|
+
|
|
97
|
+
-- Diffs între versiuni consecutive (pentru get_recent)
|
|
98
|
+
CREATE TABLE IF NOT EXISTS file_diffs (
|
|
99
|
+
filepath TEXT PRIMARY KEY,
|
|
100
|
+
prev_hash TEXT NOT NULL,
|
|
101
|
+
diff_text TEXT NOT NULL,
|
|
102
|
+
changed_at INTEGER DEFAULT (unixepoch())
|
|
103
|
+
);
|
|
104
|
+
CREATE INDEX IF NOT EXISTS idx_fd_changed ON file_diffs(changed_at);
|
|
105
|
+
|
|
106
|
+
-- Experiences: logged get_context calls for RL reward system
|
|
107
|
+
CREATE TABLE IF NOT EXISTS experiences (
|
|
108
|
+
id INTEGER PRIMARY KEY,
|
|
109
|
+
query TEXT NOT NULL,
|
|
110
|
+
query_terms TEXT NOT NULL DEFAULT '',
|
|
111
|
+
context_fps TEXT NOT NULL DEFAULT '[]',
|
|
112
|
+
strategy TEXT NOT NULL DEFAULT 'tfidf',
|
|
113
|
+
reward REAL NOT NULL DEFAULT 0.0,
|
|
114
|
+
feedback TEXT,
|
|
115
|
+
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
116
|
+
rewarded_at INTEGER
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS experiences_fts USING fts5(
|
|
120
|
+
query,
|
|
121
|
+
feedback,
|
|
122
|
+
content='experiences',
|
|
123
|
+
content_rowid='id',
|
|
124
|
+
tokenize='porter unicode61'
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
CREATE TRIGGER IF NOT EXISTS experiences_ai AFTER INSERT ON experiences BEGIN
|
|
128
|
+
INSERT INTO experiences_fts(rowid, query, feedback)
|
|
129
|
+
VALUES (new.id, new.query, COALESCE(new.feedback, ''));
|
|
130
|
+
END;
|
|
131
|
+
|
|
132
|
+
CREATE TRIGGER IF NOT EXISTS experiences_au AFTER UPDATE ON experiences BEGIN
|
|
133
|
+
INSERT INTO experiences_fts(experiences_fts, rowid, query, feedback)
|
|
134
|
+
VALUES('delete', old.id, old.query, COALESCE(old.feedback, ''));
|
|
135
|
+
INSERT INTO experiences_fts(rowid, query, feedback)
|
|
136
|
+
VALUES (new.id, new.query, COALESCE(new.feedback, ''));
|
|
137
|
+
END;
|
|
138
|
+
|
|
139
|
+
-- Denormalized reward cache per file (updated on every reward/penalize/implicit)
|
|
140
|
+
CREATE TABLE IF NOT EXISTS file_rewards (
|
|
141
|
+
filepath TEXT PRIMARY KEY,
|
|
142
|
+
total_reward REAL NOT NULL DEFAULT 0.0,
|
|
143
|
+
use_count INTEGER NOT NULL DEFAULT 0,
|
|
144
|
+
last_rewarded INTEGER
|
|
145
|
+
);
|
|
81
146
|
`);
|
|
82
147
|
}
|
|
83
148
|
export function prepareStatements(db) {
|
|
84
149
|
return {
|
|
150
|
+
// file_contents
|
|
151
|
+
getFileByPath: db.prepare("SELECT * FROM file_contents WHERE filepath = ?"),
|
|
152
|
+
upsertFile: db.prepare(`INSERT INTO file_contents (filepath, content, content_hash, original_size, compressed_size, language)
|
|
153
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
154
|
+
ON CONFLICT(filepath) DO UPDATE SET
|
|
155
|
+
content = excluded.content,
|
|
156
|
+
content_hash = excluded.content_hash,
|
|
157
|
+
original_size = excluded.original_size,
|
|
158
|
+
compressed_size = excluded.compressed_size,
|
|
159
|
+
language = excluded.language,
|
|
160
|
+
indexed_at = unixepoch()`),
|
|
161
|
+
getAllFiles: db.prepare("SELECT filepath, content, language, content_hash, indexed_at FROM file_contents"),
|
|
162
|
+
getRecentFiles: db.prepare("SELECT filepath, language, indexed_at FROM file_contents WHERE indexed_at >= ? ORDER BY indexed_at DESC"),
|
|
163
|
+
deleteFile: db.prepare("DELETE FROM file_contents WHERE filepath = ?"),
|
|
164
|
+
upsertDiff: db.prepare(`INSERT INTO file_diffs (filepath, prev_hash, diff_text)
|
|
165
|
+
VALUES (?, ?, ?)
|
|
166
|
+
ON CONFLICT(filepath) DO UPDATE SET
|
|
167
|
+
prev_hash = excluded.prev_hash,
|
|
168
|
+
diff_text = excluded.diff_text,
|
|
169
|
+
changed_at = unixepoch()`),
|
|
170
|
+
getDiff: db.prepare("SELECT * FROM file_diffs WHERE filepath = ?"),
|
|
171
|
+
getRecentDiffs: db.prepare("SELECT * FROM file_diffs WHERE changed_at >= ? ORDER BY changed_at DESC"),
|
|
172
|
+
fileStorageStats: db.prepare("SELECT COUNT(*) as count, SUM(original_size) as total_original, SUM(compressed_size) as total_compressed FROM file_contents"),
|
|
173
|
+
// entities
|
|
85
174
|
getEntityByName: db.prepare("SELECT * FROM entities WHERE name = ? COLLATE NOCASE"),
|
|
86
175
|
insertEntity: db.prepare("INSERT INTO entities (name, type, observations) VALUES (?, ?, ?)"),
|
|
87
176
|
// SQL: SET observations = ?, WHERE id = ? → 2 params
|
|
88
177
|
updateEntity: db.prepare("UPDATE entities SET observations = ?, updated_at = unixepoch() WHERE id = ?"),
|
|
89
178
|
deleteEntity: db.prepare("DELETE FROM entities WHERE name = ? COLLATE NOCASE"),
|
|
90
179
|
getAllEntities: db.prepare("SELECT * FROM entities ORDER BY updated_at DESC"),
|
|
91
|
-
getRelationsForEntity: db.prepare(`SELECT r.*, ef.name AS from_name, et.name AS to_name
|
|
92
|
-
FROM relations r
|
|
93
|
-
JOIN entities ef ON r.from_entity = ef.id
|
|
94
|
-
JOIN entities et ON r.to_entity = et.id
|
|
180
|
+
getRelationsForEntity: db.prepare(`SELECT r.*, ef.name AS from_name, et.name AS to_name
|
|
181
|
+
FROM relations r
|
|
182
|
+
JOIN entities ef ON r.from_entity = ef.id
|
|
183
|
+
JOIN entities et ON r.to_entity = et.id
|
|
95
184
|
WHERE r.from_entity = ? OR r.to_entity = ?`),
|
|
96
185
|
insertRelation: db.prepare("INSERT OR IGNORE INTO relations (from_entity, to_entity, relation_type) VALUES (?, ?, ?)"),
|
|
97
|
-
searchFTS: db.prepare(`SELECT e.* FROM entities_fts
|
|
98
|
-
JOIN entities e ON entities_fts.rowid = e.id
|
|
99
|
-
WHERE entities_fts MATCH ?
|
|
100
|
-
ORDER BY rank
|
|
186
|
+
searchFTS: db.prepare(`SELECT e.* FROM entities_fts
|
|
187
|
+
JOIN entities e ON entities_fts.rowid = e.id
|
|
188
|
+
WHERE entities_fts MATCH ?
|
|
189
|
+
ORDER BY rank
|
|
101
190
|
LIMIT 20`),
|
|
102
|
-
searchLike: db.prepare(`SELECT * FROM entities
|
|
103
|
-
WHERE name LIKE ? OR type LIKE ? OR observations LIKE ?
|
|
104
|
-
ORDER BY updated_at DESC
|
|
191
|
+
searchLike: db.prepare(`SELECT * FROM entities
|
|
192
|
+
WHERE name LIKE ? OR type LIKE ? OR observations LIKE ?
|
|
193
|
+
ORDER BY updated_at DESC
|
|
105
194
|
LIMIT 20`),
|
|
106
195
|
countEntities: db.prepare("SELECT COUNT(*) as count FROM entities"),
|
|
107
196
|
countRelations: db.prepare("SELECT COUNT(*) as count FROM relations"),
|
|
108
197
|
getWalMode: db.prepare("PRAGMA journal_mode"),
|
|
109
|
-
getAllRelations: db.prepare(`SELECT r.*, ef.name AS from_name, et.name AS to_name
|
|
110
|
-
FROM relations r
|
|
111
|
-
JOIN entities ef ON r.from_entity = ef.id
|
|
198
|
+
getAllRelations: db.prepare(`SELECT r.*, ef.name AS from_name, et.name AS to_name
|
|
199
|
+
FROM relations r
|
|
200
|
+
JOIN entities ef ON r.from_entity = ef.id
|
|
112
201
|
JOIN entities et ON r.to_entity = et.id`),
|
|
202
|
+
// experiences
|
|
203
|
+
insertExperience: db.prepare(`INSERT INTO experiences (query, query_terms, context_fps, strategy)
|
|
204
|
+
VALUES (?, ?, ?, ?)`),
|
|
205
|
+
updateExperienceReward: db.prepare(`UPDATE experiences SET
|
|
206
|
+
reward = reward + ?,
|
|
207
|
+
rewarded_at = unixepoch(),
|
|
208
|
+
feedback = COALESCE(?, feedback)
|
|
209
|
+
WHERE id = ?`),
|
|
210
|
+
getExperienceById: db.prepare("SELECT * FROM experiences WHERE id = ?"),
|
|
211
|
+
getTopExperiences: db.prepare("SELECT * FROM experiences ORDER BY reward DESC LIMIT ?"),
|
|
212
|
+
searchExperiencesFTS: db.prepare(`SELECT e.* FROM experiences_fts
|
|
213
|
+
JOIN experiences e ON experiences_fts.rowid = e.id
|
|
214
|
+
WHERE experiences_fts MATCH ?
|
|
215
|
+
ORDER BY rank
|
|
216
|
+
LIMIT ?`),
|
|
217
|
+
// file_rewards
|
|
218
|
+
upsertFileReward: db.prepare(`INSERT INTO file_rewards (filepath, total_reward, use_count, last_rewarded)
|
|
219
|
+
VALUES (?, ?, 1, unixepoch())
|
|
220
|
+
ON CONFLICT(filepath) DO UPDATE SET
|
|
221
|
+
total_reward = total_reward + excluded.total_reward,
|
|
222
|
+
use_count = use_count + 1,
|
|
223
|
+
last_rewarded = unixepoch()`),
|
|
224
|
+
getFileRewards: db.prepare("SELECT * FROM file_rewards"),
|
|
225
|
+
getTopFileRewards: db.prepare("SELECT * FROM file_rewards WHERE total_reward > 0 ORDER BY total_reward DESC LIMIT ?"),
|
|
113
226
|
};
|
|
114
227
|
}
|
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
export const CHECKLIST = `# Logic Guardian — Validation Checklist (5 passes)
|
|
2
|
-
|
|
3
|
-
## Pass 1: Logic Trace
|
|
4
|
-
Trace through the code with CONCRETE values:
|
|
5
|
-
- Happy path → real values, write each variable state
|
|
6
|
-
- Empty/zero → null, 0, "", []
|
|
7
|
-
- Boundary → first element, last element, max int, single char
|
|
8
|
-
- Error case → network down, file missing, permission denied
|
|
9
|
-
|
|
10
|
-
STOP if any trace produces unexpected output. Fix before continuing.
|
|
11
|
-
|
|
12
|
-
## Pass 2: Contract Verification
|
|
13
|
-
- [ ] Preconditions: what must be true BEFORE this runs? Is it checked?
|
|
14
|
-
- [ ] Postconditions: what must be true AFTER? Can you prove it?
|
|
15
|
-
- [ ] Invariants: what must ALWAYS be true? Does the code maintain it?
|
|
16
|
-
- [ ] Return type: does EVERY code path return the expected type?
|
|
17
|
-
- [ ] Side effects: are all side effects intentional?
|
|
18
|
-
|
|
19
|
-
## Pass 3: Stupid Mistakes Checklist
|
|
20
|
-
|
|
21
|
-
### Off-by-one
|
|
22
|
-
- [ ] < vs <= — verify with boundary values
|
|
23
|
-
- [ ] Array indices — last is length - 1
|
|
24
|
-
- [ ] Loop iterations — exactly N times?
|
|
25
|
-
|
|
26
|
-
### Null/Undefined Propagation
|
|
27
|
-
- [ ] Every .property access — can the object be null?
|
|
28
|
-
- [ ] Every array index — can the array be empty?
|
|
29
|
-
- [ ] Every map lookup — can the key be missing?
|
|
30
|
-
|
|
31
|
-
### Type Confusion
|
|
32
|
-
- [ ] String vs Number comparisons
|
|
33
|
-
- [ ] Integer vs Float division
|
|
34
|
-
- [ ] Boolean coercion edge cases
|
|
35
|
-
|
|
36
|
-
### Logic Inversions (THE #1 LLM drift pattern)
|
|
37
|
-
- [ ] if/else — is the condition testing what you THINK?
|
|
38
|
-
- [ ] Early returns — does the guard return the RIGHT value?
|
|
39
|
-
- [ ] filter/find/some — keeping the RIGHT elements?
|
|
40
|
-
- [ ] Error handling — catching and re-throwing correctly?
|
|
41
|
-
|
|
42
|
-
### State & Mutation
|
|
43
|
-
- [ ] Mutating shared object when you should copy?
|
|
44
|
-
- [ ] Async state read after it might have changed?
|
|
45
|
-
|
|
46
|
-
### Copy-Paste Drift
|
|
47
|
-
- [ ] ALL variable names updated in copied blocks?
|
|
48
|
-
- [ ] Conditions changed, not just variable names?
|
|
49
|
-
|
|
50
|
-
## Pass 4: Integration Sanity
|
|
51
|
-
- [ ] Breaks existing callers?
|
|
52
|
-
- [ ] Imports/exports correct?
|
|
53
|
-
- [ ] If async, all callers awaiting it?
|
|
54
|
-
- [ ] If type changed, all usages updated?
|
|
55
|
-
|
|
56
|
-
## Pass 5: Explain It Test
|
|
57
|
-
In ONE sentence: what does this code do?
|
|
58
|
-
If you can't explain it, or the sentence doesn't match the code → something is wrong.
|
|
59
|
-
|
|
60
|
-
## Anti-Drift Triggers
|
|
61
|
-
STOP if you find yourself thinking:
|
|
62
|
-
- "This is similar to..." → You're pattern-matching. TRACE THE LOGIC.
|
|
63
|
-
- "This should work because the other one does" → VERIFY INDEPENDENTLY.
|
|
64
|
-
- "I'll just copy and change the names" → CHECK EVERY DIFFERENCE.
|
|
65
|
-
- "The error handling is probably fine" → TRACE THE ERROR PATH.
|
|
66
|
-
- "This is standard boilerplate" → Verify it fits this context.
|
|
1
|
+
export const CHECKLIST = `# Logic Guardian — Validation Checklist (5 passes)
|
|
2
|
+
|
|
3
|
+
## Pass 1: Logic Trace
|
|
4
|
+
Trace through the code with CONCRETE values:
|
|
5
|
+
- Happy path → real values, write each variable state
|
|
6
|
+
- Empty/zero → null, 0, "", []
|
|
7
|
+
- Boundary → first element, last element, max int, single char
|
|
8
|
+
- Error case → network down, file missing, permission denied
|
|
9
|
+
|
|
10
|
+
STOP if any trace produces unexpected output. Fix before continuing.
|
|
11
|
+
|
|
12
|
+
## Pass 2: Contract Verification
|
|
13
|
+
- [ ] Preconditions: what must be true BEFORE this runs? Is it checked?
|
|
14
|
+
- [ ] Postconditions: what must be true AFTER? Can you prove it?
|
|
15
|
+
- [ ] Invariants: what must ALWAYS be true? Does the code maintain it?
|
|
16
|
+
- [ ] Return type: does EVERY code path return the expected type?
|
|
17
|
+
- [ ] Side effects: are all side effects intentional?
|
|
18
|
+
|
|
19
|
+
## Pass 3: Stupid Mistakes Checklist
|
|
20
|
+
|
|
21
|
+
### Off-by-one
|
|
22
|
+
- [ ] < vs <= — verify with boundary values
|
|
23
|
+
- [ ] Array indices — last is length - 1
|
|
24
|
+
- [ ] Loop iterations — exactly N times?
|
|
25
|
+
|
|
26
|
+
### Null/Undefined Propagation
|
|
27
|
+
- [ ] Every .property access — can the object be null?
|
|
28
|
+
- [ ] Every array index — can the array be empty?
|
|
29
|
+
- [ ] Every map lookup — can the key be missing?
|
|
30
|
+
|
|
31
|
+
### Type Confusion
|
|
32
|
+
- [ ] String vs Number comparisons
|
|
33
|
+
- [ ] Integer vs Float division
|
|
34
|
+
- [ ] Boolean coercion edge cases
|
|
35
|
+
|
|
36
|
+
### Logic Inversions (THE #1 LLM drift pattern)
|
|
37
|
+
- [ ] if/else — is the condition testing what you THINK?
|
|
38
|
+
- [ ] Early returns — does the guard return the RIGHT value?
|
|
39
|
+
- [ ] filter/find/some — keeping the RIGHT elements?
|
|
40
|
+
- [ ] Error handling — catching and re-throwing correctly?
|
|
41
|
+
|
|
42
|
+
### State & Mutation
|
|
43
|
+
- [ ] Mutating shared object when you should copy?
|
|
44
|
+
- [ ] Async state read after it might have changed?
|
|
45
|
+
|
|
46
|
+
### Copy-Paste Drift
|
|
47
|
+
- [ ] ALL variable names updated in copied blocks?
|
|
48
|
+
- [ ] Conditions changed, not just variable names?
|
|
49
|
+
|
|
50
|
+
## Pass 4: Integration Sanity
|
|
51
|
+
- [ ] Breaks existing callers?
|
|
52
|
+
- [ ] Imports/exports correct?
|
|
53
|
+
- [ ] If async, all callers awaiting it?
|
|
54
|
+
- [ ] If type changed, all usages updated?
|
|
55
|
+
|
|
56
|
+
## Pass 5: Explain It Test
|
|
57
|
+
In ONE sentence: what does this code do?
|
|
58
|
+
If you can't explain it, or the sentence doesn't match the code → something is wrong.
|
|
59
|
+
|
|
60
|
+
## Anti-Drift Triggers
|
|
61
|
+
STOP if you find yourself thinking:
|
|
62
|
+
- "This is similar to..." → You're pattern-matching. TRACE THE LOGIC.
|
|
63
|
+
- "This should work because the other one does" → VERIFY INDEPENDENTLY.
|
|
64
|
+
- "I'll just copy and change the names" → CHECK EVERY DIFFERENCE.
|
|
65
|
+
- "The error handling is probably fine" → TRACE THE ERROR PATH.
|
|
66
|
+
- "This is standard boilerplate" → Verify it fits this context.
|
|
67
67
|
`;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type QualitySeverity = "high" | "medium" | "low";
|
|
2
|
+
export interface QualityIssue {
|
|
3
|
+
file: string;
|
|
4
|
+
line: number;
|
|
5
|
+
severity: QualitySeverity;
|
|
6
|
+
ruleId: string;
|
|
7
|
+
message: string;
|
|
8
|
+
suggestion: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function analyzeCodeQuality(filepath: string, source: string, lang?: string): QualityIssue[];
|
|
11
|
+
export declare function formatQualityReport(filepath: string, issues: QualityIssue[]): string;
|