@ikon85/agent-workflow-kit 0.10.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/.agents/skills/ask-matt/SKILL.md +139 -0
- package/.agents/skills/ask-matt/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/audit-skills/SKILL.md +145 -0
- package/.agents/skills/board-to-waves/SKILL.md +135 -0
- package/.agents/skills/code-review/SKILL.md +64 -0
- package/.agents/skills/codebase-design/DEEPENING.md +37 -0
- package/.agents/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
- package/.agents/skills/codebase-design/SKILL.md +114 -0
- package/.agents/skills/codebase-design/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/codex-adapter-sync/SKILL.md +151 -0
- package/.agents/skills/decision-gate/SKILL.md +67 -0
- package/.agents/skills/diagnose/SKILL.md +136 -0
- package/.agents/skills/diagnose/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/diagnose/scripts/hitl-loop.template.sh +41 -0
- package/.agents/skills/domain-modeling/ADR-FORMAT.md +47 -0
- package/.agents/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
- package/.agents/skills/domain-modeling/SKILL.md +76 -0
- package/.agents/skills/domain-modeling/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/git-worktree-recover/SKILL.md +176 -0
- package/.agents/skills/grill-me/SKILL.md +54 -0
- package/.agents/skills/grill-me/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/grill-with-docs/ADR-FORMAT.md +47 -0
- package/.agents/skills/grill-with-docs/CONTEXT-FORMAT.md +60 -0
- package/.agents/skills/grill-with-docs/SKILL.md +137 -0
- package/.agents/skills/grill-with-docs/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/implement/SKILL.md +15 -0
- package/.agents/skills/implement/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/improve-codebase-architecture/ADR-FORMAT.md +47 -0
- package/.agents/skills/improve-codebase-architecture/CONTEXT-FORMAT.md +60 -0
- package/.agents/skills/improve-codebase-architecture/DEEPENING.md +37 -0
- package/.agents/skills/improve-codebase-architecture/HTML-REPORT.md +123 -0
- package/.agents/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +46 -0
- package/.agents/skills/improve-codebase-architecture/LANGUAGE.md +53 -0
- package/.agents/skills/improve-codebase-architecture/SKILL.md +88 -0
- package/.agents/skills/improve-codebase-architecture/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/kit-release/SKILL.md +56 -0
- package/.agents/skills/local-ci/SKILL.md +94 -0
- package/.agents/skills/orchestrate-wave/SKILL.md +261 -0
- package/.agents/skills/orchestrate-wave/references/builder-contract.md +67 -0
- package/.agents/skills/prototype/LOGIC.md +79 -0
- package/.agents/skills/prototype/SKILL.md +30 -0
- package/.agents/skills/prototype/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/prototype/UI.md +112 -0
- package/.agents/skills/research/SKILL.md +12 -0
- package/.agents/skills/research/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/resolving-merge-conflicts/SKILL.md +14 -0
- package/.agents/skills/resolving-merge-conflicts/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/retro/SKILL.md +209 -0
- package/.agents/skills/scale-check/SKILL.md +141 -0
- package/.agents/skills/security-audit/SKILL.md +67 -0
- package/.agents/skills/setup-workflow/SKILL.md +187 -0
- package/.agents/skills/setup-workflow/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/setup-workflow/board-sync.md +111 -0
- package/.agents/skills/setup-workflow/code-review.md +26 -0
- package/.agents/skills/setup-workflow/domain.md +51 -0
- package/.agents/skills/setup-workflow/issue-tracker-github.md +35 -0
- package/.agents/skills/setup-workflow/issue-tracker-gitlab.md +34 -0
- package/.agents/skills/setup-workflow/issue-tracker-local.md +30 -0
- package/.agents/skills/setup-workflow/orchestrate-wave-seed.md +44 -0
- package/.agents/skills/setup-workflow/spec-completeness-seed.md +44 -0
- package/.agents/skills/setup-workflow/spec-self-critique-seed.md +43 -0
- package/.agents/skills/setup-workflow/triage-labels.md +18 -0
- package/.agents/skills/setup-workflow/workflow-overview.md +33 -0
- package/.agents/skills/spec-self-critique/SKILL.md +152 -0
- package/.agents/skills/spec-self-critique/scenarios.md +82 -0
- package/.agents/skills/tdd/SKILL.md +120 -0
- package/.agents/skills/tdd/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/tdd/deep-modules.md +33 -0
- package/.agents/skills/tdd/interface-design.md +31 -0
- package/.agents/skills/tdd/mocking.md +59 -0
- package/.agents/skills/tdd/refactoring.md +10 -0
- package/.agents/skills/tdd/tests.md +61 -0
- package/.agents/skills/to-issues/SKILL.md +325 -0
- package/.agents/skills/to-issues/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/to-prd/PROGRAM-PRD-FORMAT.md +162 -0
- package/.agents/skills/to-prd/SKILL.md +180 -0
- package/.agents/skills/to-prd/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/to-waves/SKILL.md +260 -0
- package/.agents/skills/to-waves/SLICE-METADATA-FORMAT.md +74 -0
- package/.agents/skills/triage/AGENT-BRIEF.md +168 -0
- package/.agents/skills/triage/OUT-OF-SCOPE.md +101 -0
- package/.agents/skills/triage/SKILL.md +122 -0
- package/.agents/skills/triage/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/verify-spike/SKILL.md +39 -0
- package/.agents/skills/wayfinder/SKILL.md +127 -0
- package/.agents/skills/wayfinder/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/wrapup/SKILL.md +71 -0
- package/.agents/skills/wrapup/SOURCES.txt +6 -0
- package/.agents/skills/zoom-out/SKILL.md +7 -0
- package/.agents/skills/zoom-out/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/hooks/_hook_utils.py +184 -0
- package/.claude/hooks/drift-guard.py +176 -0
- package/.claude/hooks/skill-drift-hint.py +122 -0
- package/.claude/hooks/sync-board-status.py +191 -0
- package/.claude/skills/ask-matt/SKILL.md +139 -0
- package/.claude/skills/ask-matt/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/audit-skills/SKILL.md +145 -0
- package/.claude/skills/board-to-waves/SKILL.md +148 -0
- package/.claude/skills/code-review/SKILL.md +64 -0
- package/.claude/skills/codebase-design/DEEPENING.md +37 -0
- package/.claude/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
- package/.claude/skills/codebase-design/SKILL.md +114 -0
- package/.claude/skills/codebase-design/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/codex-build/SKILL.md +126 -0
- package/.claude/skills/codex-build/THIRD-PARTY-NOTICES.md +35 -0
- package/.claude/skills/codex-review/SKILL.md +145 -0
- package/.claude/skills/codex-review/THIRD-PARTY-NOTICES.md +31 -0
- package/.claude/skills/decision-gate/SKILL.md +67 -0
- package/.claude/skills/diagnose/SKILL.md +136 -0
- package/.claude/skills/diagnose/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/diagnose/scripts/hitl-loop.template.sh +41 -0
- package/.claude/skills/domain-modeling/ADR-FORMAT.md +47 -0
- package/.claude/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
- package/.claude/skills/domain-modeling/SKILL.md +76 -0
- package/.claude/skills/domain-modeling/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/git-guardrails-claude-code/SKILL.md +96 -0
- package/.claude/skills/git-guardrails-claude-code/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/git-guardrails-claude-code/scripts/block-dangerous-git.sh +28 -0
- package/.claude/skills/git-worktree-recover/SKILL.md +182 -0
- package/.claude/skills/grill-me/SKILL.md +54 -0
- package/.claude/skills/grill-me/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/grill-me-codex/SKILL.md +158 -0
- package/.claude/skills/grill-me-codex/THIRD-PARTY-NOTICES.md +32 -0
- package/.claude/skills/grill-with-docs/ADR-FORMAT.md +47 -0
- package/.claude/skills/grill-with-docs/CONTEXT-FORMAT.md +60 -0
- package/.claude/skills/grill-with-docs/SKILL.md +137 -0
- package/.claude/skills/grill-with-docs/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/grill-with-docs-codex/ADR-FORMAT.md +47 -0
- package/.claude/skills/grill-with-docs-codex/CONTEXT-FORMAT.md +60 -0
- package/.claude/skills/grill-with-docs-codex/SKILL.md +233 -0
- package/.claude/skills/grill-with-docs-codex/THIRD-PARTY-NOTICES.md +33 -0
- package/.claude/skills/implement/SKILL.md +15 -0
- package/.claude/skills/implement/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/improve-codebase-architecture/ADR-FORMAT.md +47 -0
- package/.claude/skills/improve-codebase-architecture/CONTEXT-FORMAT.md +60 -0
- package/.claude/skills/improve-codebase-architecture/DEEPENING.md +37 -0
- package/.claude/skills/improve-codebase-architecture/HTML-REPORT.md +123 -0
- package/.claude/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +46 -0
- package/.claude/skills/improve-codebase-architecture/LANGUAGE.md +53 -0
- package/.claude/skills/improve-codebase-architecture/SKILL.md +88 -0
- package/.claude/skills/improve-codebase-architecture/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/kit-release/SKILL.md +56 -0
- package/.claude/skills/local-ci/SKILL.md +94 -0
- package/.claude/skills/orchestrate-wave/SKILL.md +269 -0
- package/.claude/skills/orchestrate-wave/references/builder-contract.md +67 -0
- package/.claude/skills/prototype/LOGIC.md +79 -0
- package/.claude/skills/prototype/SKILL.md +30 -0
- package/.claude/skills/prototype/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/prototype/UI.md +112 -0
- package/.claude/skills/research/SKILL.md +12 -0
- package/.claude/skills/research/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/resolving-merge-conflicts/SKILL.md +14 -0
- package/.claude/skills/resolving-merge-conflicts/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/retro/SKILL.md +209 -0
- package/.claude/skills/scale-check/SKILL.md +141 -0
- package/.claude/skills/security-audit/SKILL.md +67 -0
- package/.claude/skills/setup-pre-commit/SKILL.md +104 -0
- package/.claude/skills/setup-pre-commit/scripts/pre-commit.template.sh +35 -0
- package/.claude/skills/setup-workflow/SKILL.md +187 -0
- package/.claude/skills/setup-workflow/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/setup-workflow/board-sync.md +111 -0
- package/.claude/skills/setup-workflow/code-review.md +26 -0
- package/.claude/skills/setup-workflow/domain.md +51 -0
- package/.claude/skills/setup-workflow/issue-tracker-github.md +35 -0
- package/.claude/skills/setup-workflow/issue-tracker-gitlab.md +34 -0
- package/.claude/skills/setup-workflow/issue-tracker-local.md +30 -0
- package/.claude/skills/setup-workflow/orchestrate-wave-seed.md +44 -0
- package/.claude/skills/setup-workflow/spec-completeness-seed.md +44 -0
- package/.claude/skills/setup-workflow/spec-self-critique-seed.md +43 -0
- package/.claude/skills/setup-workflow/triage-labels.md +18 -0
- package/.claude/skills/setup-workflow/workflow-overview.md +33 -0
- package/.claude/skills/skill-manifest.json +389 -0
- package/.claude/skills/spec-self-critique/SKILL.md +152 -0
- package/.claude/skills/spec-self-critique/scenarios.md +82 -0
- package/.claude/skills/tdd/SKILL.md +120 -0
- package/.claude/skills/tdd/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/tdd/deep-modules.md +33 -0
- package/.claude/skills/tdd/interface-design.md +31 -0
- package/.claude/skills/tdd/mocking.md +59 -0
- package/.claude/skills/tdd/refactoring.md +10 -0
- package/.claude/skills/tdd/tests.md +61 -0
- package/.claude/skills/to-issues/SKILL.md +325 -0
- package/.claude/skills/to-issues/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/to-prd/PROGRAM-PRD-FORMAT.md +162 -0
- package/.claude/skills/to-prd/SKILL.md +180 -0
- package/.claude/skills/to-prd/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/to-waves/SKILL.md +260 -0
- package/.claude/skills/to-waves/SLICE-METADATA-FORMAT.md +74 -0
- package/.claude/skills/triage/AGENT-BRIEF.md +168 -0
- package/.claude/skills/triage/OUT-OF-SCOPE.md +101 -0
- package/.claude/skills/triage/SKILL.md +122 -0
- package/.claude/skills/triage/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/verify-spike/SKILL.md +39 -0
- package/.claude/skills/wayfinder/SKILL.md +127 -0
- package/.claude/skills/wayfinder/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/wrapup/SKILL.md +81 -0
- package/.claude/skills/wrapup/SOURCES.txt +6 -0
- package/.claude/skills/write-a-skill/GLOSSARY.md +201 -0
- package/.claude/skills/write-a-skill/SKILL.md +88 -0
- package/.claude/skills/write-a-skill/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/zoom-out/SKILL.md +7 -0
- package/.claude/skills/zoom-out/THIRD-PARTY-NOTICES.md +29 -0
- package/LICENSE +28 -0
- package/PROVENANCE.md +39 -0
- package/README.md +619 -0
- package/agent-workflow-kit.package.json +1939 -0
- package/docs/agents/board-sync.md +71 -0
- package/docs/agents/code-review.md +14 -0
- package/docs/agents/domain.md +7 -0
- package/docs/agents/issue-tracker.md +12 -0
- package/docs/agents/security-audit-runbook-template.md +205 -0
- package/docs/agents/skills/orchestrate-wave.md +13 -0
- package/docs/agents/skills/spec-self-critique.md +18 -0
- package/docs/agents/triage-labels.md +10 -0
- package/docs/agents/wave-anchor-template.md +88 -0
- package/docs/conventions/spec-completeness.md +23 -0
- package/docs/index.html +56 -0
- package/docs/methodology.html +488 -0
- package/docs/methodology.svg +93 -0
- package/docs/workflow.png +0 -0
- package/package.json +40 -0
- package/scripts/anchor_table.py +343 -0
- package/scripts/board-sync.py +1232 -0
- package/scripts/board_config.py +147 -0
- package/scripts/board_fields.py +192 -0
- package/scripts/build-kit.mjs +116 -0
- package/scripts/build-kit.test.mjs +59 -0
- package/scripts/check-kit-staleness.mjs +45 -0
- package/scripts/check-kit-staleness.test.mjs +19 -0
- package/scripts/execute-ready-check.py +516 -0
- package/scripts/issue_deps.py +79 -0
- package/scripts/kit-release.mjs +100 -0
- package/scripts/kit-release.test.mjs +67 -0
- package/scripts/lib/audit-refs.mjs +146 -0
- package/scripts/lib/scrub.mjs +113 -0
- package/scripts/lib/scrub.test.mjs +187 -0
- package/scripts/loc_offender_core.py +196 -0
- package/scripts/loc_offender_gate.py +182 -0
- package/scripts/node_kind.py +68 -0
- package/scripts/portability_profile_scan.py +53 -0
- package/scripts/pr-body-check.py +263 -0
- package/scripts/program_graph.py +125 -0
- package/scripts/program_graph_parse.py +275 -0
- package/scripts/program_graph_validate.py +256 -0
- package/scripts/program_sync.py +160 -0
- package/scripts/release-delta-guard.mjs +96 -0
- package/scripts/release-delta-guard.test.mjs +53 -0
- package/scripts/test_board_sync_create_idempotency.py +104 -0
- package/scripts/test_dist_kit_smoke.py +199 -0
- package/scripts/test_kit_docs_language_census.py +178 -0
- package/scripts/test_skill_code_review_seed.py +89 -0
- package/scripts/test_skill_frontmatter_lint.py +226 -0
- package/scripts/test_skill_gh_lint.py +124 -0
- package/scripts/test_skill_language_census.py +254 -0
- package/scripts/test_skill_portability_lint.py +773 -0
- package/scripts/test_skill_publish_audit.py +300 -0
- package/scripts/test_skill_selfcontainment_lint.py +255 -0
- package/scripts/test_skill_setup_workflow_seeds.py +200 -0
- package/scripts/test_skill_stale_name_lint.py +126 -0
- package/scripts/test_skill_surface_refs.py +300 -0
- package/scripts/test_skill_trailing_artifact_lint.py +71 -0
- package/scripts/wrapup-land.py +573 -0
- package/src/cli.mjs +70 -0
- package/src/commands/diff.mjs +6 -0
- package/src/commands/init.mjs +59 -0
- package/src/commands/uninstall.mjs +43 -0
- package/src/commands/update.mjs +95 -0
- package/src/lib/atomicWrite.mjs +49 -0
- package/src/lib/bundle.mjs +133 -0
- package/src/lib/hash.mjs +13 -0
- package/src/lib/manifest.mjs +58 -0
- package/src/lib/sentinel.mjs +20 -0
- package/src/lib/settings.mjs +23 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-self-critique
|
|
3
|
+
description: "Use AFTER writing or editing a spec (a `SPEC.md`/`PLAN.md` or any spec/design doc), BEFORE asking the user to review — runs a 12-point structural Self-Critique checklist, fixes issues inline, and emits a visible summary. Enriches each check from a project layer if one is present. Triggers right after a spec has been written. NOT for reviewing finished code/diffs (code-review) — this pass runs on the spec text itself."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Spec Self-Critique
|
|
7
|
+
|
|
8
|
+
A portable, structural self-review pass over a freshly written spec/plan. The **generic 12-point skeleton** below ships as-is; a **project layer** (if present) enriches each point with project-specific incidents, grep patterns, conventions, and extra sub-checks.
|
|
9
|
+
|
|
10
|
+
## When to invoke
|
|
11
|
+
|
|
12
|
+
- After a spec was written/edited (a `SPEC.md` / `PLAN.md`, or a spec/design doc), BEFORE the user-review gate.
|
|
13
|
+
|
|
14
|
+
## Step 0 — Project-layer probe
|
|
15
|
+
|
|
16
|
+
First, check whether a project layer exists: from the project root, look for `docs/agents/skills/spec-self-critique.md`.
|
|
17
|
+
|
|
18
|
+
- **Present** → **full pass**: run the 12 generic checks AND apply the per-point enrichment that file defines (incidents, grep patterns, extra sub-checks).
|
|
19
|
+
- **Absent** → **base pass**: run the 12 generic checks only, then add this one-line warning to the summary:
|
|
20
|
+
> ⚠ No project layer found (`docs/agents/skills/spec-self-critique.md`) — only the generic base checks ran. `/setup-workflow` creates the layer; it fills in project-specific content via `/retro`.
|
|
21
|
+
|
|
22
|
+
> **Routing — keep this skeleton clean.** Project-specific checks, incidents, and grep patterns belong in the project layer (`docs/agents/skills/spec-self-critique.md`), **NOT here**. `/retro` appends new project-specific lore to the project layer, never into this generic skeleton.
|
|
23
|
+
|
|
24
|
+
## Altitude — a portable kit concept
|
|
25
|
+
|
|
26
|
+
The generic skeleton recognizes two spec altitudes: a **Feature-PRD** (the
|
|
27
|
+
default — every point above and below assumes this) and a **Program-PRD**
|
|
28
|
+
(marked `<!-- prd: program -->`, produced by the kit's `scale-check` →
|
|
29
|
+
`grill-with-docs` → `to-prd` program route — a native anchor over a
|
|
30
|
+
multi-wave `## Wellenplan`). This is a **portable kit concept**, not a
|
|
31
|
+
project-specific rule, so it stays **in this generic skeleton** — the
|
|
32
|
+
"project-specific → project layer" routing rule above is about *this
|
|
33
|
+
project's* incidents/grep patterns, not about a kit-wide spec shape the
|
|
34
|
+
skill itself already knows.
|
|
35
|
+
|
|
36
|
+
Two points read differently at Program-Altitude — both get a dedicated
|
|
37
|
+
fixture in `scenarios.md`:
|
|
38
|
+
|
|
39
|
+
- **Point 3 (Scope)** at `prd: program`: scope is not "small enough for one
|
|
40
|
+
plan" — it is "each wave holds 2–7 slices; the program splits via its wave
|
|
41
|
+
plan, the PRD itself is never split."
|
|
42
|
+
- **Point 12 (Vertical-slice completeness)** at `prd: program`: reads against
|
|
43
|
+
**Wellenplan rows**, not a slice/PR table — each wave is an outcome
|
|
44
|
+
cut/tracer, never a layer cut ("a backend wave" is the anti-pattern); an
|
|
45
|
+
enabler wave names the half it cuts off and the outcome wave that closes it.
|
|
46
|
+
|
|
47
|
+
Every other point runs unchanged at either altitude.
|
|
48
|
+
|
|
49
|
+
## How to invoke
|
|
50
|
+
|
|
51
|
+
Read the most recently written/edited spec in full. Walk the 12-point checklist (points 1–12; **8b/8c are sub-checks of point 8**, not main points). Per point:
|
|
52
|
+
|
|
53
|
+
1. Decide: does the spec trigger this rule?
|
|
54
|
+
2. If yes: run the check.
|
|
55
|
+
3. If violated: fix the spec inline (Edit tool, not "TODO later").
|
|
56
|
+
4. Note the correction for the summary.
|
|
57
|
+
|
|
58
|
+
End with a visible summary in the chat:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
Self-Critique complete — <N> corrections:
|
|
62
|
+
- Point <X>: <short description>
|
|
63
|
+
- ...
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
or, if none were needed: `Self-Critique complete — no corrections needed.` (append the Step-0 layer-absent warning if it applied). THEN ask the user-review question.
|
|
67
|
+
|
|
68
|
+
## The 12-point checklist
|
|
69
|
+
|
|
70
|
+
**1. Placeholder scan + empirical re-check**
|
|
71
|
+
Scan for `TBD` / `TODO` / "später" / "fill in details" / vague requirements → fix inline. Plus, when applicable:
|
|
72
|
+
- **Cited counts** ("24 call-sites: 6 start, 8 succeed, …") → re-verify each empirically (`grep`); recon from the brainstorming phase can be stale, and wrong numbers mislead the effort estimate.
|
|
73
|
+
- **Folder move / rename** → broaden the caller-audit grep (search the path-segment without a `from …`-anchor, to catch mocks, dynamic imports, type-only imports) AND require a typecheck-backstop step right after the move (path-depth breaks inside the moved files aren't found by a caller grep).
|
|
74
|
+
- **Cited prior diagnosis** (issue body, investigation, memory snapshot, earlier plan) → verify each core claim empirically before finalizing. Such artifacts are hypotheses, not validated facts; drift compounds if left unchecked.
|
|
75
|
+
- **Risk mitigation** → it must name a concretely checkable **output string**, not just an action ("rowCount is 2307" is checkable; "rowCount > 1000" is a claim about a claim).
|
|
76
|
+
Skip only if none of these apply.
|
|
77
|
+
|
|
78
|
+
**2. Internal consistency**
|
|
79
|
+
Do sections contradict each other? Does the architecture match the feature description? Do numbers/orders agree between tables and prose?
|
|
80
|
+
|
|
81
|
+
**3. Scope check**
|
|
82
|
+
Small enough for **one** implementation plan, or must it split into sub-specs?
|
|
83
|
+
**At Program-Altitude** (`prd: program`) this reads differently — see
|
|
84
|
+
"Altitude" above: each wave holds 2–7 slices, the program splits via its wave
|
|
85
|
+
plan, and the PRD itself is never split.
|
|
86
|
+
|
|
87
|
+
**4. Ambiguity check**
|
|
88
|
+
Could a requirement be read two ways? If so, pick one interpretation and make it explicit.
|
|
89
|
+
|
|
90
|
+
**5. State transitions**
|
|
91
|
+
*Trigger:* the spec mentions "Live", "SSE", "WebSocket", "Polling", "EventSource", "Realtime", "Stream", or incoming updates.
|
|
92
|
+
*Check:* are all transitions played through — `idle → running → awaiting_decision → succeeded | failed` — plus `mid-flight reload`, `multi-tab parallel`, `connection-loss + reconnect`, `aborted`?
|
|
93
|
+
|
|
94
|
+
**6. Convention scope**
|
|
95
|
+
*Trigger:* the spec introduces a new pattern, convention, single-entry broker, wrapper, or consistency layer.
|
|
96
|
+
*Check:* is it explicitly scoped — applied app-wide vs only touched surfaces? Does the spec require a follow-up item for the untouched surfaces (in the spec body, not retroactively)?
|
|
97
|
+
|
|
98
|
+
**7. User walk-through**
|
|
99
|
+
*Trigger:* the spec has UI stages, wizards, or multi-step user interactions.
|
|
100
|
+
*Check:* are the sub-steps per UI stage walked through — what does the user see at each stage — not just the data model?
|
|
101
|
+
|
|
102
|
+
**8. Project-convention check**
|
|
103
|
+
*Trigger:* always.
|
|
104
|
+
*How:* iterate your project's documented conventions. Default location: from the project root, `docs/conventions/*.md`. For each convention file that carries a `## Self-Critique-Check` block (format: **Trigger / Check / Korrektur**):
|
|
105
|
+
1. Evaluate its Trigger against the current spec.
|
|
106
|
+
2. On match: run its Check. On violation: fix the spec inline + note it.
|
|
107
|
+
3. A convention with no such block → skip it non-blocking + collect a warning ("convention `<file>` is missing a `## Self-Critique-Check` block").
|
|
108
|
+
No conventions directory / no blocks (e.g. a fresh project) → **soft skip** (non-blocking). Emit collected warnings at the end of the pass.
|
|
109
|
+
|
|
110
|
+
**8b. Marker-wording check**
|
|
111
|
+
*Trigger:* a convention mandates a header marker comment.
|
|
112
|
+
*Check:* the spec's marker must be copied **verbatim** from the convention, not paraphrased. Open the convention, compare the marker block 1:1, fix inline on any drift (drift makes the convention worthless as the single source of truth).
|
|
113
|
+
|
|
114
|
+
**8c. Structurally-trivial post-invariant**
|
|
115
|
+
*Trigger:* the spec has aggregation functions with post-invariants.
|
|
116
|
+
*Check:* for each post-invariant, can it ever fire under the current code path? Play the path through (all branches, all math ranges). If it is structurally impossible to violate under the current code, drop it or replace it with a property test (a property fires on every regression; a structurally-true post never does).
|
|
117
|
+
|
|
118
|
+
**9. Primitive recon (DRY)**
|
|
119
|
+
*Trigger:* the spec introduces a new UI primitive, hook, component, helper, repo function, or service — OR substantially touches (≥30 LOC) an existing file.
|
|
120
|
+
*Check:* did you `grep`/`ls` for an existing primitive/helper with overlapping responsibility (including in callers/pages, not just component dirs)? If one exists → switch the spec to reuse it. If a pattern is replicated 3+× → require a helper-extraction acceptance-criterion.
|
|
121
|
+
|
|
122
|
+
**10. User-action feedback**
|
|
123
|
+
*Trigger:* the spec describes a user action (click, submit, import, bulk op, setup run) that triggers a ≥2-step process.
|
|
124
|
+
*Check:* does the spec document, per sub-step, what the user sees on screen — progress, retry/throttle visibility (esp. external APIs or long waits), mode-switch visibility (e.g. bulk → per-item fallback), and a "why is this counter stalled" hint for per-resource paths?
|
|
125
|
+
|
|
126
|
+
**11. Live-verify bug-plausibility**
|
|
127
|
+
*Trigger:* the spec has a live-verify block with a bug-variant + an expected property failure.
|
|
128
|
+
*Check:* play the bug-variant through — does it actually change the target property (e.g. does it break the asserted ordering/monotonicity)? Is only one direction sharp? If the variant does NOT violate the property, pick a variant that does and fix the spec inline (a wrong variant yields a passing live-verify that catches no real regression).
|
|
129
|
+
|
|
130
|
+
**12. Vertical-slice completeness**
|
|
131
|
+
*Trigger:* the spec/PRD has a slice/phase table or splits into multiple PRs.
|
|
132
|
+
*Check:*
|
|
133
|
+
- (a) each *user-facing* slice = a tracer bullet "`<user action> → <visible result>`", **not** a layer name ("config UI", "backend resolver");
|
|
134
|
+
- (b) each byte-neutral/infra slice names its **omitted half** + the **closing follow-up slice** (otherwise the connecting path falls between two slices);
|
|
135
|
+
- (c) the first outcome slice after ≥1 prep slice is traced against the code with a concrete value (`grep`/Read), not trusted as "config-driven".
|
|
136
|
+
*Correction:* reword/split a layer-only slice; pull in a new slice for an uncovered half.
|
|
137
|
+
**At Program-Altitude** (`prd: program`), apply (a)–(c) analogously to
|
|
138
|
+
**Wellenplan rows** instead of a slice table — see "Altitude" above: each wave
|
|
139
|
+
is an outcome cut/tracer, never a layer cut, and an enabler wave names both
|
|
140
|
+
the half it omits and the outcome wave that closes it.
|
|
141
|
+
|
|
142
|
+
**Gate home.** This skill runs **automatically as the mandatory last step of `to-prd`** (on the Draft-PRD) — the visible two-line summary is required **before** the user-review question. The **slice-completeness gate (point 12)** additionally sits in `to-issues`. The skill stays **standalone-callable** for manual spec/PLAN reviews.
|
|
143
|
+
|
|
144
|
+
## Anti-patterns of this skill
|
|
145
|
+
|
|
146
|
+
- **"Skipped self-critique because the spec is small"** — it runs on mini-specs too. Cost: 2–3 min; payoff: structural bugs caught in the spec phase.
|
|
147
|
+
- **"Made corrections silently inline, no summary"** — the visible summary is part of acceptance. A silent pass is indistinguishable from a skipped one.
|
|
148
|
+
- **"Improvised what a convention would say"** — if a convention file has no `## Self-Critique-Check` block, skip it non-blocking + collect a warning. Do not invent the rule.
|
|
149
|
+
|
|
150
|
+
## Verification fixtures
|
|
151
|
+
|
|
152
|
+
See `scenarios.md` in this skill dir for project-neutral fixtures (one per check) — walk them when refactoring the checklist. If a project layer is present, it may carry richer, project-specific scenarios.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Verification fixtures — spec-self-critique (generic)
|
|
2
|
+
|
|
3
|
+
**Fixtures only — no new rules here.** Each fragment is a synthetic, project-neutral spec snippet that violates **exactly one** check. When the skill works, it should trigger the named point and name it in the summary. Walk these when refactoring the checklist. New *project-specific* checks/scenarios go in the project layer (`docs/agents/skills/spec-self-critique.md`), never here.
|
|
4
|
+
|
|
5
|
+
## Point 1 — placeholder / unverified count
|
|
6
|
+
> "Rename `oldUtil` → `newUtil` across the 9 call-sites and update imports."
|
|
7
|
+
|
|
8
|
+
Violates 1 (cited count not re-verified; rename = caller-audit + typecheck-backstop). Expected: *"Punkt 1: '9 call-sites' nicht empirisch belegt — grep + breiter Caller-Audit + Typecheck-Backstop nach dem Move ergänzt."*
|
|
9
|
+
|
|
10
|
+
## Point 2 — internal consistency
|
|
11
|
+
> "Section A: the cache TTL is 60s. Section B's diagram labels the same cache 600s."
|
|
12
|
+
|
|
13
|
+
Violates 2. Expected: *"Punkt 2: widersprüchliche TTL (60s vs 600s) — vereinheitlicht."*
|
|
14
|
+
|
|
15
|
+
## Point 3 — scope
|
|
16
|
+
> "This spec covers: new auth provider, a billing rewrite, a dashboard redesign, and a data migration."
|
|
17
|
+
|
|
18
|
+
Violates 3. Expected: *"Punkt 3: zu groß für einen Plan — in Sub-Specs zerlegen."*
|
|
19
|
+
|
|
20
|
+
## Point 3 (Program-Altitude) — a wave outgrows the band
|
|
21
|
+
> "`<!-- prd: program -->` Program-PRD. Wellenplan: Welle 1 covers 9 slices
|
|
22
|
+
> across two subsystems; Welle 2 covers 3 slices."
|
|
23
|
+
|
|
24
|
+
Violates 3 at Program-Altitude (a wave over the 2–7 slice band needs
|
|
25
|
+
splitting into two waves; the PRD itself stays unsplit). Expected: *"Punkt 3
|
|
26
|
+
(Programm-Altitude): Welle 1 mit 9 Slices sprengt den 2–7-Rahmen — in zwei
|
|
27
|
+
Wellen aufgeteilt; das PRD selbst bleibt ungesplittet."*
|
|
28
|
+
|
|
29
|
+
## Point 4 — ambiguity
|
|
30
|
+
> "When the request fails, retry it a few times before giving up."
|
|
31
|
+
|
|
32
|
+
Violates 4. Expected: *"Punkt 4: 'a few times' mehrdeutig — auf konkrete Zahl + Backoff festgelegt."*
|
|
33
|
+
|
|
34
|
+
## Point 5 — state transitions
|
|
35
|
+
> "New live progress indicator: on start a spinner appears, on finish a green check."
|
|
36
|
+
|
|
37
|
+
Violates 5 (only `running → succeeded`). Expected: *"Punkt 5: Live-Feature, nur Erfolgs-Pfad — failed / reload / multi-tab / connection-loss / aborted ergänzt."*
|
|
38
|
+
|
|
39
|
+
## Point 6 — convention scope
|
|
40
|
+
> "Introduce a `withRetry()` wrapper. Apply it in `serviceA.fetch()` and `serviceB.fetch()`."
|
|
41
|
+
|
|
42
|
+
Violates 6 (no app-wide-vs-touched scope, no follow-up). Expected: *"Punkt 6: Pattern-Scope nicht erklärt — explizit nur diese 2 + Followup für den Rest."*
|
|
43
|
+
|
|
44
|
+
## Point 7 — user walk-through
|
|
45
|
+
> "New multi-step onboarding wizard at `/onboarding`. Data model: a 3-field form posted to `/api/onboard`."
|
|
46
|
+
|
|
47
|
+
Violates 7 (only data model). Expected: *"Punkt 7: kein User-Walk-Through der Wizard-Stufen — pro Stufe ergänzt, was der User sieht."*
|
|
48
|
+
|
|
49
|
+
## Point 8 — project convention (+ 8b marker, 8c trivial post)
|
|
50
|
+
> "Refactor an aggregation module. Pre-invariant: `typeof rows[0]?.id === 'string'` (already guaranteed by the typed signature). Post-invariant: `out.length === rows.length` where the body is `for (const r of rows) out.push(...)`."
|
|
51
|
+
|
|
52
|
+
Violates 8c (post structurally guaranteed by the loop) + 8b-style trivial pre. Expected: *"Punkt 8c: Post strukturell durch den Loop garantiert — gestrichen / Property-Test; triviale Pre entfernt."* (With a project layer present, point 8 also iterates that project's `## Self-Critique-Check` convention blocks.)
|
|
53
|
+
|
|
54
|
+
## Point 9 — primitive recon (DRY)
|
|
55
|
+
> "Build a new `FilterableList` component with sort + filter."
|
|
56
|
+
|
|
57
|
+
Violates 9 (no recon for an existing list/table primitive). Expected: *"Punkt 9: neues Primitiv ohne DRY-Recon — auf Wiederverwendung des Bestehenden geprüft/umgestellt."*
|
|
58
|
+
|
|
59
|
+
## Point 10 — user-action feedback
|
|
60
|
+
> "A 'Rebuild caches' button kicks off a 4-stage backend job (~2 min). On error: a toast."
|
|
61
|
+
|
|
62
|
+
Violates 10 (no per-step feedback). Expected: *"Punkt 10: ≥2-Schritt-Prozess ohne Sub-Step-Feedback — Schritt-Labels / Progress / Retry- bzw. Modus-Sichtbarkeit ergänzt."*
|
|
63
|
+
|
|
64
|
+
## Point 11 — live-verify bug-plausibility
|
|
65
|
+
> "Live-verify for percentile indices. Bug-variant: change `p80 = 0.8*n` to `0.6*n`. Expect the ordering check `p10 < p50 < p80 < p90` to fire."
|
|
66
|
+
|
|
67
|
+
Violates 11 (`0.5 < 0.6 < 0.9` stays monotone → property does NOT fire). Expected: *"Punkt 11: Variante erhält die Monotonie — Property feuert nicht; korrekte Variante (z.B. 0.8→0.95, bricht p80>p90) gewählt."*
|
|
68
|
+
|
|
69
|
+
## Point 12 — vertical-slice completeness
|
|
70
|
+
> "Slices: 1) Config UI · 2) Backend resolver · 3) Wire-up."
|
|
71
|
+
|
|
72
|
+
Violates 12 (layer names, no tracer-bullet, no traced outcome slice). Expected: *"Punkt 12: Layer-Namen statt Tracer-Bullets — als '<Aktion> → <sichtbares Ergebnis>' umformuliert; erste Outcome-Slice gegen Code getrace't."*
|
|
73
|
+
|
|
74
|
+
## Point 12 (Program-Altitude) — layer-cut waves
|
|
75
|
+
> "`<!-- prd: program -->` Program-PRD. Wellenplan: Welle 3 — 'Backend-Migration'. Welle 4 — 'Frontend-Rollout'."
|
|
76
|
+
|
|
77
|
+
Violates 12 at Program-Altitude (layer-cut waves, not outcome tracers; no
|
|
78
|
+
enabler/closing pairing named). Expected: *"Punkt 12 (Programm-Altitude):
|
|
79
|
+
'Backend-Migration'/'Frontend-Rollout' sind Layer-Schnitte, keine
|
|
80
|
+
Outcome-Tracer — Welle 3 als Enabler benannt (abgeschnittene Hälfte:
|
|
81
|
+
sichtbares Frontend-Verhalten) mit Welle 4 als schließender Outcome-Welle,
|
|
82
|
+
oder zu echten Outcome-Wellen umgeschnitten."*
|
|
@@ -0,0 +1,120 @@
|
|
|
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
|
+
See [tests.md](tests.md) for examples and [mocking.md](mocking.md) for mocking guidelines.
|
|
17
|
+
|
|
18
|
+
## Anti-Pattern: Horizontal Slices
|
|
19
|
+
|
|
20
|
+
**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."
|
|
21
|
+
|
|
22
|
+
This produces **crap tests**:
|
|
23
|
+
|
|
24
|
+
- Tests written in bulk test _imagined_ behavior, not _actual_ behavior
|
|
25
|
+
- You end up testing the _shape_ of things (data structures, function signatures) rather than user-facing behavior
|
|
26
|
+
- Tests become insensitive to real changes - they pass when behavior breaks, fail when behavior is fine
|
|
27
|
+
- You outrun your headlights, committing to test structure before understanding the implementation
|
|
28
|
+
|
|
29
|
+
**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.
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
WRONG (horizontal):
|
|
33
|
+
RED: test1, test2, test3, test4, test5
|
|
34
|
+
GREEN: impl1, impl2, impl3, impl4, impl5
|
|
35
|
+
|
|
36
|
+
RIGHT (vertical):
|
|
37
|
+
RED→GREEN: test1→impl1
|
|
38
|
+
RED→GREEN: test2→impl2
|
|
39
|
+
RED→GREEN: test3→impl3
|
|
40
|
+
...
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Workflow
|
|
44
|
+
|
|
45
|
+
### 1. Planning
|
|
46
|
+
|
|
47
|
+
**First, mark the ticket active on the board.** When a ticket was provided (you're on a `feat/<#>-`/`fix/<#>-` branch), run once at TDD pickup:
|
|
48
|
+
|
|
49
|
+
<!-- mirror-xform:start codex-board-sync-command -->
|
|
50
|
+
```
|
|
51
|
+
python3 "$CLAUDE_PROJECT_DIR/.claude/hooks/sync-board-status.py"
|
|
52
|
+
```
|
|
53
|
+
<!-- mirror-xform:end -->
|
|
54
|
+
|
|
55
|
+
It parses the issue # from the current branch and moves the board item to the profile's in-progress status (`fields.status.roles.inProgress`; only from the idea/triaged/spec roles, idempotent). No ticket / no parseable branch → it's a silent no-op, so this is safe to run unconditionally. This closes the gap where the SessionStart sync already ran on `main` before the worktree existed, leaving the board stale.
|
|
56
|
+
|
|
57
|
+
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.
|
|
58
|
+
|
|
59
|
+
Before writing any code:
|
|
60
|
+
|
|
61
|
+
- [ ] Confirm with user what interface changes are needed
|
|
62
|
+
- [ ] Confirm with user which behaviors to test (prioritize)
|
|
63
|
+
- [ ] Identify opportunities for [deep modules](deep-modules.md) (small interface, deep implementation)
|
|
64
|
+
- [ ] Design interfaces for [testability](interface-design.md)
|
|
65
|
+
- [ ] List the behaviors to test (not implementation steps)
|
|
66
|
+
- [ ] Get user approval on the plan
|
|
67
|
+
|
|
68
|
+
Ask: "What should the public interface look like? Which behaviors are most important to test?"
|
|
69
|
+
|
|
70
|
+
**You can't test everything.** Confirm with the user exactly which behaviors matter most. Focus testing effort on critical paths and complex logic, not every possible edge case.
|
|
71
|
+
|
|
72
|
+
### 2. Tracer Bullet
|
|
73
|
+
|
|
74
|
+
Write ONE test that confirms ONE thing about the system:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
RED: Write test for first behavior → test fails
|
|
78
|
+
GREEN: Write minimal code to pass → test passes
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
This is your tracer bullet - proves the path works end-to-end.
|
|
82
|
+
|
|
83
|
+
### 3. Incremental Loop
|
|
84
|
+
|
|
85
|
+
For each remaining behavior:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
RED: Write next test → fails
|
|
89
|
+
GREEN: Minimal code to pass → passes
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Rules:
|
|
93
|
+
|
|
94
|
+
- One test at a time
|
|
95
|
+
- Only enough code to pass current test
|
|
96
|
+
- Don't anticipate future tests
|
|
97
|
+
- Keep tests focused on observable behavior
|
|
98
|
+
|
|
99
|
+
### 4. Refactor
|
|
100
|
+
|
|
101
|
+
After all tests pass, look for [refactor candidates](refactoring.md):
|
|
102
|
+
|
|
103
|
+
- [ ] Extract duplication
|
|
104
|
+
- [ ] Deepen modules (move complexity behind simple interfaces)
|
|
105
|
+
- [ ] Apply SOLID principles where natural
|
|
106
|
+
- [ ] Consider what new code reveals about existing code
|
|
107
|
+
- [ ] Run tests after each refactor step
|
|
108
|
+
|
|
109
|
+
**Never refactor while RED.** Get to GREEN first.
|
|
110
|
+
|
|
111
|
+
## Checklist Per Cycle
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
[ ] Test describes behavior, not implementation
|
|
115
|
+
[ ] Test uses public interface only
|
|
116
|
+
[ ] Test would survive internal refactor
|
|
117
|
+
[ ] Code is minimal for this test
|
|
118
|
+
[ ] No speculative features added
|
|
119
|
+
[ ] Wave slice: a flipped/new assumption affecting an unbuilt sibling issue → log it to ANNAHMEN.md (worktree root; wrapup Step 0c reads it)
|
|
120
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Third-Party Notices
|
|
2
|
+
|
|
3
|
+
This skill is adapted from **Matt Pocock's skills**
|
|
4
|
+
(https://github.com/mattpocock/skills), `skills/engineering/tdd` @ d574778, Copyright (c) 2026 Matt Pocock,
|
|
5
|
+
used under the MIT License. Locally adapted (fork-and-own); see PROVENANCE.md.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2026 Matt Pocock
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Deep Modules
|
|
2
|
+
|
|
3
|
+
From "A Philosophy of Software Design":
|
|
4
|
+
|
|
5
|
+
**Deep module** = small interface + lots of implementation
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────────────┐
|
|
9
|
+
│ Small Interface │ ← Few methods, simple params
|
|
10
|
+
├─────────────────────┤
|
|
11
|
+
│ │
|
|
12
|
+
│ │
|
|
13
|
+
│ Deep Implementation│ ← Complex logic hidden
|
|
14
|
+
│ │
|
|
15
|
+
│ │
|
|
16
|
+
└─────────────────────┘
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Shallow module** = large interface + little implementation (avoid)
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
┌─────────────────────────────────┐
|
|
23
|
+
│ Large Interface │ ← Many methods, complex params
|
|
24
|
+
├─────────────────────────────────┤
|
|
25
|
+
│ Thin Implementation │ ← Just passes through
|
|
26
|
+
└─────────────────────────────────┘
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
When designing interfaces, ask:
|
|
30
|
+
|
|
31
|
+
- Can I reduce the number of methods?
|
|
32
|
+
- Can I simplify the parameters?
|
|
33
|
+
- Can I hide more complexity inside?
|
|
@@ -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,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
|
+
```
|