@tenkara/afm-linux-arm64 0.0.0-stage → 4.0.0-alpha.11

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 (283) hide show
  1. package/bin/afm +4 -0
  2. package/content/.coupling-baseline.tsv +1 -0
  3. package/content/.pending-commands.txt +2 -0
  4. package/content/CHANGELOG-archive.md +806 -0
  5. package/content/CHANGELOG.md +4330 -0
  6. package/content/PRINCIPLES.md +119 -0
  7. package/content/README-light.md +158 -0
  8. package/content/README.md +150 -0
  9. package/content/code-style/_any/file-size.md +62 -0
  10. package/content/code-style/_any/imports.md +68 -0
  11. package/content/code-style/_any/naming.md +72 -0
  12. package/content/code-style/_any/test-placement.md +57 -0
  13. package/content/code-style/nextjs-app-router/imports.md +50 -0
  14. package/content/code-style/nextjs-app-router/naming.md +50 -0
  15. package/content/code-style/prisma-postgres/error-boundary.md +55 -0
  16. package/content/code-style/prisma-postgres/imports.md +61 -0
  17. package/content/code-style/shadcn-ui/naming.md +48 -0
  18. package/content/code-style/stripe-billing/naming.md +76 -0
  19. package/content/code-style/trigger-dev-v4/imports.md +58 -0
  20. package/content/code-style/trigger-dev-v4/naming.md +49 -0
  21. package/content/code-style/trigger-dev-v4/test-placement.md +61 -0
  22. package/content/code-style/trpc-v11/error-boundary.md +51 -0
  23. package/content/code-style/trpc-v11/file-size.md +44 -0
  24. package/content/code-style/trpc-v11/naming.md +60 -0
  25. package/content/code-style/trpc-v11/test-placement.md +52 -0
  26. package/content/core/ach.md +260 -0
  27. package/content/core/afm.md +514 -0
  28. package/content/core/gotchas.md +18 -0
  29. package/content/core/prd.md +141 -0
  30. package/content/core/protocol.md +158 -0
  31. package/content/core/ust.md +65 -0
  32. package/content/guardrails/README.md +55 -0
  33. package/content/guardrails/dsl-com-ordem-obrigatoria.md +47 -0
  34. package/content/guardrails/exaustividade-de-union.md +48 -0
  35. package/content/guardrails/fronteira-de-import.md +57 -0
  36. package/content/hooks/README.md +70 -0
  37. package/content/interview/bootstrap.md +417 -0
  38. package/content/interview/promotion.md +115 -0
  39. package/content/interview/refactor.md +379 -0
  40. package/content/interview/triggers.md +107 -0
  41. package/content/modules/nextjs-app-router/ach.patch.md +44 -0
  42. package/content/modules/nextjs-app-router/gotchas.seed.md +78 -0
  43. package/content/modules/nextjs-app-router/rules.patch.md +35 -0
  44. package/content/modules/prisma-postgres/ach.patch.md +65 -0
  45. package/content/modules/prisma-postgres/rules.patch.md +28 -0
  46. package/content/modules/shadcn-ui/ach.patch.md +42 -0
  47. package/content/modules/stripe-billing/ach.patch.md +46 -0
  48. package/content/modules/stripe-billing/gotchas.seed.md +73 -0
  49. package/content/modules/stripe-billing/rules.patch.md +30 -0
  50. package/content/modules/trigger-dev-v4/ach.patch.md +64 -0
  51. package/content/modules/trigger-dev-v4/gotchas.seed.md +53 -0
  52. package/content/modules/trigger-dev-v4/rules.patch.md +35 -0
  53. package/content/modules/trpc-v11/ach.patch.md +56 -0
  54. package/content/modules/trpc-v11/rules.patch.md +34 -0
  55. package/content/modules/vireya-ui/ach.patch.md +85 -0
  56. package/content/modules/vireya-ui/gotchas.seed.md +98 -0
  57. package/content/modules/vireya-ui/rules.patch.md +36 -0
  58. package/content/ops/adr.md +54 -0
  59. package/content/ops/analyze.md +130 -0
  60. package/content/ops/clarify.md +86 -0
  61. package/content/ops/deliver.md +209 -0
  62. package/content/ops/diagnose.md +143 -0
  63. package/content/ops/evolve.md +366 -0
  64. package/content/ops/export-template.md +97 -0
  65. package/content/ops/generalize.md +117 -0
  66. package/content/ops/gotcha.md +46 -0
  67. package/content/ops/obligations.md +145 -0
  68. package/content/ops/plan.md +61 -0
  69. package/content/ops/policy.md +61 -0
  70. package/content/ops/promote.md +72 -0
  71. package/content/ops/protocol.md +51 -0
  72. package/content/ops/reconcile.md +44 -0
  73. package/content/ops/reflect.md +182 -0
  74. package/content/ops/remediate.md +143 -0
  75. package/content/ops/restructure.md +142 -0
  76. package/content/ops/rule.md +170 -0
  77. package/content/ops/specify.md +62 -0
  78. package/content/ops/tasks.md +67 -0
  79. package/content/ops/update.md +252 -0
  80. package/content/ops/verify.md +67 -0
  81. package/content/patterns/adapter.md +46 -0
  82. package/content/patterns/facade.md +47 -0
  83. package/content/patterns/factory.md +46 -0
  84. package/content/patterns/null-object.md +55 -0
  85. package/content/patterns/result-vs-exception.md +52 -0
  86. package/content/patterns/strategy.md +45 -0
  87. package/content/patterns/template-method-vs-composition.md +50 -0
  88. package/content/questions/adr.questions.yaml +14 -0
  89. package/content/questions/analyze.questions.yaml +12 -0
  90. package/content/questions/bootstrap-mapping.questions.yaml +14 -0
  91. package/content/questions/bootstrap-rules.questions.yaml +10 -0
  92. package/content/questions/bootstrap-stack.questions.yaml +23 -0
  93. package/content/questions/clarify.questions.yaml +10 -0
  94. package/content/questions/code-style.questions.yaml +12 -0
  95. package/content/questions/confirm.questions.yaml +12 -0
  96. package/content/questions/deliver.questions.yaml +23 -0
  97. package/content/questions/evolve.questions.yaml +15 -0
  98. package/content/questions/export-template-apply.questions.yaml +11 -0
  99. package/content/questions/export-template.questions.yaml +23 -0
  100. package/content/questions/gates.questions.yaml +27 -0
  101. package/content/questions/generalize.questions.yaml +13 -0
  102. package/content/questions/gotcha.questions.yaml +11 -0
  103. package/content/questions/init-template.questions.yaml +10 -0
  104. package/content/questions/init.questions.yaml +41 -0
  105. package/content/questions/obligations.questions.yaml +17 -0
  106. package/content/questions/plan.questions.yaml +14 -0
  107. package/content/questions/refactor.questions.yaml +23 -0
  108. package/content/questions/reflect.questions.yaml +13 -0
  109. package/content/questions/remediate.questions.yaml +27 -0
  110. package/content/questions/restructure.questions.yaml +15 -0
  111. package/content/questions/rf-mapping.questions.yaml +12 -0
  112. package/content/questions/rule-scope.questions.yaml +12 -0
  113. package/content/questions/rule.questions.yaml +12 -0
  114. package/content/questions/specify.questions.yaml +23 -0
  115. package/content/questions/update-artifacts.questions.yaml +10 -0
  116. package/content/questions/update-strings.questions.yaml +14 -0
  117. package/content/questions/update.questions.yaml +10 -0
  118. package/content/questions/verify.questions.yaml +9 -0
  119. package/content/roles/executor.md +18 -0
  120. package/content/roles/explorer.md +22 -0
  121. package/content/roles/reviewer.md +23 -0
  122. package/content/rubrics/enum-vs-union-vs-branded.md +40 -0
  123. package/content/rubrics/episodic-vs-semantic-boundary.md +37 -0
  124. package/content/rubrics/error-classification.md +98 -0
  125. package/content/rubrics/failure-classification.md +111 -0
  126. package/content/rubrics/negative-filters.md +38 -0
  127. package/content/rubrics/solid-triggers.md +119 -0
  128. package/content/rubrics/template-vs-streaming-precedence.md +34 -0
  129. package/content/rubrics/validation-boundary.md +94 -0
  130. package/content/rubrics/when-to-create-dsl.md +65 -0
  131. package/content/rubrics/when-to-create-lib.md +49 -0
  132. package/content/rubrics/when-to-create-module.md +39 -0
  133. package/content/rubrics/when-to-evolve-methodology.md +62 -0
  134. package/content/skills/adr.md +42 -0
  135. package/content/skills/analyze.md +28 -0
  136. package/content/skills/clarify.md +28 -0
  137. package/content/skills/deliver.md +26 -0
  138. package/content/skills/diagnose.md +42 -0
  139. package/content/skills/evolve.md +43 -0
  140. package/content/skills/export-template.md +37 -0
  141. package/content/skills/generalize.md +31 -0
  142. package/content/skills/gotcha.md +40 -0
  143. package/content/skills/init.md +77 -0
  144. package/content/skills/obligations.md +27 -0
  145. package/content/skills/plan.md +28 -0
  146. package/content/skills/policy.md +25 -0
  147. package/content/skills/promote.md +39 -0
  148. package/content/skills/protocol.md +41 -0
  149. package/content/skills/reconcile.md +45 -0
  150. package/content/skills/refactor.md +79 -0
  151. package/content/skills/reflect.md +43 -0
  152. package/content/skills/remediate.md +33 -0
  153. package/content/skills/restructure.md +46 -0
  154. package/content/skills/rule.md +43 -0
  155. package/content/skills/specify.md +28 -0
  156. package/content/skills/tasks.md +24 -0
  157. package/content/skills/update.md +58 -0
  158. package/content/skills/verify.md +29 -0
  159. package/content/templates/adr.template.md +51 -0
  160. package/content/templates/evolution-report.template.md +132 -0
  161. package/content/templates/feature-plan.template.md +84 -0
  162. package/content/templates/feature-research.template.md +56 -0
  163. package/content/templates/feature-spec.template.md +86 -0
  164. package/content/templates/feature-tasks.induced.template.md +91 -0
  165. package/content/templates/feature-tasks.template.md +82 -0
  166. package/content/templates/focus.template.md +30 -0
  167. package/content/templates/gotcha.template.md +31 -0
  168. package/content/templates/guardrail-runner.template.md +97 -0
  169. package/content/templates/guardrail.template.md +63 -0
  170. package/content/templates/learning.template.md +40 -0
  171. package/content/templates/procedure.template.md +47 -0
  172. package/content/templates/protocols/p1.md +29 -0
  173. package/content/templates/protocols/p2.md +28 -0
  174. package/content/templates/protocols/p3.md +47 -0
  175. package/content/templates/research.template.md +50 -0
  176. package/content/templates/session-handoff.template.md +58 -0
  177. package/content/templates/us.template.md +39 -0
  178. package/content/tools/gate/core-rules/PLUGIN-13-secrets.sh +36 -0
  179. package/content/tools/gate/core-rules/PLUGIN-21-code-language.sh +27 -0
  180. package/content/tools/gate/core-rules/PLUGIN-35-gate-complete.sh +19 -0
  181. package/content/tools/gate/core-rules/PLUGIN-36-absolute-path.sh +38 -0
  182. package/content/tools/gate/core-rules/PLUGIN-37-prose-language.sh +56 -0
  183. package/content/tools/gate/core-rules/PLUGIN-38-parser-marker.sh +82 -0
  184. package/content/tools/gate/core-rules/PLUGIN-39-frontmatter-ops.sh +325 -0
  185. package/content/tools/gate/core-rules/PLUGIN-40-dead-reference.sh +74 -0
  186. package/content/tools/gate/core-rules/README.md +55 -0
  187. package/content/tools/gate/guardrails.sh +740 -0
  188. package/content/tools/gate/lib/ratchet.sh +119 -0
  189. package/content/tools/gate/lib/scope.sh +85 -0
  190. package/content/tools/gate/ratchet.seed.tsv +1 -0
  191. package/content/tools/gate/rules/README.md +50 -0
  192. package/package.json +19 -5
  193. package/plugin/agy/hooks.json +29 -0
  194. package/plugin/agy/mcp_config.json +7 -0
  195. package/plugin/agy/plugin.json +6 -0
  196. package/plugin/agy/skills/afm-adr/SKILL.md +48 -0
  197. package/plugin/agy/skills/afm-analyze/SKILL.md +34 -0
  198. package/plugin/agy/skills/afm-clarify/SKILL.md +34 -0
  199. package/plugin/agy/skills/afm-deliver/SKILL.md +30 -0
  200. package/plugin/agy/skills/afm-diagnose/SKILL.md +46 -0
  201. package/plugin/agy/skills/afm-evolve/SKILL.md +49 -0
  202. package/plugin/agy/skills/afm-export-template/SKILL.md +43 -0
  203. package/plugin/agy/skills/afm-generalize/SKILL.md +37 -0
  204. package/plugin/agy/skills/afm-gotcha/SKILL.md +46 -0
  205. package/plugin/agy/skills/afm-init/SKILL.md +81 -0
  206. package/plugin/agy/skills/afm-obligations/SKILL.md +31 -0
  207. package/plugin/agy/skills/afm-plan/SKILL.md +34 -0
  208. package/plugin/agy/skills/afm-policy/SKILL.md +29 -0
  209. package/plugin/agy/skills/afm-promote/SKILL.md +43 -0
  210. package/plugin/agy/skills/afm-protocol/SKILL.md +45 -0
  211. package/plugin/agy/skills/afm-reconcile/SKILL.md +49 -0
  212. package/plugin/agy/skills/afm-refactor/SKILL.md +83 -0
  213. package/plugin/agy/skills/afm-reflect/SKILL.md +49 -0
  214. package/plugin/agy/skills/afm-remediate/SKILL.md +39 -0
  215. package/plugin/agy/skills/afm-restructure/SKILL.md +52 -0
  216. package/plugin/agy/skills/afm-rule/SKILL.md +49 -0
  217. package/plugin/agy/skills/afm-specify/SKILL.md +34 -0
  218. package/plugin/agy/skills/afm-tasks/SKILL.md +28 -0
  219. package/plugin/agy/skills/afm-update/SKILL.md +64 -0
  220. package/plugin/agy/skills/afm-verify/SKILL.md +35 -0
  221. package/plugin/claude-code/.claude-plugin/marketplace.json +15 -0
  222. package/plugin/claude-code/.claude-plugin/plugin.json +9 -0
  223. package/plugin/claude-code/.mcp.json +7 -0
  224. package/plugin/claude-code/agents/afm-executor.md +18 -0
  225. package/plugin/claude-code/agents/afm-explorer.md +20 -0
  226. package/plugin/claude-code/agents/afm-reviewer.md +21 -0
  227. package/plugin/claude-code/hooks/hooks.json +85 -0
  228. package/plugin/claude-code/skills/adr/SKILL.md +48 -0
  229. package/plugin/claude-code/skills/analyze/SKILL.md +34 -0
  230. package/plugin/claude-code/skills/clarify/SKILL.md +34 -0
  231. package/plugin/claude-code/skills/deliver/SKILL.md +30 -0
  232. package/plugin/claude-code/skills/diagnose/SKILL.md +46 -0
  233. package/plugin/claude-code/skills/evolve/SKILL.md +49 -0
  234. package/plugin/claude-code/skills/export-template/SKILL.md +43 -0
  235. package/plugin/claude-code/skills/generalize/SKILL.md +37 -0
  236. package/plugin/claude-code/skills/gotcha/SKILL.md +46 -0
  237. package/plugin/claude-code/skills/init/SKILL.md +81 -0
  238. package/plugin/claude-code/skills/obligations/SKILL.md +31 -0
  239. package/plugin/claude-code/skills/plan/SKILL.md +34 -0
  240. package/plugin/claude-code/skills/policy/SKILL.md +29 -0
  241. package/plugin/claude-code/skills/promote/SKILL.md +43 -0
  242. package/plugin/claude-code/skills/protocol/SKILL.md +45 -0
  243. package/plugin/claude-code/skills/reconcile/SKILL.md +49 -0
  244. package/plugin/claude-code/skills/refactor/SKILL.md +83 -0
  245. package/plugin/claude-code/skills/reflect/SKILL.md +49 -0
  246. package/plugin/claude-code/skills/remediate/SKILL.md +39 -0
  247. package/plugin/claude-code/skills/restructure/SKILL.md +52 -0
  248. package/plugin/claude-code/skills/rule/SKILL.md +49 -0
  249. package/plugin/claude-code/skills/specify/SKILL.md +34 -0
  250. package/plugin/claude-code/skills/tasks/SKILL.md +28 -0
  251. package/plugin/claude-code/skills/update/SKILL.md +64 -0
  252. package/plugin/claude-code/skills/verify/SKILL.md +35 -0
  253. package/plugin/opencode/afm/index.js +245 -0
  254. package/plugin/opencode/afm/tui.js +21 -0
  255. package/plugin/opencode/agents/afm-executor.md +39 -0
  256. package/plugin/opencode/agents/afm-explorer.md +92 -0
  257. package/plugin/opencode/agents/afm-reviewer.md +93 -0
  258. package/plugin/opencode/skills/afm-adr/SKILL.md +48 -0
  259. package/plugin/opencode/skills/afm-analyze/SKILL.md +34 -0
  260. package/plugin/opencode/skills/afm-clarify/SKILL.md +34 -0
  261. package/plugin/opencode/skills/afm-deliver/SKILL.md +30 -0
  262. package/plugin/opencode/skills/afm-diagnose/SKILL.md +46 -0
  263. package/plugin/opencode/skills/afm-evolve/SKILL.md +49 -0
  264. package/plugin/opencode/skills/afm-export-template/SKILL.md +43 -0
  265. package/plugin/opencode/skills/afm-generalize/SKILL.md +37 -0
  266. package/plugin/opencode/skills/afm-gotcha/SKILL.md +46 -0
  267. package/plugin/opencode/skills/afm-init/SKILL.md +81 -0
  268. package/plugin/opencode/skills/afm-obligations/SKILL.md +31 -0
  269. package/plugin/opencode/skills/afm-plan/SKILL.md +34 -0
  270. package/plugin/opencode/skills/afm-policy/SKILL.md +29 -0
  271. package/plugin/opencode/skills/afm-promote/SKILL.md +43 -0
  272. package/plugin/opencode/skills/afm-protocol/SKILL.md +45 -0
  273. package/plugin/opencode/skills/afm-reconcile/SKILL.md +49 -0
  274. package/plugin/opencode/skills/afm-refactor/SKILL.md +83 -0
  275. package/plugin/opencode/skills/afm-reflect/SKILL.md +49 -0
  276. package/plugin/opencode/skills/afm-remediate/SKILL.md +39 -0
  277. package/plugin/opencode/skills/afm-restructure/SKILL.md +52 -0
  278. package/plugin/opencode/skills/afm-rule/SKILL.md +49 -0
  279. package/plugin/opencode/skills/afm-specify/SKILL.md +34 -0
  280. package/plugin/opencode/skills/afm-tasks/SKILL.md +28 -0
  281. package/plugin/opencode/skills/afm-update/SKILL.md +64 -0
  282. package/plugin/opencode/skills/afm-verify/SKILL.md +35 -0
  283. package/README.md +0 -3
