@imix-js/taproot 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/README.md +88 -0
  2. package/dist/adapters/index.d.ts +20 -0
  3. package/dist/adapters/index.js +452 -0
  4. package/dist/adapters/index.js.map +1 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.js +40 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/commands/acceptance-check.d.ts +26 -0
  9. package/dist/commands/acceptance-check.js +213 -0
  10. package/dist/commands/acceptance-check.js.map +1 -0
  11. package/dist/commands/check-orphans.d.ts +8 -0
  12. package/dist/commands/check-orphans.js +157 -0
  13. package/dist/commands/check-orphans.js.map +1 -0
  14. package/dist/commands/commithook.d.ts +15 -0
  15. package/dist/commands/commithook.js +389 -0
  16. package/dist/commands/commithook.js.map +1 -0
  17. package/dist/commands/coverage.d.ts +41 -0
  18. package/dist/commands/coverage.js +390 -0
  19. package/dist/commands/coverage.js.map +1 -0
  20. package/dist/commands/dod.d.ts +13 -0
  21. package/dist/commands/dod.js +141 -0
  22. package/dist/commands/dod.js.map +1 -0
  23. package/dist/commands/init.d.ts +14 -0
  24. package/dist/commands/init.js +378 -0
  25. package/dist/commands/init.js.map +1 -0
  26. package/dist/commands/link-commits.d.ts +12 -0
  27. package/dist/commands/link-commits.js +126 -0
  28. package/dist/commands/link-commits.js.map +1 -0
  29. package/dist/commands/overview.d.ts +6 -0
  30. package/dist/commands/overview.js +192 -0
  31. package/dist/commands/overview.js.map +1 -0
  32. package/dist/commands/plan.d.ts +23 -0
  33. package/dist/commands/plan.js +167 -0
  34. package/dist/commands/plan.js.map +1 -0
  35. package/dist/commands/sync-check.d.ts +8 -0
  36. package/dist/commands/sync-check.js +118 -0
  37. package/dist/commands/sync-check.js.map +1 -0
  38. package/dist/commands/update.d.ts +7 -0
  39. package/dist/commands/update.js +309 -0
  40. package/dist/commands/update.js.map +1 -0
  41. package/dist/commands/validate-format.d.ts +8 -0
  42. package/dist/commands/validate-format.js +93 -0
  43. package/dist/commands/validate-format.js.map +1 -0
  44. package/dist/commands/validate-structure.d.ts +8 -0
  45. package/dist/commands/validate-structure.js +29 -0
  46. package/dist/commands/validate-structure.js.map +1 -0
  47. package/dist/core/config.d.ts +6 -0
  48. package/dist/core/config.js +86 -0
  49. package/dist/core/config.js.map +1 -0
  50. package/dist/core/configuration.d.ts +7 -0
  51. package/dist/core/configuration.js +112 -0
  52. package/dist/core/configuration.js.map +1 -0
  53. package/dist/core/dod-runner.d.ts +20 -0
  54. package/dist/core/dod-runner.js +233 -0
  55. package/dist/core/dod-runner.js.map +1 -0
  56. package/dist/core/dor-runner.d.ts +18 -0
  57. package/dist/core/dor-runner.js +156 -0
  58. package/dist/core/dor-runner.js.map +1 -0
  59. package/dist/core/fs-walker.d.ts +5 -0
  60. package/dist/core/fs-walker.js +74 -0
  61. package/dist/core/fs-walker.js.map +1 -0
  62. package/dist/core/git.d.ts +24 -0
  63. package/dist/core/git.js +76 -0
  64. package/dist/core/git.js.map +1 -0
  65. package/dist/core/impl-reader.d.ts +8 -0
  66. package/dist/core/impl-reader.js +39 -0
  67. package/dist/core/impl-reader.js.map +1 -0
  68. package/dist/core/language.d.ts +39 -0
  69. package/dist/core/language.js +159 -0
  70. package/dist/core/language.js.map +1 -0
  71. package/dist/core/markdown-parser.d.ts +3 -0
  72. package/dist/core/markdown-parser.js +37 -0
  73. package/dist/core/markdown-parser.js.map +1 -0
  74. package/dist/core/reporter.d.ts +3 -0
  75. package/dist/core/reporter.js +33 -0
  76. package/dist/core/reporter.js.map +1 -0
  77. package/dist/templates/index.d.ts +4 -0
  78. package/dist/templates/index.js +126 -0
  79. package/dist/templates/index.js.map +1 -0
  80. package/dist/validators/format-rules.d.ts +10 -0
  81. package/dist/validators/format-rules.js +238 -0
  82. package/dist/validators/format-rules.js.map +1 -0
  83. package/dist/validators/structure-rules.d.ts +10 -0
  84. package/dist/validators/structure-rules.js +94 -0
  85. package/dist/validators/structure-rules.js.map +1 -0
  86. package/dist/validators/types.d.ts +68 -0
  87. package/dist/validators/types.js +2 -0
  88. package/dist/validators/types.js.map +1 -0
  89. package/docs/agents.md +88 -0
  90. package/docs/architecture.md +53 -0
  91. package/docs/cli.md +226 -0
  92. package/docs/concepts.md +268 -0
  93. package/docs/configuration.md +255 -0
  94. package/docs/demo.svg +111 -0
  95. package/docs/patterns.md +118 -0
  96. package/docs/security.md +95 -0
  97. package/docs/workflows.md +151 -0
  98. package/languages/de.json +20 -0
  99. package/languages/en.json +20 -0
  100. package/languages/es.json +20 -0
  101. package/languages/fr.json +20 -0
  102. package/languages/ja.json +20 -0
  103. package/languages/pt.json +20 -0
  104. package/package.json +54 -0
  105. package/skills/analyse-change.md +101 -0
  106. package/skills/behaviour.md +179 -0
  107. package/skills/bug.md +70 -0
  108. package/skills/commit.md +99 -0
  109. package/skills/decompose.md +101 -0
  110. package/skills/discover.md +392 -0
  111. package/skills/grill-me.md +65 -0
  112. package/skills/guide.md +118 -0
  113. package/skills/implement.md +149 -0
  114. package/skills/ineed.md +147 -0
  115. package/skills/intent.md +104 -0
  116. package/skills/plan.md +63 -0
  117. package/skills/promote.md +69 -0
  118. package/skills/refine.md +78 -0
  119. package/skills/research.md +122 -0
  120. package/skills/review-all.md +92 -0
  121. package/skills/review.md +80 -0
  122. package/skills/status.md +103 -0
  123. package/skills/sweep.md +89 -0
  124. package/skills/trace.md +151 -0
