slash-do 1.5.1 → 1.6.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/commands/do/better.md +160 -19
- package/lib/code-review-checklist.md +2 -0
- package/package.json +1 -1
package/commands/do/better.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Unified DevSecOps audit, remediation, per-category PRs, CI verification, and Copilot review loop with worktree isolation
|
|
2
|
+
description: Unified DevSecOps audit, remediation, test enhancement, per-category PRs, CI verification, and Copilot review loop with worktree isolation
|
|
3
3
|
argument-hint: "[--scan-only] [--no-merge] [path filter or focus areas]"
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -58,6 +58,9 @@ When compacting during this workflow, always preserve:
|
|
|
58
58
|
- All PR numbers and URLs created so far
|
|
59
59
|
- `BUILD_CMD`, `TEST_CMD`, `PROJECT_TYPE`, `WORKTREE_DIR` values
|
|
60
60
|
- `VCS_HOST`, `CLI_TOOL`, `DEFAULT_BRANCH`, `CURRENT_BRANCH`
|
|
61
|
+
- `PHASE_4C_START_SHA` (needed for FILE_OWNER_MAP update in Phase 4c.3)
|
|
62
|
+
- `VACUOUS_TESTS_FIXED`, `WEAK_TESTS_STRENGTHENED`, `NEW_TEST_CASES`, `NEW_TEST_FILES`
|
|
63
|
+
- `CREATED_CATEGORY_SLUGS` (list of branch slugs created in Phase 5)
|
|
61
64
|
|
|
62
65
|
|
|
63
66
|
## Phase 0: Discovery & Setup
|
|
@@ -173,9 +176,31 @@ Skip step 4 if steps 1-3 reveal the code is correct.
|
|
|
173
176
|
- **Database migrations**: exclusive-lock ALTER TABLE on large tables, CREATE INDEX without CONCURRENTLY, missing down migrations or untested rollback paths
|
|
174
177
|
- General: framework-specific security issues, language-specific gotchas, domain-specific compliance, environment variable hygiene (missing `.env.example`, required env vars not validated at startup, secrets in config files that should be in env)
|
|
175
178
|
|
|
176
|
-
7. **Test Coverage**
|
|
177
|
-
Uses Batch 1 findings as context to prioritize
|
|
178
|
-
Focus
|
|
179
|
+
7. **Test Quality & Coverage**
|
|
180
|
+
Uses Batch 1 findings as context to prioritize.
|
|
181
|
+
Focus areas:
|
|
182
|
+
|
|
183
|
+
**Coverage gaps:**
|
|
184
|
+
- Missing test files for critical modules, untested edge cases, tests that only cover happy paths
|
|
185
|
+
- Areas with high complexity (identified by agents 1-5) but no tests
|
|
186
|
+
- Remediation changes from agents 1-6 that lack corresponding test coverage
|
|
187
|
+
|
|
188
|
+
**Vacuous tests (tests that don't actually test anything):**
|
|
189
|
+
- Tests that assert on mocked return values instead of real behavior (testing the mock, not the code)
|
|
190
|
+
- Tests that only check truthiness (`assert.ok(result)`) when they should verify specific values or shapes
|
|
191
|
+
- Tests with assertions that can never fail (e.g., asserting a hardcoded value equals itself, asserting `typeof x === 'object'` on a literal `{}`)
|
|
192
|
+
- Tests that re-implement the logic under test instead of importing the real function — these pass even when real code regresses
|
|
193
|
+
- `it('should work', ...)` tests with no meaningful assertion or with assertions commented out
|
|
194
|
+
- Tests that mock the module they're testing (testing mock behavior, not real behavior)
|
|
195
|
+
|
|
196
|
+
**Weak test patterns:**
|
|
197
|
+
- Tests that verify implementation details (internal state, private methods, call counts) instead of observable behavior
|
|
198
|
+
- Tests where all assertions pass even if the function under test returns `null`/`undefined`/empty — verify by mentally substituting a no-op and checking if the test would still pass
|
|
199
|
+
- Integration tests that mock so aggressively they become unit tests of glue code
|
|
200
|
+
- Tests missing negative cases (invalid input, error paths, boundary conditions)
|
|
201
|
+
- Tests with shared mutable state between cases (`beforeEach` that doesn't reset, module-level variables)
|
|
202
|
+
|
|
203
|
+
Report each finding with a severity prefix `**[CRITICAL]**`, `**[HIGH]**`, `**[MEDIUM]**`, or `**[LOW]**` followed immediately by a quality prefix `[VACUOUS]`, `[WEAK]`, or `[MISSING]` (for example, `**[HIGH][VACUOUS]**`) to distinguish quality issues from coverage gaps while keeping the format consistent with other agents. Include the specific test name and file:line for existing test issues.
|
|
179
204
|
|
|
180
205
|
Wait for ALL agents to complete before proceeding.
|
|
181
206
|
|
|
@@ -220,10 +245,18 @@ For each file touched by multiple categories, document why it was assigned to on
|
|
|
220
245
|
### Architecture & SOLID
|
|
221
246
|
### Bugs, Performance & Error Handling
|
|
222
247
|
### Stack-Specific
|
|
223
|
-
### Test
|
|
248
|
+
### Test Quality & Coverage
|
|
224
249
|
```
|
|
225
250
|
|
|
226
|
-
6. Print a summary table:
|
|
251
|
+
6. Print a summary table (short labels → full category → branch slug):
|
|
252
|
+
- Security → Security & Secrets → `security`
|
|
253
|
+
- Code Quality → Code Quality & Style → `code-quality`
|
|
254
|
+
- DRY & YAGNI → DRY & YAGNI → `dry`
|
|
255
|
+
- Architecture → Architecture & SOLID → `architecture`
|
|
256
|
+
- Bugs & Perf → Bugs, Performance & Error Handling → `bugs-perf`
|
|
257
|
+
- Stack-Specific → Stack-Specific → `stack-specific`
|
|
258
|
+
- Tests → Test Quality & Coverage → `tests`
|
|
259
|
+
|
|
227
260
|
```
|
|
228
261
|
| Category | CRITICAL | HIGH | MEDIUM | LOW | Total |
|
|
229
262
|
|-------------------|----------|------|--------|-----|-------|
|
|
@@ -233,7 +266,7 @@ For each file touched by multiple categories, document why it was assigned to on
|
|
|
233
266
|
| Architecture | ... | ... | ... | ... | ... |
|
|
234
267
|
| Bugs & Perf | ... | ... | ... | ... | ... |
|
|
235
268
|
| Stack-Specific | ... | ... | ... | ... | ... |
|
|
236
|
-
|
|
|
269
|
+
| Tests | ... | ... | ... | ... | ... |
|
|
237
270
|
| TOTAL | ... | ... | ... | ... | ... |
|
|
238
271
|
```
|
|
239
272
|
|
|
@@ -241,7 +274,7 @@ For each file touched by multiple categories, document why it was assigned to on
|
|
|
241
274
|
|
|
242
275
|
## Phase 3: Worktree Remediation
|
|
243
276
|
|
|
244
|
-
Only proceed with CRITICAL, HIGH, and MEDIUM findings
|
|
277
|
+
Only proceed with CRITICAL, HIGH, and MEDIUM findings for code remediation. LOW findings remain tracked in PLAN.md but are not auto-remediated. Test Quality & Coverage findings are handled separately in Phase 4c.
|
|
245
278
|
|
|
246
279
|
### 3a: Setup
|
|
247
280
|
|
|
@@ -349,18 +382,119 @@ Before creating PRs, run a deep code review on all remediation changes to catch
|
|
|
349
382
|
```
|
|
350
383
|
5. If "Show diff" selected, print the diff and re-ask. If "Abort", stop and print the worktree path.
|
|
351
384
|
|
|
385
|
+
## Phase 4c: Test Enhancement
|
|
386
|
+
|
|
387
|
+
After internal code review passes, evaluate and enhance the project's test suite. This phase acts on Agent 7's findings AND ensures all remediation work from Phase 3 has proper test coverage.
|
|
388
|
+
|
|
389
|
+
### 4c.0: Record Start SHA
|
|
390
|
+
|
|
391
|
+
Before any test enhancement commits, capture the current HEAD so Phase 4c changes can be diffed later:
|
|
392
|
+
```bash
|
|
393
|
+
cd {WORKTREE_DIR}
|
|
394
|
+
PHASE_4C_START_SHA="$(git rev-parse HEAD)"
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### 4c.1: Test Audit Triage
|
|
398
|
+
|
|
399
|
+
Review Agent 7 findings from Phase 1 and categorize them:
|
|
400
|
+
|
|
401
|
+
1. **`[VACUOUS]` findings** — tests that exist but don't test real behavior. These are the highest priority because they create a false sense of safety.
|
|
402
|
+
2. **`[WEAK]` findings** — tests that partially cover behavior but miss important cases. Strengthen with additional assertions and edge cases.
|
|
403
|
+
3. **`[MISSING]` findings** — no tests exist for critical paths. Write new test files or add test cases to existing files.
|
|
404
|
+
|
|
405
|
+
Additionally, scan all remediation changes from Phase 3:
|
|
406
|
+
- For each file modified by remediation agents, check if corresponding tests exist
|
|
407
|
+
- If tests exist, verify they cover the specific behavior that was fixed/changed
|
|
408
|
+
- If no tests exist for a remediated module, flag for new test creation
|
|
409
|
+
|
|
410
|
+
### 4c.2: Test Enhancement Execution
|
|
411
|
+
|
|
412
|
+
Spawn a general-purpose agent (using `REMEDIATION_MODEL`) in the worktree to fix and write tests. Populate the template placeholders below from Phase 4c.1 triage output: `{VACUOUS_AND_WEAK_FINDINGS}` from `[VACUOUS]`/`[WEAK]` findings, `{MISSING_FINDINGS}` from `[MISSING]` findings, and `{REMEDIATED_FILES_WITHOUT_TESTS}` from the remediation-change scan. The agent instructions:
|
|
413
|
+
|
|
414
|
+
```
|
|
415
|
+
You are a test enhancement agent working in {WORKTREE_DIR}.
|
|
416
|
+
Project type: {PROJECT_TYPE}. Test command: {TEST_CMD}.
|
|
417
|
+
|
|
418
|
+
Your job is to fix weak/vacuous tests and write missing tests that verify REAL BEHAVIOR.
|
|
419
|
+
|
|
420
|
+
## Rules for writing good tests
|
|
421
|
+
|
|
422
|
+
1. **Test observable behavior, not implementation.** Assert on return values, side effects (files written, state changed), and error messages — never on internal variable names, call counts, or private method invocations.
|
|
423
|
+
|
|
424
|
+
2. **Every assertion must be falsifiable.** For each assertion you write, mentally substitute a broken implementation (returns null, returns wrong value, throws instead of succeeding, succeeds instead of throwing). If your assertion would still pass, it's vacuous — rewrite it.
|
|
425
|
+
|
|
426
|
+
3. **Prefer real modules over mocks.** Only mock at system boundaries (filesystem, network, time). If you must mock, assert on the arguments passed TO the mock, not on its return value.
|
|
427
|
+
|
|
428
|
+
4. **Test the edges.** Each test function needs at minimum:
|
|
429
|
+
- Happy path with specific expected output
|
|
430
|
+
- Empty/null/undefined input
|
|
431
|
+
- Invalid input that should error
|
|
432
|
+
- Boundary values (0, -1, MAX, empty string vs null)
|
|
433
|
+
|
|
434
|
+
5. **Use concrete expected values.** `assert.equal(result, 'expected string')` not `assert.ok(result)`. `assert.deepEqual(output, { key: 'value' })` not `assert.ok(typeof output === 'object')`.
|
|
435
|
+
|
|
436
|
+
6. **One behavior per test.** Each `it()` block tests exactly one scenario. The test name describes the scenario and expected outcome.
|
|
437
|
+
|
|
438
|
+
7. **No shared mutable state.** Each test must be independently runnable. Use `beforeEach` to create fresh fixtures. Never rely on test execution order.
|
|
439
|
+
|
|
440
|
+
## Task list
|
|
441
|
+
|
|
442
|
+
Fix these vacuous/weak tests:
|
|
443
|
+
{VACUOUS_AND_WEAK_FINDINGS}
|
|
444
|
+
|
|
445
|
+
Write tests for these gaps:
|
|
446
|
+
{MISSING_FINDINGS}
|
|
447
|
+
|
|
448
|
+
Write tests for these remediated files:
|
|
449
|
+
{REMEDIATED_FILES_WITHOUT_TESTS}
|
|
450
|
+
|
|
451
|
+
## Verification
|
|
452
|
+
|
|
453
|
+
After writing/fixing each test file:
|
|
454
|
+
1. Run `{TEST_CMD}` to verify all tests pass
|
|
455
|
+
2. For each NEW test, verify that it fails when the behavior under test is wrong:
|
|
456
|
+
- Ensure you have no unstaged changes (`git diff` is clean)
|
|
457
|
+
- Apply a small, obvious, and **uncommitted** change to the code under test (e.g., return a constant, flip a conditional)
|
|
458
|
+
- Run `{TEST_CMD}` and confirm the new test FAILS
|
|
459
|
+
- Immediately restore the code: `git checkout -- {file_path}`
|
|
460
|
+
- Confirm the worktree is clean again (`git diff` shows no changes)
|
|
461
|
+
This is the key quality gate — a test that does not fail when the code is broken is worthless.
|
|
462
|
+
3. After confirming the code is restored and the worktree is clean, commit passing tests: `test: {description of what's tested}`
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### 4c.3: Verification
|
|
466
|
+
|
|
467
|
+
After the test agent completes:
|
|
468
|
+
|
|
469
|
+
1. Run the full test suite:
|
|
470
|
+
```bash
|
|
471
|
+
cd {WORKTREE_DIR} && {TEST_CMD}
|
|
472
|
+
```
|
|
473
|
+
2. If tests fail, fix in a new commit
|
|
474
|
+
3. Count new/fixed tests and record four variables:
|
|
475
|
+
- `VACUOUS_TESTS_FIXED` — number of vacuous tests fixed
|
|
476
|
+
- `WEAK_TESTS_STRENGTHENED` — number of weak tests strengthened
|
|
477
|
+
- `NEW_TEST_CASES` — number of new test cases added
|
|
478
|
+
- `NEW_TEST_FILES` — number of new test files created
|
|
479
|
+
4. **Update `FILE_OWNER_MAP`** — Phase 4c may have created or modified test files that were not in the Phase 2 map. Before Phase 5 assembles branches:
|
|
480
|
+
- List all files changed by Phase 4c commits: `git diff --name-only "$PHASE_4C_START_SHA"..HEAD`
|
|
481
|
+
- For each file not already in `FILE_OWNER_MAP`, assign it to the `tests` category
|
|
482
|
+
- For each file already owned by another category, leave it in that category (co-located test changes ship with the code they test — the `tests` branch only contains standalone test files not owned by other categories)
|
|
483
|
+
|
|
352
484
|
## Phase 5: Per-Category PR Creation
|
|
353
485
|
|
|
354
486
|
Instead of one mega PR, create **separate branches and PRs for each category**. This enables independent review, targeted CI, and granular merge decisions.
|
|
355
487
|
|
|
356
488
|
### 5a: Build the Category Branches
|
|
357
489
|
|
|
358
|
-
Using the `FILE_OWNER_MAP` from Phase 2, create one branch per category
|
|
490
|
+
Using the `FILE_OWNER_MAP` from Phase 2 (updated in Phase 4c.3), create one branch per category.
|
|
491
|
+
|
|
492
|
+
Initialize `CREATED_CATEGORY_SLUGS=""` (empty space-delimited string). After each category branch is successfully created and pushed below, append its slug: `CREATED_CATEGORY_SLUGS="$CREATED_CATEGORY_SLUGS {CATEGORY_SLUG}"`. Phase 7 uses this for cleanup.
|
|
359
493
|
|
|
360
494
|
For each category that has findings:
|
|
361
495
|
1. Switch to `{DEFAULT_BRANCH}`: `git checkout {DEFAULT_BRANCH}`
|
|
362
496
|
2. Create a category branch: `git checkout -b better/{CATEGORY_SLUG}`
|
|
363
|
-
- Use slugs: `security`, `code-quality`, `dry`, `
|
|
497
|
+
- Use slugs: `security`, `code-quality`, `dry`, `architecture`, `bugs-perf`, `stack-specific`, `tests`
|
|
364
498
|
3. For each file assigned to this category in `FILE_OWNER_MAP`:
|
|
365
499
|
- **Modified files**: `git checkout origin/better/{DATE} -- {file_path}`
|
|
366
500
|
- **New files (Added)**: `git checkout origin/better/{DATE} -- {file_path}`
|
|
@@ -546,16 +680,16 @@ If merge fails (e.g., branch protection, merge conflicts from a prior PR):
|
|
|
546
680
|
```bash
|
|
547
681
|
git worktree remove {WORKTREE_DIR}
|
|
548
682
|
```
|
|
549
|
-
2. Delete local AND remote branches (only
|
|
683
|
+
2. Delete local AND remote branches (only categories that were created and merged). Use the tracked list of branches from Phase 5 rather than a fixed list:
|
|
550
684
|
```bash
|
|
551
685
|
git branch -d better/{DATE}
|
|
552
|
-
|
|
686
|
+
# CREATED_CATEGORY_SLUGS is a space-delimited string, e.g. "security code-quality tests"
|
|
687
|
+
for slug in $CREATED_CATEGORY_SLUGS; do
|
|
688
|
+
git branch -d "better/$slug" || echo "warning: local branch better/$slug not found or not fully merged"
|
|
689
|
+
git push origin --delete "better/$slug" 2>/dev/null || echo "warning: remote branch better/$slug not found"
|
|
690
|
+
done
|
|
553
691
|
```
|
|
554
|
-
|
|
555
|
-
git push origin --delete better/{DATE}
|
|
556
|
-
git push origin --delete better/security better/code-quality better/dry better/arch-bugs better/stack-specific
|
|
557
|
-
```
|
|
558
|
-
Ignore errors from `--delete` if a branch doesn't exist remotely.
|
|
692
|
+
The guards prevent errors from interrupting cleanup. Warnings are printed so leftover branches are visible.
|
|
559
693
|
3. Restore stashed changes (if stashed in Phase 3a):
|
|
560
694
|
```bash
|
|
561
695
|
git stash pop
|
|
@@ -575,8 +709,14 @@ If merge fails (e.g., branch protection, merge conflicts from a prior PR):
|
|
|
575
709
|
| Architecture | ... | ... | ... | #number | pass | approved |
|
|
576
710
|
| Bugs & Perf | ... | ... | ... | #number | pass | approved |
|
|
577
711
|
| Stack-Specific | ... | ... | ... | #number | pass | approved |
|
|
578
|
-
|
|
|
712
|
+
| Tests | ... | ... | ... | #number | pass | approved |
|
|
579
713
|
| TOTAL | ... | ... | ... | N PRs | | |
|
|
714
|
+
|
|
715
|
+
Test Enhancement Stats:
|
|
716
|
+
- Vacuous tests fixed: {VACUOUS_TESTS_FIXED}
|
|
717
|
+
- Weak tests strengthened: {WEAK_TESTS_STRENGTHENED}
|
|
718
|
+
- New test cases added: {NEW_TEST_CASES}
|
|
719
|
+
- New test files created: {NEW_TEST_FILES}
|
|
580
720
|
```
|
|
581
721
|
|
|
582
722
|
## Error Recovery
|
|
@@ -602,6 +742,7 @@ If merge fails (e.g., branch protection, merge conflicts from a prior PR):
|
|
|
602
742
|
- Each file appears in exactly ONE PR (file ownership map) to prevent merge conflicts between PRs
|
|
603
743
|
- When extracting modules, always add backward-compatible re-exports in the original module to prevent cross-PR breakage
|
|
604
744
|
- Version bump happens exactly once on the first category branch based on aggregate commit analysis
|
|
605
|
-
- Only CRITICAL, HIGH, and MEDIUM findings are auto-remediated; LOW
|
|
745
|
+
- Only CRITICAL, HIGH, and MEDIUM findings are auto-remediated for code categories; LOW findings remain tracked in PLAN.md
|
|
746
|
+
- Test Quality & Coverage findings are remediated in Phase 4c with a dedicated test enhancement agent that verifies tests fail when code is broken
|
|
606
747
|
- GitLab projects skip the Copilot review loop entirely (Phase 6) and stop after MR creation
|
|
607
748
|
- CI must pass on each PR before requesting Copilot review or merging
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
**Validation & consistency** _[applies when: code handles user input, schemas, or API contracts]_
|
|
61
61
|
- API versioning: breaking changes to public endpoints without version bump or deprecation path
|
|
62
62
|
- Backward-incompatible response shape changes without client migration plan
|
|
63
|
+
- Backward compatibility breaking changes — renamed/removed config keys, changed file formats, altered DB schemas, modified event payloads, or restructured persisted data (localStorage, files, database rows) without a migration path or fallback that reads the old format. Trace all consumers of the changed contract (other services, CLI versions, stored data) and verify they still work or have an upgrade path. For schema changes, require a migration script; for config/format changes, support both old and new formats during a transition period or provide a one-time converter
|
|
63
64
|
- New endpoints/schemas should match validation patterns of existing similar endpoints — field limits, required fields, types, error handling. If validation exists on one endpoint for a param, the same param on other endpoints needs the same validation
|
|
64
65
|
- When a validation/sanitization function is introduced for a field, trace ALL write paths (create, update, sync, import) — partial application means invalid values re-enter through the unguarded path
|
|
65
66
|
- Schema fields accepting values downstream code can't handle; Zod/schema stripping fields the service reads (silent `undefined`); config values persisted but silently ignored by the implementation — trace each field through schema → service → consumer. Update schemas derived from create schemas (e.g., `.partial()`) must also make nested object fields optional — shallow partial on a deeply-required schema rejects valid partial updates. Additionally, `.deepPartial()` or `.partial()` on schemas with `.default()` values will apply those defaults on update, silently overwriting existing persisted values with defaults — create explicit update schemas without defaults instead
|
|
@@ -133,6 +134,7 @@
|
|
|
133
134
|
- Labels, comments, status messages, or documentation that describe behavior the code doesn't implement — e.g., a map named "renamed" that only deletes, or an action labeled "migrated" that never creates the target
|
|
134
135
|
- Inline code examples, command templates, and query snippets that aren't syntactically valid as written — template placeholders must use a consistent format, queries must use correct syntax for their language (e.g., single `{}` in GraphQL, not `{{}}`)
|
|
135
136
|
- Cross-references between files (identifiers, parameter names, format conventions, operational thresholds) that disagree — when one reference changes, trace all other files that reference the same entity and update them
|
|
137
|
+
- Template/workflow variables referenced (`{VAR_NAME}`) but never assigned — trace each placeholder to a definition step; undefined variables cause silent failures or confusing instructions. Also check for colliding identifiers (two distinct concepts mapped to the same slug, key, or name)
|
|
136
138
|
- Responsibility relocated from one module to another (e.g., writes moved from handler to middleware) without updating all consumers that depended on the old location's timing, return value, or side effects — trace callers that relied on the synchronous or co-located behavior and verify they still work with the new execution point. Remove dead code left behind at the old location
|
|
137
139
|
- Sequential instructions or steps whose ordering doesn't match the required execution order — readers following in order will perform actions at the wrong time (e.g., "record X" in step 2 when X must be captured before step 1's action)
|
|
138
140
|
- Sequential numbering (section numbers, step numbers) with gaps or jumps after edits — verify continuity
|
package/package.json
CHANGED