@joshski/dust 0.1.108 → 0.1.110
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/dist/audits.js +666 -28
- package/dist/dust.js +710 -56
- package/dist/filesystem/error-codes.d.ts +2 -0
- package/dist/loop/iteration.d.ts +2 -2
- package/dist/patch.js +23 -14
- package/dist/validation.js +20 -11
- package/package.json +1 -1
package/dist/audits.js
CHANGED
|
@@ -510,6 +510,72 @@ function deadCode() {
|
|
|
510
510
|
- No changes to files outside \`.dust/\`
|
|
511
511
|
`;
|
|
512
512
|
}
|
|
513
|
+
function directoryHierarchy() {
|
|
514
|
+
return dedent`
|
|
515
|
+
# Directory Hierarchy
|
|
516
|
+
|
|
517
|
+
Review directory structure and create improvement ideas.
|
|
518
|
+
|
|
519
|
+
${ideasHint}
|
|
520
|
+
|
|
521
|
+
## Scope
|
|
522
|
+
|
|
523
|
+
Analyze the project's directory organization for these issues:
|
|
524
|
+
|
|
525
|
+
1. **Concern mixing** - Directories containing files that serve different purposes
|
|
526
|
+
2. **Missing grouping** - Related files scattered across multiple locations
|
|
527
|
+
3. **Depth inconsistency** - Similar directories at inconsistent depths
|
|
528
|
+
4. **Naming inconsistency** - Directory names that don't follow established patterns
|
|
529
|
+
5. **Singleton directories** - Directories with only a single file or subdirectory
|
|
530
|
+
6. **Orphaned files** - Files at inappropriate directory levels
|
|
531
|
+
|
|
532
|
+
## Analysis Steps
|
|
533
|
+
|
|
534
|
+
1. **Explore the directory tree** - Walk the project's file system recursively, excluding \`node_modules\`, \`.git\`, \`dist\`, \`build\`, \`coverage\`, and other common build artifact directories
|
|
535
|
+
2. **Identify issues** - For each of the issue types listed above, look for concrete examples in the directory structure
|
|
536
|
+
3. **Create ideas** - For each issue found, create an idea file in \`.dust/ideas/\` with:
|
|
537
|
+
- Descriptive filename based on the issue type and affected paths
|
|
538
|
+
- The specific paths affected
|
|
539
|
+
- Why the current structure is problematic
|
|
540
|
+
- A proposed reorganization
|
|
541
|
+
- Migration complexity estimate (low/medium/high)
|
|
542
|
+
|
|
543
|
+
## Output Format
|
|
544
|
+
|
|
545
|
+
Each idea file should follow this structure:
|
|
546
|
+
|
|
547
|
+
\`\`\`markdown
|
|
548
|
+
# [Issue Type]: [Brief Description]
|
|
549
|
+
|
|
550
|
+
## Current Structure
|
|
551
|
+
|
|
552
|
+
[List specific paths from affectedPaths]
|
|
553
|
+
|
|
554
|
+
## Problem
|
|
555
|
+
|
|
556
|
+
[Description of why this is problematic]
|
|
557
|
+
|
|
558
|
+
## Proposed Solution
|
|
559
|
+
|
|
560
|
+
[Suggested reorganization]
|
|
561
|
+
|
|
562
|
+
## Migration Complexity
|
|
563
|
+
|
|
564
|
+
[Low/Medium/High with brief rationale]
|
|
565
|
+
\`\`\`
|
|
566
|
+
|
|
567
|
+
## Blocked By
|
|
568
|
+
|
|
569
|
+
(none)
|
|
570
|
+
|
|
571
|
+
## Definition of Done
|
|
572
|
+
|
|
573
|
+
- Explored the directory tree excluding standard build/tool directories
|
|
574
|
+
- Created idea files for all findings in \`.dust/ideas/\`
|
|
575
|
+
- Each idea includes specific paths, problem description, proposed solution, and complexity
|
|
576
|
+
- No changes to files outside \`.dust/\`
|
|
577
|
+
`;
|
|
578
|
+
}
|
|
513
579
|
function documentationDrift() {
|
|
514
580
|
return dedent`
|
|
515
581
|
# Documentation Drift
|
|
@@ -660,6 +726,110 @@ function factsVerification() {
|
|
|
660
726
|
- No changes to files outside \`.dust/\`
|
|
661
727
|
`;
|
|
662
728
|
}
|
|
729
|
+
function factsExpansion() {
|
|
730
|
+
return dedent`
|
|
731
|
+
# Facts Expansion
|
|
732
|
+
|
|
733
|
+
Review the codebase for significant facts that should be documented in \`.dust/facts/\`.
|
|
734
|
+
|
|
735
|
+
${ideasHint}
|
|
736
|
+
|
|
737
|
+
## Context
|
|
738
|
+
|
|
739
|
+
Facts capture how things work today, providing context for agents and contributors. However, not all significant aspects of the codebase are currently documented as facts. This creates gaps where agents working in specific areas may lack important context that isn't obvious from scanning code or having prior framework knowledge.
|
|
740
|
+
|
|
741
|
+
## Applicability
|
|
742
|
+
|
|
743
|
+
This audit applies to all codebases. If \`.dust/facts/\` does not exist, the audit will identify initial facts to document.
|
|
744
|
+
|
|
745
|
+
## Scope
|
|
746
|
+
|
|
747
|
+
Analyze the codebase for undocumented facts across these areas:
|
|
748
|
+
|
|
749
|
+
### Architectural Decisions
|
|
750
|
+
- Separation of concerns patterns not enforced by directory structure
|
|
751
|
+
- Dependency flow rules (e.g., what can depend on what)
|
|
752
|
+
- Layer boundaries and their purposes
|
|
753
|
+
- Module initialization order requirements
|
|
754
|
+
- Plugin or extension mechanisms
|
|
755
|
+
|
|
756
|
+
### Implementation Conventions
|
|
757
|
+
- Naming patterns for specific types of code (factories, builders, validators)
|
|
758
|
+
- Error handling conventions (when to throw vs return errors)
|
|
759
|
+
- Async/await patterns and Promise handling
|
|
760
|
+
- Resource cleanup patterns
|
|
761
|
+
- State management approaches
|
|
762
|
+
|
|
763
|
+
### External Integration Points
|
|
764
|
+
- CLI command structure and parsing approach
|
|
765
|
+
- Event emission patterns
|
|
766
|
+
- File system conventions
|
|
767
|
+
- Process spawning patterns
|
|
768
|
+
- Network communication protocols
|
|
769
|
+
|
|
770
|
+
### Performance Characteristics
|
|
771
|
+
- Known performance bottlenecks
|
|
772
|
+
- Caching strategies
|
|
773
|
+
- Lazy loading patterns
|
|
774
|
+
- Resource pooling approaches
|
|
775
|
+
- Optimization trade-offs
|
|
776
|
+
|
|
777
|
+
### Historical Context
|
|
778
|
+
- Migration paths from previous approaches
|
|
779
|
+
- Deprecated patterns still present in legacy code
|
|
780
|
+
- Trade-offs made in past decisions
|
|
781
|
+
- Features that were removed and why
|
|
782
|
+
|
|
783
|
+
## Analysis Approach
|
|
784
|
+
|
|
785
|
+
1. **Scan for patterns** - Look for repeated implementation patterns across multiple files
|
|
786
|
+
2. **Identify conventions** - Find coding conventions that aren't enforced by linters
|
|
787
|
+
3. **Review configuration** - Document configuration systems and their purposes
|
|
788
|
+
4. **Trace data flows** - Identify how data moves through the system
|
|
789
|
+
5. **Check existing facts** - Compare findings against what's already documented in \`.dust/facts/\`
|
|
790
|
+
6. **Filter for significance** - Only suggest facts that would genuinely help future agents (facts that aren't obvious from code inspection or general framework knowledge)
|
|
791
|
+
|
|
792
|
+
## Significance Criteria
|
|
793
|
+
|
|
794
|
+
A fact is worth documenting if:
|
|
795
|
+
- It's not obvious from reading the code in isolation
|
|
796
|
+
- It represents a project-specific decision or convention
|
|
797
|
+
- Future agents would benefit from knowing it before making changes
|
|
798
|
+
- It documents framework patterns actually used in this project
|
|
799
|
+
|
|
800
|
+
## Output Format
|
|
801
|
+
|
|
802
|
+
For each suggested fact, create an idea file in \`.dust/ideas/\` that includes:
|
|
803
|
+
|
|
804
|
+
### Fact Title
|
|
805
|
+
A clear, concise title for the proposed fact.
|
|
806
|
+
|
|
807
|
+
### Why This Matters
|
|
808
|
+
Explanation of why this fact would be valuable to document (what gaps it fills, what problems it prevents).
|
|
809
|
+
|
|
810
|
+
### What to Document
|
|
811
|
+
Specific aspects to cover in the fact file.
|
|
812
|
+
|
|
813
|
+
### Where to Look
|
|
814
|
+
File paths or code locations that demonstrate this fact.
|
|
815
|
+
|
|
816
|
+
### Example Content
|
|
817
|
+
A sketch of what the fact file might contain (2-3 sentences showing the style and key points).
|
|
818
|
+
|
|
819
|
+
## Blocked By
|
|
820
|
+
|
|
821
|
+
(none)
|
|
822
|
+
|
|
823
|
+
## Definition of Done
|
|
824
|
+
|
|
825
|
+
- Analyzed codebase for undocumented patterns across all specified areas
|
|
826
|
+
- Compared findings against existing facts in \`.dust/facts/\`
|
|
827
|
+
- Applied significance criteria to filter suggestions
|
|
828
|
+
- Created idea files for each suggested fact with complete metadata
|
|
829
|
+
- Each idea includes: fact title, why it matters, what to document, where to look, example content
|
|
830
|
+
- No changes to files outside \`.dust/\`
|
|
831
|
+
`;
|
|
832
|
+
}
|
|
663
833
|
function feedbackLoopSpeed() {
|
|
664
834
|
return dedent`
|
|
665
835
|
# Feedback Loop Speed
|
|
@@ -670,7 +840,7 @@ function feedbackLoopSpeed() {
|
|
|
670
840
|
|
|
671
841
|
## Context
|
|
672
842
|
|
|
673
|
-
The
|
|
843
|
+
The primary feedback loop—write code, run checks, see results—should be as fast as possible. Agents especially benefit because they operate in tight loops of change-and-verify; slow feedback wastes tokens and context window space on waiting rather than working.
|
|
674
844
|
|
|
675
845
|
This audit focuses specifically on measuring the development feedback loop speed to help identify which checks consume the most time.
|
|
676
846
|
|
|
@@ -1116,6 +1286,223 @@ function ideasFromPrinciples() {
|
|
|
1116
1286
|
- No changes to files outside \`.dust/\`
|
|
1117
1287
|
`;
|
|
1118
1288
|
}
|
|
1289
|
+
function incidentalTestDetails() {
|
|
1290
|
+
return dedent`
|
|
1291
|
+
# Incidental Test Details
|
|
1292
|
+
|
|
1293
|
+
Identify tests with overly specific data and other incidental details that obscure test intent.
|
|
1294
|
+
|
|
1295
|
+
${ideasHint}
|
|
1296
|
+
|
|
1297
|
+
## Context
|
|
1298
|
+
|
|
1299
|
+
Test clarity suffers when tests include incidental complexity — details that aren't relevant to what's being tested. Overly specific data, unused properties, magic numbers, excessive mocking, and complex nested structures all make tests harder to understand and maintain. This audit identifies these patterns as candidates for simplification.
|
|
1300
|
+
|
|
1301
|
+
The audit flags patterns for review without making judgments about whether they're necessary in specific cases. Some tests legitimately need complex setup to verify specific behaviors; the goal is to surface candidates so agents can evaluate each case and simplify where appropriate.
|
|
1302
|
+
|
|
1303
|
+
## Guidance
|
|
1304
|
+
|
|
1305
|
+
### Readable Test Data
|
|
1306
|
+
|
|
1307
|
+
Test data setup should use natural structures that mirror what they represent.
|
|
1308
|
+
|
|
1309
|
+
When test data is easy to read, tests become self-documenting. A file system hierarchy expressed as a nested object immediately conveys structure, while a flat Map with path strings requires mental parsing to understand the relationships.
|
|
1310
|
+
|
|
1311
|
+
Prefer literal structures that visually match the domain:
|
|
1312
|
+
|
|
1313
|
+
\`\`\`javascript
|
|
1314
|
+
// Avoid: flat paths that obscure hierarchy
|
|
1315
|
+
const fs = createFileSystemEmulator({
|
|
1316
|
+
files: new Map([['/project/.dust/principles/my-goal.md', '# My Goal']]),
|
|
1317
|
+
existingPaths: new Set(['/project/.dust/ideas']),
|
|
1318
|
+
})
|
|
1319
|
+
|
|
1320
|
+
// Prefer: nested object that mirrors file system structure
|
|
1321
|
+
const fs = createFileSystemEmulator({
|
|
1322
|
+
project: {
|
|
1323
|
+
'.dust': {
|
|
1324
|
+
principles: {
|
|
1325
|
+
'my-goal.md': '# My Goal'
|
|
1326
|
+
},
|
|
1327
|
+
ideas: {}
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
})
|
|
1331
|
+
\`\`\`
|
|
1332
|
+
|
|
1333
|
+
The nested form:
|
|
1334
|
+
- Shows parent-child relationships through indentation
|
|
1335
|
+
- Makes empty directories explicit with empty objects
|
|
1336
|
+
- Requires no mental path concatenation to understand structure
|
|
1337
|
+
|
|
1338
|
+
### Comprehensive Assertions
|
|
1339
|
+
|
|
1340
|
+
Assert the whole, not the parts.
|
|
1341
|
+
|
|
1342
|
+
When you break a complex object into many small assertions, a failure tells you *one thing that's wrong*. When you assert against the whole expected value, the diff tells you *what actually happened versus what you expected* — the full picture, in one glance.
|
|
1343
|
+
|
|
1344
|
+
Small assertions are like yes/no questions to a witness. A whole-object assertion is like asking "tell me what you saw."
|
|
1345
|
+
|
|
1346
|
+
Collapse multiple partial assertions into one comprehensive assertion:
|
|
1347
|
+
|
|
1348
|
+
\`\`\`javascript
|
|
1349
|
+
// Fragmented — each failure is a narrow keyhole
|
|
1350
|
+
expect(result.name).toBe("Alice");
|
|
1351
|
+
expect(result.age).toBe(30);
|
|
1352
|
+
expect(result.role).toBe("admin");
|
|
1353
|
+
|
|
1354
|
+
// Whole — a failure diff tells the full story
|
|
1355
|
+
expect(result).toEqual({
|
|
1356
|
+
name: "Alice",
|
|
1357
|
+
age: 30,
|
|
1358
|
+
role: "admin",
|
|
1359
|
+
});
|
|
1360
|
+
\`\`\`
|
|
1361
|
+
|
|
1362
|
+
If \`role\` is \`"user"\` and \`age\` is \`29\`, the fragmented version stops at the first failure. The whole-object assertion shows both discrepancies at once, in context.
|
|
1363
|
+
|
|
1364
|
+
### Self-Diagnosing Tests
|
|
1365
|
+
|
|
1366
|
+
When a big test fails, it should be self-evident how to diagnose and fix the failure.
|
|
1367
|
+
|
|
1368
|
+
The more moving parts a test has — end-to-end, system, integration — the more critical this becomes. A test that fails with \`expected true, received false\` forces the developer (or agent) to re-run, add logging, and guess. A test that fails with a rich diff showing the actual state versus the expected state turns diagnosis into reading.
|
|
1369
|
+
|
|
1370
|
+
Anti-patterns:
|
|
1371
|
+
|
|
1372
|
+
**Boolean flattening** — collapsing a rich value into true/false before asserting:
|
|
1373
|
+
\`\`\`javascript
|
|
1374
|
+
// Bad: "expected true, received false" — what events arrived?
|
|
1375
|
+
expect(events.some(e => e.type === 'check-passed')).toBe(true)
|
|
1376
|
+
|
|
1377
|
+
// Good: shows the actual event types on failure
|
|
1378
|
+
expect(events.map(e => e.type)).toContain('check-passed')
|
|
1379
|
+
\`\`\`
|
|
1380
|
+
|
|
1381
|
+
**Length-only assertions** — checking count without showing contents:
|
|
1382
|
+
\`\`\`javascript
|
|
1383
|
+
// Bad: "expected 2, received 0" — what requests were captured?
|
|
1384
|
+
expect(requests.length).toBe(2)
|
|
1385
|
+
|
|
1386
|
+
// Good: shows the actual requests on failure
|
|
1387
|
+
expect(requests).toHaveLength(2) // vitest shows the array
|
|
1388
|
+
\`\`\`
|
|
1389
|
+
|
|
1390
|
+
**Silent guards** — using \`if\` where an assertion belongs:
|
|
1391
|
+
\`\`\`javascript
|
|
1392
|
+
// Bad: silently passes when settings is undefined
|
|
1393
|
+
if (settings) {
|
|
1394
|
+
expect(JSON.parse(settings).key).toBeDefined()
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
// Good: fails explicitly if settings is missing
|
|
1398
|
+
expect(settings).toBeDefined()
|
|
1399
|
+
const parsed = JSON.parse(settings!)
|
|
1400
|
+
expect(parsed.key).toBeDefined()
|
|
1401
|
+
\`\`\`
|
|
1402
|
+
|
|
1403
|
+
### Functional Core, Imperative Shell
|
|
1404
|
+
|
|
1405
|
+
Separate code into a pure "functional core" and a thin "imperative shell." The core takes values in and returns values out, with no side effects. The shell handles I/O and wires things together.
|
|
1406
|
+
|
|
1407
|
+
Purely functional code makes some things easier to understand: because values don't change, you can call functions and know that only their return value matters—they don't change anything outside themselves.
|
|
1408
|
+
|
|
1409
|
+
The functional core contains business logic as pure functions that take values and return values. The imperative shell sits at the boundary, reading input, calling into the core, and performing side effects with the results. This keeps the majority of code easy to test (no mocks or stubs needed for pure functions) and makes the I/O surface area small and explicit.
|
|
1410
|
+
|
|
1411
|
+
## Scope
|
|
1412
|
+
|
|
1413
|
+
Search for test files and analyze them for clarity issues:
|
|
1414
|
+
|
|
1415
|
+
1. **Test files** - Files matching \`*.test.ts\`, \`*.test.js\`, \`*.spec.ts\`, \`*.spec.js\`
|
|
1416
|
+
- Include unit, integration, and system tests
|
|
1417
|
+
- Exclude exploratory test files
|
|
1418
|
+
|
|
1419
|
+
2. **Patterns to identify**:
|
|
1420
|
+
- Object literals with unused properties in test setup
|
|
1421
|
+
- Magic numbers without semantic meaning
|
|
1422
|
+
- Excessive mock/stub setup
|
|
1423
|
+
- Complex nested structures where simpler ones would suffice
|
|
1424
|
+
- Brittle string assertions coupled to formatting
|
|
1425
|
+
- Boolean flattening (testing \`.toBe(true)\` instead of showing actual values)
|
|
1426
|
+
- Length-only assertions (testing \`.length\` instead of \`.toHaveLength()\`)
|
|
1427
|
+
- Silent guards (using \`if\` where assertions belong)
|
|
1428
|
+
|
|
1429
|
+
## Analysis Steps
|
|
1430
|
+
|
|
1431
|
+
1. **Find test files**
|
|
1432
|
+
- Search for \`**/*.test.ts\`, \`**/*.test.js\`, \`**/*.spec.ts\`, \`**/*.spec.js\`
|
|
1433
|
+
- Filter out exploratory tests
|
|
1434
|
+
|
|
1435
|
+
2. **Analyze each test file**
|
|
1436
|
+
- Look for object literals in test setup with properties that aren't used in assertions
|
|
1437
|
+
- Identify numeric literals that lack semantic meaning (e.g., \`42\`, \`123\` without explaining what they represent)
|
|
1438
|
+
- Count mock/stub setup lines relative to actual test logic
|
|
1439
|
+
- Check for deeply nested test data structures (3+ levels)
|
|
1440
|
+
- Find string assertions that compare exact formatting (spaces, newlines, etc.) rather than semantic content
|
|
1441
|
+
- Detect boolean flattening patterns (\`.some()\`, \`.every()\`, \`.includes()\` followed by \`.toBe(true/false)\`)
|
|
1442
|
+
- Find length checks using \`.length\` property instead of \`.toHaveLength()\`
|
|
1443
|
+
- Locate conditional logic in tests (\`if\` statements) that should be assertions
|
|
1444
|
+
|
|
1445
|
+
3. **Create ideas for issues found**
|
|
1446
|
+
- Group issues by test file
|
|
1447
|
+
- For each file with issues, create an idea file documenting:
|
|
1448
|
+
- Test file path
|
|
1449
|
+
- List of patterns found with line numbers
|
|
1450
|
+
- Pattern categories
|
|
1451
|
+
- Current problematic patterns
|
|
1452
|
+
- Recommended refactoring approaches
|
|
1453
|
+
|
|
1454
|
+
## Output Format
|
|
1455
|
+
|
|
1456
|
+
For each test file with clarity issues, create an idea file with:
|
|
1457
|
+
|
|
1458
|
+
### Title
|
|
1459
|
+
"Simplify test data in [filename]"
|
|
1460
|
+
|
|
1461
|
+
### Content Structure
|
|
1462
|
+
\`\`\`markdown
|
|
1463
|
+
# Simplify test data in [filename]
|
|
1464
|
+
|
|
1465
|
+
The test file \`[path]\` contains incidental details that obscure test intent.
|
|
1466
|
+
|
|
1467
|
+
## Issues Found
|
|
1468
|
+
|
|
1469
|
+
### [Pattern Name] (line X)
|
|
1470
|
+
- **Current**: \`[code snippet]\`
|
|
1471
|
+
- **Issue**: [explanation of how this obscures intent]
|
|
1472
|
+
- **Recommendation**: [specific simplification guidance]
|
|
1473
|
+
|
|
1474
|
+
[Repeat for each issue]
|
|
1475
|
+
\`\`\`
|
|
1476
|
+
|
|
1477
|
+
## Applicability
|
|
1478
|
+
|
|
1479
|
+
This audit applies to codebases with test files. If the codebase has no test files (\`*.test.ts\`, \`*.spec.js\`, etc.), document that finding and skip the detailed analysis.
|
|
1480
|
+
|
|
1481
|
+
## Focus
|
|
1482
|
+
|
|
1483
|
+
This audit focuses purely on test clarity — whether tests clearly communicate intent. It does not evaluate test performance or execution speed.
|
|
1484
|
+
|
|
1485
|
+
## Blocked By
|
|
1486
|
+
|
|
1487
|
+
(none)
|
|
1488
|
+
|
|
1489
|
+
## Definition of Done
|
|
1490
|
+
|
|
1491
|
+
- Searched for all test files in the codebase
|
|
1492
|
+
- Analyzed test files for incidental complexity patterns
|
|
1493
|
+
- Identified tests with unused properties in setup data
|
|
1494
|
+
- Found magic numbers lacking semantic meaning
|
|
1495
|
+
- Flagged excessive mock/stub setup
|
|
1496
|
+
- Located complex nested structures
|
|
1497
|
+
- Detected brittle string assertions
|
|
1498
|
+
- Found boolean flattening patterns
|
|
1499
|
+
- Located length-only assertions
|
|
1500
|
+
- Identified silent guards (if statements in tests)
|
|
1501
|
+
- Created idea files for each test file with findings
|
|
1502
|
+
- Each idea includes: file path, issues with line numbers, pattern categories, current patterns, recommendations
|
|
1503
|
+
- No changes to files outside \`.dust/\`
|
|
1504
|
+
`;
|
|
1505
|
+
}
|
|
1119
1506
|
function commitReview() {
|
|
1120
1507
|
return dedent`
|
|
1121
1508
|
# Commit Review
|
|
@@ -1126,7 +1513,13 @@ function commitReview() {
|
|
|
1126
1513
|
|
|
1127
1514
|
## Scope
|
|
1128
1515
|
|
|
1129
|
-
|
|
1516
|
+
Determine which commits to analyze:
|
|
1517
|
+
|
|
1518
|
+
1. Check VCS history for a prior commit-review run: \`git log --grep="Audit: Commit Review" -1 --format=%H\`
|
|
1519
|
+
2. If found, analyze commits since that commit
|
|
1520
|
+
3. If not found, analyze the last 20 commits as a fallback
|
|
1521
|
+
|
|
1522
|
+
Focus on these signals:
|
|
1130
1523
|
|
|
1131
1524
|
1. **File churn** - Files modified frequently across multiple commits may have unclear responsibilities or be accumulating technical debt
|
|
1132
1525
|
2. **Size growth** - Files that have grown significantly may benefit from decomposition
|
|
@@ -1472,6 +1865,168 @@ function slowTests() {
|
|
|
1472
1865
|
- No changes to files outside \`.dust/\`
|
|
1473
1866
|
`;
|
|
1474
1867
|
}
|
|
1868
|
+
function overAbstraction() {
|
|
1869
|
+
return dedent`
|
|
1870
|
+
# Over-Abstraction
|
|
1871
|
+
|
|
1872
|
+
Identify violations of the "reasonably-dry" principle where code has been over-engineered with excessive abstraction.
|
|
1873
|
+
|
|
1874
|
+
${ideasHint}
|
|
1875
|
+
|
|
1876
|
+
## Scope
|
|
1877
|
+
|
|
1878
|
+
Detect these over-abstraction patterns:
|
|
1879
|
+
|
|
1880
|
+
1. **Single-use abstractions** - Interfaces, base classes, or utility functions used in only one place
|
|
1881
|
+
2. **Deep inheritance hierarchies** - Classes extending more than 2 levels deep
|
|
1882
|
+
3. **Premature generalization** - Parameters always used with the same value, unused options/flags
|
|
1883
|
+
4. **Excessive indirection** - Multiple layers of wrappers adding no value
|
|
1884
|
+
|
|
1885
|
+
## Analysis Steps
|
|
1886
|
+
|
|
1887
|
+
### 1. Find Single-Use Abstractions
|
|
1888
|
+
|
|
1889
|
+
Search for abstractions that are only used once:
|
|
1890
|
+
|
|
1891
|
+
1. **Interfaces with one implementation**
|
|
1892
|
+
- Search for \`interface\` declarations
|
|
1893
|
+
- Check if each interface has only one implementing class
|
|
1894
|
+
- Flag interfaces that exist solely for testing (can be replaced with the concrete type)
|
|
1895
|
+
|
|
1896
|
+
2. **Base classes with one subclass**
|
|
1897
|
+
- Search for \`abstract class\` or classes used as base classes
|
|
1898
|
+
- Count implementations extending each base class
|
|
1899
|
+
- Flag base classes with only one subclass
|
|
1900
|
+
|
|
1901
|
+
3. **Utility functions called once**
|
|
1902
|
+
- Search for exported utility functions
|
|
1903
|
+
- Check call sites - if only called from one location, it's over-abstraction
|
|
1904
|
+
- Consider inlining single-use utilities
|
|
1905
|
+
|
|
1906
|
+
4. **Generic types with one concrete usage**
|
|
1907
|
+
- Find generic type parameters: \`<T>\`, \`<TData>\`, etc.
|
|
1908
|
+
- Check if T is always the same type at all call sites
|
|
1909
|
+
- Flag generics that could be concrete types
|
|
1910
|
+
|
|
1911
|
+
### 2. Detect Deep Inheritance Hierarchies
|
|
1912
|
+
|
|
1913
|
+
Find inheritance chains longer than 2 levels:
|
|
1914
|
+
|
|
1915
|
+
1. Search for \`extends\` keywords in class declarations
|
|
1916
|
+
2. Build inheritance tree for each class
|
|
1917
|
+
3. Flag chains deeper than 2 (A extends B extends C extends D...)
|
|
1918
|
+
4. Respect framework conventions (don't flag React.Component, etc.)
|
|
1919
|
+
|
|
1920
|
+
### 3. Identify Premature Generalization
|
|
1921
|
+
|
|
1922
|
+
Look for flexibility that's never used:
|
|
1923
|
+
|
|
1924
|
+
1. **Always-same parameter values**
|
|
1925
|
+
- Find function parameters
|
|
1926
|
+
- Check all call sites - if always the same value, it's not needed
|
|
1927
|
+
- Flag parameters that could be constants or removed
|
|
1928
|
+
|
|
1929
|
+
2. **Unused configuration options**
|
|
1930
|
+
- Search for configuration objects/interfaces
|
|
1931
|
+
- Check which options are actually used
|
|
1932
|
+
- Flag options that are never set or always default
|
|
1933
|
+
|
|
1934
|
+
3. **Unused function parameters**
|
|
1935
|
+
- Find parameters that aren't referenced in function bodies
|
|
1936
|
+
- Flag as candidates for removal
|
|
1937
|
+
|
|
1938
|
+
### 4. Find Excessive Indirection
|
|
1939
|
+
|
|
1940
|
+
Detect wrapper chains that add no value:
|
|
1941
|
+
|
|
1942
|
+
1. **Delegation chains**
|
|
1943
|
+
- Search for functions that only call another function
|
|
1944
|
+
- Flag wrappers that don't add logic, just forward calls
|
|
1945
|
+
- Example: \`function foo(x) { return bar(x) }\`
|
|
1946
|
+
|
|
1947
|
+
2. **Proxy patterns without behavior**
|
|
1948
|
+
- Find classes that wrap another class
|
|
1949
|
+
- Check if wrapper adds any logic beyond forwarding
|
|
1950
|
+
- Flag pure proxies
|
|
1951
|
+
|
|
1952
|
+
3. **Middleware without transformation**
|
|
1953
|
+
- Look for middleware/interceptor patterns
|
|
1954
|
+
- Check if they modify data or just pass through
|
|
1955
|
+
- Flag pass-through middleware
|
|
1956
|
+
|
|
1957
|
+
## Output Format
|
|
1958
|
+
|
|
1959
|
+
For each over-abstraction found, create an idea file in \`.dust/ideas/\` with:
|
|
1960
|
+
|
|
1961
|
+
\`\`\`markdown
|
|
1962
|
+
# Over-Abstraction: [Type] in [Location]
|
|
1963
|
+
|
|
1964
|
+
## Type
|
|
1965
|
+
|
|
1966
|
+
[Single-use | Deep hierarchy | Premature generalization | Excessive indirection]
|
|
1967
|
+
|
|
1968
|
+
## Location
|
|
1969
|
+
|
|
1970
|
+
\`\`\`
|
|
1971
|
+
[file path]:[line number]
|
|
1972
|
+
\`\`\`
|
|
1973
|
+
|
|
1974
|
+
## Description
|
|
1975
|
+
|
|
1976
|
+
[What the abstraction is]
|
|
1977
|
+
|
|
1978
|
+
## Problem
|
|
1979
|
+
|
|
1980
|
+
[Why this is over-abstraction - complexity without benefit]
|
|
1981
|
+
|
|
1982
|
+
## Usage Analysis
|
|
1983
|
+
|
|
1984
|
+
- **Times used**: [count]
|
|
1985
|
+
- **Variation in usage**: [how different are the use cases]
|
|
1986
|
+
- **Complexity cost**: [lines of code, indirection levels, etc.]
|
|
1987
|
+
|
|
1988
|
+
## Suggested Simplification
|
|
1989
|
+
|
|
1990
|
+
[How to remove or reduce this abstraction]
|
|
1991
|
+
|
|
1992
|
+
## Impact
|
|
1993
|
+
|
|
1994
|
+
[Lines of code saved, reduced complexity, improved clarity]
|
|
1995
|
+
\`\`\`
|
|
1996
|
+
|
|
1997
|
+
## Special Considerations
|
|
1998
|
+
|
|
1999
|
+
1. **Framework conventions** - Don't flag patterns mandated by frameworks:
|
|
2000
|
+
- React: Component base classes, hooks patterns
|
|
2001
|
+
- Express: Middleware signatures
|
|
2002
|
+
- Testing: Test base classes, fixture patterns
|
|
2003
|
+
|
|
2004
|
+
2. **Library boundaries** - Public API abstractions may be justified even if internal usage is simple
|
|
2005
|
+
|
|
2006
|
+
3. **Test code** - Apply the same standards to test code as production code
|
|
2007
|
+
|
|
2008
|
+
4. **Context depth thresholds**:
|
|
2009
|
+
- Deep hierarchies (>2 levels) make understanding difficult
|
|
2010
|
+
- Wrapper chains (>2 levels) obscure actual behavior
|
|
2011
|
+
- Generic parameters should have multiple concrete usages
|
|
2012
|
+
|
|
2013
|
+
## Blocked By
|
|
2014
|
+
|
|
2015
|
+
(none)
|
|
2016
|
+
|
|
2017
|
+
## Definition of Done
|
|
2018
|
+
|
|
2019
|
+
- Searched for single-use interfaces, base classes, and utility functions
|
|
2020
|
+
- Identified deep inheritance hierarchies (>2 levels)
|
|
2021
|
+
- Found parameters always used with the same value
|
|
2022
|
+
- Detected unused configuration options
|
|
2023
|
+
- Located excessive wrapper chains and delegation
|
|
2024
|
+
- Respected framework conventions (didn't flag framework-mandated patterns)
|
|
2025
|
+
- Created idea files for each over-abstraction found
|
|
2026
|
+
- Each idea includes usage analysis and simplification suggestions
|
|
2027
|
+
- No changes to files outside \`.dust/\`
|
|
2028
|
+
`;
|
|
2029
|
+
}
|
|
1475
2030
|
function primitiveObsession() {
|
|
1476
2031
|
return dedent`
|
|
1477
2032
|
# Primitive Obsession
|
|
@@ -1743,7 +2298,7 @@ function testAssertions() {
|
|
|
1743
2298
|
|
|
1744
2299
|
## Background
|
|
1745
2300
|
|
|
1746
|
-
|
|
2301
|
+
Comprehensive assertions (asserting the whole, not the parts) provide richer failure diagnostics. Self-diagnosing tests ensure that failures reveal enough context to guide a fix without re-running. This audit addresses complementary assertion quality signals not covered by those principles.
|
|
1747
2302
|
|
|
1748
2303
|
## Scope
|
|
1749
2304
|
|
|
@@ -1802,7 +2357,7 @@ function testAssertions() {
|
|
|
1802
2357
|
- Require test updates for unrelated changes
|
|
1803
2358
|
- Obscure what the test is actually verifying
|
|
1804
2359
|
|
|
1805
|
-
This works in tension with
|
|
2360
|
+
This works in tension with comprehensive assertions (asserting the whole, not the parts). Let context determine the balance:
|
|
1806
2361
|
- Public API contracts → comprehensive assertions
|
|
1807
2362
|
- Internal implementation tests → precise assertions
|
|
1808
2363
|
- Snapshot tests → consider \`toMatchSnapshot()\` with care
|
|
@@ -1829,7 +2384,7 @@ function testAssertions() {
|
|
|
1829
2384
|
|
|
1830
2385
|
Tests should ideally verify one behavior or scenario. When a test has multiple unrelated assertions, a failure in the first masks all subsequent ones.
|
|
1831
2386
|
|
|
1832
|
-
This does not mean "one \`expect\` call per test". A single logical assertion may require multiple \`expect\` calls to express (especially for complex state).
|
|
2387
|
+
This does not mean "one \`expect\` call per test". A single logical assertion may require multiple \`expect\` calls to express (especially for complex state). Comprehensive assertions (asserting the whole, not the parts) often allow collapsing multiple calls into one whole-object assertion.
|
|
1833
2388
|
|
|
1834
2389
|
The anti-pattern to avoid:
|
|
1835
2390
|
\`\`\`javascript
|
|
@@ -1992,6 +2547,95 @@ function loggingAndTraceability() {
|
|
|
1992
2547
|
- No changes to files outside \`.dust/\`
|
|
1993
2548
|
`;
|
|
1994
2549
|
}
|
|
2550
|
+
function testDeterminism() {
|
|
2551
|
+
return dedent`
|
|
2552
|
+
# Test Determinism
|
|
2553
|
+
|
|
2554
|
+
Audit unit tests for non-deterministic patterns that cause tests to produce inconsistent results across different environments or executions.
|
|
2555
|
+
|
|
2556
|
+
${ideasHint}
|
|
2557
|
+
|
|
2558
|
+
## Context
|
|
2559
|
+
|
|
2560
|
+
Tests must produce the same result regardless of where they run. Non-deterministic tests undermine confidence in CI, make debugging harder, and waste developer time chasing phantom failures. This audit identifies patterns that introduce non-determinism: time dependencies, randomness, environment variable access, filesystem operations, real timers, and platform-specific behavior.
|
|
2561
|
+
|
|
2562
|
+
## Scope
|
|
2563
|
+
|
|
2564
|
+
Search for unit test files and analyze them for determinism issues:
|
|
2565
|
+
|
|
2566
|
+
1. **Unit test files** - Files matching \`*.test.ts\`, \`*.test.js\`, \`*.spec.ts\`, \`*.spec.js\`
|
|
2567
|
+
- Exclude system test files (files containing 'system-test' or in 'system-tests/' directories)
|
|
2568
|
+
- Exclude exploratory test files
|
|
2569
|
+
|
|
2570
|
+
2. **Issue categories to detect**:
|
|
2571
|
+
- Time dependencies (\`Date.now()\`, \`new Date()\`) — should use dependency injection or stubbed time
|
|
2572
|
+
- Randomness (\`Math.random()\`, \`crypto.randomBytes()\`, \`randomUUID()\`) — should use seeded random or injection
|
|
2573
|
+
- Environment variables (\`process.env.VARIABLE\` without \`stubEnv\`) — should use \`stubEnv()\` or pass env as a parameter
|
|
2574
|
+
- Filesystem operations (file reads/writes in unit tests) — should use in-memory filesystem or ensure cleanup
|
|
2575
|
+
- Real timers (\`setTimeout\`, \`setInterval\` without fake timers) — should use \`vi.useFakeTimers()\`
|
|
2576
|
+
- Platform-specific code (\`process.platform\`, \`__dirname\`, \`os.EOL\`) — should use dependency injection or normalize paths
|
|
2577
|
+
|
|
2578
|
+
## Analysis Steps
|
|
2579
|
+
|
|
2580
|
+
1. **Find unit test files**
|
|
2581
|
+
- Search for \`**/*.test.ts\`, \`**/*.test.js\`, \`**/*.spec.ts\`, \`**/*.spec.js\`
|
|
2582
|
+
- Filter out system test files and exploratory tests
|
|
2583
|
+
|
|
2584
|
+
2. **Analyze each test file**
|
|
2585
|
+
- Read the file content
|
|
2586
|
+
- Look for the patterns listed above
|
|
2587
|
+
- Note: patterns used inside stub/mock setups (\`vi.fn()\`, \`vi.mock()\`, \`vi.spyOn()\`), function parameter type annotations, or \`stubEnv()\` calls are not issues — they represent proper test practices
|
|
2588
|
+
|
|
2589
|
+
3. **Create ideas for issues found**
|
|
2590
|
+
- Group issues by test file
|
|
2591
|
+
- For each file with issues, create an idea file documenting:
|
|
2592
|
+
- Test file path
|
|
2593
|
+
- List of issues with line numbers
|
|
2594
|
+
- Issue categories
|
|
2595
|
+
- Current problematic patterns
|
|
2596
|
+
- Recommended refactoring approaches
|
|
2597
|
+
|
|
2598
|
+
## Output Format
|
|
2599
|
+
|
|
2600
|
+
For each test file with determinism issues, create an idea file with:
|
|
2601
|
+
|
|
2602
|
+
### Title
|
|
2603
|
+
"Refactor [filename] for test determinism"
|
|
2604
|
+
|
|
2605
|
+
### Content Structure
|
|
2606
|
+
\`\`\`markdown
|
|
2607
|
+
# Refactor [filename] for test determinism
|
|
2608
|
+
|
|
2609
|
+
The test file \`[path]\` contains non-deterministic patterns that should be refactored.
|
|
2610
|
+
|
|
2611
|
+
## Issues Found
|
|
2612
|
+
|
|
2613
|
+
### [Category Name] (line X)
|
|
2614
|
+
- **Pattern**: \`[code snippet]\`
|
|
2615
|
+
- **Issue**: [explanation of why this is non-deterministic]
|
|
2616
|
+
- **Recommendation**: [specific refactoring guidance]
|
|
2617
|
+
|
|
2618
|
+
[Repeat for each issue]
|
|
2619
|
+
\`\`\`
|
|
2620
|
+
|
|
2621
|
+
## Applicability
|
|
2622
|
+
|
|
2623
|
+
This audit applies to codebases with unit tests. If the codebase has no unit test files (\`*.test.ts\`, \`*.spec.js\`, etc.), document that finding and skip the detailed analysis.
|
|
2624
|
+
|
|
2625
|
+
## Blocked By
|
|
2626
|
+
|
|
2627
|
+
(none)
|
|
2628
|
+
|
|
2629
|
+
## Definition of Done
|
|
2630
|
+
|
|
2631
|
+
- Searched for unit test files (\`*.test.ts\`, \`*.test.js\`, \`*.spec.ts\`, \`*.spec.js\`)
|
|
2632
|
+
- Excluded system test and exploratory test files
|
|
2633
|
+
- Analyzed each unit test file for determinism issues
|
|
2634
|
+
- Created idea files for test files containing determinism issues
|
|
2635
|
+
- Each idea includes specific line numbers, patterns, and refactoring guidance
|
|
2636
|
+
- No changes to files outside \`.dust/\`
|
|
2637
|
+
`;
|
|
2638
|
+
}
|
|
1995
2639
|
function testPyramid() {
|
|
1996
2640
|
return dedent`
|
|
1997
2641
|
# Test Pyramid
|
|
@@ -2360,7 +3004,7 @@ function ciDevelopmentParity() {
|
|
|
2360
3004
|
2. **Wasted cycles** - Developers push code that passes locally only to have CI fail
|
|
2361
3005
|
3. **Agent confusion** - AI agents rely on consistent feedback; discrepancies trigger incorrect debugging paths
|
|
2362
3006
|
|
|
2363
|
-
|
|
3007
|
+
Every check must produce the same result regardless of who runs it, when, or on what machine.
|
|
2364
3008
|
|
|
2365
3009
|
## Scope
|
|
2366
3010
|
|
|
@@ -2450,7 +3094,7 @@ function ciDevelopmentParity() {
|
|
|
2450
3094
|
|
|
2451
3095
|
- Developers may push code that passes locally but fails CI on other checks
|
|
2452
3096
|
- CI provides no coverage for [check category]
|
|
2453
|
-
-
|
|
3097
|
+
- Problems aren't caught before merge—any worker should halt and fix a problem the moment they detect it
|
|
2454
3098
|
|
|
2455
3099
|
## Suggested Fix
|
|
2456
3100
|
|
|
@@ -2474,7 +3118,7 @@ function ciDevelopmentParity() {
|
|
|
2474
3118
|
## Impact
|
|
2475
3119
|
|
|
2476
3120
|
- Developers don't get [check category] feedback until CI runs
|
|
2477
|
-
-
|
|
3121
|
+
- Fast feedback loops are broken—local checks give incomplete picture
|
|
2478
3122
|
- Agents may make changes that pass local checks but fail CI
|
|
2479
3123
|
|
|
2480
3124
|
## Suggested Fix
|
|
@@ -2512,7 +3156,7 @@ function commitMessageQuality() {
|
|
|
2512
3156
|
|
|
2513
3157
|
## Context
|
|
2514
3158
|
|
|
2515
|
-
|
|
3159
|
+
Commit history should explain why changes were made, not just what changed. Good commit messages help agents understand project history and make better decisions. This audit evaluates commit message quality itself, not the code changes.
|
|
2516
3160
|
|
|
2517
3161
|
## Scope
|
|
2518
3162
|
|
|
@@ -2653,20 +3297,14 @@ function commitMessageQuality() {
|
|
|
2653
3297
|
`;
|
|
2654
3298
|
}
|
|
2655
3299
|
function suggestAudits() {
|
|
2656
|
-
|
|
2657
|
-
const template = render();
|
|
2658
|
-
const description = extractOpeningSentence(template);
|
|
2659
|
-
return `- **${name}**: ${description}`;
|
|
2660
|
-
}).join(`
|
|
2661
|
-
`);
|
|
2662
|
-
let content = dedent`
|
|
3300
|
+
return dedent`
|
|
2663
3301
|
# Suggest Audits
|
|
2664
3302
|
|
|
2665
3303
|
Analyze recent commits and create tasks for relevant audits to run.
|
|
2666
3304
|
|
|
2667
3305
|
## Context
|
|
2668
3306
|
|
|
2669
|
-
This audit examines recent commit history and suggests which
|
|
3307
|
+
This audit examines recent commit history and suggests which audits would be valuable based on what changed. Rather than manually selecting audits, this provides an automated way to maintain codebase health by matching recent work to appropriate audits.
|
|
2670
3308
|
|
|
2671
3309
|
## Commit Range
|
|
2672
3310
|
|
|
@@ -2678,21 +3316,17 @@ function suggestAudits() {
|
|
|
2678
3316
|
|
|
2679
3317
|
## Available Audits
|
|
2680
3318
|
|
|
2681
|
-
|
|
2682
|
-
content += `
|
|
2683
|
-
|
|
2684
|
-
` + auditList + `
|
|
2685
|
-
`;
|
|
2686
|
-
content += dedent`
|
|
3319
|
+
Run \`dust audit\` to list all available audits (including both stock audits and any repository-specific audits configured in \`.dust/config/audits/\`). This will show the audit name and description for each available audit.
|
|
2687
3320
|
|
|
2688
3321
|
## Analysis Steps
|
|
2689
3322
|
|
|
2690
|
-
1. **
|
|
2691
|
-
2. **
|
|
2692
|
-
3. **
|
|
3323
|
+
1. **List audits** - Run \`dust audit\` to get the complete list of available audits with descriptions
|
|
3324
|
+
2. **Gather commits** - Get the list of commits in the determined range with their messages and changed files
|
|
3325
|
+
3. **Categorize changes** - Group commits by the type of work (features, fixes, refactoring, tests, docs, config)
|
|
3326
|
+
4. **Match to audits** - For each relevant audit, explain why recent changes make it valuable:
|
|
2693
3327
|
- What specific commits or file changes triggered the suggestion?
|
|
2694
3328
|
- What might the audit uncover given this context?
|
|
2695
|
-
|
|
3329
|
+
5. **Create tasks** - For each suggested audit, create a task file in \`.dust/tasks/\`
|
|
2696
3330
|
|
|
2697
3331
|
## Output
|
|
2698
3332
|
|
|
@@ -2741,7 +3375,6 @@ function suggestAudits() {
|
|
|
2741
3375
|
- Each task explains why the audit is valuable given recent changes
|
|
2742
3376
|
- No changes to files outside \`.dust/\`
|
|
2743
3377
|
`;
|
|
2744
|
-
return content;
|
|
2745
3378
|
}
|
|
2746
3379
|
var stockAuditFunctions = {
|
|
2747
3380
|
"agent-developer-experience": agentDeveloperExperience,
|
|
@@ -2757,7 +3390,9 @@ var stockAuditFunctions = {
|
|
|
2757
3390
|
"data-access-review": dataAccessReview,
|
|
2758
3391
|
"dead-code": deadCode,
|
|
2759
3392
|
"design-patterns": designPatterns,
|
|
3393
|
+
"directory-hierarchy": directoryHierarchy,
|
|
2760
3394
|
"error-handling": errorHandling,
|
|
3395
|
+
"facts-expansion": factsExpansion,
|
|
2761
3396
|
"facts-verification": factsVerification,
|
|
2762
3397
|
"feedback-loop-speed": feedbackLoopSpeed,
|
|
2763
3398
|
"flaky-tests": flakyTests,
|
|
@@ -2765,7 +3400,9 @@ var stockAuditFunctions = {
|
|
|
2765
3400
|
"commit-review": commitReview,
|
|
2766
3401
|
"ideas-from-principles": ideasFromPrinciples,
|
|
2767
3402
|
"idiomatic-style": idiomaticStyle,
|
|
3403
|
+
"incidental-test-details": incidentalTestDetails,
|
|
2768
3404
|
"logging-and-traceability": loggingAndTraceability,
|
|
3405
|
+
"over-abstraction": overAbstraction,
|
|
2769
3406
|
"primitive-obsession": primitiveObsession,
|
|
2770
3407
|
"repository-context": repositoryContext,
|
|
2771
3408
|
"security-review": securityReview,
|
|
@@ -2774,6 +3411,7 @@ var stockAuditFunctions = {
|
|
|
2774
3411
|
"stale-ideas": staleIdeas,
|
|
2775
3412
|
"suggest-audits": suggestAudits,
|
|
2776
3413
|
"test-assertions": testAssertions,
|
|
3414
|
+
"test-determinism": testDeterminism,
|
|
2777
3415
|
"test-pyramid": testPyramid,
|
|
2778
3416
|
"ubiquitous-language": ubiquitousLanguage,
|
|
2779
3417
|
"ux-audit": uxAudit
|