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

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 (276) 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 +4256 -0
  6. package/content/PRINCIPLES.md +121 -0
  7. package/content/README-light.md +160 -0
  8. package/content/README.md +152 -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 +265 -0
  27. package/content/core/afm.md +496 -0
  28. package/content/core/gotchas.md +18 -0
  29. package/content/core/prd.md +143 -0
  30. package/content/core/protocol.md +160 -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 +72 -0
  37. package/content/interview/bootstrap.md +415 -0
  38. package/content/interview/promotion.md +117 -0
  39. package/content/interview/refactor.md +381 -0
  40. package/content/interview/triggers.md +109 -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 +129 -0
  60. package/content/ops/clarify.md +86 -0
  61. package/content/ops/deliver.md +211 -0
  62. package/content/ops/diagnose.md +146 -0
  63. package/content/ops/evolve.md +317 -0
  64. package/content/ops/export-template.md +97 -0
  65. package/content/ops/generalize.md +120 -0
  66. package/content/ops/gotcha.md +46 -0
  67. package/content/ops/plan.md +61 -0
  68. package/content/ops/policy.md +63 -0
  69. package/content/ops/promote.md +72 -0
  70. package/content/ops/protocol.md +51 -0
  71. package/content/ops/reconcile.md +44 -0
  72. package/content/ops/reflect.md +180 -0
  73. package/content/ops/remediate.md +146 -0
  74. package/content/ops/restructure.md +145 -0
  75. package/content/ops/rule.md +165 -0
  76. package/content/ops/specify.md +62 -0
  77. package/content/ops/tasks.md +67 -0
  78. package/content/ops/update.md +223 -0
  79. package/content/ops/verify.md +69 -0
  80. package/content/patterns/adapter.md +46 -0
  81. package/content/patterns/facade.md +47 -0
  82. package/content/patterns/factory.md +46 -0
  83. package/content/patterns/null-object.md +55 -0
  84. package/content/patterns/result-vs-exception.md +52 -0
  85. package/content/patterns/strategy.md +45 -0
  86. package/content/patterns/template-method-vs-composition.md +50 -0
  87. package/content/questions/adr.questions.yaml +14 -0
  88. package/content/questions/analyze.questions.yaml +12 -0
  89. package/content/questions/bootstrap-mapping.questions.yaml +14 -0
  90. package/content/questions/bootstrap-rules.questions.yaml +10 -0
  91. package/content/questions/bootstrap-stack.questions.yaml +23 -0
  92. package/content/questions/clarify.questions.yaml +10 -0
  93. package/content/questions/code-style.questions.yaml +12 -0
  94. package/content/questions/confirm.questions.yaml +12 -0
  95. package/content/questions/deliver.questions.yaml +23 -0
  96. package/content/questions/evolve.questions.yaml +15 -0
  97. package/content/questions/export-template-apply.questions.yaml +11 -0
  98. package/content/questions/export-template.questions.yaml +23 -0
  99. package/content/questions/gates.questions.yaml +27 -0
  100. package/content/questions/generalize.questions.yaml +13 -0
  101. package/content/questions/gotcha.questions.yaml +11 -0
  102. package/content/questions/init-template.questions.yaml +10 -0
  103. package/content/questions/init.questions.yaml +28 -0
  104. package/content/questions/plan.questions.yaml +14 -0
  105. package/content/questions/refactor.questions.yaml +23 -0
  106. package/content/questions/reflect.questions.yaml +13 -0
  107. package/content/questions/remediate.questions.yaml +27 -0
  108. package/content/questions/restructure.questions.yaml +15 -0
  109. package/content/questions/rf-mapping.questions.yaml +12 -0
  110. package/content/questions/rule-scope.questions.yaml +12 -0
  111. package/content/questions/rule.questions.yaml +12 -0
  112. package/content/questions/specify.questions.yaml +23 -0
  113. package/content/questions/update-artifacts.questions.yaml +10 -0
  114. package/content/questions/update-strings.questions.yaml +14 -0
  115. package/content/questions/update.questions.yaml +10 -0
  116. package/content/questions/verify.questions.yaml +9 -0
  117. package/content/roles/executor.md +18 -0
  118. package/content/roles/explorer.md +22 -0
  119. package/content/roles/reviewer.md +23 -0
  120. package/content/rubrics/enum-vs-union-vs-branded.md +40 -0
  121. package/content/rubrics/episodic-vs-semantic-boundary.md +37 -0
  122. package/content/rubrics/error-classification.md +98 -0
  123. package/content/rubrics/failure-classification.md +113 -0
  124. package/content/rubrics/negative-filters.md +38 -0
  125. package/content/rubrics/solid-triggers.md +121 -0
  126. package/content/rubrics/template-vs-streaming-precedence.md +34 -0
  127. package/content/rubrics/validation-boundary.md +94 -0
  128. package/content/rubrics/when-to-create-dsl.md +65 -0
  129. package/content/rubrics/when-to-create-lib.md +49 -0
  130. package/content/rubrics/when-to-create-module.md +39 -0
  131. package/content/rubrics/when-to-evolve-methodology.md +62 -0
  132. package/content/skills/adr.md +42 -0
  133. package/content/skills/analyze.md +34 -0
  134. package/content/skills/clarify.md +34 -0
  135. package/content/skills/deliver.md +42 -0
  136. package/content/skills/diagnose.md +50 -0
  137. package/content/skills/evolve.md +67 -0
  138. package/content/skills/export-template.md +40 -0
  139. package/content/skills/generalize.md +47 -0
  140. package/content/skills/gotcha.md +40 -0
  141. package/content/skills/init.md +82 -0
  142. package/content/skills/plan.md +34 -0
  143. package/content/skills/policy.md +31 -0
  144. package/content/skills/promote.md +41 -0
  145. package/content/skills/protocol.md +42 -0
  146. package/content/skills/reconcile.md +49 -0
  147. package/content/skills/refactor.md +84 -0
  148. package/content/skills/reflect.md +53 -0
  149. package/content/skills/remediate.md +39 -0
  150. package/content/skills/restructure.md +52 -0
  151. package/content/skills/rule.md +44 -0
  152. package/content/skills/specify.md +34 -0
  153. package/content/skills/tasks.md +34 -0
  154. package/content/skills/update.md +56 -0
  155. package/content/skills/verify.md +31 -0
  156. package/content/templates/adr.template.md +51 -0
  157. package/content/templates/evolution-report.template.md +129 -0
  158. package/content/templates/feature-plan.template.md +86 -0
  159. package/content/templates/feature-research.template.md +57 -0
  160. package/content/templates/feature-spec.template.md +86 -0
  161. package/content/templates/feature-tasks.induced.template.md +67 -0
  162. package/content/templates/feature-tasks.template.md +60 -0
  163. package/content/templates/focus.template.md +30 -0
  164. package/content/templates/gotcha.template.md +31 -0
  165. package/content/templates/guardrail-runner.template.md +81 -0
  166. package/content/templates/guardrail.template.md +63 -0
  167. package/content/templates/learning.template.md +40 -0
  168. package/content/templates/procedure.template.md +47 -0
  169. package/content/templates/protocols/p1.md +29 -0
  170. package/content/templates/protocols/p2.md +28 -0
  171. package/content/templates/protocols/p3.md +47 -0
  172. package/content/templates/research.template.md +50 -0
  173. package/content/templates/session-handoff.template.md +58 -0
  174. package/content/templates/us.template.md +39 -0
  175. package/content/tools/gate/core-rules/PLUGIN-13-secrets.sh +36 -0
  176. package/content/tools/gate/core-rules/PLUGIN-21-code-language.sh +27 -0
  177. package/content/tools/gate/core-rules/PLUGIN-35-gate-complete.sh +19 -0
  178. package/content/tools/gate/core-rules/PLUGIN-36-absolute-path.sh +38 -0
  179. package/content/tools/gate/core-rules/PLUGIN-37-prose-language.sh +56 -0
  180. package/content/tools/gate/core-rules/PLUGIN-38-parser-marker.sh +82 -0
  181. package/content/tools/gate/core-rules/PLUGIN-39-frontmatter-ops.sh +325 -0
  182. package/content/tools/gate/core-rules/PLUGIN-40-dead-reference.sh +74 -0
  183. package/content/tools/gate/core-rules/README.md +55 -0
  184. package/content/tools/gate/guardrails.sh +740 -0
  185. package/content/tools/gate/lib/ratchet.sh +119 -0
  186. package/content/tools/gate/lib/scope.sh +85 -0
  187. package/content/tools/gate/ratchet.seed.tsv +1 -0
  188. package/content/tools/gate/rules/README.md +50 -0
  189. package/package.json +19 -5
  190. package/plugin/agy/hooks.json +29 -0
  191. package/plugin/agy/mcp_config.json +7 -0
  192. package/plugin/agy/plugin.json +6 -0
  193. package/plugin/agy/skills/afm-adr/SKILL.md +44 -0
  194. package/plugin/agy/skills/afm-analyze/SKILL.md +36 -0
  195. package/plugin/agy/skills/afm-clarify/SKILL.md +36 -0
  196. package/plugin/agy/skills/afm-deliver/SKILL.md +44 -0
  197. package/plugin/agy/skills/afm-diagnose/SKILL.md +50 -0
  198. package/plugin/agy/skills/afm-evolve/SKILL.md +69 -0
  199. package/plugin/agy/skills/afm-export-template/SKILL.md +42 -0
  200. package/plugin/agy/skills/afm-generalize/SKILL.md +49 -0
  201. package/plugin/agy/skills/afm-gotcha/SKILL.md +42 -0
  202. package/plugin/agy/skills/afm-init/SKILL.md +84 -0
  203. package/plugin/agy/skills/afm-plan/SKILL.md +36 -0
  204. package/plugin/agy/skills/afm-policy/SKILL.md +31 -0
  205. package/plugin/agy/skills/afm-promote/SKILL.md +41 -0
  206. package/plugin/agy/skills/afm-protocol/SKILL.md +42 -0
  207. package/plugin/agy/skills/afm-reconcile/SKILL.md +49 -0
  208. package/plugin/agy/skills/afm-refactor/SKILL.md +86 -0
  209. package/plugin/agy/skills/afm-reflect/SKILL.md +55 -0
  210. package/plugin/agy/skills/afm-remediate/SKILL.md +41 -0
  211. package/plugin/agy/skills/afm-restructure/SKILL.md +54 -0
  212. package/plugin/agy/skills/afm-rule/SKILL.md +46 -0
  213. package/plugin/agy/skills/afm-specify/SKILL.md +36 -0
  214. package/plugin/agy/skills/afm-tasks/SKILL.md +34 -0
  215. package/plugin/agy/skills/afm-update/SKILL.md +58 -0
  216. package/plugin/agy/skills/afm-verify/SKILL.md +33 -0
  217. package/plugin/claude-code/.claude-plugin/marketplace.json +15 -0
  218. package/plugin/claude-code/.claude-plugin/plugin.json +9 -0
  219. package/plugin/claude-code/.mcp.json +7 -0
  220. package/plugin/claude-code/agents/afm-executor.md +18 -0
  221. package/plugin/claude-code/agents/afm-explorer.md +20 -0
  222. package/plugin/claude-code/agents/afm-reviewer.md +21 -0
  223. package/plugin/claude-code/hooks/hooks.json +85 -0
  224. package/plugin/claude-code/skills/adr/SKILL.md +44 -0
  225. package/plugin/claude-code/skills/analyze/SKILL.md +36 -0
  226. package/plugin/claude-code/skills/clarify/SKILL.md +36 -0
  227. package/plugin/claude-code/skills/deliver/SKILL.md +44 -0
  228. package/plugin/claude-code/skills/diagnose/SKILL.md +50 -0
  229. package/plugin/claude-code/skills/evolve/SKILL.md +69 -0
  230. package/plugin/claude-code/skills/export-template/SKILL.md +42 -0
  231. package/plugin/claude-code/skills/generalize/SKILL.md +49 -0
  232. package/plugin/claude-code/skills/gotcha/SKILL.md +42 -0
  233. package/plugin/claude-code/skills/init/SKILL.md +84 -0
  234. package/plugin/claude-code/skills/plan/SKILL.md +36 -0
  235. package/plugin/claude-code/skills/policy/SKILL.md +31 -0
  236. package/plugin/claude-code/skills/promote/SKILL.md +41 -0
  237. package/plugin/claude-code/skills/protocol/SKILL.md +42 -0
  238. package/plugin/claude-code/skills/reconcile/SKILL.md +49 -0
  239. package/plugin/claude-code/skills/refactor/SKILL.md +86 -0
  240. package/plugin/claude-code/skills/reflect/SKILL.md +55 -0
  241. package/plugin/claude-code/skills/remediate/SKILL.md +41 -0
  242. package/plugin/claude-code/skills/restructure/SKILL.md +54 -0
  243. package/plugin/claude-code/skills/rule/SKILL.md +46 -0
  244. package/plugin/claude-code/skills/specify/SKILL.md +36 -0
  245. package/plugin/claude-code/skills/tasks/SKILL.md +34 -0
  246. package/plugin/claude-code/skills/update/SKILL.md +58 -0
  247. package/plugin/claude-code/skills/verify/SKILL.md +33 -0
  248. package/plugin/opencode/afm.js +173 -0
  249. package/plugin/opencode/agents/afm-executor.md +31 -0
  250. package/plugin/opencode/agents/afm-explorer.md +47 -0
  251. package/plugin/opencode/agents/afm-reviewer.md +48 -0
  252. package/plugin/opencode/skills/afm-adr/SKILL.md +44 -0
  253. package/plugin/opencode/skills/afm-analyze/SKILL.md +36 -0
  254. package/plugin/opencode/skills/afm-clarify/SKILL.md +36 -0
  255. package/plugin/opencode/skills/afm-deliver/SKILL.md +44 -0
  256. package/plugin/opencode/skills/afm-diagnose/SKILL.md +50 -0
  257. package/plugin/opencode/skills/afm-evolve/SKILL.md +69 -0
  258. package/plugin/opencode/skills/afm-export-template/SKILL.md +42 -0
  259. package/plugin/opencode/skills/afm-generalize/SKILL.md +49 -0
  260. package/plugin/opencode/skills/afm-gotcha/SKILL.md +42 -0
  261. package/plugin/opencode/skills/afm-init/SKILL.md +84 -0
  262. package/plugin/opencode/skills/afm-plan/SKILL.md +36 -0
  263. package/plugin/opencode/skills/afm-policy/SKILL.md +31 -0
  264. package/plugin/opencode/skills/afm-promote/SKILL.md +41 -0
  265. package/plugin/opencode/skills/afm-protocol/SKILL.md +42 -0
  266. package/plugin/opencode/skills/afm-reconcile/SKILL.md +49 -0
  267. package/plugin/opencode/skills/afm-refactor/SKILL.md +86 -0
  268. package/plugin/opencode/skills/afm-reflect/SKILL.md +55 -0
  269. package/plugin/opencode/skills/afm-remediate/SKILL.md +41 -0
  270. package/plugin/opencode/skills/afm-restructure/SKILL.md +54 -0
  271. package/plugin/opencode/skills/afm-rule/SKILL.md +46 -0
  272. package/plugin/opencode/skills/afm-specify/SKILL.md +36 -0
  273. package/plugin/opencode/skills/afm-tasks/SKILL.md +34 -0
  274. package/plugin/opencode/skills/afm-update/SKILL.md +58 -0
  275. package/plugin/opencode/skills/afm-verify/SKILL.md +33 -0
  276. package/README.md +0 -3