package/docs/cli.md ADDED
@@ -0,0 +1,226 @@
1
+ # CLI Reference
2
+
3
+ The Taproot CLI handles setup, validation, and reporting. It does not generate content — that's what the agent skills do. The rule of thumb: use `/tr-*` commands when you want the AI to write or update documents; use `taproot` CLI commands to validate, report, and check structural integrity.
4
+
5
+ ---
6
+
7
+ ## Setup
8
+
9
+ ### `taproot init`
10
+
11
+ ```bash
12
+ taproot init [--with-hooks] [--with-ci github|gitlab] [--with-skills] [--agent claude|cursor|copilot|windsurf|generic|all]
13
+ ```
14
+
15
+ Initializes Taproot in the current directory. Creates `taproot/` and `.taproot/settings.yaml` if they don't exist, then installs whichever integrations you request.
16
+
17
+ | Option | Effect |
18
+ |--------|--------|
19
+ | `--with-hooks` | Installs `.git/hooks/pre-commit` running `taproot commithook` |
20
+ | `--with-ci github` | Generates `.github/workflows/taproot.yml` with validate-structure, validate-format, and check-orphans |
21
+ | `--with-ci gitlab` | Generates a `taproot-validate` job in `.gitlab-ci.yml` |
22
+ | `--with-skills` | Copies skill definitions to `.taproot/skills/`. Implied by `--agent claude` — only needed if you want skills without a Claude adapter. |
23
+ | `--agent <name>` | Generates agent adapter files (see [Agent Setup](agents.md)) |
24
+
25
+ Running `taproot init` again on an existing project is safe — it skips files that already exist and reports `exists` for each.
26
+
27
+ ### `taproot update`
28
+
29
+ ```bash
30
+ taproot update [--with-hooks]
31
+ ```
32
+
33
+ Refreshes installed agent adapters and skills to the current version. Run this after upgrading the `taproot` package.
34
+
35
+ The update command also:
36
+ - Removes stale artefacts from older Taproot layouts (e.g., the pre-v0.1 `taproot/skills/` directory)
37
+ - Refreshes `.taproot/docs/` with the current taproot documentation (patterns, architecture, security, etc.) so agent skills have up-to-date reference material
38
+ - Runs a cross-link refresh: adds missing `## Behaviours <!-- taproot-managed -->` sections to `intent.md` files and `## Implementations <!-- taproot-managed -->` sections to `usecase.md` files, then appends any missing child links and prunes any links to non-existent files
39
+ - Migrates old `taproot validate-structure` / `taproot validate-format` pre-commit hooks to the newer `taproot commithook` format
40
+
41
+ ---
42
+
43
+ ## Validation
44
+
45
+ ### `taproot validate-structure`
46
+
47
+ ```bash
48
+ taproot validate-structure [--path taproot/] [--strict]
49
+ ```
50
+
51
+ Verifies that the folder hierarchy follows Taproot's nesting rules:
52
+ - Intent folders contain `intent.md` and optionally behaviour subdirectories
53
+ - Behaviour folders contain `usecase.md` and optionally impl or sub-behaviour subdirectories
54
+ - Implementation folders contain `impl.md` and are always leaves (no children)
55
+ - Folder names match the allowed pattern (lowercase kebab-case)
56
+
57
+ Exit 0 if valid, exit 1 with violations. Use `--strict` to treat warnings as errors.
58
+
59
+ ### `taproot validate-format`
60
+
61
+ ```bash
62
+ taproot validate-format [--path taproot/] [--fix]
63
+ ```
64
+
65
+ Validates that marker files (`intent.md`, `usecase.md`, `impl.md`) conform to their schemas — required sections present, required fields populated, state values from the allowed set. Also checks:
66
+
67
+ - Every `intent.md` with child behaviour folders has a `## Behaviours <!-- taproot-managed -->` section
68
+ - Every `usecase.md` with child impl folders has an `## Implementations <!-- taproot-managed -->` section
69
+ - Every link in those sections resolves to an existing file (detects `STALE_LINK`)
70
+ - `impl.md` `## Behaviour` references point to existing `usecase.md` files
71
+ - Every `usecase.md` with child impl folders has a `## Acceptance Criteria` section (warns `MISSING_ACCEPTANCE_CRITERIA` if absent)
72
+ - Acceptance criterion IDs (`AC-N` and `NFR-N`) are unique within their respective prefix namespace within a file (errors `DUPLICATE_CRITERION_ID` if duplicate)
73
+
74
+ Use `--fix` to scaffold missing section headers automatically. This is safe to run repeatedly — it only adds what's missing, never overwrites existing content.
75
+
76
+ ### `taproot acceptance-check`
77
+
78
+ ```bash
79
+ taproot acceptance-check [--path taproot/] [--tests <dir>] [--format json]
80
+ ```
81
+
82
+ Verifies that every acceptance criterion ID (`AC-N` and `NFR-N`) defined in `## Acceptance Criteria` sections is referenced by at least one test or verification file, and that no test file references a criterion that doesn't exist in any spec.
83
+
84
+ Reports three categories:
85
+ - **Uncovered:** criterion IDs present in specs but not found in any test file (exit 1)
86
+ - **Orphaned:** criterion IDs found in test files but not defined in any `usecase.md` (exit 1)
87
+ - **Missing sections:** `usecase.md` files with child implementations but no `## Acceptance Criteria` section (warning only)
88
+
89
+ | Option | Effect |
90
+ |--------|--------|
91
+ | `--path <path>` | Limit spec collection to a subtree; test files are still scanned globally |
92
+ | `--tests <dir>` | Override test directory (repeatable; defaults to `test/`, `tests/`, `spec/`) |
93
+ | `--format json` | Output a JSON report instead of human-readable text |
94
+
95
+ Criterion ID matching is grep-based: the strings `AC-N` and `NFR-N` must appear verbatim somewhere in the test or verification file. Common patterns: `it('AC-1: ...')`, `describe('AC-3')`, `// covers AC-2`, `// NFR-1 verified by load-test/search.k6.js`. NFR-N references may point to load tests, security scan configs, or manual verification artefacts — any file containing the verbatim ID counts. Deprecated criteria (lines starting with `~~**AC-N` or `~~**NFR-N`) are excluded from the check.
96
+
97
+ ---
98
+
99
+ ## Traceability
100
+
101
+ ### `taproot link-commits`
102
+
103
+ ```bash
104
+ taproot link-commits [--since <date|hash>] [--dry-run]
105
+ ```
106
+
107
+ Scans the git log for commits matching the conventional format (`taproot(<path>): message` or `Taproot: <path>` trailer) and adds them to the `## Commits` section of the corresponding `impl.md`. Use `--dry-run` to preview changes without writing them. Use `--since` to limit the scan to recent commits.
108
+
109
+ ### `taproot check-orphans`
110
+
111
+ ```bash
112
+ taproot check-orphans [--path taproot/] [--include-unimplemented]
113
+ ```
114
+
115
+ Finds broken references across the hierarchy:
116
+ - Source files listed in `impl.md` that no longer exist on disk
117
+ - `## Behaviour` references in `impl.md` that point to non-existent `usecase.md` files
118
+ - Commits in `## Commits` that are not in git history
119
+
120
+ Use `--include-unimplemented` to also report behaviours with no implementations (useful for coverage gaps, not just broken links).
121
+
122
+ ---
123
+
124
+ ## Reporting
125
+
126
+ ### `taproot coverage`
127
+
128
+ ```bash
129
+ taproot coverage [--path taproot/] [--format tree|json|markdown|context]
130
+ ```
131
+
132
+ Summarizes implementation completeness across the hierarchy: how many behaviours have at least one implementation, how many are still planned. The default output is a tree view. Use `--format context` to write `taproot/CONTEXT.md` — a compact summary suitable for pasting into an agent context window.
133
+
134
+ ### `taproot sync-check`
135
+
136
+ ```bash
137
+ taproot sync-check [--path taproot/] [--since <date>]
138
+ ```
139
+
140
+ Detects staleness in two directions:
141
+ - **Code newer than spec:** a source file in `## Source Files` has been modified more recently than the `impl.md` was last verified — the implementation may have drifted from the spec
142
+ - **Spec newer than implementation:** a `usecase.md` was reviewed after the corresponding `impl.md` was completed — the implementation may not reflect the latest spec
143
+
144
+ Run this before a release or when you suspect specs have drifted from the code.
145
+
146
+ ### `taproot overview`
147
+
148
+ ```bash
149
+ taproot overview
150
+ ```
151
+
152
+ Regenerates `taproot/OVERVIEW.md` — a compact hierarchy summary with clickable links to every intent, behaviour, and impl in the tree. The overview is the agent's entry point for orientation: agent skills read it to understand the shape of the project before drilling into individual files.
153
+
154
+ ### `taproot plan`
155
+
156
+ ```bash
157
+ taproot plan [--format tree|json]
158
+ ```
159
+
160
+ Surfaces unimplemented behaviours as work items, ordered by priority (intents with more coverage are prioritized to reach completion). Useful for sprint planning or for orienting a new contributor. The `/tr-plan` skill provides an AI-driven version with more context.
161
+
162
+ ---
163
+
164
+ ## Definition of Done
165
+
166
+ ### `taproot dod`
167
+
168
+ ```bash
169
+ taproot dod [impl-path] [--dry-run]
170
+ taproot dod <impl-path> --resolve <condition> --note "<text>" [--resolve <condition> --note "<text>" ...]
171
+ ```
172
+
173
+ Runs all configured DoD conditions from `.taproot/settings.yaml` against the specified implementation (or all implementations if no path is given). If all conditions pass and an `impl-path` is provided, marks the impl `complete`, records the results in `## DoD Resolutions`, and automatically advances the parent `usecase.md` state from `specified` to `implemented` if it hasn't been already.
174
+
175
+ Use `--resolve`/`--note` to record agent resolutions for agent-driven conditions (e.g. `document-current`, `check-if-affected`, `check-if-affected-by`). Multiple pairs can be supplied in a single invocation — conditions are paired with notes by position.
176
+
177
+ See [Configuration](configuration.md) for how to define DoD conditions.
178
+
179
+ ---
180
+
181
+ ## Pre-commit Hook
182
+
183
+ ### `taproot commithook`
184
+
185
+ ```bash
186
+ taproot commithook
187
+ ```
188
+
189
+ Classifies the staged files and runs the appropriate quality gate. Installed by `taproot init --with-hooks` as the content of `.git/hooks/pre-commit` — you do not call this directly.
190
+
191
+ The hook uses a three-tier classification, where the implementation tier is detected by **reverse-lookup**: the hook walks all `impl.md` files in `taproot/` and builds a map of every source file path listed in their `## Source Files` sections. Any staged file that appears in this map triggers the implementation tier. Files not tracked by any `impl.md` (e.g. `.gitignore`, CI configs) always pass as plain commits.
192
+
193
+ | Staged files | Gate applied |
194
+ |---|---|
195
+ | Only hierarchy files (`intent.md`, `usecase.md`) | `validate-structure` + `validate-format` — hierarchy must be valid before the commit lands |
196
+ | Only `impl.md` (no source files in map) | Definition of Ready — the parent `usecase.md` must be in `specified` state and have `## Flow` and `## Related` sections |
197
+ | Source files found in map + `impl.md` staged | Verify only `## Status` (and `## DoD Resolutions`) changed in `impl.md`; then run DoD |
198
+ | Source files found in map but `impl.md` NOT staged | **Blocked** — "Stage `impl.md` alongside your source files. No implementation commit should proceed without its traceability record." |
199
+ | No tracked source files, no hierarchy or impl files | No checks; commit proceeds |
200
+
201
+ The DoR gate prevents committing an implementation record before the behaviour is fully specified. The DoD gate prevents marking an implementation complete without passing the quality checks defined in `.taproot/settings.yaml`.
202
+
203
+ ---
204
+
205
+ ## Commit Convention
206
+
207
+ Link commits to implementations using the conventional tag format:
208
+
209
+ ```
210
+ taproot(<intent>/<behaviour>/<impl>): <message>
211
+ ```
212
+
213
+ For example:
214
+ ```
215
+ taproot(password-reset/request-reset/email-trigger): add rate limiting
216
+ ```
217
+
218
+ Or use a commit trailer:
219
+
220
+ ```
221
+ fix: handle missing user gracefully
222
+
223
+ Taproot: password-reset/request-reset/email-trigger
224
+ ```
225
+
226
+ After tagging commits, run `taproot link-commits` to update the `## Commits` section of the corresponding `impl.md` automatically. The CI integration (see [Configuration](configuration.md)) can run this on every merge.
@@ -0,0 +1,268 @@
1
+ # Document Types
2
+
3
+ Taproot uses three layers, each represented by a markdown file. Every layer answers a different question:
4
+
5
+ | Layer | File | Question |
6
+ |-------|------|----------|
7
+ | Intent | `intent.md` | *Why* does this feature exist, and for whom? |
8
+ | Behaviour | `usecase.md` | *What* does the system do — observable, testable actions? |
9
+ | Implementation | `impl.md` | *How* is this built — code, tests, design decisions? |
10
+
11
+ This separation matters because the layers evolve at different rates. Business goals (intents) are stable. Specific use cases (behaviours) change when users give feedback. Implementations change every sprint. Keeping them separate means a code refactor doesn't invalidate a behaviour spec, and a scope change doesn't orphan an implementation.
12
+
13
+ ---
14
+
15
+ ## Intent (`intent.md`)
16
+
17
+ An intent captures a business goal — the *why* behind a feature. It is written from a business perspective, not a technical one. The question it answers is: "Why are we building this at all, and how will we know it's done?"
18
+
19
+ An intent contains:
20
+
21
+ - **Goal** — one or two sentences on what outcome the feature delivers for the business or user
22
+ - **Stakeholders** — who cares about this and why; their priorities often conflict, and naming them makes trade-offs explicit
23
+ - **Success Criteria** — concrete, checkable statements; these become the acceptance criteria for the entire feature tree below this intent
24
+ - **Constraints** — scope boundaries: things this feature must not do, or must be compatible with. Constraints are not the same as NFR criteria — they define the intent's boundaries, not quality thresholds on specific behaviours (e.g. "must not reveal whether an email is registered" is a constraint; "all endpoints must respond within 500ms" is a cross-cutting NFR and belongs in `quality-gates/`)
25
+ - **Behaviours** — auto-maintained list of child behaviour specs (managed by `taproot update`)
26
+ - **Status** — lifecycle state: `draft` → `active` → `achieved` → `deprecated`
27
+
28
+ ```markdown
29
+ # Intent: Password Reset Without Support Contact
30
+
31
+ ## Goal
32
+ Enable users to reset their password without contacting support,
33
+ while preventing unauthorized account access.
34
+
35
+ ## Stakeholders
36
+ - Product: Jane — reduce support ticket volume by 30%
37
+ - Security: team — prevent account takeover via reset flow
38
+
39
+ ## Success Criteria
40
+ - [ ] Users can request a reset link via email
41
+ - [ ] Reset links expire after 15 minutes
42
+ - [ ] Failed attempts are rate-limited to prevent brute force
43
+
44
+ ## Constraints
45
+ - Must not reveal whether an email address is registered (prevent enumeration)
46
+
47
+ ## Behaviours <!-- taproot-managed -->
48
+ - [Request Password Reset](./request-reset/usecase.md)
49
+ - [Validate Reset Token](./validate-token/usecase.md)
50
+
51
+ ## Status
52
+ - **State:** active
53
+ - **Created:** 2024-01-15
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Behaviour (`usecase.md`)
59
+
60
+ A behaviour is one observable thing the system does — from the perspective of an actor trying to accomplish something. It is written in UseCase format: preconditions, main flow, alternate flows, postconditions.
61
+
62
+ A behaviour spec is the contract between the intent (business goals) and the implementation (code). If you write the spec well, you can implement it without asking the product owner any more questions. If you write the code first and add a spec later, it reveals whether the code actually does what was intended.
63
+
64
+ A behaviour contains:
65
+
66
+ - **Actor** — who or what triggers this behaviour (a user, a scheduled job, another service)
67
+ - **Preconditions** — what must be true before this can happen
68
+ - **Main Flow** — the steps in the happy path, written as active-voice actions (subject + verb + object)
69
+ - **Alternate Flows** — named variations: what if the user cancels? what if a network call fails?
70
+ - **Postconditions** — what is true after successful completion (these should map to success criteria in the parent intent)
71
+ - **Error Conditions** — unrecoverable failures with specific triggers and specific system responses
72
+ - **Flow** — a Mermaid diagram of the main flow; the human-readable visual contract
73
+ - **Related** — other behaviours that share an actor, have precondition overlap, or must precede/follow this one
74
+ - **Implementations** — auto-maintained list of child impl records (managed by `taproot update`)
75
+ - **Status** — lifecycle state: `proposed` → `specified` → `implemented` → `tested` → `deprecated` (or `deferred` to park without deleting)
76
+
77
+ ```markdown
78
+ # Behaviour: Request Password Reset
79
+
80
+ ## Actor
81
+ Registered user who has forgotten their password
82
+
83
+ ## Preconditions
84
+ - User account exists and is not locked
85
+ - User is not currently logged in
86
+
87
+ ## Main Flow
88
+ 1. User navigates to the login page and clicks "Forgot password"
89
+ 2. User enters their email address and submits
90
+ 3. System validates the email address format
91
+ 4. System checks whether the email exists in the database
92
+ 5. System generates a time-limited reset token and sends an email
93
+ 6. System displays a "Check your email" confirmation page
94
+
95
+ ## Alternate Flows
96
+
97
+ ### Email not registered
98
+ - **Trigger:** Email address not found in the database at step 4
99
+ - **Steps:**
100
+ 1. System displays the same "Check your email" confirmation (prevent enumeration)
101
+ 2. No email is sent
102
+
103
+ ### Rate limit exceeded
104
+ - **Trigger:** More than 3 reset requests from the same email within an hour
105
+ - **Steps:**
106
+ 1. System returns 429 and displays a "Try again later" message
107
+
108
+ ## Postconditions
109
+ - A reset token exists in the database, expiring in 15 minutes
110
+ - A reset email has been sent to the provided address (if the account existed)
111
+
112
+ ## Error Conditions
113
+ - **Email service unavailable:** System shows an inline error, does not expose service details, preserves the form so the user can retry
114
+
115
+ ## Flow
116
+ ```mermaid
117
+ sequenceDiagram
118
+ User->>LoginPage: clicks "Forgot password"
119
+ User->>System: submits email address
120
+ System->>DB: check email exists
121
+ alt email found
122
+ System->>EmailService: send reset token
123
+ System-->>User: "Check your email"
124
+ else email not found
125
+ System-->>User: "Check your email" (same message)
126
+ end
127
+ ```
128
+
129
+ ## Related
130
+ - `./validate-token/usecase.md` — must follow this flow; consumes the token generated here
131
+
132
+ ## Acceptance Criteria
133
+
134
+ **AC-1: Reset email sent**
135
+ - Given the user has a registered account and is not logged in
136
+ - When they submit their email address on the forgot-password form
137
+ - Then the system sends a reset email and displays "Check your email"
138
+
139
+ **AC-2: Unregistered email — same confirmation shown**
140
+ - Given the email address is not registered
141
+ - When the user submits it on the forgot-password form
142
+ - Then the system displays "Check your email" without sending an email
143
+
144
+ **AC-3: Rate limit exceeded**
145
+ - Given the user has already requested 3 resets in the last hour
146
+ - When they submit the form again
147
+ - Then the system returns a 429 response and displays "Try again later"
148
+
149
+ **NFR-1: Reset email delivery time**
150
+ - Given normal mail service conditions
151
+ - When the system sends a password reset email
152
+ - Then the email is delivered within 60 seconds (p95)
153
+ ```
154
+
155
+ NFR criteria (`**NFR-N:**`) express *how well* the system must perform a behaviour — quality constraints with measurable thresholds. They live in the same `## Acceptance Criteria` section, after the functional ACs. The `NFR-` prefix is distinct from `AC-` so IDs never collide.
156
+
157
+ A measurable threshold is one of:
158
+ - A number with a unit (`200ms`, `60%`, `500 concurrent users`)
159
+ - A named standard (`WCAG 2.1 AA`, `PCI DSS 4.0`)
160
+ - A testable boolean condition (`account is locked`, `notification email is sent`)
161
+
162
+ ISO 25010 provides a useful taxonomy for NFR categories: **performance efficiency**, **reliability**, **security**, **maintainability**, **portability**, **compatibility**, **interaction capability**. Teams are not required to use these names — any consistent label works.
163
+
164
+ ```markdown
165
+ ## Implementations <!-- taproot-managed -->
166
+ - [Email Trigger](./email-trigger/impl.md)
167
+
168
+ ## Status
169
+ - **State:** implemented
170
+ - **Created:** 2024-01-20
171
+ - **Last reviewed:** 2024-03-01
172
+ ```
173
+
174
+ ---
175
+
176
+ ## Implementation (`impl.md`)
177
+
178
+ An implementation record is the traceability bridge between a behaviour spec and actual code. It is not a technical spec — that belongs in code comments or ADRs. Instead it answers: "Where in the codebase does this behaviour live, what decisions were made, and is it still current?"
179
+
180
+ An implementation contains:
181
+
182
+ - **Behaviour** — relative path to the parent `usecase.md`
183
+ - **Design Decisions** — choices made during implementation that aren't obvious from the code; the *why* behind architectural choices
184
+ - **Source Files** — the files that constitute this implementation; used by `sync-check` to detect staleness
185
+ - **Commits** — linked by `taproot link-commits` automatically from conventional commit messages
186
+ - **Tests** — test files that verify this behaviour; used by DoD checks
187
+ - **DoD Resolutions** — recorded outcomes of Definition of Done checks
188
+ - **Status** — lifecycle state: `planned` → `in-progress` → `complete` → `needs-rework`
189
+
190
+ ```markdown
191
+ # Implementation: Email Trigger
192
+
193
+ ## Behaviour
194
+ ../usecase.md
195
+
196
+ ## Design Decisions
197
+ - Generic error message regardless of email existence (prevent enumeration attacks)
198
+ - Rate limit: 3 requests per email per hour, enforced via Redis with TTL
199
+ - Token stored as a bcrypt hash — raw token only in the email, never logged
200
+
201
+ ## Source Files
202
+ - `src/auth/password-reset.ts`
203
+ - `src/auth/password-reset-email.ts`
204
+ - `src/auth/reset-token.ts`
205
+
206
+ ## Commits
207
+ - `a1b2c3d` — Add password reset request endpoint
208
+ - `f4e5d6c` — Add rate limiting to reset requests
209
+
210
+ ## Tests
211
+ - `test/auth/password-reset.test.ts`
212
+ - `test/auth/reset-token.test.ts`
213
+
214
+ ## Status
215
+ - **State:** complete
216
+ - **Created:** 2024-02-01
217
+ - **Last verified:** 2024-03-01
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Nesting
223
+
224
+ Behaviours can contain sub-behaviours. Use sub-behaviours when a single UseCase has distinct phases with different actors, different preconditions, or enough complexity to warrant separate testing. Sub-behaviours are still leaves relative to their parent behaviour but can have their own implementations.
225
+
226
+ Implementations are always leaves — they never contain child folders.
227
+
228
+ ```
229
+ taproot/
230
+ └── password-reset/
231
+ ├── intent.md
232
+ ├── request-reset/
233
+ │ ├── usecase.md
234
+ │ └── email-trigger/
235
+ │ └── impl.md
236
+ └── validate-token/
237
+ ├── usecase.md
238
+ ├── token-validation/
239
+ │ └── impl.md
240
+ └── rate-limit-check/ ← sub-behaviour
241
+ ├── usecase.md
242
+ └── redis-check/
243
+ └── impl.md
244
+ ```
245
+
246
+ ## Document States
247
+
248
+ Each document has a `State` field that tracks its lifecycle. States are validated by `taproot validate-format` and enforced by the pre-commit hook.
249
+
250
+ | State | Intent | Behaviour | Implementation |
251
+ |-------|--------|-----------|----------------|
252
+ | `draft` | Being written, not ready for dev | — | — |
253
+ | `active` | Feature in progress | — | — |
254
+ | `proposed` | — | Idea, not yet specified | — |
255
+ | `specified` | — | Fully specced, ready to implement | — |
256
+ | `implemented` | — | Code exists | — |
257
+ | `tested` | — | Tests passing and reviewed | — |
258
+ | `planned` | — | — | Scoped, not started |
259
+ | `in-progress` | — | — | Being implemented |
260
+ | `complete` | — | — | Done; DoD passed |
261
+ | `needs-rework` | — | — | Implementation failed DoD |
262
+ | `achieved` | All behaviours complete | — | — |
263
+ | `deprecated` | No longer relevant | No longer relevant | — |
264
+ | `deferred` | — | Not pursuing for now | Not pursuing for now |
265
+
266
+ The pre-commit hook uses state transitions to enforce workflow gates: you cannot declare an implementation without the parent behaviour being in `specified` state, and you cannot mark an implementation complete without passing Definition of Done checks.
267
+
268
+ **Deferred items** are consciously parked — `deferred` is not a synonym for `proposed` (not started) or `needs-rework` (broken). It means "we explored or attempted this and decided to stop for now." Deferred behaviours are excluded from `taproot plan` candidates, and deferred implementations are excluded from `check-orphans` errors (missing source files, missing test files). Both are reported in a separate Parked section by `tr-status`. Use `deprecated` (not `deferred`) on intents.