@phuc1403/musketeer 0.1.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/INSTALLATION.md +22 -0
- package/LICENSE +21 -0
- package/README.md +38 -0
- package/bin/musketeer.js +72 -0
- package/manifest.json +238 -0
- package/package.json +46 -0
- package/src/copier.js +119 -0
- package/src/lockfile.js +61 -0
- package/src/manifest-loader.js +46 -0
- package/src/muster.js +48 -0
- package/src/provisioner/detect.js +93 -0
- package/src/provisioner/guide.js +32 -0
- package/src/provisioner/index.js +113 -0
- package/src/provisioner/mcp.js +26 -0
- package/src/provisioner/os-package-manager.js +71 -0
- package/src/provisioner/venv.js +44 -0
- package/src/reconcile.js +94 -0
- package/src/resolver.js +130 -0
- package/src/schema.js +152 -0
- package/src/settings-merger.js +0 -0
- package/template/.claude/agents/code-reviewer.md +166 -0
- package/template/.claude/agents/hallmark-auditor.md +78 -0
- package/template/.claude/agents/hallmark-explorer.md +81 -0
- package/template/.claude/agents/researcher.md +33 -0
- package/template/.claude/hooks/block-migration-edits.cjs +31 -0
- package/template/.claude/hooks/format-json-hook.js +91 -0
- package/template/.claude/hooks/inject-design-docs.cjs +86 -0
- package/template/.claude/hooks/lib/colors.cjs +122 -0
- package/template/.claude/hooks/lib/git-info-cache.cjs +191 -0
- package/template/.claude/hooks/lib/transcript-parser.cjs +277 -0
- package/template/.claude/hooks/usage-context-awareness.cjs +166 -0
- package/template/.claude/hooks/validate-cml-hook.js +145 -0
- package/template/.claude/skills/adr-writer/SKILL.md +78 -0
- package/template/.claude/skills/adr-writer/references/adr-example.md +38 -0
- package/template/.claude/skills/adr-writer/references/adr-template.md +46 -0
- package/template/.claude/skills/architecture-characteristic-writer/SKILL.md +117 -0
- package/template/.claude/skills/architecture-characteristic-writer/assets/worksheet-template.md +40 -0
- package/template/.claude/skills/architecture-characteristic-writer/references/characteristics-catalog.md +106 -0
- package/template/.claude/skills/code-review/SKILL.md +54 -0
- package/template/.claude/skills/code-review/references/adversarial-review.md +223 -0
- package/template/.claude/skills/code-review/references/checklists/api.md +52 -0
- package/template/.claude/skills/code-review/references/checklists/base.md +100 -0
- package/template/.claude/skills/code-review/references/checklists/web-app.md +54 -0
- package/template/.claude/skills/context-map/SKILL.md +80 -0
- package/template/.claude/skills/context-map/example.cml +106 -0
- package/template/.claude/skills/context-map/reference/Aggregate/Aggregate.md +1 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/Bounded Context.md +41 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/businessModel.md +6 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/domainVisionStatement.md +3 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/evolution.md +6 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/implementationTechnology.md +1 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/implements.md +1 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/knowledgeLevel.md +5 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/realizes.md +9 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/refines.md +10 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/responsibilities.md +26 -0
- package/template/.claude/skills/context-map/reference/Bounded Context/type.md +23 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Anticorruption Layer.md +5 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Bounded Context Relationship.md +13 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Conformist.md +5 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Customer-Supplier (C-S).md +23 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Open Host Service.md +5 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Partnership (P).md +14 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Published Language.md +5 -0
- package/template/.claude/skills/context-map/reference/Bounded Context Relationship/Shared Kernel (SK).md +13 -0
- package/template/.claude/skills/context-map/reference/Context Map.md +63 -0
- package/template/.claude/skills/context-map/reference/Domain/Domain.md +30 -0
- package/template/.claude/skills/context-map/reference/Domain/supports.md +34 -0
- package/template/.claude/skills/context-map/reference/Domain/type.md +3 -0
- package/template/.claude/skills/context-map/reference/Semantic Rules.md +33 -0
- package/template/.claude/skills/hallmark/SKILL.md +552 -0
- package/template/.claude/skills/hallmark/references/anti-patterns.md +412 -0
- package/template/.claude/skills/hallmark/references/assets.md +406 -0
- package/template/.claude/skills/hallmark/references/color.md +95 -0
- package/template/.claude/skills/hallmark/references/component-cookbook.md +256 -0
- package/template/.claude/skills/hallmark/references/components/c1-outlined-chip.md +12 -0
- package/template/.claude/skills/hallmark/references/components/c2-inline-form-as-cta.md +16 -0
- package/template/.claude/skills/hallmark/references/components/c3-typographic-link.md +8 -0
- package/template/.claude/skills/hallmark/references/components/c4-sticky-bottom-bar.md +16 -0
- package/template/.claude/skills/hallmark/references/components/f1-bento-grid.md +20 -0
- package/template/.claude/skills/hallmark/references/components/f2-sticky-scroll-stack.md +20 -0
- package/template/.claude/skills/hallmark/references/components/f3-tabular-spec-sheet.md +11 -0
- package/template/.claude/skills/hallmark/references/components/f4-step-sequence.md +11 -0
- package/template/.claude/skills/hallmark/references/components/f5-annotated-screenshot.md +11 -0
- package/template/.claude/skills/hallmark/references/components/f6-product-card-grid.md +41 -0
- package/template/.claude/skills/hallmark/references/components/ft1-mast-headed.md +13 -0
- package/template/.claude/skills/hallmark/references/components/ft2-inline-rule-single-line.md +10 -0
- package/template/.claude/skills/hallmark/references/components/ft3-index-style-category-list.md +12 -0
- package/template/.claude/skills/hallmark/references/components/ft4-dense-typographic.md +10 -0
- package/template/.claude/skills/hallmark/references/components/ft5-statement.md +21 -0
- package/template/.claude/skills/hallmark/references/components/ft6-letter-close.md +19 -0
- package/template/.claude/skills/hallmark/references/components/ft7-newsletter-first.md +27 -0
- package/template/.claude/skills/hallmark/references/components/ft8-marquee-scroll.md +25 -0
- package/template/.claude/skills/hallmark/references/components/h1-marquee.md +15 -0
- package/template/.claude/skills/hallmark/references/components/h2-split-diptych.md +15 -0
- package/template/.claude/skills/hallmark/references/components/h3-quote-led.md +11 -0
- package/template/.claude/skills/hallmark/references/components/h4-stat-led.md +14 -0
- package/template/.claude/skills/hallmark/references/components/h5-letter-hero.md +11 -0
- package/template/.claude/skills/hallmark/references/components/h6-photographic-fold.md +16 -0
- package/template/.claude/skills/hallmark/references/components/h7-demo-video-clipped-by-viewport-edge.md +27 -0
- package/template/.claude/skills/hallmark/references/components/h8-mockup-split-browser-framed.md +23 -0
- package/template/.claude/skills/hallmark/references/components/h9-custom-illustration-centerpiece.md +27 -0
- package/template/.claude/skills/hallmark/references/components/n1-wordmark-2-links.md +12 -0
- package/template/.claude/skills/hallmark/references/components/n10-floating-on-scroll-morph.md +19 -0
- package/template/.claude/skills/hallmark/references/components/n2-floating-chip.md +14 -0
- package/template/.claude/skills/hallmark/references/components/n3-side-rail.md +14 -0
- package/template/.claude/skills/hallmark/references/components/n4-hidden-behind-k.md +9 -0
- package/template/.claude/skills/hallmark/references/components/n5-floating-pill.md +28 -0
- package/template/.claude/skills/hallmark/references/components/n6-newspaper-masthead.md +24 -0
- package/template/.claude/skills/hallmark/references/components/n7-brutal-slab.md +22 -0
- package/template/.claude/skills/hallmark/references/components/n8-terminal-command.md +21 -0
- package/template/.claude/skills/hallmark/references/components/n9-edge-aligned-minimal.md +17 -0
- package/template/.claude/skills/hallmark/references/components/s1-left-margin-numbered.md +15 -0
- package/template/.claude/skills/hallmark/references/components/s2-hanging.md +13 -0
- package/template/.claude/skills/hallmark/references/components/s3-sticky-pinned.md +19 -0
- package/template/.claude/skills/hallmark/references/components/s4-inline-no-break.md +11 -0
- package/template/.claude/skills/hallmark/references/components/s5-bottom-anchored.md +13 -0
- package/template/.claude/skills/hallmark/references/components/t1-pull-quote-with-marginalia.md +12 -0
- package/template/.claude/skills/hallmark/references/components/t2-logo-wall-hairline.md +19 -0
- package/template/.claude/skills/hallmark/references/components/t3-single-huge-quote.md +11 -0
- package/template/.claude/skills/hallmark/references/components/t4-numbered-stat-strip.md +14 -0
- package/template/.claude/skills/hallmark/references/contract.md +24 -0
- package/template/.claude/skills/hallmark/references/copy.md +182 -0
- package/template/.claude/skills/hallmark/references/custom-craft.md +626 -0
- package/template/.claude/skills/hallmark/references/custom-theme.md +329 -0
- package/template/.claude/skills/hallmark/references/design-md.md +116 -0
- package/template/.claude/skills/hallmark/references/export-formats.md +328 -0
- package/template/.claude/skills/hallmark/references/floating-nav.md +89 -0
- package/template/.claude/skills/hallmark/references/genres/atmospheric.md +65 -0
- package/template/.claude/skills/hallmark/references/genres/editorial.md +70 -0
- package/template/.claude/skills/hallmark/references/genres/modern-minimal.md +67 -0
- package/template/.claude/skills/hallmark/references/genres/playful.md +65 -0
- package/template/.claude/skills/hallmark/references/hero-enrichment.md +474 -0
- package/template/.claude/skills/hallmark/references/imagery-kit.md +170 -0
- package/template/.claude/skills/hallmark/references/interaction-and-states.md +207 -0
- package/template/.claude/skills/hallmark/references/layout-and-space.md +111 -0
- package/template/.claude/skills/hallmark/references/macrostructures/01-bento-grid.md +35 -0
- package/template/.claude/skills/hallmark/references/macrostructures/02-long-document.md +34 -0
- package/template/.claude/skills/hallmark/references/macrostructures/03-marquee-hero.md +31 -0
- package/template/.claude/skills/hallmark/references/macrostructures/04-stat-led.md +32 -0
- package/template/.claude/skills/hallmark/references/macrostructures/05-workbench.md +32 -0
- package/template/.claude/skills/hallmark/references/macrostructures/06-conversational-faq.md +33 -0
- package/template/.claude/skills/hallmark/references/macrostructures/07-manifesto.md +32 -0
- package/template/.claude/skills/hallmark/references/macrostructures/08-photographic.md +34 -0
- package/template/.claude/skills/hallmark/references/macrostructures/09-quote-led.md +32 -0
- package/template/.claude/skills/hallmark/references/macrostructures/10-specimen.md +32 -0
- package/template/.claude/skills/hallmark/references/macrostructures/11-catalogue.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/12-letter.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/13-index-first.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/14-narrative-workflow.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/15-split-studio.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/16-feature-stack.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/17-type-specimen.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/18-portfolio-grid.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/19-map-diagram.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/20-ecosystem-index.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures/21-component-playground.md +23 -0
- package/template/.claude/skills/hallmark/references/macrostructures.md +89 -0
- package/template/.claude/skills/hallmark/references/microinteractions.md +260 -0
- package/template/.claude/skills/hallmark/references/motion.md +109 -0
- package/template/.claude/skills/hallmark/references/preview-examples.md +49 -0
- package/template/.claude/skills/hallmark/references/responsive.md +138 -0
- package/template/.claude/skills/hallmark/references/slop-test.md +205 -0
- package/template/.claude/skills/hallmark/references/structure.md +164 -0
- package/template/.claude/skills/hallmark/references/study.md +511 -0
- package/template/.claude/skills/hallmark/references/typography.md +243 -0
- package/template/.claude/skills/hallmark/references/verbs/audit.md +25 -0
- package/template/.claude/skills/hallmark/references/verbs/redesign.md +269 -0
- package/template/.claude/skills/hallmark-explore/SKILL.md +137 -0
- package/template/.claude/skills/hallmark-explore/references/direction-matrix.md +124 -0
- package/template/.claude/skills/hallmark-explore/references/explorer-call.md +68 -0
- package/template/.claude/skills/hallmark-explore/scripts/build_compare.py +174 -0
- package/template/.claude/skills/hallmark-explore/scripts/scaffold_exploration.py +122 -0
- package/template/.claude/skills/hallmark-loop/SKILL.md +105 -0
- package/template/.claude/skills/hallmark-loop/references/auditor-call.md +60 -0
- package/template/.claude/skills/hallmark-loop/references/capture.md +78 -0
- package/template/.claude/skills/hallmark-loop/references/loop-control.md +79 -0
- package/template/.claude/skills/handoff/SKILL.md +15 -0
- package/template/.claude/skills/install.ps1 +42 -0
- package/template/.claude/skills/install.sh +54 -0
- package/template/.claude/skills/knowledge-crunching/SKILL.md +130 -0
- package/template/.claude/skills/knowledge-crunching/assets/context.template.md +59 -0
- package/template/.claude/skills/knowledge-crunching/references/crunching-dialogue.md +113 -0
- package/template/.claude/skills/research/SKILL.md +69 -0
- package/template/.claude/skills/skill-creator/LICENSE.txt +202 -0
- package/template/.claude/skills/skill-creator/SKILL.md +149 -0
- package/template/.claude/skills/skill-creator/agents/analyzer.md +274 -0
- package/template/.claude/skills/skill-creator/agents/comparator.md +202 -0
- package/template/.claude/skills/skill-creator/agents/grader.md +223 -0
- package/template/.claude/skills/skill-creator/assets/eval_review.html +146 -0
- package/template/.claude/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/template/.claude/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/template/.claude/skills/skill-creator/references/benchmark-optimization-guide.md +86 -0
- package/template/.claude/skills/skill-creator/references/distribution-guide.md +79 -0
- package/template/.claude/skills/skill-creator/references/eval-infrastructure-guide.md +129 -0
- package/template/.claude/skills/skill-creator/references/eval-schemas.md +121 -0
- package/template/.claude/skills/skill-creator/references/mcp-skills-integration.md +71 -0
- package/template/.claude/skills/skill-creator/references/metadata-quality-criteria.md +94 -0
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-hosting.md +104 -0
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-overview.md +89 -0
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-schema.md +93 -0
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-sources.md +103 -0
- package/template/.claude/skills/skill-creator/references/plugin-marketplace-troubleshooting.md +76 -0
- package/template/.claude/skills/skill-creator/references/script-quality-criteria.md +106 -0
- package/template/.claude/skills/skill-creator/references/skill-anatomy-and-requirements.md +77 -0
- package/template/.claude/skills/skill-creator/references/skill-creation-workflow.md +151 -0
- package/template/.claude/skills/skill-creator/references/skill-design-patterns.md +75 -0
- package/template/.claude/skills/skill-creator/references/skillmark-benchmark-criteria.md +102 -0
- package/template/.claude/skills/skill-creator/references/structure-organization-criteria.md +114 -0
- package/template/.claude/skills/skill-creator/references/testing-and-iteration.md +78 -0
- package/template/.claude/skills/skill-creator/references/token-efficiency-criteria.md +74 -0
- package/template/.claude/skills/skill-creator/references/troubleshooting-guide.md +81 -0
- package/template/.claude/skills/skill-creator/references/validation-checklist.md +83 -0
- package/template/.claude/skills/skill-creator/references/writing-effective-instructions.md +88 -0
- package/template/.claude/skills/skill-creator/references/yaml-frontmatter-reference.md +92 -0
- package/template/.claude/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/template/.claude/skills/skill-creator/scripts/encoding_utils.py +36 -0
- package/template/.claude/skills/skill-creator/scripts/generate_report.py +326 -0
- package/template/.claude/skills/skill-creator/scripts/improve_description.py +248 -0
- package/template/.claude/skills/skill-creator/scripts/init_skill.py +360 -0
- package/template/.claude/skills/skill-creator/scripts/package_skill.py +143 -0
- package/template/.claude/skills/skill-creator/scripts/quick_validate.py +110 -0
- package/template/.claude/skills/skill-creator/scripts/run_eval.py +310 -0
- package/template/.claude/skills/skill-creator/scripts/run_loop.py +332 -0
- package/template/.claude/skills/skill-creator/scripts/utils.py +47 -0
- package/template/.claude/skills/tdd/SKILL.md +142 -0
- package/template/.claude/skills/tdd/assets/Directory.Build.props +26 -0
- package/template/.claude/skills/tdd/deep-modules.md +15 -0
- package/template/.claude/skills/tdd/dotnet-build-config.md +21 -0
- package/template/.claude/skills/tdd/interface-design.md +31 -0
- package/template/.claude/skills/tdd/mocking.md +59 -0
- package/template/.claude/skills/tdd/refactoring.md +10 -0
- package/template/.claude/skills/tdd/test-per-layer.md +69 -0
- package/template/.claude/skills/tdd/tests.md +61 -0
- package/template/.claude/statusline.cjs +0 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tdd
|
|
3
|
+
description: Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", wants integration tests, or asks for test-first development.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test-Driven Development
|
|
7
|
+
|
|
8
|
+
## Philosophy
|
|
9
|
+
|
|
10
|
+
**Core principle**: Tests should verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't.
|
|
11
|
+
|
|
12
|
+
**Good tests** are integration-style: they exercise real code paths through public APIs. They describe _what_ the system does, not _how_ it does it. A good test reads like a specification - "user can checkout with valid cart" tells you exactly what capability exists. These tests survive refactors because they don't care about internal structure.
|
|
13
|
+
|
|
14
|
+
**Bad tests** are coupled to implementation. They mock internal collaborators, test private methods, or verify through external means (like querying a database directly instead of using the interface). The warning sign: your test breaks when you refactor, but behavior hasn't changed. If you rename an internal function and tests fail, those tests were testing implementation, not behavior.
|
|
15
|
+
|
|
16
|
+
Note: "integration-_style_" here means _through the public surface_ — it is **not** the same as an out-of-process "integration test" (real HTTP + real DB). Which layer uses which is settled in [Build inside-out, and match the test to the layer](#build-inside-out-and-match-the-test-to-the-layer) below.
|
|
17
|
+
|
|
18
|
+
See [tests.md](tests.md) for examples and [mocking.md](mocking.md) for mocking guidelines.
|
|
19
|
+
|
|
20
|
+
## Anti-Pattern: Horizontal Slices
|
|
21
|
+
|
|
22
|
+
**DO NOT write all tests first, then all implementation.** This is "horizontal slicing" - treating RED as "write all tests" and GREEN as "write all code."
|
|
23
|
+
|
|
24
|
+
This produces **crap tests**:
|
|
25
|
+
|
|
26
|
+
- Tests written in bulk test _imagined_ behavior, not _actual_ behavior
|
|
27
|
+
- You end up testing the _shape_ of things (data structures, function signatures) rather than user-facing behavior
|
|
28
|
+
- Tests become insensitive to real changes - they pass when behavior breaks, fail when behavior is fine
|
|
29
|
+
- You outrun your headlights, committing to test structure before understanding the implementation
|
|
30
|
+
|
|
31
|
+
**Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat. Each test responds to what you learned from the previous cycle. Because you just wrote the code, you know exactly what behavior matters and how to verify it.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
WRONG (horizontal):
|
|
35
|
+
RED: test1, test2, test3, test4, test5
|
|
36
|
+
GREEN: impl1, impl2, impl3, impl4, impl5
|
|
37
|
+
|
|
38
|
+
RIGHT (vertical):
|
|
39
|
+
RED→GREEN: test1→impl1
|
|
40
|
+
RED→GREEN: test2→impl2
|
|
41
|
+
RED→GREEN: test3→impl3
|
|
42
|
+
...
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Build inside-out, and match the test to the layer
|
|
46
|
+
|
|
47
|
+
Grow a feature from the **domain core outward** — never build the whole stack and test at the end.
|
|
48
|
+
Test-drive each layer as you reach it; the _kind_ of first test follows the layer:
|
|
49
|
+
|
|
50
|
+
| Layer | First test | Project |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| Domain | **unit** | `*.Domain.UnitTests` |
|
|
53
|
+
| Application (handlers) | **unit**, mocking only boundaries (repository, clock, LLM) | `*.Application.UnitTests` |
|
|
54
|
+
| Contracts | **unit** only if they carry logic | — |
|
|
55
|
+
| Infrastructure + API (outer edge) | **integration** — one suite, real HTTP + real DB | `*.IntegrationTests` |
|
|
56
|
+
|
|
57
|
+
Order: **domain → application → outer edge.** The integration suite boots the _composed app_, so the
|
|
58
|
+
real EF mapping/repository only runs through it — there is no separate infra test before the API.
|
|
59
|
+
|
|
60
|
+
"Integration-_style_" (Philosophy: through the public surface) ≠ "integration _test_" (out-of-process,
|
|
61
|
+
real HTTP + DB). Don't conflate them.
|
|
62
|
+
|
|
63
|
+
See [test-per-layer.md](test-per-layer.md): why "first" is per-layer and red-green-refactor stays
|
|
64
|
+
intact; why integration tests are few-but-load-bearing, not cosmetic; and how many ACs to
|
|
65
|
+
integration-test.
|
|
66
|
+
|
|
67
|
+
## Build configuration (strict gates)
|
|
68
|
+
|
|
69
|
+
Treat the build as a quality gate, not just "it compiled". The solution should enforce
|
|
70
|
+
warnings-as-errors, code-style, and full security analysis via a root `Directory.Build.props`
|
|
71
|
+
(`TreatWarningsAsErrors`, `EnforceCodeStyleInBuild`, `AnalysisLevel=latest-recommended`,
|
|
72
|
+
`AnalysisModeSecurity=All`). Ensure these are present — see
|
|
73
|
+
[dotnet-build-config.md](dotnet-build-config.md) (reference: [assets/Directory.Build.props](assets/Directory.Build.props)).
|
|
74
|
+
|
|
75
|
+
## Workflow
|
|
76
|
+
|
|
77
|
+
### 1. Planning
|
|
78
|
+
|
|
79
|
+
When exploring the codebase, use the project's domain glossary so that test names and interface vocabulary match the project's language, and respect ADRs in the area you're touching.
|
|
80
|
+
|
|
81
|
+
**Default to the full flow. Do not ask the user to approve the plan or choose scope — decide and build.** When the task names a behavior (e.g. a story/AC set), implement the entire vertical slice for it: domain → application → outer edge, every layer that the behavior touches, inside-out (see the layer table). "Backend only" / "frontend only" scopes the stack, not the depth — go all the way down the named side. Pick the sensible default for any open decision, state it in one line, and proceed. Only stop to ask if a choice is genuinely irreversible or the requirements truly contradict each other — not merely because more than one option exists.
|
|
82
|
+
|
|
83
|
+
Before writing any code, work this out for yourself (no approval gate):
|
|
84
|
+
|
|
85
|
+
- [ ] Decide what interface changes are needed
|
|
86
|
+
- [ ] List the behaviors to test, ordered (not implementation steps) — cover every AC of the named work
|
|
87
|
+
- [ ] Identify opportunities for [deep modules](deep-modules.md) (small interface, deep implementation)
|
|
88
|
+
- [ ] Design interfaces for [testability](interface-design.md)
|
|
89
|
+
- [ ] Identify the layer(s) you're touching and the matching first-test type (see the layer table)
|
|
90
|
+
|
|
91
|
+
State the plan in one short message, then immediately start the tracer-bullet loop in the same turn.
|
|
92
|
+
|
|
93
|
+
**You can't test everything**, but the named behavior's ACs are all in scope. Focus extra effort on critical paths and complex logic; don't burn cycles on every theoretical edge case beyond the spec.
|
|
94
|
+
|
|
95
|
+
### 2. Tracer Bullet
|
|
96
|
+
|
|
97
|
+
Write ONE test that confirms ONE thing about the system:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
RED: Write test for first behavior → test fails
|
|
101
|
+
GREEN: Write minimal code to pass → test passes
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
This is your tracer bullet - proves the path works end-to-end.
|
|
105
|
+
|
|
106
|
+
### 3. Incremental Loop
|
|
107
|
+
|
|
108
|
+
For each remaining behavior:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
RED: Write next test → fails
|
|
112
|
+
GREEN: Minimal code to pass → passes
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Rules:
|
|
116
|
+
|
|
117
|
+
- One test at a time
|
|
118
|
+
- Only enough code to pass current test
|
|
119
|
+
- Don't anticipate future tests
|
|
120
|
+
- Keep tests focused on observable behavior
|
|
121
|
+
|
|
122
|
+
### 4. Refactor
|
|
123
|
+
|
|
124
|
+
After all tests pass, look for [refactor candidates](refactoring.md):
|
|
125
|
+
|
|
126
|
+
- [ ] Extract duplication
|
|
127
|
+
- [ ] Deepen modules (move complexity behind simple interfaces)
|
|
128
|
+
- [ ] Apply SOLID principles where natural
|
|
129
|
+
- [ ] Consider what new code reveals about existing code
|
|
130
|
+
- [ ] Run tests after each refactor step
|
|
131
|
+
|
|
132
|
+
**Never refactor while RED.** Get to GREEN first.
|
|
133
|
+
|
|
134
|
+
## Checklist Per Cycle
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
[ ] Test describes behavior, not implementation
|
|
138
|
+
[ ] Test uses public interface only
|
|
139
|
+
[ ] Test would survive internal refactor
|
|
140
|
+
[ ] Code is minimal for this test
|
|
141
|
+
[ ] No speculative features added
|
|
142
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<Project>
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
musketeer · dotnet company — strict build & analysis gates.
|
|
5
|
+
Place this at your solution/backend root (above your .csproj files). MSBuild auto-imports
|
|
6
|
+
the nearest Directory.Build.props up the directory tree, so these apply to every project under it.
|
|
7
|
+
If one already exists, MERGE in any of the properties below that are missing.
|
|
8
|
+
TargetFramework / RootNamespace / AssemblyName stay in each .csproj — intentionally NOT set here,
|
|
9
|
+
so this file layers cleanly onto any project without overriding its target framework.
|
|
10
|
+
-->
|
|
11
|
+
<PropertyGroup>
|
|
12
|
+
<!-- Language & nullability -->
|
|
13
|
+
<LangVersion>latest</LangVersion>
|
|
14
|
+
<Nullable>enable</Nullable>
|
|
15
|
+
<ImplicitUsings>enable</ImplicitUsings>
|
|
16
|
+
|
|
17
|
+
<!-- Quality gates: fail the build on warnings & unformatted code -->
|
|
18
|
+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
|
19
|
+
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
|
20
|
+
|
|
21
|
+
<!-- Static analysis: latest recommended rules + full security analysis -->
|
|
22
|
+
<AnalysisLevel>latest-recommended</AnalysisLevel>
|
|
23
|
+
<AnalysisModeSecurity>All</AnalysisModeSecurity>
|
|
24
|
+
</PropertyGroup>
|
|
25
|
+
|
|
26
|
+
</Project>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Deep Modules Summary
|
|
2
|
+
|
|
3
|
+
The concept of deep modules comes from "A Philosophy of Software Design" and contrasts two design approaches:
|
|
4
|
+
|
|
5
|
+
**Deep modules** feature a "small interface + lots of implementation." They expose minimal methods and parameters while concealing substantial internal complexity. This design reduces cognitive load for users of the module.
|
|
6
|
+
|
|
7
|
+
**Shallow modules** present the opposite problem: they expose many methods with complex parameters but provide little substantive logic—essentially acting as thin wrappers.
|
|
8
|
+
|
|
9
|
+
When designing module interfaces, the guidance is to consider three key questions:
|
|
10
|
+
|
|
11
|
+
- Can the number of exposed methods be reduced?
|
|
12
|
+
- Can parameter signatures be simplified?
|
|
13
|
+
- Can additional complexity be internalized rather than exposed?
|
|
14
|
+
|
|
15
|
+
The deep module approach represents superior software design because it maximizes the value delivered relative to the interface burden imposed on developers using that code.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# .NET build configuration (strict gates)
|
|
2
|
+
|
|
3
|
+
Treat the build as a quality gate. When working in a .NET solution under the **dotnet** company,
|
|
4
|
+
ensure the repo enforces warnings-as-errors, code-style, and full security analysis via a root
|
|
5
|
+
`Directory.Build.props`.
|
|
6
|
+
|
|
7
|
+
**Do this before relying on the build as a signal:**
|
|
8
|
+
|
|
9
|
+
1. Find the solution/backend root — the directory above your `.csproj` projects.
|
|
10
|
+
2. If no `Directory.Build.props` exists there, copy [assets/Directory.Build.props](assets/Directory.Build.props) to it.
|
|
11
|
+
3. If one already exists, MERGE in any of these properties that are missing (don't remove the project's own):
|
|
12
|
+
- `<TreatWarningsAsErrors>true</TreatWarningsAsErrors>` — warnings fail the build.
|
|
13
|
+
- `<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>` — `.editorconfig` style violations fail the build.
|
|
14
|
+
- `<AnalysisLevel>latest-recommended</AnalysisLevel>` — newest recommended analyzer rules.
|
|
15
|
+
- `<AnalysisModeSecurity>All</AnalysisModeSecurity>` — all security (CA3xxx/CA5xxx) rules enabled.
|
|
16
|
+
- Language defaults: `<Nullable>enable</Nullable>`, `<LangVersion>latest</LangVersion>`, `<ImplicitUsings>enable</ImplicitUsings>`.
|
|
17
|
+
4. Keep `TargetFramework`, `RootNamespace`, `AssemblyName` per-project in each `.csproj` — don't pin them here.
|
|
18
|
+
|
|
19
|
+
MSBuild auto-imports the nearest `Directory.Build.props` up the tree, so one root file covers every
|
|
20
|
+
project beneath it. With these on, a green build means zero warnings, enforced style, and security
|
|
21
|
+
analysis — so the agent can trust the build as a gate, not just "it compiled".
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Interface Design for Testability
|
|
2
|
+
|
|
3
|
+
Good interfaces make testing natural:
|
|
4
|
+
|
|
5
|
+
1. **Accept dependencies, don't create them**
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// Testable
|
|
9
|
+
function processOrder(order, paymentGateway) {}
|
|
10
|
+
|
|
11
|
+
// Hard to test
|
|
12
|
+
function processOrder(order) {
|
|
13
|
+
const gateway = new StripeGateway();
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
2. **Return results, don't produce side effects**
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// Testable
|
|
21
|
+
function calculateDiscount(cart): Discount {}
|
|
22
|
+
|
|
23
|
+
// Hard to test
|
|
24
|
+
function applyDiscount(cart): void {
|
|
25
|
+
cart.total -= discount;
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
3. **Small surface area**
|
|
30
|
+
- Fewer methods = fewer tests needed
|
|
31
|
+
- Fewer params = simpler test setup
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# When to Mock
|
|
2
|
+
|
|
3
|
+
Mock at **system boundaries** only:
|
|
4
|
+
|
|
5
|
+
- External APIs (payment, email, etc.)
|
|
6
|
+
- Databases (sometimes - prefer test DB)
|
|
7
|
+
- Time/randomness
|
|
8
|
+
- File system (sometimes)
|
|
9
|
+
|
|
10
|
+
Don't mock:
|
|
11
|
+
|
|
12
|
+
- Your own classes/modules
|
|
13
|
+
- Internal collaborators
|
|
14
|
+
- Anything you control
|
|
15
|
+
|
|
16
|
+
## Designing for Mockability
|
|
17
|
+
|
|
18
|
+
At system boundaries, design interfaces that are easy to mock:
|
|
19
|
+
|
|
20
|
+
**1. Use dependency injection**
|
|
21
|
+
|
|
22
|
+
Pass external dependencies in rather than creating them internally:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// Easy to mock
|
|
26
|
+
function processPayment(order, paymentClient) {
|
|
27
|
+
return paymentClient.charge(order.total);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Hard to mock
|
|
31
|
+
function processPayment(order) {
|
|
32
|
+
const client = new StripeClient(process.env.STRIPE_KEY);
|
|
33
|
+
return client.charge(order.total);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**2. Prefer SDK-style interfaces over generic fetchers**
|
|
38
|
+
|
|
39
|
+
Create specific functions for each external operation instead of one generic function with conditional logic:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
// GOOD: Each function is independently mockable
|
|
43
|
+
const api = {
|
|
44
|
+
getUser: (id) => fetch(`/users/${id}`),
|
|
45
|
+
getOrders: (userId) => fetch(`/users/${userId}/orders`),
|
|
46
|
+
createOrder: (data) => fetch('/orders', { method: 'POST', body: data }),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// BAD: Mocking requires conditional logic inside the mock
|
|
50
|
+
const api = {
|
|
51
|
+
fetch: (endpoint, options) => fetch(endpoint, options),
|
|
52
|
+
};
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The SDK approach means:
|
|
56
|
+
- Each mock returns one specific shape
|
|
57
|
+
- No conditional logic in test setup
|
|
58
|
+
- Easier to see which endpoints a test exercises
|
|
59
|
+
- Type safety per endpoint
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Refactor Candidates
|
|
2
|
+
|
|
3
|
+
After TDD cycle, look for:
|
|
4
|
+
|
|
5
|
+
- **Duplication** → Extract function/class
|
|
6
|
+
- **Long methods** → Break into private helpers (keep tests on public interface)
|
|
7
|
+
- **Shallow modules** → Combine or deepen
|
|
8
|
+
- **Feature envy** → Move logic to where data lives
|
|
9
|
+
- **Primitive obsession** → Introduce value objects
|
|
10
|
+
- **Existing code** the new code reveals as problematic
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Test per layer: inside-out, and which test drives which layer
|
|
2
|
+
|
|
3
|
+
Companion to the "Build inside-out, and match the test to the layer" section in SKILL.md. The
|
|
4
|
+
layer table and the two senses of "integration" live there; this file covers the _why_ and the
|
|
5
|
+
judgement calls.
|
|
6
|
+
|
|
7
|
+
## "First" means first within its layer, not first in the feature
|
|
8
|
+
|
|
9
|
+
"First test" in the layer table means first _within that layer_ — not first in the feature. You
|
|
10
|
+
build inward-out, so by the time you reach the outer edge the domain and application are already
|
|
11
|
+
green; the integration test you write there goes red→green over just the wiring. It does **not** sit
|
|
12
|
+
red across the whole feature.
|
|
13
|
+
|
|
14
|
+
That keeps red-green-refactor intact. The loop's invariant is "every cycle _ends_ on green — never
|
|
15
|
+
park on a committed red test," not "only green tests ever exist." Each integration test is
|
|
16
|
+
red→green→refactor within its own cycle: no lingering red. The failure inside-out avoids — because
|
|
17
|
+
the inner layers are already unit-proven — is one red integration test as your only feedback while
|
|
18
|
+
you write a pile of code with no inner green checkpoints (outrunning your headlights).
|
|
19
|
+
|
|
20
|
+
## Integration tests are few but load-bearing — not cosmetic
|
|
21
|
+
|
|
22
|
+
Once domain edge cases are unit-covered, the integration test is _not_ a final sanity check. It owns
|
|
23
|
+
a class of risk unit tests structurally can't reach (they mock the boundaries away):
|
|
24
|
+
|
|
25
|
+
- **Wiring / DI** — is the handler/repository actually registered? A missing registration passes
|
|
26
|
+
every unit test, fails only in production.
|
|
27
|
+
- **Routing** — does `POST /api/me` actually reach the endpoint?
|
|
28
|
+
- **Auth** — 401/403, and the OWASP JWT-negative matrix (expired, wrong audience/issuer, tampered
|
|
29
|
+
signature, `alg=none`).
|
|
30
|
+
- **Serialization** — the real JSON contract (shape, casing, nulls), not the handler's return
|
|
31
|
+
object.
|
|
32
|
+
- **Real persistence** — EF mapping + DB constraints (e.g. the one-Learner-per-identity unique
|
|
33
|
+
index), real only against a real DB.
|
|
34
|
+
- **Concurrency / transactions** — five concurrent requests → exactly one row: a real-DB property a
|
|
35
|
+
mocked repository can't prove.
|
|
36
|
+
|
|
37
|
+
Reframe: **unit tests prove the rules are right; integration tests prove the system is wired and the
|
|
38
|
+
infrastructure honors those rules.** _Two passing unit tests, zero integration tests_ — both green,
|
|
39
|
+
feature broken because the parts were never bolted together.
|
|
40
|
+
|
|
41
|
+
Don't re-assert domain edge cases through HTTP — that enumeration belongs in unit tests.
|
|
42
|
+
|
|
43
|
+
## How many ACs get an integration test?
|
|
44
|
+
|
|
45
|
+
**Every acceptance criterion needs a test — not every AC needs an _integration_ test.** Cover each
|
|
46
|
+
AC at the layer that owns its risk; put the AC id in the test name for traceability (which doesn't
|
|
47
|
+
require the integration layer specifically).
|
|
48
|
+
|
|
49
|
+
Default:
|
|
50
|
+
|
|
51
|
+
- One representative **happy-path** integration test.
|
|
52
|
+
- One per **integration-distinct** AC: auth/authz, persistence/uniqueness/concurrency, the
|
|
53
|
+
serialization contract, a distinct status-code mapping (e.g. "entry rejected → 4xx").
|
|
54
|
+
- **None** for pure domain-rule ACs already unit-covered that take the same wiring/serialization/auth
|
|
55
|
+
path as the happy case.
|
|
56
|
+
|
|
57
|
+
`MeEndpointTests` is the worked reference: happy + returning-same + concurrent→one + no-email→403 +
|
|
58
|
+
the auth/JWT matrix — the integration-distinct behaviors — while display-name/email-parsing
|
|
59
|
+
permutations stay in `LearnerTests` / `SharedKernelTests`.
|
|
60
|
+
|
|
61
|
+
Example — **LEARNING-1** ("load progress"): its six ACs are all cursor-resolution domain rules → six
|
|
62
|
+
_unit_ tests; the integration layer gets ~one test for the distinct question (does `LoadProgress`
|
|
63
|
+
resolve the right cursor over HTTP against a _persisted_ progress + real curriculum?), not six
|
|
64
|
+
mirroring the ACs.
|
|
65
|
+
|
|
66
|
+
Cost: these tests are Docker-gated (`SkippableFact`) — a full AC×Testcontainers matrix is slow in
|
|
67
|
+
CI, gives zero signal on Docker-less machines, and inverts the pyramid (ice-cream-cone). Exception:
|
|
68
|
+
in a compliance/audited context where each AC must be demonstrably exercised end-to-end, deliberate
|
|
69
|
+
1:1 AC→integration traceability earns its cost — a documented choice, not the default.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Good and Bad Tests
|
|
2
|
+
|
|
3
|
+
## Good Tests
|
|
4
|
+
|
|
5
|
+
**Integration-style**: Test through real interfaces, not mocks of internal parts.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// GOOD: Tests observable behavior
|
|
9
|
+
test("user can checkout with valid cart", async () => {
|
|
10
|
+
const cart = createCart();
|
|
11
|
+
cart.add(product);
|
|
12
|
+
const result = await checkout(cart, paymentMethod);
|
|
13
|
+
expect(result.status).toBe("confirmed");
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Characteristics:
|
|
18
|
+
|
|
19
|
+
- Tests behavior users/callers care about
|
|
20
|
+
- Uses public API only
|
|
21
|
+
- Survives internal refactors
|
|
22
|
+
- Describes WHAT, not HOW
|
|
23
|
+
- One logical assertion per test
|
|
24
|
+
|
|
25
|
+
## Bad Tests
|
|
26
|
+
|
|
27
|
+
**Implementation-detail tests**: Coupled to internal structure.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
// BAD: Tests implementation details
|
|
31
|
+
test("checkout calls paymentService.process", async () => {
|
|
32
|
+
const mockPayment = jest.mock(paymentService);
|
|
33
|
+
await checkout(cart, payment);
|
|
34
|
+
expect(mockPayment.process).toHaveBeenCalledWith(cart.total);
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Red flags:
|
|
39
|
+
|
|
40
|
+
- Mocking internal collaborators
|
|
41
|
+
- Testing private methods
|
|
42
|
+
- Asserting on call counts/order
|
|
43
|
+
- Test breaks when refactoring without behavior change
|
|
44
|
+
- Test name describes HOW not WHAT
|
|
45
|
+
- Verifying through external means instead of interface
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// BAD: Bypasses interface to verify
|
|
49
|
+
test("createUser saves to database", async () => {
|
|
50
|
+
await createUser({ name: "Alice" });
|
|
51
|
+
const row = await db.query("SELECT * FROM users WHERE name = ?", ["Alice"]);
|
|
52
|
+
expect(row).toBeDefined();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// GOOD: Verifies through interface
|
|
56
|
+
test("createUser makes user retrievable", async () => {
|
|
57
|
+
const user = await createUser({ name: "Alice" });
|
|
58
|
+
const retrieved = await getUser(user.id);
|
|
59
|
+
expect(retrieved.name).toBe("Alice");
|
|
60
|
+
});
|
|
61
|
+
```
|
|
Binary file
|