@@ -0,0 +1,415 @@
1
+ ---
2
+ type: interview
3
+ description: The greenfield interview that materializes a new instance.
4
+ load: cold
5
+ ---
6
+
7
+ # Bootstrap — interview script
8
+
9
+ > This doc is an instruction **for the agent** when the operator runs `afm init` (or asks for something
10
+ > equivalent, like "set up the project doc"). The CLI materializes everything a repository can answer; this
11
+ > script runs the interview for what only the operator knows, a 7-step one, and fills the result into `docs/`.
12
+
13
+ > **In this file:** Invariant principles · Initial setup · Alternate branch — from-template · Step 0 — Problem context · Step 1 — Tech stack · Step 2 — Core data model · Step 3 — Critical flows · Step 4 — Mapping to the meta-framework · Step 5 — Inherited and new rules · Step 6 — Validation rituals · Step 7 — Gotchas and ADRs · Closing · Interview anti-patterns · Interview success criteria
14
+
15
+ ---
16
+
17
+ ## Invariant principles (do not violate)
18
+
19
+ **AFM universals**: see the single canonical source, `afm path PRINCIPLES` § Universals (§1-8). They apply
20
+ here. In particular:
21
+
22
+ - **#2** (discover-first): `afm init --mechanical` already scanned the repo. Where it found a signal (a
23
+ manifest with real dependencies, existing CI or hooks), bring it as the recommendation BEFORE you offer
24
+ options. Do not ask a blank question about what the repo already shows.
25
+ - **#4** (`[TBD]` beats invention): bootstrap never guesses the operator's answer.
26
+ - **#5** (do not invent an entity, rule or module): write only what the operator said.
27
+ - **#8** (questions are data, recommendation-first): every confirmation or selection with closed options
28
+ goes through `afm ask <op>`, whose questions live in `content/questions/<op>.questions.yaml` and carry
29
+ the recommended option. Free text is only for genuinely open questions (describe the product or the pain,
30
+ list entities, describe a flow).
31
+
32
+ **Specific to the bootstrap interview** (rules for *running* the interview, not for the methodology):
33
+
34
+ 1. **A pre-filled suggestion beats a blank question, wherever a signal exists (#2 + #8).** The report of
35
+ `afm init --mechanical` is the signal. Every suggestion still needs the operator's confirmation: the
36
+ stack is the operator's decision, so nothing is final without their agreement. Open free-text
37
+ questions are only for what you cannot infer: product, pain, persona, entities, flows. Ask one thing
38
+ at a time.
39
+ 2. **Validate before you move on.** After each free-text answer, restate it in one line, then
40
+ `afm ask confirm --scope <step-slug>` (for example `step0-product`). Move on only after `Yes, exact`
41
+ (or after you process the fix).
42
+ 3. **Record what the operator said, nothing more.** If they described 3 RFs, write 3 RFs. Do not add
43
+ "RF-04 security" because "every project needs it" (universal #5 in the interview context).
44
+ 4. **At the end, list every `[TBD]`.** The operator decides whether to fill them in now or later.
45
+
46
+ ---
47
+
48
+ ## Initial setup (before step 1)
49
+
50
+ 1. `afm preflight`. Exit 3 means there is no `docs/.afm-version`: a real greenfield, continue. Any other
51
+ exit means the project is already bootstrapped: **do not run bootstrap again**. The atomic ops stay
52
+ available (`afm gotcha`, `afm adr`, `afm rule`), and a newer version is `afm update`.
53
+ 2. **Detect the `docs/.template` marker.** If it exists, go to § Alternate branch below.
54
+ 3. **Ask the two decisions the mechanical pass needs:** `afm ask init` (harnesses whose instruction files
55
+ the project covers, and the product's string language). The language is a **product** decision, not a
56
+ rule: it goes to `prd.md § 11.1`, is declared and never enforced, and is what makes the english-first
57
+ exception mechanical. Without it, a later language migration (`afm update`) cannot tell an artifact
58
+ from a string the user reads, and it would translate the UI. `Decide later` records `[TBD]`.
59
+ 4. **Materialize:** `afm init --mechanical` (add `--dry-run` first to preview). It creates, and never
60
+ overwrites a file the operator already has:
61
+ - `docs/{prd,ach,afm,ust}.md` from the shipped skeletons, the project name from the manifest and every
62
+ placeholder filled by what the code answers, `[TBD]` where it does not;
63
+ - the five rule constants **measured, not assumed**: the source root and extension (the root with the
64
+ most non-test files), the file-size limit, the domain-function prefix and its subfolder. The report
65
+ prints each as `measured<TAB><constant><TAB><value><TAB><evidence>`;
66
+ - empty `docs/gotchas/` and `docs/rules/`, `docs/adr/0000-template.md`, every rubric and every pattern
67
+ the index lists (no hand-written list of names: `afm index --type rubric` is the list);
68
+ - `AGENTS.md` (the tool-agnostic file, canonical) and one stub per answered harness that imports it;
69
+ - `docs/.afm-version` last, so a run that stops half way can simply be run again.
70
+ The gate is the CLI (`afm gate`): nothing is copied into `docs/tools/` for it.
71
+ 5. **Read the report back to the operator** and go to step 0. A project that maintains the plugin itself
72
+ calls the shipped content through `afm path` instead of copying it (hard rule 34, one canonical source).
73
+
74
+ ---
75
+
76
+ ## Alternate branch — from-template (active only if setup detected `docs/.template`)
77
+
78
+ Scenario: the project comes from an architectural template (a clone of a starter with an inherited
79
+ `ach.md`, `afm.md` and `gotchas/`). Stack, rules and architecture are already decided. The interview
80
+ covers only the product.
81
+
82
+ 1. **Read the metadata** from `docs/.template` (JSON). Accept an empty file with the fallback
83
+ `{"template-name": "<unknown>", "template-version": "<unknown>", "exported-from-afm": "<unknown>"}`.
84
+ If metadata is missing, record it as unknown; do not invent it (#5).
85
+ 2. **Confirm the branch:** `afm ask init-template`. `Product only` runs steps 0, 3, 6 short and 7 adapted;
86
+ `Full interview` follows the standard flow and ignores the marker for this session (it stays on disk).
87
+ 3. On `Product only`, run `afm ask init` and `afm init --mechanical` as in setup: it writes the product
88
+ docs and the version marker and leaves the inherited `ach.md`, `afm.md` and `gotchas/` untouched. Then
89
+ **load the technical context** by reading those three inherited files (read-only). Note the stack
90
+ internally, to cite component types from `ach.md § 3.1` at closing.
91
+ 4. Tell the operator: *"Stack, architecture and rules are already set in the template. I will ask only
92
+ about the product."* Go to step 0.
93
+
94
+ ### Step subset in from-template mode
95
+
96
+ - **Step 0** (product, pain, persona, metric): full, materializes `prd.md`.
97
+ - **Step 3** (critical flows): full, materializes `ust.md`.
98
+ - **Step 6**, **short version**: one question, `afm ask gates` pre-checked from the inherited DoD in
99
+ `afm.md § 6`. The operator keeps it or lists the edits.
100
+ - **Step 7**, **adapted**: if the inherited `gotchas/` has entries, keep them unchanged and offer to add a
101
+ file (do not erase prior discovery, #5). If it is empty, follow the standard flow. Inherited `adr/`
102
+ files stay. New ADRs are born on demand through `afm adr`.
103
+
104
+ **Explicit skip:** steps 1 (stack), 2 (data model), 4 (component mapping) and 5 (inherited rules). All of
105
+ that is in the template. Asking again is redundant, and it would break principle #5 if the agent tried to
106
+ "validate" what was already decided.
107
+
108
+ ### Adapted closing (when from-template)
109
+
110
+ 1. **List the pending `[TBD]` items** (usually few: only steps 0 and 3). The operator replies with the ones
111
+ to fill in now.
112
+ 2. **Quick check:** the PRD has §1 + §2 + §3 + at least one RF. The UST has at least US-001. The inherited
113
+ `ach.md`, `afm.md` and `gotchas/` are unchanged. `docs/rubrics/` exists: if it is missing (a template
114
+ exported before 3.0.0-rc.5), `afm init --mechanical` copies it without touching what is inherited.
115
+ 3. **Add the inheritance line** under the version `afm init` wrote into `docs/.afm-version`:
116
+ ```
117
+ <version of the afm in use>
118
+
119
+ Inherited from template "<template-name>" v<template-version> (exported with afm v<exported-from-afm>)
120
+ ```
121
+ 4. **Origin note.** Add one bullet in the `## Canonical documentation` section of `AGENTS.md`: the project
122
+ started from architectural template `<template-name>` v<template-version>; stack, rules and
123
+ architecture are inherited (`docs/ach.md`, `docs/afm.md`, `docs/gotchas/`).
124
+ 5. **Generate the indexes:** `afm index --materialize`, then `afm index --check`.
125
+ 6. **Suggested commit:**
126
+ ```
127
+ docs(afm): bootstrap from-template — template "<template-name>" v<template-version>
128
+
129
+ Materializes PRD/UST from a product-focused interview.
130
+ Architecture and rules inherited from the template, untouched.
131
+ Open [TBD] items: <list>.
132
+ ```
133
+ 7. **Reminder for the operator:** the bootstrap is done; `docs/` is now a living source that evolves
134
+ through passive reconcile (every session watches the signals in `afm path interview/triggers` and
135
+ proposes edits); the atomic ops (`afm gotcha`, `afm adr`, `afm rule`, `afm promote`, `afm specify`,
136
+ `afm plan`, `afm tasks`, `afm clarify`, `afm analyze`) stay available on demand. The
137
+ single test for memory versus doc: *if another dev needs it to avoid breaking something, it is a doc.*
138
+
139
+ ### Anti-patterns of the from-template branch
140
+
141
+ - ❌ Re-check the inherited stack or rules through a re-ask. It breaks trust in the template; the operator
142
+ is responsible for keeping the template current.
143
+ - ❌ Modify the inherited `ach.md`, `afm.md` or `gotchas/` during this branch. They are read-only in this
144
+ session. Changes come through passive reconcile or the on-demand ops.
145
+ - ❌ Invent product details if the operator did not answer step 0 or 3. Use `[TBD]` (#4 and #5).
146
+ - ❌ Skip marker detection in setup: the branch only activates if setup confirmed that `docs/.template`
147
+ exists.
148
+
149
+ ---
150
+
151
+ ## Step 0 — Problem context (becomes PRD §1, §2, §3)
152
+
153
+ **Goal:** understand the product, the pain point and the persona. Materializes into `prd.md`.
154
+
155
+ **Questions (free text; a genuine description does not fit closed options):**
156
+
157
+ 1. *"In 3 sentences, what product are you building, and who is the user?"*
158
+ 2. *"What hurts today in this user's flow, without your product?"*
159
+ 3. *"What is the success criterion for a session? How do you know the user's job is done?"*
160
+
161
+ **Validation after each answer:** restate it ("I restated it as: «X»"), then `afm ask confirm --scope step0-q<N>`. Move to the next question only after `Yes, exact` (or after you process the fix).
162
+
163
+ **Materializes into `prd.md`:**
164
+
165
+ - §1 Summary: 1 paragraph drawn from answer 1.
166
+ - §2 Problem & Opportunity: the pain (answer 2) plus why now (`[TBD]` if the operator did not say).
167
+ - §3 Persona: extracted from answer 1.
168
+ - §6 MVP acceptance criteria + metric: derived from answer 3.
169
+ - §11.1 App-facing string language: the answer of `afm ask init` from setup, or `[TBD]`.
170
+
171
+ **Do not invent:** market size; target companies, if none was named; "why now", if no reason was given.
172
+
173
+ ---
174
+
175
+ ## Step 1 — Tech stack (becomes ACH §1, §2)
176
+
177
+ ### 1.0 — The stack scan is already done (gap-driven #2: infer before you ask)
178
+
179
+ `afm init --mechanical` enumerated the manifests, read each one and printed the stacks per manifest, **and
180
+ where each was found**. Do not re-derive it. A workspace root declares the tooling and none of the stacks,
181
+ so a root-only scan answers "no stacks here" for a repository full of them; the report is per manifest for
182
+ that reason. A stack present in one package out of eight is a true finding and a different fact from a
183
+ stack present everywhere: the operator needs the second half to judge the first. Report the union of the
184
+ stacks and say **where** each was found. `afm detect --stacks` repeats the scan on demand.
185
+
186
+ - **Signal found:** each layer comes with its evidence (the installed dependency), not with popularity.
187
+ The question becomes a **confirmation of a suggestion**, not a blank choice. A layer with no signal gets
188
+ no guessed recommendation: it stays blank for the operator.
189
+ - **Nothing found** (empty repo, no stack named in step 0): ask the layers as open questions in plain
190
+ conversation (web framework, API layer, DB + ORM, async tasks), with sensible defaults offered where one
191
+ exists.
192
+
193
+ ### 1.1 — Confirm the stack and the modules
194
+
195
+ Ask `afm ask bootstrap-stack` (questions in `content/questions/bootstrap-stack.questions.yaml`): the stack
196
+ as reported, and whether to apply the detected opt-in modules. `Leave as TBD` marks the layer `[TBD]` in
197
+ `ach.md` and says: *"I leave the pending layers as `[TBD]` instead of recommending now; a recommendation
198
+ works better once you have also defined what you do NOT want."* An answer outside the options is recorded
199
+ as given, without inventing a module.
200
+
201
+ **Materializes into `ach.md`:** §1 Macro architecture (an ASCII diagram of the layers based on the fixed
202
+ stack; an open component is a `[TBD]` box) and §2 Folders (a tree following the stack's conventions).
203
+
204
+ **Opt-in modules.** `afm index --triggers` lists one row per module with its stack and its `detect`
205
+ command; a zero exit means the stack is present. Apply every file under `modules/<stack>/` (read each
206
+ with `afm path modules/<stack>/<file>`) for each hit, unless the operator opted the module out. Do not
207
+ maintain a list of modules here: it was a hand-written list of six stacks until 3.31.0 while seven
208
+ existed, because the prose that named the modules was not the directory that held them. A stack with no
209
+ module (Nest, FastAPI, BullMQ) is `[TBD]` in the component types of `core/ach`. **Do not invent a
210
+ module**: promote it to the shipped content later (`afm promote`) once the learning is proven. A
211
+ `gotchas.seed` is a **commented reference** only, never an active gotcha: the project's `docs/gotchas/`
212
+ starts empty.
213
+
214
+ **Code-style seeds are opt-in item by item, never wholesale.** For each stack that hit, list the files
215
+ `afm index --type code-style` reports under `code-style/<stack>/` and `code-style/_any/`. Unlike a module
216
+ (applied whole, opt-out), a code-style file is one house convention its author observed in a single
217
+ project: naming, test placement, a file-size ceiling, an error-boundary shape, an import order. It is never
218
+ a fact of the stack. Applying it wholesale would rebuild the defect the split fixed, a `(mandatory)`
219
+ naming convention the operator never got a say in. State what each file decides in one line, then ask
220
+ `afm ask code-style`. **Materialize only what the operator marks**, verbatim, into
221
+ `docs/code-style/<stack>/<concern>.md`. An unmarked item is written nowhere: not as a note, not as a
222
+ commented-out stub. **Default = nothing marked, nothing applies**: the opposite default from modules and
223
+ rubrics, and deliberately so. Silent opt-in is the defect, not a shortcut around it.
224
+
225
+ ---
226
+
227
+ ## Step 2 — Core data model (becomes PRD §10 + ACH §1)
228
+
229
+ **Question (free text):** *"List the 3-5 core entities of the product and the relation between them, one
230
+ sentence each."*
231
+
232
+ **Materializes:** a mini ER diagram in ASCII into ACH §1, and one PRD §10 Glossary entry per entity.
233
+
234
+ **Validate:** show the restated ASCII ER diagram, then `afm ask confirm --scope step2-er`.
235
+
236
+ **Do not invent** attributes the operator did not mention, nor a relation they did not describe.
237
+
238
+ ---
239
+
240
+ ## Step 3 — Critical flows (becomes UST + PRD §4)
241
+
242
+ **Questions (one at a time):**
243
+
244
+ 1. *"Describe the main user flow, from the first click to the success state."* Materializes as **US-001**
245
+ in `ust.md`, with a happy-path Gherkin scenario.
246
+ 2. *"And the most likely error flow?"* Materializes as **US-002** or an extra scenario in US-001
247
+ (depending on scope).
248
+
249
+ **For each US written, ask** `afm ask rf-mapping --scope <us-id>` (for example `us-001`): which PRD RF it
250
+ implements. A new RF is drafted from the story as RF-01, RF-02 and so on in PRD §4; an existing one is
251
+ named by the operator; `Not yet` records `[TBD]`.
252
+
253
+ ---
254
+
255
+ ## Step 4 — Mapping to the meta-framework (becomes ACH §3)
256
+
257
+ **Present the generic component types:**
258
+
259
+ > "AFM works with 5 component types:
260
+ > 1. **Procedure-like**: sync request/response, under 5s.
261
+ > 2. **Domain-like**: a pure business-rule function.
262
+ > 3. **Task-like**: async, retry-safe.
263
+ > 4. **Lib-like**: an isolated, publishable package.
264
+ > 5. **Adapter-like**: a typed port implementation (registries, storages, etc).
265
+ >
266
+ > In your stack:
267
+ > - Procedure-like = {{tool inferred from step 1, e.g. a tRPC procedure}}
268
+ > - Domain-like = {{e.g. an exported TS function with the measured domain prefix}}
269
+ > - Task-like = {{e.g. a Trigger.dev v4 task}}
270
+ > - Lib-like = {{e.g. a folder under the source root with no framework import}}
271
+ > - Adapter-like = {{e.g. a port implementation under `<src-path>/lib/<provider>/<adapter>`}}"
272
+
273
+ **Confirm:** `afm ask bootstrap-mapping`. **Materializes into `ach.md` §3.1** with the stack's concrete
274
+ naming convention.
275
+
276
+ ---
277
+
278
+ ## Step 5 — Inherited and new rules (becomes AFM §3)
279
+
280
+ **The inherited rules are already in `afm.md § 3`**: `afm init --mechanical` copied every one. List them
281
+ for the operator with the numbers and headlines **read from `afm.md § 3`**, not from memory. The file
282
+ numbers slots up to 21; four of them (3, 8, 9, 14) are **demoted principles** that live in § 1.3 and carry
283
+ no trigger, so there is nothing to opt out of, and slot 21 is **INALIENABLE**. **Do not renumber to close
284
+ the gap**: the number is the rule's identity, and `afm doctor` compares the instance against the plugin by
285
+ number.
286
+
287
+ Ask `afm ask bootstrap-rules`. **Default = keep all.** For each rule the operator opts out of, ask why in
288
+ free text and record it with `afm rule na <id> --reason "<why>"`: the index line in `afm.md § 3` becomes
289
+ "N/A — <reason>" and the number stays. **Rules marked `INALIENABLE` do NOT enter this question.** They are
290
+ not silently omitted: list them, with a note that they apply to every project and are not opt-out. Offering
291
+ an opt-out and then refusing it would be worse than not offering one at all (`afm rule na` refuses them).
292
+
293
+ ### Rule constants: measured first, then proposed, never assumed
294
+
295
+ Five values belong to the **operator, not the framework**: the line limit (rule 6), the domain-function
296
+ prefix (rule 7), the source root, the domain-function subfolder inside it and the source-file extension. A
297
+ default disguised as best practice is invention (#5), and a rule whose constant the owner did not choose is
298
+ a rule the owner turns off at first friction. `afm init --mechanical` already **measured** them from the
299
+ code, and its report carries each value with the evidence. Propose each one with that measurement
300
+ attached: *"your file p90 is N lines, I propose a limit of N rounded up"*; *"your code already uses
301
+ `<prefix>` in X files, I propose it as the domain prefix"*; *"domain-prefixed functions already live under
302
+ `<subfolder>`"*. The operator accepts or changes each.
303
+
304
+ - **Greenfield project (nothing to measure):** the report proposes `300`, `domain_`, `src`, `ts` (or the
305
+ extension the chosen stack generates) and `domain`. **State that these are template defaults**, not a
306
+ measurement. The difference between an assumed default and a chosen default decides whether the rule
307
+ survives.
308
+ - **The operator does not answer, for any of the five:** the constant stays `[TBD]`. **Say that the rule
309
+ or path has no trigger until someone fills it in** (#4). Do not invent a value "to make it work": a
310
+ wrong literal replaced by an unfilled placeholder still fails silently.
311
+
312
+ **Free-text question:** *"Does your team have a specific rule that applies from day one?"* Examples:
313
+ "every PR needs 2 reviewers", "commits are always in English", "no direct commits to main". A ready-made
314
+ trigger for the last one: `git rev-parse --abbrev-ref HEAD | grep -qE '^(main|master)$'`. If yes, write it
315
+ with `afm rule` (numbers 18–29 are reserved for the template's universal rules; the command picks the next
316
+ free number). Each new rule MUST have a mechanical trigger; without one it becomes a principle in §1.3.
317
+
318
+ ---
319
+
320
+ ## Step 6 — Validation rituals (becomes AFM §6 + §6.1)
321
+
322
+ **Signal first (gap-driven #2).** The `afm init` report lists the checks the repo already runs (CI on a
323
+ PR, a pre-push hook, a lint-staged entry, a script, a Makefile target) as `check<TAB><check><TAB><stage>`.
324
+ Bring them **pre-marked**: CI on a PR maps to the merge DoD, a pre-push hook to pre-push. The question
325
+ becomes a confirmation. No signal means nothing is pre-marked.
326
+
327
+ **Ask `afm ask gates`** (two multi-selects, because DoD and pre-push are independent lists). Marking
328
+ nothing in either leaves that section `[TBD]` with the note "define before the first merge". If the
329
+ pre-push sequence needs a specific order or a custom command, ask a follow-up in free text: *"Any extra
330
+ command or specific order for pre-push?"*
331
+
332
+ **Materializes into `afm.md`:**
333
+
334
+ - §6 Definition of Done: the options marked for the merge DoD.
335
+ - §6.1 Pre-push validation: the command sequence for a push (for example tests, then the type check, then
336
+ the build) from the pre-push answer plus the optional free text.
337
+
338
+ ---
339
+
340
+ ## Step 7 — Gotchas and ADRs (start empty)
341
+
342
+ `afm init --mechanical` already created the structure; this step only decides what stays empty:
343
+
344
+ - `gotchas/`: empty. A gotcha is one file per entry, and `afm gotcha` writes the first.
345
+ - `rules/`: empty. A hard rule is one file per rule; section 3 of `afm.md` carries one index line per rule
346
+ in the `N. **title**` shape two hooks parse, and `afm rule` writes both sides.
347
+ - `adr/0000-template.md` exists; `adr/` is otherwise empty. ADRs are born when a real decision happens.
348
+ - `rubrics/` and `patterns/` hold every file the index lists, copied verbatim. They are runnable,
349
+ stack-agnostic decision tables, the highest-value content at apply time, and the placeholders in them
350
+ (the source root, domain path and extension) were filled by the measurement of step 5. A pattern only
351
+ ever *suggests*: it becomes a project norm solely when the operator accepts it, and only then does it
352
+ materialize into `code-style/`, `ach.md` or an ADR. The copy is not that acceptance.
353
+ - `evolution/` is **not** materialized now. It is born on demand at the first `afm evolve` cycle.
354
+ `docs/research/` is born the same way, at the first research.
355
+
356
+ **Do not write a retroactive ADR during the interview.** An ADR is a real decision with a concrete
357
+ symptom. If one comes up during development and is non-obvious, create the ADR at that moment (see
358
+ `afm path interview/triggers`).
359
+
360
+ ---
361
+
362
+ ## Closing
363
+
364
+ After the 7 steps:
365
+
366
+ 1. **List every `[TBD]`** (file and section, for example `prd.md § 3 Persona`) and let the operator reply
367
+ with the ones to fill in now. Marked items become free-text questions, one at a time. Unmarked items
368
+ stay `[TBD]` in the doc and are recorded in the commit note.
369
+ 2. **Generate the indexes:** `afm index --materialize`, then `afm index --check`. It writes an `index.md` in
370
+ every documentation directory plus the bundle-root `index.md` that declares `okf_version`. Hard rule 39
371
+ fails on a missing or stale index, so a bootstrap that skips this step hands the owner a red gate on the
372
+ first commit.
373
+ 3. **Quick check** with `afm doctor` and `afm gate --worktree`: the PRD has §1 + §2 + §3 + at least RF-01;
374
+ the ACH has a diagram plus component types mapped to the stack; the AFM has hard rules plus DoD plus
375
+ pre-push; the UST has at least US-001; `.afm-version` points to the version in use.
376
+ 4. **Instruction files.** `AGENTS.md` and the per-harness stubs were written by the mechanical pass. Add
377
+ the libraries detected in step 1 where the block asks for them. If the repo already had an
378
+ `AGENTS.md`, only the managed AFM block was merged in, never a duplicated rule.
379
+ 5. **Suggested commit:**
380
+ ```
381
+ docs(afm): initial bootstrap — afm version <version>
382
+
383
+ Creates PRD/ACH/AFM/UST/gotchas/adr from a guided interview.
384
+ Open [TBD] items: <list>.
385
+ ```
386
+ 6. **Reminder for the operator:** the bootstrap is done. `docs/` is now a living source that evolves with
387
+ the project through passive reconcile: every session watches the signals in
388
+ `afm path interview/triggers` (architectural decision, runtime surprise 2x, correction with a reusable
389
+ rule, gotcha, etc.) and proposes an edit to the right file. There is no need to run `afm init` again.
390
+ The ops `afm gotcha`, `afm adr`, `afm rule` and `afm promote` stay available on demand, for when the
391
+ operator wants to be explicit. The single test for memory versus doc: *if another dev needs it to avoid
392
+ breaking something, it is a doc.*
393
+
394
+ ---
395
+
396
+ ## Interview anti-patterns
397
+
398
+ - ❌ Fire 5+ free-text questions in the same turn: the operator loses context. (`afm ask` renders several
399
+ structured questions together, and that is fine: each one is a click, not typing.)
400
+ - ❌ "Do you want X or Y?" without having heard the problem first: a premature recommendation.
401
+ - ❌ Ask about the stack blank when the report shows one, or when the operator already named it in step 0.
402
+ Bring the inference as the recommendation to confirm (#2). An inference anchored in an installed
403
+ dependency is not a premature recommendation: the first has evidence, the second does not.
404
+ - ❌ Materialize before you validate: it produces a wrong doc the operator has to fix.
405
+ - ❌ Invent an RF "because it is best practice": write only what the operator asked for.
406
+ - ❌ Add a gotcha proactively: gotchas start empty and get discovered over time.
407
+ - ❌ Skip a `[TBD]` by guessing: invention is worse than a pending item.
408
+ - ❌ Write a retroactive ADR during the interview: an ADR is a real decision, not proactive documentation.
409
+
410
+ ## Interview success criteria
411
+
412
+ - The generated doc is useful **without** the operator having to edit it by hand (except to fill in `[TBD]`).
413
+ - No section contains invention that goes beyond what the operator said.
414
+ - Another dev who clones the repo and reads `docs/` can understand the product, the architecture and how
415
+ to contribute, with no need to ask.
@@ -0,0 +1,117 @@
1
+ ---
2
+ type: interview
3
+ description: The criteria that move a local learning into the plugin.
4
+ load: cold
5
+ ---
6
+
7
+ # Promotion — when to promote `/docs` to `framework-template/`
8
+
9
+ > This doc gives instructions **to Claude**. It detects a promotion candidate and proposes a PR.
10
+
11
+ > **In this file:** Principle · Decision table · Promotion flow · Criterion for "valid for any project" · Anti-patterns · Concrete example
12
+
13
+
14
+ ---
15
+
16
+ ## Principle
17
+
18
+ A learning in the project's `/docs/` can be:
19
+ - **Specific to the project** → it stays in `/docs/`.
20
+ - **Valid for any project with the same stack** → promote it to `framework-template/modules/<stack>/`.
21
+ - **Valid for any project, regardless of stack** → promote it to `framework-template/core/`.
22
+
23
+ **Promotion here means registering a candidate. It does not mean writing to the plugin.** The table below decides the finding's `target:` field. The maintainer applies the change, in the plugin's own repo, from the `afm_findings` entries. The boundary is absolute (`PRINCIPLES.md` #7). From inside an adopting project, the reachable `framework-template/` is only the **install cache** — a copy the next `plugin update` discards.
24
+
25
+ ---
26
+
27
+ ## Decision table
28
+
29
+ | Learning in the project's `/docs/` | Promote? | Where to |
30
+ | --- | --- | --- |
31
+ | Depends on a project entity (`SdkSource`, `App`, `Order`) | ❌ | Stays in `/docs/` |
32
+ | Local naming convention ("we prefix routes with X") | ❌ | Stays in `/docs/` |
33
+ | Current project status (auth wired? RFs pending?) | ❌ | Stays in `/docs/` |
34
+ | Valid for any project with the same stack (tRPC, Trigger, Stripe, etc.) | ✅ | `modules/<stack>/` |
35
+ | SDK or external library gotcha (Stripe Schedule, tsdown subprocess) | ✅ | `modules/<lib>/gotchas.seed.md` |
36
+ | Universal hard rule (valid in any project, any stack) | ✅ | `core/afm.md` §3 |
37
+ | Universal anti-pattern (a Lib that imports an ORM, a Domain that imports TRPCError) | ✅ | `core/ach.md` or `rubrics/` |
38
+ | Universal principle (saga ordering, error classification) | ✅ | `core/afm.md` §1.3 or §3 |
39
+ | Decision rubric (when to create X, which type to use) | ✅ | `rubrics/<name>.md` |
40
+
41
+ ---
42
+
43
+ ## Promotion flow
44
+
45
+ When Claude detects a candidate:
46
+
47
+ ### 1. Ask the user
48
+
49
+ > "I just added X to `/docs/{{file}}.md`. Does this learning **apply to any project {{with tRPC | with Stripe | universally}}**, not just this one? Do you want me to register it as a finding for the AFM plugin? `afm findings record` stores it in the project state for the maintainer to collect. This project does not change."
50
+
51
+ ### 2. If the user approves:
52
+
53
+ a. Check the **mechanical evidence**. Find the command that proves the learning: a passing test, `tsc`, or a `grep`/`test -e` that shows the defect. With no reproducible command, do not register it (#5).
54
+
55
+ b. Decide the `target:` field with the table above (`core/` vs. `modules/<stack>/`).
56
+
57
+ c. Append the entry to the session file's `afm_findings`. Use the issue-body format from `ops/promote.md` step 4. Include an imperative title, `target:`, `evidence:`, and `origin:` — project plus the version pinned in `docs/.afm-version`. Add 1-3 sentences on why the learning applies to any instance.
58
+
59
+ d. Report where the entry went. **Do not bump `VERSION`/`CHANGELOG`, and do not open a PR or commit in the plugin.** That is maintenance work. It happens in the plugin's repo.
60
+
61
+ ### 3. If the user declines:
62
+
63
+ The learning stays in the project's `/docs/`. Add an internal note ("X is specific to {{project}}").
64
+
65
+ ---
66
+
67
+ ## Criterion for "valid for any project"
68
+
69
+ Validation questions to ask before proposing:
70
+
71
+ 1. **Does the rule or gotcha reference a project-specific entity or model?**
72
+ If yes → it stays. If no → it might promote.
73
+ 2. **Does the solution depend on stack-specific tech?**
74
+ If yes → it goes to `modules/<stack>/`, not `core/`.
75
+ 3. **Would another project without this stack break without this rule?**
76
+ If yes → `core/`. If no → `modules/`.
77
+ 4. **Would the rule still hold if we changed the language?**
78
+ If yes → it is universal, and goes to `core/`.
79
+ 5. **Can I describe the rule without naming anything specific to the project?**
80
+ If yes → universal. If no → rewrite it as generic before promoting.
81
+
82
+ ---
83
+
84
+ ## Anti-patterns
85
+
86
+ - ❌ **Writing to `framework-template/`.** The boundary is absolute (#7). From here you can only register a candidate. The reachable path is the install cache. The edit dies at the next `plugin update`, with no error and no signal.
87
+ - ❌ **Registering a candidate without confirming with the user.** It might be specific to the project.
88
+ - ❌ **Registering a rule that names a project entity** ("App.healthStatus must...") without generalizing it first.
89
+ - ❌ **Registering an ADR.** An ADR is a decision for this project. A learning from that decision (a gotcha, a rule) can become a finding. The ADR itself cannot.
90
+ - ❌ **Registering a candidate with no reproducible mechanical evidence.** A finding with no command is just an impression (#5). The maintainer needs to be able to rerun it and see the same result.
91
+ - ❌ **Registering a candidate ahead of need** ("it will be useful later"). Register on demand, with a real case.
92
+
93
+ ---
94
+
95
+ ## Concrete example
96
+
97
+ ### Scenario
98
+
99
+ The `sdk.mapree.dev` project found that `package.json.type` must be `"module"` even in `format=cjs`, because of a tsdown subprocess.
100
+
101
+ ### Decision
102
+
103
+ - Goes to the project's `/docs/gotchas/`, one file per entry. ✅
104
+ - Goes to `framework-template/modules/trigger-dev-v4/gotchas.seed.md`? **Not directly** — it is not a Trigger.dev gotcha.
105
+ - Goes to `framework-template/modules/sdk-generator/`? **This module does not exist.** It is specific to this project.
106
+ - **Conclusion:** it stays in `/docs/`. No promotion (this learning lives in the project, not in the template).
107
+
108
+ ### Scenario 2
109
+
110
+ The `sdk.mapree.dev` project found that a Stripe webhook can arrive twice, and needs an idempotent UPSERT.
111
+
112
+ ### Decision
113
+
114
+ - Goes to the project's `/docs/gotchas/`, one file per entry. ✅
115
+ - `target: modules/stripe-billing/gotchas.seed.md`? **Yes** — every Stripe project runs into this.
116
+ - Register it in `afm_findings`. Use the title "Gotcha: Stripe webhook is at-least-once — needs an idempotent UPSERT". Add `evidence:` the test that reproduced the repeated delivery. Add `origin:` sdk.mapree.dev plus the pinned version.
117
+ - The `VERSION` bump and the `CHANGELOG` entry happen **in the plugin's repo**, when the maintainer collects the finding. Not here.