@codyswann/lisa 1.76.5 → 1.77.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.
Files changed (33) hide show
  1. package/all/deletions.json +5 -1
  2. package/package.json +1 -1
  3. package/plugins/lisa/.claude-plugin/plugin.json +21 -1
  4. package/plugins/lisa/hooks/inject-rules.sh +22 -0
  5. package/{all/copy-overwrite/.claude → plugins/lisa}/rules/base-rules.md +4 -3
  6. package/{all/copy-overwrite/.claude → plugins/lisa}/rules/verification.md +10 -0
  7. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  8. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  9. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  10. package/plugins/lisa-rails/.claude-plugin/plugin.json +23 -1
  11. package/plugins/lisa-rails/hooks/inject-rules.sh +22 -0
  12. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  13. package/plugins/lisa-typescript/hooks/lint-on-edit.sh +3 -1
  14. package/plugins/src/base/.claude-plugin/plugin.json +4 -0
  15. package/plugins/src/base/hooks/inject-rules.sh +22 -0
  16. package/plugins/src/base/rules/base-rules.md +89 -0
  17. package/plugins/src/base/rules/coding-philosophy.md +428 -0
  18. package/plugins/src/base/rules/intent-routing.md +126 -0
  19. package/plugins/src/base/rules/security-audit-handling.md +30 -0
  20. package/plugins/src/base/rules/verification.md +93 -0
  21. package/plugins/src/rails/.claude-plugin/plugin.json +6 -0
  22. package/plugins/src/rails/hooks/inject-rules.sh +22 -0
  23. package/plugins/src/rails/rules/rails-conventions.md +176 -0
  24. package/plugins/src/typescript/hooks/lint-on-edit.sh +3 -1
  25. package/rails/deletions.json +2 -1
  26. package/plugins/lisa/hooks/enforce-plan-rules.sh +0 -15
  27. package/plugins/lisa/hooks/sync-tasks.sh +0 -107
  28. package/plugins/src/base/hooks/enforce-plan-rules.sh +0 -15
  29. package/plugins/src/base/hooks/sync-tasks.sh +0 -107
  30. /package/{all/copy-overwrite/.claude → plugins/lisa}/rules/coding-philosophy.md +0 -0
  31. /package/{all/copy-overwrite/.claude → plugins/lisa}/rules/intent-routing.md +0 -0
  32. /package/{all/copy-overwrite/.claude → plugins/lisa}/rules/security-audit-handling.md +0 -0
  33. /package/{rails/copy-overwrite/.claude → plugins/lisa-rails}/rules/rails-conventions.md +0 -0