@@ -0,0 +1,46 @@
1
+ ---
2
+ type: pattern
3
+ description: Wraps a vendor SDK type or payload shape at the boundary so domain and lib code depend on an owned interface instead of the vendor's.
4
+ load: cold
5
+ smell: 'a vendor SDK type (a Stripe object, an S3 response, an ORM row) is imported and used directly inside domain or lib code, past the boundary it arrived at'
6
+ when_to_use: the vendor type crosses more than one file, or it is expected to change independently of the domain model that consumes it
7
+ when_not_to_use: the vendor call happens in exactly one file and its result is consumed nowhere else
8
+ ---
9
+
10
+ # Pattern — Adapter
11
+
12
+ > Suggestion only. This pattern does not become project convention by existing here — it
13
+ > materializes into `code-style/`, `ach.md`, or an ADR only when the operator accepts it for
14
+ > this codebase.
15
+
16
+ Continues DIP in `rubrics/solid-triggers.md` (domain must not import infra) and
17
+ `rubrics/validation-boundary.md` (the parser lives at exactly 2 places). Adapter is what sits at
18
+ that same boundary for a *type*, not a schema: it converts the vendor's shape to an owned one on
19
+ the way in, once.
20
+
21
+ ## Decision
22
+
23
+ | Situation | Verdict | Anti-pattern |
24
+ | --- | --- | --- |
25
+ | `Stripe.Customer` (or equivalent) is read in 2+ files | Adapter: one function maps it to an owned `Customer` type at the boundary, everything past that line uses the owned type | Passing the SDK type through domain and re-reading its fields in each consumer |
26
+ | The SDK's field names or nesting are unstable across major versions (checked: it has broken before) | Adapter absorbs the next breaking change in 1 file | The breaking change ships and touches every call site that read the SDK type directly |
27
+ | The SDK call and its one consumer live in the same file, never exported | No adapter yet — see `when-to-create-lib.md`, one caller does not earn extraction | A `StripeCustomerAdapter` class for a value read once and discarded |
28
+ | The domain needs to call back into the vendor (not just read its output) | Wrap the vendor client behind a port your domain defines (this is DIP, Adapter's usual partner) | Domain importing the vendor SDK client directly to make the call itself |
29
+
30
+ ## Why this works
31
+
32
+ A vendor's shape is out of your control; a domain model is not. Every field of the vendor type
33
+ read directly in domain code is a place a vendor upgrade can break — with the adapter, an upgrade
34
+ that renames or restructures the vendor type is absorbed in the 1 function that does the mapping,
35
+ never in the N places that use the resulting owned type.
36
+
37
+ ## Anti-patterns
38
+
39
+ - ❌ An adapter that just renames fields 1:1 and adds no real translation, guarding a type used in
40
+ exactly one place. That's indirection with no boundary to protect — see `when-to-create-lib.md`.
41
+ - ❌ The adapter returns the vendor's own error type unchanged. Errors need the same translation as
42
+ data — see `error-classification.md` for what the domain-facing shape should be.
43
+ - ❌ Two adapters for the same vendor type, one per module, silently drifting. Vendor type → owned
44
+ type is a boundary fact, not a per-module preference; it belongs in one shared place.
45
+ - ❌ Calling the adapter function conditionally, so some call sites still see the raw vendor type.
46
+ A boundary that is optional is not a boundary.
@@ -0,0 +1,47 @@
1
+ ---
2
+ type: pattern
3
+ description: Bundles a repeated sequence of calls across 3 or more collaborators, that always represents one business step, behind a single function.
4
+ load: cold
5
+ smell: 'a call site wires 3 or more collaborators in the same order, in more than one place, to carry out one coherent business step'
6
+ when_to_use: the same sequence of calls across 3+ collaborators repeats at 2+ call sites and always represents one step
7
+ when_not_to_use: the collaborators are used independently at each call site — a different subset, or a different order, each time
8
+ ---
9
+
10
+ # Pattern — Facade
11
+
12
+ > Suggestion only. This pattern does not become project convention by existing here — it
13
+ > materializes into `code-style/`, `ach.md`, or an ADR only when the operator accepts it for
14
+ > this codebase.
15
+
16
+ Continues ISP in `rubrics/solid-triggers.md`, from the other direction: ISP narrows what a single
17
+ function receives; Facade narrows what a *caller* must know to perform one step, by hiding the
18
+ fan-out to several collaborators behind one call.
19
+
20
+ ## Decision
21
+
22
+ | Situation | Verdict | Anti-pattern |
23
+ | --- | --- | --- |
24
+ | 2+ call sites each wire the same 3+ collaborators, in the same order, for the same outcome | Extract a facade function; the call sites call it once and stop knowing the collaborators exist | Each call site re-derives the correct order, one of them getting it wrong under time pressure |
25
+ | One of the wired collaborators is itself a vendor SDK crossing a boundary | Apply Adapter to that one collaborator first, then wrap the sequence in the Facade | The Facade re-exports the raw vendor type through its own return value, leaking the boundary it should hide |
26
+ | The call sites use *different* subsets or orders of the same collaborators | Do not extract — that variation is the actual logic, and a facade would hide it, not simplify it | A facade with a boolean flag per caller's variant — the flags are the switch this pattern was meant to avoid |
27
+ | Only one call site exists | No facade yet — inline the sequence until a 2nd real caller needs the same one | A `CheckoutFacade` built for a single call site "to keep the handler short" |
28
+
29
+ ## Why this works
30
+
31
+ A caller wiring C collaborators must know all C APIs, their call order, and how errors from each
32
+ propagate — that knowledge is repeated at every call site that performs the same step. A facade
33
+ moves it to 1 place: each call site's coupling drops from C collaborators to 1 function, and a
34
+ change to the internal wiring (a 4th collaborator added, the order changed) touches that 1 place.
35
+
36
+ ## Anti-patterns
37
+
38
+ - ❌ A facade over collaborators that are each already simple to call alone. If wiring them takes
39
+ 1 line each, the facade adds a name to remember without reducing real complexity.
40
+ - ❌ A "God facade" that grows to wrap every collaborator in the module, becoming the module's only
41
+ entry point for unrelated steps. Facade wraps *one* coherent business step, not the whole module
42
+ — see `rubrics/solid-triggers.md` § SRP if it starts doing 2+ things.
43
+ - ❌ Swallowing or generically catching every collaborator's error inside the facade. Each
44
+ collaborator's failure still needs its own classification — see `error-classification.md`;
45
+ a facade changes who calls, not how errors are represented.
46
+ - ❌ Building the facade before the 2nd call site exists, on the belief the sequence will repeat.
47
+ That is the same premature-extraction risk `when-to-create-lib.md` names for helpers in general.
@@ -0,0 +1,46 @@
1
+ ---
2
+ type: pattern
3
+ description: Centralizes a multi-step object construction that is copy-pasted at 2 or more call sites into one named function.
4
+ load: cold
5
+ smell: 'the same multi-step construction (apply defaults, validate, wire 2+ collaborators) is copy-pasted at 2 or more call sites to build the same kind of object'
6
+ when_to_use: constructing the object takes more than one step, and that construction already repeats at 2+ call sites
7
+ when_not_to_use: the value is a single-field object literal, or only one call site builds it today
8
+ ---
9
+
10
+ # Pattern — Factory
11
+
12
+ > Suggestion only. This pattern does not become project convention by existing here — it
13
+ > materializes into `code-style/`, `ach.md`, or an ADR only when the operator accepts it for
14
+ > this codebase.
15
+
16
+ Continues the Rule-of-Three trigger already used in `rubrics/when-to-create-lib.md`: that rubric
17
+ extracts a helper on the 3rd caller. Factory is the same threshold applied specifically to
18
+ *construction* logic — defaults, validation, wiring 2+ collaborators into one object.
19
+
20
+ ## Decision
21
+
22
+ | Situation | Verdict | Anti-pattern |
23
+ | --- | --- | --- |
24
+ | 2+ call sites build the same kind of object with the same defaults and the same wiring steps | Extract a `create<X>()` factory function; call sites pass only what varies | Each call site re-applies the same defaults, one of them drifting when a default changes |
25
+ | The object needs 1+ collaborator injected (a clock, an id generator, a config) to be testable | Factory takes the collaborators as parameters, with production defaults | The object reaches for `Date.now()` or a singleton internally — untestable without mocking modules |
26
+ | Construction is a single field literal (`{ id, name }`) | No factory. A function that returns its own argument is ceremony | `createUser({ id, name })` that does nothing `{ id, name }` didn't already do |
27
+ | Only one call site exists today | No factory yet — wait for the 2nd real caller, per `when-to-create-lib.md` | A `UserFactory` class built ahead of the 2nd caller, on the promise it is coming |
28
+
29
+ ## Why this works
30
+
31
+ Construction logic duplicated at K call sites means a changed default, a new required field, or a
32
+ new invariant must be applied K times — and K-1 of those edits are typically missed. A factory
33
+ collapses that to 1 place: the invariant is enforced once, and every call site that changes still
34
+ compiles because they pass arguments to a function, not fields to a literal.
35
+
36
+ ## Anti-patterns
37
+
38
+ - ❌ A factory with a config object with 12 optional fields, most unused by every caller. That is
39
+ the object's own complexity leaking into the factory's signature — fix the object first.
40
+ - ❌ A factory that also performs I/O (saves to the DB, calls an API) as a side effect of
41
+ "constructing." Construction builds a value; persistence is a separate step the caller invokes.
42
+ - ❌ A factory function per call site (`createUserForSignup`, `createUserForAdmin`) that each
43
+ duplicate 90% of the same logic. That is the smell this pattern exists to remove, reintroduced
44
+ one layer down — collapse them into one factory with a parameter for the 10% that differs.
45
+ - ❌ Naming it `UserFactory.getInstance()` to imitate a singleton when nothing requires only one
46
+ instance to exist. A plain exported function is the smaller design (KISS).
@@ -0,0 +1,55 @@
1
+ ---
2
+ type: pattern
3
+ description: Replaces a null guard repeated at 3 or more call sites with a default implementation that behaves like the absent case's known, safe outcome.
4
+ load: cold
5
+ smell: 'the same `if (x == null) { ...default behavior... }` guard, followed by using `x`, is repeated at 3 or more call sites'
6
+ when_to_use: the absent case has one well-known default behavior and every caller currently branches on null to reach it
7
+ when_not_to_use: callers must react differently to absence, or must distinguish absent from present-but-default
8
+ ---
9
+
10
+ # Pattern — Null Object
11
+
12
+ > Suggestion only. This pattern does not become project convention by existing here — it
13
+ > materializes into `code-style/`, `ach.md`, or an ADR only when the operator accepts it for
14
+ > this codebase.
15
+
16
+ A narrower cousin of Strategy in this same library: instead of one implementation per real case,
17
+ it adds exactly one extra implementation standing in for "nothing here" — so the caller's `switch`
18
+ or `if (x == null)` collapses to zero branches, not one fewer.
19
+
20
+ ## Decision
21
+
22
+ - ✅ 3+ call sites do `if (x == null) return fallbackValue` (or an equivalent guard) right before
23
+ using `x`, and `fallbackValue` is the same at every one → give the absent case a real
24
+ implementation of the same interface (an empty cart, a no-op logger, a zero-total invoice) and
25
+ stop returning `null` in the first place.
26
+ - ✅ The type already has a real interface with 1+ methods (a `Logger`, a `Cart`) → the Null Object
27
+ implements that interface with safe, inert behavior (`NullLogger.log()` does nothing).
28
+ - ❌ Fewer than 3 call sites guard the same way, or two callers want a *different* fallback → a
29
+ shared Null Object would force one fallback where callers legitimately need their own; keep the
30
+ guards local, or pass the fallback in per caller instead.
31
+ - ❌ The caller must tell "absent" apart from "present with the default value" (e.g. a form field
32
+ the user explicitly cleared vs. one never touched) → collapsing both into one Null Object erases
33
+ that distinction; `Result`/`Option` is the honest fit — see `result-vs-exception.md`.
34
+
35
+ ## Why this works
36
+
37
+ Every `if (x == null)` guard is a branch a reader and the compiler must both track; N call sites
38
+ with the same guard is N places that branch identically and N places a future change to the
39
+ fallback must be kept in sync. A Null Object moves the branch inside the 1 place that decides
40
+ "use the real thing or the null thing" (usually the factory or lookup that produces `x`), so the
41
+ N call sites go back to unconditional code — 1 branch total instead of N.
42
+
43
+ ## Anti-patterns
44
+
45
+ - ❌ A Null Object that throws when any of its methods is called. That is not a null object, it is
46
+ a differently-shaped exception — it defeats the purpose, which is *safe* default behavior.
47
+ - ❌ Using Null Object where the caller actually needs to know absence happened (an audit log that
48
+ must record "no discount was found," not silently apply a $0 discount and look identical to a
49
+ real $0 discount). Prefer an explicit `Option`/`Result` there instead.
50
+ - ❌ A Null Object with mutable shared state (`NullCart` that collects items across unrelated
51
+ calls). The point of the pattern is a stateless, inert stand-in — shared mutable state turns it
52
+ into a hidden singleton bug.
53
+ - ❌ Silently swapping `null` for a Null Object across a serialization boundary (DB, API response).
54
+ Null Object is an in-process convenience; a stored `null` still means "absent" to every reader
55
+ outside this process, so translate at that boundary instead of upstream.
@@ -0,0 +1,52 @@
1
+ ---
2
+ type: pattern
3
+ description: Replaces a thrown exception for an expected, listable failure with a typed Result value the immediate caller must handle.
4
+ load: cold
5
+ smell: 'a function throws for an outcome the caller already anticipates and branches on (validation failure, not-found, conflict), and the caller wraps the call in try/catch to recover that one branch'
6
+ when_to_use: the failure modes are known, finite, and the immediate caller needs to react differently to each one
7
+ when_not_to_use: the failure is unexpected or unrecoverable — a network drop, a timeout, a bug
8
+ ---
9
+
10
+ # Pattern — Result / Either over exception-as-control-flow
11
+
12
+ > Suggestion only. This pattern does not become project convention by existing here — it
13
+ > materializes into `code-style/`, `ach.md`, or an ADR only when the operator accepts it for
14
+ > this codebase.
15
+
16
+ `rubrics/error-classification.md` already prescribes the shape (`Result<T, E>` with a literal
17
+ `as const` code) for the Domain layer specifically. This pattern generalizes the same call: apply
18
+ it to *any* function, domain or not, where a `try { } catch { }` exists only to recover one
19
+ specific, anticipated branch — not to handle a genuine surprise.
20
+
21
+ ## Decision
22
+
23
+ - ✅ The function has 2 or more named, expected outcomes (`EMAIL_TAKEN`, `NOT_FOUND`,
24
+ `WEAK_PASSWORD`) → return `Result<T, E>` with `E` a literal union, and force the caller to
25
+ `switch` with an exhaustive `never` default (see `error-classification.md`).
26
+ - ✅ Today's code throws a custom error class only to `catch (e) { if (e instanceof X) }` one line
27
+ above the call → that `catch` is the tell; replace both sides with `Result`.
28
+ - ❌ The failure is a bug, a timeout, or anything the immediate caller cannot meaningfully act on
29
+ → let it rise. Wrapping every infra call in `Result` just relocates the `try/catch`, it does not
30
+ remove it — see `error-classification.md`'s Infra-error row.
31
+ - ❌ The function is called in exactly one place and that place already has a correct
32
+ `try/catch` → converting it buys nothing; the try/catch already IS the handling.
33
+
34
+ ## Why this works
35
+
36
+ An exception's type is invisible at the call site — nothing in a function's signature says it can
37
+ throw, so the caller either wraps every call defensively or misses a case entirely. A `Result<T,
38
+ E>` return type puts the failure in the signature: TypeScript's exhaustiveness check on the
39
+ `switch` (the `never` default) then makes an unhandled case a compile error instead of a runtime
40
+ surprise, at zero added `try/catch` blocks.
41
+
42
+ ## Anti-patterns
43
+
44
+ - ❌ Wrapping infra failures (DB down, network drop) in `Result` "for consistency." Those are not
45
+ anticipated outcomes — see `error-classification.md`: infra errors rise and get caught once at
46
+ the process boundary, they do not become a case in every caller's switch.
47
+ - ❌ A `Result<T, string>` with a free-text message instead of a literal code. The caller cannot
48
+ `switch` on a string; the whole benefit (exhaustiveness) is gone. The code must be `as const`.
49
+ - ❌ Mixing `Result` and exceptions in the same function — return `Result` for the expected branch,
50
+ then also `throw` for another branch of the same function. Callers must handle two mechanisms.
51
+ - ❌ A generic `try/catch` around a `Result`-returning call "just in case." If the function no
52
+ longer throws for its expected failures, the surrounding `try` should not exist either.
@@ -0,0 +1,45 @@
1
+ ---
2
+ type: pattern
3
+ description: Replaces a branching conditional keyed on a kind, type, or provider field with one interface and one implementation per case, selected through a registry.
4
+ load: cold
5
+ smell: 'a `switch` or `if`/`else if` chain keyed on a kind, type, or provider field, duplicated across 2+ files or functions'
6
+ when_to_use: a new case of the same kind arrives on a predictable cadence and every case can share one call shape
7
+ when_not_to_use: only one implementation exists today, or the cases would return incompatible shapes
8
+ ---
9
+
10
+ # Pattern — Strategy
11
+
12
+ > Suggestion only. This pattern does not become project convention by existing here — it
13
+ > materializes into `code-style/`, `ach.md`, or an ADR only when the operator accepts it for
14
+ > this codebase.
15
+
16
+ Continues the OCP trigger in `rubrics/solid-triggers.md`: that rubric tells you a `switch` on a
17
+ provider is a problem the moment a 2nd `switch` on the same field appears elsewhere. Strategy is
18
+ the concrete extraction once that trigger fires.
19
+
20
+ ## Decision
21
+
22
+ | Situation | Verdict | Anti-pattern |
23
+ | --- | --- | --- |
24
+ | A `switch(kind)` selects behavior, and a second `switch(kind)` on the same field lives in another function or file | Apply Strategy: one file per case implementing a shared interface, wired through a lookup table | Adding a 4th `case` to both switches and hoping they stay in sync |
25
+ | Every case already returns the same shape (LSP, see `solid-triggers.md`) | Safe to extract now — the interface is exactly that shared shape | Extracting before the shapes agree — the interface degrades to `any` or a union of incompatibles |
26
+ | Only one case exists and no second is concretely planned | Do not extract. A single `if` is not a smell | A `StrategyRegistry` with one entry — OCP paid for a case that never happened |
27
+ | The active case is fixed for the process lifetime (an env-driven backend chosen once at boot) | Plain dependency injection of the one active implementation | A registry of N strategies when exactly 1 is ever selected at runtime |
28
+
29
+ ## Why this works
30
+
31
+ A `switch` on a variant duplicates its list of cases every time the branch is copy-pasted into a
32
+ new function: N call sites × M cases means up to N×M places that drift when case M+1 arrives.
33
+ Strategy collapses that to N call sites each holding one lookup, plus M single-purpose files —
34
+ adding case M+1 then touches exactly 1 new file and 1 registry line, never the N call sites.
35
+
36
+ ## Anti-patterns
37
+
38
+ - ❌ A `StrategyRegistry` holding one entry "for when we add the second provider." Inline the one
39
+ implementation. Extract on the second real case, not the imagined one.
40
+ - ❌ Interfaces that leak the framework in the port (`RegistryAdapter.publish(ctx: TRPCContext)`).
41
+ The port must be as narrow as ISP allows — see `solid-triggers.md` § ISP.
42
+ - ❌ A registry keyed by a raw `string` instead of the closed literal union of kinds. A typo in the
43
+ key then fails at runtime instead of at compile time.
44
+ - ❌ Keeping the old `switch` alongside the new registry "just in case." Delete it in the same
45
+ change — two selection mechanisms for the same kind is worse than the one you started with.
@@ -0,0 +1,50 @@
1
+ ---
2
+ type: pattern
3
+ description: Chooses between an inherited algorithm skeleton with overridable steps and a plain function that takes the varying step as a parameter.
4
+ load: cold
5
+ smell: 'two or more functions or classes repeat the same ordered sequence of steps, differing only in 1-2 of those steps'
6
+ when_to_use: the skeleton has 3+ fixed steps and only 1-2 vary across callers
7
+ when_not_to_use: the varying step is the only step, or fewer than 3 callers share the skeleton
8
+ ---
9
+
10
+ # Pattern — Template Method vs. composition
11
+
12
+ > Suggestion only. This pattern does not become project convention by existing here — it
13
+ > materializes into `code-style/`, `ach.md`, or an ADR only when the operator accepts it for
14
+ > this codebase.
15
+
16
+ Shares the Rule-of-Three threshold from `rubrics/when-to-create-lib.md`, applied to a *sequence*
17
+ of steps instead of a single helper — and it decides between two ways to remove the duplication,
18
+ not just whether to remove it.
19
+
20
+ ## Decision
21
+
22
+ | Situation | Verdict | Anti-pattern |
23
+ | --- | --- | --- |
24
+ | 3+ callers share an ordered skeleton (validate → transform → persist → notify), 1-2 steps vary, and the language has first-class functions | Composition: one function takes the varying step(s) as parameters/callbacks | Copy-pasting the whole skeleton per caller so the 1 varying line can differ |
25
+ | Same skeleton, but the varying steps need to read or mutate protected state shared across steps (a running total, an accumulator built up across the sequence) | Template Method: a base class fixes the sequence, subclasses override only the varying steps | Threading that shared state through 4 separate callback parameters to fake what inheritance gives for free |
26
+ | Only 1-2 callers share the skeleton today | Do not extract either way — inline duplication for 2 callers costs less than an abstraction (Rule of Three, `when-to-create-lib.md`) | A base class with exactly one subclass, built ahead of the 2nd real caller |
27
+ | The "skeleton" is actually just the 1 step that varies, wrapped in ceremony | There is no skeleton to extract — this is a Strategy situation instead, see `strategy.md` | Template Method with a base class whose every method is abstract — nothing is actually shared |
28
+
29
+ ## Why this works
30
+
31
+ A skeleton with S total steps where V of them vary means V×N points of difference across N
32
+ callers when duplicated in full. Extracting the skeleton — either way — reduces that to N call
33
+ sites providing only the V varying steps, plus 1 shared definition of the S−V fixed ones.
34
+ Composition and Template Method both hit that number; the choice between them is only about
35
+ where the shared state between steps needs to live — a closure (composition) or `this`
36
+ (inheritance).
37
+
38
+ ## Anti-patterns
39
+
40
+ - ❌ Reaching for inheritance by default. Composition is the smaller design (KISS) whenever no
41
+ step needs shared mutable state across the sequence — prefer it, and use Template Method only
42
+ when composition would require threading that state through every callback.
43
+ - ❌ A Template Method base class with a step marked `abstract` that every subclass overrides
44
+ identically. That step isn't varying — fold it back into the fixed skeleton.
45
+ - ❌ Composition where the "varying step" callback secretly depends on 3+ pieces of the caller's
46
+ outer scope. At that point the callback IS the logic and the shared skeleton is the smaller
47
+ part — question whether extracting the skeleton was the right cut at all.
48
+ - ❌ Extracting the skeleton before the 3rd caller exists. Two callers sharing steps can be
49
+ coincidence, not a real pattern — the same Rule-of-Three reasoning `when-to-create-lib.md` uses
50
+ for helpers applies here.
@@ -0,0 +1,14 @@
1
+ questions:
2
+ - id: status
3
+ prompt: What is the status of this decision?
4
+ header: Status
5
+ recommended: Accepted
6
+ options:
7
+ - label: Proposed
8
+ description: Written down, not yet in force. Pass it as --status proposed.
9
+ - label: Accepted
10
+ description: In force today. Pass it as --status accepted.
11
+ - label: Superseded by ADR-NNNN
12
+ description: A later decision replaced it; write the new ADR with --supersedes N.
13
+ - label: Deprecated
14
+ description: No longer in force and nothing replaced it. Pass it as --status deprecated.
@@ -0,0 +1,12 @@
1
+ questions:
2
+ - id: remediation
3
+ prompt: Do you want concrete edits for the top findings?
4
+ header: Remediation
5
+ recommended: top-5
6
+ options:
7
+ - label: top-5
8
+ description: Apply the edits for the top 5 findings in severity order, then report what changed and where.
9
+ - label: top-10
10
+ description: Same as top-5, for the top 10 findings.
11
+ - label: report-only
12
+ description: The report is enough. Nothing is edited and the findings are addressed manually.
@@ -0,0 +1,14 @@
1
+ questions:
2
+ - id: mapping
3
+ prompt: Does the component-type to stack mapping drafted for the architecture doc make sense?
4
+ header: Mapping
5
+ recommended: All match
6
+ options:
7
+ - label: All match
8
+ description: Materializes the mapping as drafted.
9
+ - label: Adjust
10
+ description: One or two entries change; the operator points them out.
11
+ - label: Some do not apply
12
+ description: The operator lists the component types the project does not have.
13
+ - label: Rewrite
14
+ description: The operator dictates the mapping again.
@@ -0,0 +1,10 @@
1
+ questions:
2
+ - id: rules
3
+ prompt: Does any inherited hard rule not fit this project? Inalienable rules are never offered.
4
+ header: Rules
5
+ recommended: Keep all
6
+ options:
7
+ - label: Keep all
8
+ description: Every opt-out-able rule stays in force.
9
+ - label: Opt out of some
10
+ description: The operator names each rule and why; each becomes N/A with that reason.
@@ -0,0 +1,23 @@
1
+ questions:
2
+ - id: stack
3
+ prompt: Is the stack that afm init reported, layer by layer with its evidence, right?
4
+ header: Stack
5
+ recommended: Confirm
6
+ options:
7
+ - label: Confirm
8
+ description: Records every reported layer as decided.
9
+ - label: Adjust
10
+ description: Some layers are wrong or missing; the operator names them and the answer is recorded as given.
11
+ - label: Leave as TBD
12
+ description: Records [TBD] for the layers; a recommendation works better once the operator also knows what they do not want.
13
+ - id: modules
14
+ prompt: Apply every opt-in module detected for the stack? A module is applied whole, so the default is to opt out only what does not fit.
15
+ header: Modules
16
+ recommended: All
17
+ options:
18
+ - label: All
19
+ description: Merges each detected module's architecture and rule patches.
20
+ - label: Some
21
+ description: Applies all but the modules the operator names; those simply stay out.
22
+ - label: None
23
+ description: No module is applied.
@@ -0,0 +1,10 @@
1
+ questions:
2
+ - id: underspecified
3
+ prompt: Most categories are Missing and many markers are open. How should clarify proceed?
4
+ header: Thin spec
5
+ recommended: respecify
6
+ options:
7
+ - label: respecify
8
+ description: Re-run specify with new input. A spec this thin needs rewriting, not a long question loop.
9
+ - label: continue
10
+ description: Keep clarifying anyway, within the limit of 5 questions for this session.
@@ -0,0 +1,12 @@
1
+ questions:
2
+ - id: code-style
3
+ prompt: The listed code-style files are house conventions one project observed, not facts of the stack. Apply any? An unmarked item is written nowhere.
4
+ header: Code style
5
+ recommended: None
6
+ options:
7
+ - label: None
8
+ description: Nothing applies. The default, because a silent opt-in is the defect this question corrects.
9
+ - label: Some
10
+ description: The operator names the files; each is copied verbatim as the project's rule.
11
+ - label: All
12
+ description: Every listed file is copied verbatim as the project's rule.
@@ -0,0 +1,12 @@
1
+ questions:
2
+ - id: restated
3
+ prompt: Is the restatement above correct?
4
+ header: Confirmation
5
+ recommended: Yes, exact
6
+ options:
7
+ - label: Yes, exact
8
+ description: Materializes it as restated.
9
+ - label: Almost
10
+ description: A small adjustment; the operator describes the fix.
11
+ - label: No, rewrite
12
+ description: The operator dictates it again.
@@ -0,0 +1,23 @@
1
+ questions:
2
+ - id: outcome
3
+ prompt: The plan is drafted and verified. What should the delivery do now?
4
+ header: Outcome
5
+ recommended: run-to-completion
6
+ options:
7
+ - label: run-to-completion
8
+ description: Approve the plan and execute every task, stopping only at a halt or the push boundary.
9
+ - label: pause-per-phase
10
+ description: Approve the plan, execute it, and stop after each phase to ask whether to continue.
11
+ - label: materialize-only
12
+ description: Keep the drafted spec, plan and tasks on disk and execute nothing.
13
+ - label: adjust-or-cancel
14
+ description: Record no approval. Say what to change in the drafts, or stop here.
15
+ - id: phase-continue
16
+ prompt: The phase is done. Continue to the next phase?
17
+ header: Next phase
18
+ recommended: continue
19
+ options:
20
+ - label: continue
21
+ description: Run the next phase.
22
+ - label: stop
23
+ description: Stop here; re-running deliver resumes at the first open task.
@@ -0,0 +1,15 @@
1
+ # One question per (b) item of the evolve package. Run it once per item:
2
+ # afm ask evolve --scope <item-slug> --recommend <label>
3
+ # The item's evidence, its recommendation and "what changes if this is wrong" sit in the package the
4
+ # agent shows before asking; the answer applies to that one item only.
5
+ questions:
6
+ - id: apply
7
+ prompt: Apply this proposed change to the docs?
8
+ header: Apply
9
+ options:
10
+ - label: Apply
11
+ description: Apply the change after the gate, exactly as itemized in the package.
12
+ - label: Skip
13
+ description: Reject it; the report records the rejection as attempt memory, so it is not proposed again without new evidence.
14
+ - label: Stage
15
+ description: Defer it to the next cycle; the report records it as staged.
@@ -0,0 +1,11 @@
1
+ questions:
2
+ - id: apply
3
+ prompt: Delete the listed files and write the template marker?
4
+ header: Apply
5
+ options:
6
+ - label: Apply
7
+ description: Runs the same command with --yes. The deletion is not reversible outside git.
8
+ - label: Adjust
9
+ description: Go back to the keep question and review the plan again.
10
+ - label: Cancel
11
+ description: Nothing is touched.
@@ -0,0 +1,23 @@
1
+ questions:
2
+ - id: keep
3
+ prompt: Which of the artifacts a template normally drops should STAY? Leave empty to keep none.
4
+ header: Keep
5
+ multiSelect: true
6
+ options:
7
+ - label: prd
8
+ description: prd.md is product-specific; a template usually drops it.
9
+ - label: ust
10
+ description: ust.md holds the product's stories; a template usually drops it.
11
+ - label: features
12
+ description: docs/features/ is product work; its tasks are first induced into a reusable shape.
13
+ - label: afm-version
14
+ description: A template is not an instance, so the version pin is dropped unless kept.
15
+ - id: research
16
+ prompt: What happens to docs/research/, which may hold reusable technical research?
17
+ header: Research
18
+ recommended: Keep
19
+ options:
20
+ - label: Keep
21
+ description: The research stays in the template.
22
+ - label: Delete
23
+ description: The research goes with the product content.
@@ -0,0 +1,27 @@
1
+ questions:
2
+ - id: dod
3
+ prompt: Which checks must pass to merge? Pre-check the ones the scan reported as gating merge.
4
+ header: Merge DoD
5
+ multiSelect: true
6
+ options:
7
+ - label: Test runner
8
+ description: The project's tests.
9
+ - label: Type check
10
+ description: The type checker with no emit.
11
+ - label: Lint
12
+ description: The linter or formatter check.
13
+ - label: Build
14
+ description: A production build.
15
+ - id: pre-push
16
+ prompt: Which checks run before a push? Pre-check the ones the scan reported in a pre-push hook.
17
+ header: Pre-push
18
+ multiSelect: true
19
+ options:
20
+ - label: Test runner
21
+ description: The project's tests.
22
+ - label: Type check
23
+ description: The type checker with no emit.
24
+ - label: Lint
25
+ description: The linter or formatter check.
26
+ - label: Build
27
+ description: A production build.
@@ -0,0 +1,13 @@
1
+ # One question per merge of gotchas into an abstract rule:
2
+ # afm ask generalize --scope <rule-slug>
3
+ questions:
4
+ - id: merge
5
+ prompt: Merge the batch of gotchas into the proposed rule and archive the members with tombstones?
6
+ header: Merge
7
+ options:
8
+ - label: Merge as a rule
9
+ description: Write a hard rule in afm.md section 3 with its 0/1 trigger, then archive the merged gotchas with tombstones.
10
+ - label: Merge as a principle
11
+ description: Write the abstraction in afm.md section 1.3 (guidance only, no executable trigger), then archive the merged gotchas with tombstones.
12
+ - label: Keep separate
13
+ description: The abstraction loses too much; keep the gotchas as they are and report "not generalizable without loss".
@@ -0,0 +1,11 @@
1
+ questions:
2
+ - id: basis
3
+ prompt: Does this behavior qualify for registration?
4
+ header: Qualify
5
+ options:
6
+ - label: bitten-twice
7
+ description: Confirmed to have bitten a developer at least twice.
8
+ - label: documented-sdk
9
+ description: Documented behavior of a known external SDK or runtime that surprises its users.
10
+ - label: neither
11
+ description: No second incidence and no external documentation; nothing is registered.
@@ -0,0 +1,10 @@
1
+ questions:
2
+ - id: branch
3
+ prompt: This project comes from an architectural template (docs/.template). How should the interview run?
4
+ header: Interview
5
+ recommended: Product only
6
+ options:
7
+ - label: Product only
8
+ description: Runs only product, flows, a short validation step and gotchas. Stack, data model, mapping and rules are inherited.
9
+ - label: Full interview
10
+ description: Ignores the marker for this session and runs all seven steps. The marker stays on disk.