@@ -0,0 +1,428 @@
1
+ # Coding Philosophy
2
+
3
+ This rule enforces the core coding philosophy: **immutability**, **predictable structure**, **functional transformations**, **test-driven development**, **clean deletion**, and **simplicity**.
4
+
5
+ ## Guiding Principles: YAGNI + SOLID + DRY + KISS
6
+
7
+ Follow these software engineering principles, **deferring to Occam's Razor/KISS whenever principles conflict**:
8
+
9
+ ### KISS (Keep It Simple, Stupid) - The Tiebreaker
10
+
11
+ When principles conflict, **always choose the simpler solution**.
12
+
13
+ ```typescript
14
+ // KISS: Simple direct approach
15
+ const isAdmin = user.role === "admin";
16
+
17
+ // Over-engineered: Abstraction without value
18
+ const isAdmin = RoleChecker.getInstance().checkRole(user, RoleTypes.ADMIN);
19
+ ```
20
+
21
+ ### YAGNI (You Ain't Gonna Need It)
22
+
23
+ Don't build features, abstractions, or flexibility you don't need **right now**.
24
+
25
+ ```typescript
26
+ // Correct: Solve today's problem
27
+ const formatDate = (date: Date) => date.toISOString().split("T")[0];
28
+
29
+ // Wrong: Building for hypothetical future needs
30
+ const formatDate = (date: Date, format?: string, locale?: string, timezone?: string) => {
31
+ // 50 lines handling cases that may never be used
32
+ };
33
+ ```
34
+
35
+ ### DRY (Don't Repeat Yourself) - With KISS Constraint
36
+
37
+ Extract duplication only when:
38
+ 1. The same logic appears **3+ times**
39
+ 2. The abstraction is **simpler** than the duplication
40
+ 3. The extracted code has a **clear single purpose**
41
+
42
+ ### SOLID Principles - Applied Pragmatically
43
+
44
+ | Principle | Apply When | Skip When |
45
+ | ------------------------- | --------------------------------------------- | --------------------------------------- |
46
+ | **S**ingle Responsibility | Function does 2+ unrelated things | Splitting adds complexity |
47
+ | **O**pen/Closed | Extension points have clear use cases | No foreseeable extensions |
48
+ | **L**iskov Substitution | Using inheritance hierarchies | Using composition (preferred) |
49
+ | **I**nterface Segregation | Consumers need different subsets | Interface is already small |
50
+ | **D**ependency Inversion | Testing requires mocking external services | Direct dependency is simpler |
51
+
52
+ ### Decision Framework
53
+
54
+ When unsure, ask in order:
55
+ 1. **Do I need this now?** (YAGNI) - If no, don't build it
56
+ 2. **Is there a simpler way?** (KISS) - Choose the simpler option
57
+ 3. **Am I repeating myself 3+ times?** (DRY) - Extract if the abstraction is simpler
58
+ 4. **Does this function do one thing?** (SOLID-SRP) - Split only if clearer
59
+
60
+ ---
61
+
62
+ ## Core Principles
63
+
64
+ ### 1. Immutability First
65
+
66
+ Never mutate data. Always create new references.
67
+
68
+ ```typescript
69
+ // Correct - spread creates new object
70
+ const updated = { ...user, name: "New Name" };
71
+
72
+ // Incorrect - mutation
73
+ user.name = "New Name";
74
+ ```
75
+
76
+ ### 2. Function Structure Ordering
77
+
78
+ All functions, hooks, and components follow a strict ordering:
79
+
80
+ ```text
81
+ 1. Variable definitions and derived state (const, useState, useMemo, useCallback)
82
+ 2. Side effects (useEffect, function calls with no return value)
83
+ 3. Return statement
84
+ ```
85
+
86
+ ### 3. Functional Transformations
87
+
88
+ Use `map`, `filter`, `reduce` instead of imperative loops and mutations.
89
+
90
+ ```typescript
91
+ // Correct - functional transformation
92
+ const names = users.map(u => u.name);
93
+
94
+ // Incorrect - imperative mutation
95
+ const names = [];
96
+ users.forEach(u => names.push(u.name));
97
+ ```
98
+
99
+ ### 4. Test-Driven Development (TDD)
100
+
101
+ **Always write failing tests before implementation code.** This is mandatory, not optional.
102
+
103
+ ```text
104
+ TDD Cycle:
105
+ 1. RED: Write a failing test that defines expected behavior
106
+ 2. GREEN: Write the minimum code to make the test pass
107
+ 3. REFACTOR: Clean up while keeping tests green
108
+ ```
109
+
110
+ ### 5. Clean Deletion
111
+
112
+ **Delete old code completely.** No deprecation warnings, migration shims, or backward-compatibility layers unless explicitly requested.
113
+
114
+ ```typescript
115
+ // Correct: Remove the old code entirely
116
+ const calculateScore = (player: Player): number => player.stats.overall;
117
+
118
+ // Wrong: Keeping deprecated versions around
119
+ /** @deprecated Use calculateScore instead */
120
+ const getPlayerScore = (player: Player): number => calculateScore(player);
121
+ ```
122
+
123
+ **Clean deletion rules:**
124
+ - When replacing code, delete the old version completely
125
+ - Never create `V2`, `New`, or `Old` suffixed functions/variables
126
+ - Never add `@deprecated` comments - just remove the code
127
+ - Never write migration code unless explicitly asked
128
+ - Trust git history for recovery if needed
129
+
130
+ ---
131
+
132
+ ## Quick Reference
133
+
134
+ ### Variable Declaration
135
+
136
+ | Pattern | Status | Example |
137
+ | ------- | --------- | ----------------------------- |
138
+ | `const` | Required | `const value = calculate();` |
139
+ | `let` | Forbidden | Use ternary or reduce instead |
140
+ | `var` | Forbidden | Never use |
141
+
142
+ ### Array Operations
143
+
144
+ | Instead of | Use |
145
+ | ----------------------- | -------------------------------------------- |
146
+ | `arr.push(item)` | `[...arr, item]` |
147
+ | `arr.pop()` | `arr.slice(0, -1)` |
148
+ | `arr.splice(i, 1)` | `arr.filter((_, idx) => idx !== i)` |
149
+ | `arr.sort()` | `[...arr].sort()` |
150
+ | `arr[i] = value` | `arr.map((v, idx) => idx === i ? value : v)` |
151
+ | `forEach` with mutation | `reduce` or `map` |
152
+
153
+ ### Object Operations
154
+
155
+ | Instead of | Use |
156
+ | ------------------------- | ----------------------------- |
157
+ | `obj.key = value` | `{ ...obj, key: value }` |
158
+ | `delete obj.key` | `({ key: _, ...rest } = obj)` |
159
+ | `Object.assign(obj, ...)` | `{ ...obj, ...other }` |
160
+
161
+ ### Building Lookup Objects
162
+
163
+ ```typescript
164
+ // Correct - reduce with spread
165
+ const lookup = items.reduce(
166
+ (acc, item) => ({ ...acc, [item.id]: item }),
167
+ {} as Record<string, Item>
168
+ );
169
+
170
+ // Incorrect - forEach with Map.set
171
+ const lookup = new Map();
172
+ items.forEach(item => lookup.set(item.id, item));
173
+ ```
174
+
175
+ ### Conditional Values
176
+
177
+ ```typescript
178
+ // Correct - ternary expression
179
+ const status = isComplete ? "done" : "pending";
180
+
181
+ // Incorrect - let with reassignment
182
+ let status = "pending";
183
+ if (isComplete) {
184
+ status = "done";
185
+ }
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Hook Structure Example
191
+
192
+ ```typescript
193
+ export const usePlayerData = (playerId: string) => {
194
+ // 1. VARIABLES & STATE (first)
195
+ const [isLoading, setIsLoading] = useState(true);
196
+ const { data } = useQuery(GetPlayerDocument, { variables: { playerId } });
197
+
198
+ const playerName = useMemo(() => data?.player?.name ?? "Unknown", [data]);
199
+
200
+ const handleRefresh = useCallback(() => {
201
+ refetch();
202
+ }, [refetch]);
203
+
204
+ // 2. SIDE EFFECTS (second)
205
+ useEffect(() => {
206
+ console.log("Player loaded:", playerName);
207
+ }, [playerName]);
208
+
209
+ // 3. RETURN (last)
210
+ return { playerName, isLoading, handleRefresh };
211
+ };
212
+ ```
213
+
214
+ ## Container Component Example
215
+
216
+ ```typescript
217
+ const PlayerCardContainer: React.FC<Props> = ({ playerId }) => {
218
+ // 1. VARIABLES & STATE
219
+ const { data, loading } = useQuery(GetPlayerDocument, { variables: { playerId } });
220
+ const { colors } = useTheme();
221
+
222
+ const formattedStats = useMemo(
223
+ () => data?.stats?.map(s => ({ ...s, display: formatStat(s) })) ?? [],
224
+ [data?.stats]
225
+ );
226
+
227
+ const handlePress = useCallback(() => {
228
+ router.push(`/players/${playerId}`);
229
+ }, [playerId]);
230
+
231
+ // 2. SIDE EFFECTS (none in this example)
232
+
233
+ // 3. RETURN
234
+ return (
235
+ <PlayerCardView
236
+ stats={formattedStats}
237
+ colors={colors}
238
+ loading={loading}
239
+ onPress={handlePress}
240
+ />
241
+ );
242
+ };
243
+ ```
244
+
245
+ ## Utility Function Example
246
+
247
+ ```typescript
248
+ export const calculateTeamRankings = (
249
+ players: readonly Player[]
250
+ ): readonly TeamRanking[] => {
251
+ // 1. VARIABLES & DERIVED VALUES
252
+ const validPlayers = players.filter(p => p.team && p.score != null);
253
+
254
+ const teamScores = validPlayers.reduce(
255
+ (acc, player) => ({
256
+ ...acc,
257
+ [player.team.id]: {
258
+ teamId: player.team.id,
259
+ totalScore: (acc[player.team.id]?.totalScore ?? 0) + player.score,
260
+ count: (acc[player.team.id]?.count ?? 0) + 1,
261
+ },
262
+ }),
263
+ {} as Record<string, { teamId: string; totalScore: number; count: number }>
264
+ );
265
+
266
+ const rankings = Object.values(teamScores).map(t => ({
267
+ teamId: t.teamId,
268
+ avgScore: t.totalScore / t.count,
269
+ }));
270
+
271
+ const sorted = [...rankings].sort((a, b) => b.avgScore - a.avgScore);
272
+
273
+ // 2. NO SIDE EFFECTS IN PURE FUNCTIONS
274
+
275
+ // 3. RETURN
276
+ return sorted;
277
+ };
278
+ ```
279
+
280
+ ---
281
+
282
+ ## Anti-Patterns to Avoid
283
+
284
+ ### Never use `let` for conditional assignment
285
+
286
+ ```typescript
287
+ // Wrong
288
+ let result;
289
+ if (condition) {
290
+ result = valueA;
291
+ } else {
292
+ result = valueB;
293
+ }
294
+
295
+ // Correct
296
+ const result = condition ? valueA : valueB;
297
+ ```
298
+
299
+ ### Never mutate arrays
300
+
301
+ ```typescript
302
+ // Wrong
303
+ const items = [];
304
+ data.forEach(d => items.push(transform(d)));
305
+
306
+ // Correct
307
+ const items = data.map(d => transform(d));
308
+ ```
309
+
310
+ ### Never use Map when Record suffices
311
+
312
+ ```typescript
313
+ // Wrong
314
+ const lookup = new Map<string, User>();
315
+ users.forEach(u => lookup.set(u.id, u));
316
+ const user = lookup.get(userId);
317
+
318
+ // Correct
319
+ const lookup = users.reduce(
320
+ (acc, u) => ({ ...acc, [u.id]: u }),
321
+ {} as Record<string, User>
322
+ );
323
+ const user = lookup[userId];
324
+ ```
325
+
326
+ ### Never sort in place
327
+
328
+ ```typescript
329
+ // Wrong - mutates original
330
+ const sorted = items.sort((a, b) => a.value - b.value);
331
+
332
+ // Correct - creates new array
333
+ const sorted = [...items].sort((a, b) => a.value - b.value);
334
+ ```
335
+
336
+ ### Never place useEffect before variable definitions
337
+
338
+ ```typescript
339
+ // Wrong
340
+ useEffect(() => {
341
+ /* ... */
342
+ }, [value]);
343
+ const value = useMemo(() => calculate(), [dep]);
344
+
345
+ // Correct
346
+ const value = useMemo(() => calculate(), [dep]);
347
+ useEffect(() => {
348
+ /* ... */
349
+ }, [value]);
350
+ ```
351
+
352
+ ---
353
+
354
+ ## Immutable Patterns Reference
355
+
356
+ ### Building Lookup Objects with Reduce
357
+
358
+ ```typescript
359
+ const colorMap =
360
+ edges?.reduce(
361
+ (acc, edge) => (edge.color ? { ...acc, [edge.tagId]: edge.color } : acc),
362
+ {} as Record<string, string>
363
+ ) ?? {};
364
+ ```
365
+
366
+ ### Accumulating Multiple Properties
367
+
368
+ ```typescript
369
+ const teamGprAccumulator = validPlayers.reduce(
370
+ (acc, player) => {
371
+ const teamId = player.team?.id;
372
+ if (!teamId) return acc;
373
+
374
+ const existing = acc[teamId];
375
+ return {
376
+ ...acc,
377
+ [teamId]: {
378
+ teamId,
379
+ teamName: player.team.name,
380
+ gprSum: (existing?.gprSum ?? 0) + player.gpr,
381
+ playerCount: (existing?.playerCount ?? 0) + 1,
382
+ },
383
+ };
384
+ },
385
+ {} as Record<string, { teamId: string; teamName: string; gprSum: number; playerCount: number }>
386
+ );
387
+ ```
388
+
389
+ ### Nested Object Updates
390
+
391
+ ```typescript
392
+ const updated = {
393
+ ...state,
394
+ user: {
395
+ ...state.user,
396
+ profile: {
397
+ ...state.user.profile,
398
+ avatar: newAvatar,
399
+ },
400
+ },
401
+ };
402
+ ```
403
+
404
+ ### Conditional Property Addition
405
+
406
+ ```typescript
407
+ const result = {
408
+ ...baseObj,
409
+ ...(condition && { optionalProp: value }),
410
+ };
411
+ ```
412
+
413
+ ### Ternary Chain for Multiple Conditions
414
+
415
+ ```typescript
416
+ const priority = score > 90 ? "high" : score > 70 ? "medium" : "low";
417
+ ```
418
+
419
+ ### Readonly Types for Function Parameters
420
+
421
+ ```typescript
422
+ export const calculateTeamGprRank = (
423
+ leaguePlayers: readonly (PlayerWithScores | null | undefined)[],
424
+ myTeamId: string | null | undefined
425
+ ): number | null => {
426
+ // ...
427
+ };
428
+ ```
@@ -0,0 +1,126 @@
1
+ # Intent Routing
2
+
3
+ Classify the user's request and execute the matching flow. Each flow is a sequence of agents. Sub-flows can be invoked by any flow.
4
+
5
+ ## Flows
6
+
7
+ ### Fix
8
+ When: Bug reports, broken behavior, error messages, JIRA bug tickets.
9
+
10
+ Sequence:
11
+ 1. `git-history-analyzer` — understand why affected code exists, find related past fixes/reverts
12
+ 2. `debug-specialist` — reproduce the bug, prove root cause with evidence
13
+ 3. `architecture-specialist` — assess fix risk, identify files to change, check for ripple effects
14
+ 4. `test-specialist` — design regression test strategy
15
+ 5. `bug-fixer` — implement fix via TDD (reproduction becomes failing test)
16
+ 6. **Verify sub-flow**
17
+ 7. **Ship sub-flow**
18
+ 8. `learner` — capture discoveries for future sessions
19
+
20
+ ### Build
21
+ When: New features, stories, tasks, JIRA story/task tickets.
22
+
23
+ Sequence:
24
+ 1. `product-specialist` — define acceptance criteria, user flows, error states
25
+ 2. `architecture-specialist` — research codebase, design approach, map dependencies
26
+ 3. `test-specialist` — design test strategy (coverage, edge cases, TDD sequence)
27
+ 4. `builder` — implement via TDD (acceptance criteria become tests)
28
+ 5. **Verify sub-flow**
29
+ 6. **Review sub-flow**
30
+ 7. **Ship sub-flow**
31
+ 8. `learner` — capture discoveries
32
+
33
+ ### Investigate
34
+ When: "Why is this happening?", triage requests, JIRA spike tickets.
35
+
36
+ Sequence:
37
+ 1. `git-history-analyzer` — understand code evolution, find related changes
38
+ 2. `debug-specialist` — reproduce, trace execution, prove root cause
39
+ 3. `ops-specialist` — check logs, errors, health (if runtime issue)
40
+ 4. Report findings with evidence, recommend next action (Fix, Build, or escalate)
41
+
42
+ ### Plan
43
+ When: "Break this down", epic planning, large scope work, JIRA epic tickets.
44
+
45
+ Sequence:
46
+ 1. `product-specialist` — define acceptance criteria for the whole scope
47
+ 2. `architecture-specialist` — understand scope, map dependencies, identify cross-cutting concerns
48
+ 3. Break down into ordered tasks, each with: acceptance criteria, verification type, dependencies
49
+
50
+ ### Verify
51
+ When: Pre-ship quality gate. Used as a sub-flow by Fix and Build.
52
+
53
+ Sequence:
54
+ 1. Run full test suite — all tests must pass before proceeding
55
+ 2. Run quality checks — lint, typecheck, and format
56
+ 3. `verification-specialist` — verify acceptance criteria are met empirically
57
+
58
+ ### Ship
59
+ When: Code is ready to deploy. Used as a sub-flow by Fix, Build, and Improve.
60
+
61
+ Sequence:
62
+ 1. Commit — atomic conventional commits via `git-commit` skill
63
+ 2. PR — create/update pull request via `git-submit-pr` skill
64
+ 3. **Review sub-flow** (if not already done)
65
+ 4. PR Watch Loop (repeat until mergeable):
66
+ - If status checks fail → fix and push
67
+ - If merge conflicts → resolve and push
68
+ - If bot review feedback (CodeRabbit, etc.):
69
+ - Valid feedback → implement fix, push, resolve comment
70
+ - Invalid feedback → reply explaining why, resolve comment
71
+ - Repeat until all checks pass and all comments are resolved
72
+ 5. Merge the PR
73
+ 6. `ops-specialist` — deploy to target environment
74
+ 7. `verification-specialist` — post-deploy health check and smoke test
75
+ 8. `ops-specialist` — monitor for errors in first minutes
76
+
77
+ ### Review
78
+ When: Code review requests, PR review, quality assessment. Used as a sub-flow by Build.
79
+
80
+ Sequence:
81
+ 1. Run in parallel: `quality-specialist`, `security-specialist`, `performance-specialist`
82
+ 2. `product-specialist` — verify acceptance criteria are met empirically
83
+ 3. `test-specialist` — verify test coverage and quality
84
+ 4. Consolidate findings, ranked by severity
85
+
86
+ ### Improve
87
+ When: Refactoring, optimization, coverage improvement, complexity reduction.
88
+
89
+ Sequence:
90
+ 1. `architecture-specialist` — identify target, measure baseline, plan approach
91
+ 2. `test-specialist` — ensure existing test coverage before refactoring (safety net)
92
+ 3. `builder` — implement improvements via TDD
93
+ 4. `verification-specialist` — measure again, prove improvement
94
+ 5. **Ship sub-flow**
95
+ 6. `learner` — capture discoveries
96
+
97
+ #### Improve: Test Quality
98
+ When: "Improve tests", "strengthen test suite", "fix weak tests", test quality improvement.
99
+
100
+ Sequence:
101
+ 1. `test-specialist` — scan tests, identify weak/brittle tests, rank by improvement impact
102
+ 2. `builder` — implement test improvements
103
+ 3. **Verify sub-flow**
104
+ 4. **Ship sub-flow**
105
+ 5. `learner` — capture discoveries
106
+
107
+ ### Monitor
108
+ When: "Check the logs", "Any errors?", health checks, production monitoring.
109
+
110
+ Sequence:
111
+ 1. `ops-specialist` — health checks, log inspection, error monitoring, performance analysis
112
+ 2. Report findings, escalate if action needed
113
+
114
+ ## JIRA Entry Point
115
+
116
+ When the request references a JIRA ticket (ticket ID like PROJ-123 or a JIRA URL):
117
+
118
+ 1. Hand off to `jira-agent`
119
+ 2. `jira-agent` reads the ticket, validates structural quality, and runs analytical triage
120
+ 3. If triage finds unresolved ambiguities, `jira-agent` posts findings and STOPS — no work begins
121
+ 4. `jira-agent` determines intent and delegates to the appropriate flow above
122
+ 5. `jira-agent` syncs progress at milestones and posts evidence at completion
123
+
124
+ ## Sub-flow Usage
125
+
126
+ Flows reference sub-flows by name. When a flow says "Ship sub-flow", execute the full Ship sequence. When it says "Review sub-flow", execute the full Review sequence. Sub-flows can be nested (e.g., Ship includes Review).
@@ -0,0 +1,30 @@
1
+ # Security Audit Handling
2
+
3
+ If `git push` fails because the pre-push hook reports security vulnerabilities, follow these steps. Never use `--no-verify` to bypass the security audit.
4
+
5
+ ## Node.js Projects (GHSA advisories)
6
+
7
+ 1. Note the GHSA ID(s), affected package(s), and advisory URL from the error output
8
+ 2. Check the advisory URL to determine if a patched version of the vulnerable package exists
9
+ 3. If a patched version exists: add a resolution/override in package.json to force the patched version (add to both `resolutions` and `overrides` sections), then run the package manager install command to regenerate the lockfile, commit the changes, and retry the push
10
+ 4. If no patched version exists and the vulnerability is safe for this project (e.g., transitive dependency with no untrusted input, devDeps only, or build tool only): add an exclusion entry to `audit.ignore.local.json` with the format `{"id": "GHSA-xxx", "package": "pkg-name", "reason": "why this is safe for this project"}`, then commit and retry the push
11
+
12
+ ### Critical: Override the vulnerable package, not its parent
13
+
14
+ When the audit output shows a dependency chain like `@expo/cli › glob › minimatch`, the vulnerable package is **minimatch**, not glob. Always override the **leaf package** that has the actual vulnerability.
15
+
16
+ **Never override a parent package to force a lower major version** — other packages in the project may depend on a newer major version, and a resolution/override forces ALL installations to the specified version. For example, overriding `glob` to `^8.1.0` will break `@expo/cli` which requires `glob@^13.0.0`, causing `expo prebuild` to fail with `files.map is not a function`.
17
+
18
+ Before adding a resolution/override, verify:
19
+ - You are targeting the **actually vulnerable package**, not a parent in the chain
20
+ - The override version is **compatible with all dependents** (check with `bun why <package>` or `npm ls <package>`)
21
+ - The override does not **downgrade** a package across a major version boundary that other dependencies require
22
+
23
+ ## Rails Projects (bundler-audit)
24
+
25
+ 1. Note the advisory ID, affected gem, and advisory URL from the error output
26
+ 2. Check if a patched version of the gem exists
27
+ 3. If a patched version exists:
28
+ - If the gem is a **direct dependency** (listed in Gemfile): update its version constraint in Gemfile, run `bundle update <gem>`, commit the changes, and retry the push
29
+ - If the gem is a **transitive dependency** (not in Gemfile, only in Gemfile.lock): run `bundle update <gem>` to pull the patched version without changing the Gemfile, commit the lockfile change, and retry the push
30
+ 4. If no patched version exists and the vulnerability is safe for this project: document the exception and retry the push
@@ -0,0 +1,93 @@
1
+ # Empirical Verification
2
+
3
+ This repository supports AI agents as first-class contributors.
4
+
5
+ This file is the operational contract that defines how agents plan work, execute changes, verify outcomes, and escalate when blocked.
6
+
7
+ If anything here conflicts with other repo docs, treat this file as authoritative for agent behavior.
8
+
9
+ ---
10
+
11
+ ## Core Principle
12
+
13
+ Agents must close the loop between code changes and observable system behavior.
14
+
15
+ No agent may claim success without evidence from runtime verification.
16
+
17
+ Never assume something works because the code "looks correct." Run a command, observe the output, compare to expected result.
18
+
19
+ **Verification is not linting, typechecking, or testing.** Those are quality checks. Verification is using the resulting software the way a user would — interacting with the UI, calling the API, running the CLI command, observing the behavior. Tests pass in isolation; verification proves the system works as a whole. Passing tests, linting, and typechecking does not constitute verification.
20
+
21
+ Verification is mandatory. Never skip it, defer it, or claim it was unnecessary. Every task must be verified before claiming completion.
22
+
23
+ Before starting implementation, state your verification plan — how you will use the resulting software to prove it works. Do not begin implementation until the plan is confirmed.
24
+
25
+ After verifying a change empirically, encode that verification as automated tests. The manual proof that something works should become a repeatable regression test that catches future regressions. Every verification should answer: "How do I turn this into a test?"
26
+
27
+ Every pull request must include step-by-step instructions for reviewers to independently replicate the verification. These are not test commands — they are the exact steps a human would follow to use the software and confirm the change works. If a reviewer cannot reproduce your verification from the PR description alone, the PR is incomplete.
28
+
29
+ ---
30
+
31
+ ## Roles
32
+
33
+ ### Builder Agent
34
+
35
+ Implements the change in code and infrastructure.
36
+
37
+ ### Verifier Agent
38
+
39
+ Acts as the end user (human user, API client, operator, attacker, or system) and produces proof artifacts.
40
+
41
+ Verifier Agent must be independent from Builder Agent when possible.
42
+
43
+ ### Human Overseer
44
+
45
+ Approves risky operations, security boundary crossings, and any work the agents cannot fully verify.
46
+
47
+ ---
48
+
49
+ ## Verification Levels
50
+
51
+ Agents must label every task outcome with exactly one of these:
52
+
53
+ - **FULLY VERIFIED**: Verified in the target environment with end-user simulation and captured artifacts.
54
+ - **PARTIALLY VERIFIED**: Verified in a lower-fidelity environment or with incomplete surfaces, with explicit gaps documented.
55
+ - **UNVERIFIED**: Verification blocked, human action required, no claim of correctness permitted.
56
+
57
+ ---
58
+
59
+ ## Verification Types
60
+
61
+ Every change requires one or more verification types. Classify the change first, then verify each applicable type.
62
+
63
+ ### Always Required
64
+
65
+ | Type | What to prove | Acceptable proof |
66
+ |------|---------------|------------------|
67
+ | **Test** | Unit and integration tests pass for all changed code paths | Test runner output showing all relevant tests green with no skips |
68
+ | **Type Safety** | No type errors introduced by the change | Type checker exits clean on the full project |
69
+ | **Lint/Format** | Code meets project style and quality rules | Linter and formatter exit clean on changed files |
70
+
71
+ ### Conditional
72
+
73
+ | Type | When it applies | What to prove | Acceptable proof |
74
+ |------|----------------|---------------|------------------|
75
+ | **UI** | Change affects user-visible interface | Feature renders correctly and interactions work as expected | Automated session recording or screenshots showing correct states; for cross-platform changes, evidence from each platform or explicit gap documentation |
76
+ | **API** | Change affects HTTP/GraphQL/RPC endpoints | Endpoint returns correct status, headers, and body for success and error cases | Request/response capture showing schema and data match expectations |
77
+ | **Database** | Change involves schema, migrations, or queries | Schema is correct after migration; data integrity is maintained | Query output showing expected schema and data state |
78
+ | **Auth** | Change affects authentication or authorization | Correct access for allowed roles; rejection for disallowed roles | Request traces showing enforcement across at least two roles |
79
+ | **Security** | Change involves input handling, secrets, or attack surfaces | Exploit is prevented; safe handling is enforced | Reproduction of attack pre-fix failing post-fix, or evidence of sanitization/rejection |
80
+ | **Performance** | Change claims performance improvement or affects hot paths | Measurable improvement in latency, throughput, or resource usage | Before/after benchmarks with methodology documented |
81
+ | **Infrastructure** | Change affects deployment, scaling, or cloud resources | Resources are created/updated correctly; system is stable | Infrastructure state output showing expected configuration; stability metrics during transition |
82
+ | **Observability** | Change affects logging, metrics, or tracing | Events are emitted with correct structure and correlation | Log or metric output showing expected entries with correlation IDs |
83
+ | **Background Jobs** | Change affects queues, workers, or scheduled tasks | Job enqueues, processes, and reaches terminal state correctly | Evidence of enqueue, processing, and final state; idempotency check when relevant |
84
+ | **Configuration** | Change affects config files, feature flags, or environment variables | Configuration is loaded and applied correctly at runtime | Application output showing the configuration taking effect |
85
+ | **Documentation** | Change affects documentation content or structure | Documentation is accurate and matches implementation | Content inspection confirming accuracy against actual behavior |
86
+ | **Cache** | Change affects caching behavior or invalidation | Cache hits, misses, and invalidation work as expected | Evidence of cache behavior (hit/miss logs, TTL verification, key inspection) |
87
+ | **Email/Notification** | Change affects outbound messages | Message is sent with correct content to correct recipient | Captured message content or delivery log showing expected output |
88
+ | **PR** | Shipping code (always applies when opening a PR) | PR includes goal summary, verification level, proof artifacts, and reproduction steps | PR description containing all required sections |
89
+ | **Deploy** | Shipping code to an environment | Deployment completes and application is healthy in the target environment | Deployment output and health check evidence from the target environment |
90
+
91
+ ---
92
+
93
+ For the full verification lifecycle (classify, check tooling, plan, execute, loop), surfaces, escalation protocol, and proof artifact requirements, see the `verification-lifecycle` skill loaded by the `verification-specialist` agent.
@@ -4,6 +4,12 @@
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": { "name": "Cody Swann" },
6
6
  "hooks": {
7
+ "SessionStart": [
8
+ { "matcher": "", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/inject-rules.sh" }] }
9
+ ],
10
+ "SubagentStart": [
11
+ { "matcher": "", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/inject-rules.sh" }] }
12
+ ],
7
13
  "PostToolUse": [
8
14
  {
9
15
  "matcher": "Write|Edit",