@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,379 @@
1
+ ---
2
+ type: interview
3
+ description: The brownfield roadmap that infers an instance from code that already exists.
4
+ load: cold
5
+ ---
6
+
7
+ # Refactor — retroactive AFM adoption roadmap
8
+
9
+ > This doc is an instruction **for the agent** when the operator runs `afm refactor` (or asks for something
10
+ > equivalent, like "adopt AFM here", "build retroactive docs for the project", "infer docs from the code").
11
+ > The CLI runs the **autonomous code archaeology** and materializes the skeleton of `docs/`; the agent
12
+ > fills the drafts from the report, runs **a short gap interview** and writes the forward-only rules.
13
+ >
14
+ > Difference from `afm path interview/bootstrap`: bootstrap interviews the operator in 7 steps about a new
15
+ > project. Refactor scans existing code, proposes drafts, and asks only what the code cannot reveal
16
+ > (persona, pain, intentional decisions).
17
+
18
+ ---
19
+
20
+ ## Invariant principles (do not violate)
21
+
22
+ **AFM universals**: see the single canonical source, `afm path PRINCIPLES`. Refactor applies **all** of
23
+ them: § Universals (§1-8) + § Additional (#9, a retroactive ADR is load-bearing-only). Especially
24
+ relevant here:
25
+
26
+ - **#2** (discover-first): Part A is the literal application. The CLI scans stack, folders, entities, git
27
+ and rules on its own. Do not ask "what is the stack" or "where is X".
28
+ - **#4** (`[TBD]` beats invention): refactor never infers persona, pain or intent from code. Code does not
29
+ reveal that.
30
+ - **#5** (do not invent an entity or module): refactor does not materialize an entity that is not in the
31
+ schema (or its equivalent).
32
+ - **#6** (autonomy-first): invoking `afm refactor` **is** the approval. There is no "start?" gate and no
33
+ per-file confirmation. Part B materializes the docs and **reports** (summary + paths). Review happens
34
+ over the `git diff` of the whole set, not a stop at each write. The same applies to D.10 (forward-only
35
+ default) and Closing (`[TBD]` goes to reconcile).
36
+ - **#8** (questions are data, recommendation-first): every closed confirmation or selection goes through
37
+ `afm ask <op>`. Free text is only for genuinely open questions (pain, persona, justify N/A).
38
+ - **#9** (a retroactive ADR is load-bearing): this sets refactor apart from bootstrap, which forbids one.
39
+
40
+ **Refactor-specific rules** (how the retroactive adoption runs, not the methodology itself):
41
+
42
+ 1. **Materialize and report, no gate.** Write all the docs and report a summary + paths. The operator
43
+ reviews via `git diff`. No "start?", "want to review?" or "adjust granularity?": the invocation is the
44
+ approval (#6).
45
+ 2. **Inherited hard rules are forward-only by default.** Legacy code does not need to retroactively pass a
46
+ strict type check or 100% coverage. Forward-only is documented in `afm.md § 3.1` with a cutoff date.
47
+ 3. **Do not ask what is discoverable.** Stack, folders, entities and broken rules all come from the scan.
48
+ **DoD and pre-push** also come from the scan (the CI and hooks it reports). The interview spends turns
49
+ only on **intent** the code cannot reveal: pain, persona, problem/MVP, load-bearing ADR, lived gotcha.
50
+
51
+ ---
52
+
53
+ ## Pre-check (before Part A)
54
+
55
+ 1. **Is this really brownfield?** `afm refactor --mechanical` checks all of it and refuses with the reasons
56
+ (exit 1) when any is false: `docs/.afm-version` does not exist (if it does, the project is already
57
+ bootstrapped: use `afm update` to raise the version, and the atomic ops stay available); a manifest
58
+ with real dependencies exists; the source root holds more than 0 non-test files; the git history has
59
+ more than 20 commits (a sign of a project with history, not a scaffold). A project with `docs/.template`
60
+ needs `afm init` (its from-template branch). Not brownfield: suggest `afm init`.
61
+ 2. **Ask the two decisions the mechanical pass needs:** `afm ask init` (the harnesses whose instruction
62
+ files the project covers, and the string language of the product). A brownfield project already HAS
63
+ strings on screen, so scan first (#2): read the UI strings the code carries, and tell the operator what
64
+ you found before they answer. The language is a **product** decision, declared and never enforced; it
65
+ goes to `prd.md § 11.1`. `afm update` reads it before a language migration and excludes those strings
66
+ by construction. Without it, a migration cannot tell an artifact from a string the user reads, and it
67
+ would translate the UI.
68
+ 3. **Announce the plan in one line and go straight in, no gate.** Invoking `afm refactor` is already the
69
+ approval (#6). Print: *"Running retroactive adoption: **A** — autonomous scan (stack, folders,
70
+ entities, README, git, CI and hooks, rule audit) · **B** — materialize the docs · **C** — short
71
+ interview, intent only (pain, persona, ADR, gotcha) · **D** — § 3.1 forward-only. Review at the end via
72
+ `git diff`."* If the operator wants to adjust or cancel, they interrupt.
73
+
74
+ ---
75
+
76
+ ## Part A — Code archaeology (autonomous, no operator turns)
77
+
78
+ **Run `afm refactor --mechanical`** (add `--dry-run` first to see the plan; `--answers <file>` runs it
79
+ headless). One command does every mechanical operation of this part and prints the facts, one
80
+ tab-separated line each. Keep the report: Part B writes it all at once.
81
+
82
+ ### A.1 Stack scan
83
+
84
+ The command enumerates the manifests first and reads each one, because a workspace root declares the
85
+ tooling and none of the stacks. Reading only the root manifest answers "no stacks here" for a repository
86
+ full of them; measured on 2026-09-04 across nine real JS/TS workspaces, 63 root-level probes were all
87
+ empty while the same probes fired correctly inside the packages. The report records **where** each
88
+ dependency was found, not only that it exists: a stack present in one package out of eight is a true
89
+ finding and a different fact from a stack present throughout. `afm detect --stacks` repeats the scan.
90
+
91
+ Map the stacks to the opt-in modules with `afm index --triggers` (one row per module with its `detect`
92
+ command), never with a table kept here. A stack with no module (Nest, FastAPI, Bun, BullMQ, Sidekiq) is
93
+ `[TBD]` in the component types of `core/ach`; consider future promotion with `afm promote`.
94
+
95
+ ### A.2 Folder tree scan
96
+
97
+ The report lists `component<TAB><type><TAB><convention><TAB><evidence>` lines: the dominant folder patterns
98
+ mapped to the universal component types (Procedure-like route handlers, Domain-like pure functions,
99
+ Task-like jobs, Lib-like isolated packages, Adapter-like port implementations). The **observed** shapes stay
100
+ literal on purpose: it is how this op recognises an existing project. Only the convention it writes into the
101
+ consumer's `ach.md` is parameterised by the measured source root. Output: a draft of `ach.md` §1 (macro
102
+ diagram), §2 (folder rules) and §3.1 (the component-type to concrete-stack mapping).
103
+
104
+ ### A.3 Entity scan
105
+
106
+ The report lists `entity<TAB><name><TAB><relations>` lines read from the project schema (a Prisma schema or
107
+ its equivalent). For each entity: the name goes to `prd.md` §10 (Glossary) with a one-line inferred role,
108
+ and the declared relations (foreign keys, relation attributes) go to a mini ER in ASCII in `ach.md` §1.
109
+ **Do not invent attributes** the schema does not have: if it only has an id, a creation date and a name,
110
+ the glossary says "Entity with a name (details in the schema file)".
111
+
112
+ ### A.4 README + git log scan
113
+
114
+ Read the README and the recent history yourself: they are prose, and judgment is the point.
115
+
116
+ - **PRD §1 (Summary):** the first one or two paragraphs of the README, if they describe the product. If the
117
+ README is only "how to install", mark §1 `[TBD]`.
118
+ - **PRD §4 (implicit RFs):** derived from the commits that open features. List 3-5 candidates as
119
+ `RF-01..RF-N` with the note *(inferred from commit `<sha>`)*.
120
+ - **PRD §2 (Problem), §3 (Persona), §6 (MVP/success criteria):** typically NOT inferable from code. Mark
121
+ `[TBD]` directly and ask in Part C.
122
+
123
+ ### A.5 Hard-rule audit
124
+
125
+ The report lists `audit<TAB><rule><TAB><violations><TAB><recommendation>` lines: the mechanical checklist
126
+ of the hard-rule slots run against the current code. Four slots (3, 8, 9, 14) are demoted principles with
127
+ no trigger: they are skipped, and the report says so. A rule that cannot be audited mechanically (idempotent
128
+ tasks, saga ordering, error classification, boundary validation) gets a quick visual check on sample files,
129
+ or is marked **N/A in the audit and applied forward-only by default**.
130
+
131
+ **The path constants are measured first** (`src-path`, `domain-path`, `ext`, then the file-size limit and the
132
+ domain prefix), the same way as in bootstrap: skipping this swaps a wrong literal for a placeholder nobody
133
+ fills, which fails silently, this repository's most expensive defect class. The report prints
134
+ `measured<TAB><constant><TAB><value><TAB><evidence>`. Propose each as `<constant> = <measured value>` with
135
+ the count attached, and record `[TBD]` for any the code does not answer (#4). The file-size audit is
136
+ reported against the measured p90, never against a number assumed here: *"p90 = 240; 7 files over the
137
+ proposal"*.
138
+
139
+ Output: a `rule | trigger | violations found | recommendation` table, for example:
140
+
141
+ | Rule | Trigger | Violations | Recommendation |
142
+ | --- | --- | --- | --- |
143
+ | 1 — TDD | tests/src ratio | 12 / 184 (6%) | forward-only from `<DATE>` |
144
+ | 2 — file ≤ limit | file lines | p90 = 240; 7 files over the proposal | propose the p90 rounded up, forward-only + split tickets |
145
+ | 4 — zero `any` | typed-escape count | 23 occurrences | forward-only from `<DATE>` |
146
+ | 11 — ADR for arch change | ADR count | 0 ADRs | apply now |
147
+
148
+ This table feeds Part D (it writes § 3.1 forward-only).
149
+
150
+ ### A.6 Decisions inferable as retroactive ADRs (candidate list)
151
+
152
+ The report lists `adr-candidate<TAB><stack>` lines. Decisions that **were probably intentional** and still
153
+ load-bear: the chosen stack ("tRPC instead of REST", where switching breaks every typed client), the ORM
154
+ ("Prisma instead of Drizzle", declarative schema plus generated migrations), the runtime or deploy target
155
+ ("Trigger.dev instead of BullMQ", ergonomics plus observability) and the adoption of a custom design
156
+ system. This list feeds C.9.4.
157
+
158
+ **Do NOT list as candidates:** naming conventions (emergent patterns, not decisions), a dependency version
159
+ (state, not a decision), folder structure (it goes in `ach.md` § 2, not an ADR).
160
+
161
+ ### A.7 CI and hooks scan (input for DoD + pre-push)
162
+
163
+ The report lists `check<TAB><check><TAB><stage><TAB><source>` lines, and `pr-flow<TAB>yes` when recurring
164
+ merges or a CODEOWNERS file show a PR flow. Each check is classified (`test`, type check, `lint`, `build`)
165
+ and by the stage it runs at: **CI on a PR or on a push to a protected branch** is a candidate for the
166
+ **DoD**, a **pre-push hook** for **pre-push**, and a PR flow points to a protected main branch, a candidate
167
+ for the "no direct commits to main" rule (`afm path interview/bootstrap` § Step 5). Output: two
168
+ pre-marked sets for C.9.6. Discovery-by-evidence is not invention (#5): what gates today is a fact. Whether
169
+ it *should* gate is what the operator confirms.
170
+
171
+ ---
172
+
173
+ ## Part B — Draft materialization + presentation
174
+
175
+ ### B.7 — Fill the docs from the report
176
+
177
+ `afm refactor --mechanical` already wrote the skeleton, and never over a file the operator has: `prd.md`,
178
+ `ach.md`, `afm.md` and `ust.md` with the measured constants filled and `[TBD]` where the code answers
179
+ nothing; `adr/0000-template.md`; empty `gotchas/` and `rules/`; every rubric and pattern; `AGENTS.md` with a
180
+ block recording the retroactive date; the per-harness stubs; and `docs/.afm-version`. Fill the gaps from
181
+ Part A, marking `[TBD]` for every one left:
182
+
183
+ - **`docs/prd.md`:** §1 from A.4; §2 and §3 `[TBD]`; §4 from the A.4 commits with an origin note; §6
184
+ `[TBD]`; §10 from the A.3 entities.
185
+ - **`docs/ach.md`:** §1 from A.2 and the A.3 mini ER; §2 from the observed tree; §3.1 the A.2 mapping; §3.2+
186
+ empty or `[TBD]`. Apply `modules/<stack>/ach.patch` (read it with `afm path`) for each stack detected.
187
+ - **`docs/afm.md`:** §1.1 and §1.2 from the universals; §1.3 `[TBD]` (project-specific principles come from
188
+ the interview); §3 carries **all** the rules (the file numbers slots up to 21; never copy a prefix, since
189
+ 17-20 and the INALIENABLE 21 live at the end and a "1-16" copy drops them in silence); §3.1 is filled in
190
+ Part D; §6 and §6.1 are `[TBD]` until C.9.6. Apply `modules/<stack>/rules.patch` for each stack.
191
+ - **`docs/ust.md`:** reverse-engineer from existing tests whose `describe`/`it` reads like a story,
192
+ US-001 onward, with the origin (`*test ref:* path/to/test`). With no narrative tests leave it empty with
193
+ the note "*USs to be created as features evolve*". The persona in each US is `[TBD]` (it comes from
194
+ Part C).
195
+ - **`docs/gotchas/`:** empty. For each detected stack with a `gotchas.seed`, **do not copy it as active**:
196
+ add a commented block at the end with the seeds, for the operator to review.
197
+ - **The gate** is the CLI, so nothing is copied into `docs/tools/`. **In a brownfield project run
198
+ `afm gate --baseline` as soon as the first runner exists**: the code predates the rule by definition, so
199
+ the gate would start red, and a gate that starts red is disabled the next day. The baseline turns what
200
+ HEAD already breaks into declared debt that only decreases. `afm install git` arms it when the
201
+ operator asks.
202
+ - **`docs/rubrics/` and `docs/patterns/`** were copied from the lists `afm index --type rubric` and
203
+ `afm index --type pattern` give: no hand-written names (a hand-written set of eight rubric names shipped
204
+ until 3.40.0 while twelve existed, and four never reached a refactored project). The path-constants
205
+ measurement of A.5 filled their placeholders. A pattern only ever *suggests*; it becomes a convention
206
+ when the operator accepts one in C.9.7.
207
+ - **`docs/code-style/`:** **not written here.** Every code-style seed is opt-in item by item, asked in
208
+ C.9.7. Writing it during this no-gate step would apply what the operator has not yet seen. (`evolution/`
209
+ is not materialized either: it appears on demand at the first `afm evolve` cycle.)
210
+
211
+ ### B.8 — Report
212
+
213
+ Report a summary + paths, **no review gate** (#6). Review happens via `git diff`, since the docs are
214
+ already on disk:
215
+
216
+ ```
217
+ I materialized the docs (+ rubrics/ + patterns/) in docs/ based on the scan. Summary:
218
+
219
+ - prd.md: N [TBD] (problem, persona, MVP, "why now").
220
+ - ach.md: diagram + inferred component types. 1 [TBD] in § 3.2 project-specific conventions.
221
+ - afm.md: all hard rules + the forward-only ones (filled in the next part). DoD/pre-push pre-filled from A.7.
222
+ - ust.md: N stories inferred from tests. Persona in [TBD].
223
+ - gotchas/: empty. K seeds from detected modules available in a comment.
224
+ - rubrics/, patterns/: copied. Nothing in patterns/ is a rule until you accept one, next in C.9.7.
225
+ - code-style/: nothing yet. Coming up next, item by item.
226
+
227
+ Review: git diff. To see a whole doc, just ask. Moving on to intent questions.
228
+ ```
229
+
230
+ Go straight to Part C. No need to ask "want to review?".
231
+
232
+ ---
233
+
234
+ ## Part C — Short gap interview (turns with the operator)
235
+
236
+ **Principles** (mirror bootstrap): ONE question per turn. Validate by rephrasing ("I understood: X.
237
+ Correct?"), then `afm ask confirm --scope <slug>`. If the operator says "I don't know", accept `[TBD]`. Do
238
+ not guess.
239
+
240
+ ### C.9 — Questions
241
+
242
+ - **C.9.1 Pain (free text):** *"In 1 sentence: what pain does this product solve?"* Rephrase, validate with
243
+ `afm ask confirm --scope refactor-pain`, fill `prd.md` § 2.
244
+ - **C.9.2 Persona (free text):** *"Who is the primary user, in 1 sentence (role + context)?"* Rephrase,
245
+ validate with `afm ask confirm --scope refactor-persona`, fill `prd.md` § 3.
246
+ - **C.9.3 Validate the README summary:** state *"I inferred the product summary from the README as: «X»"*,
247
+ then `afm ask confirm --scope refactor-summary`. Correct `prd.md` § 1 per the answer.
248
+ - **C.9.3b App-facing string language:** already answered in the pre-check by `afm ask init`: fill
249
+ `prd.md` § 11.1 from it. Nothing is asked twice.
250
+ - **C.9.4 Retroactive ADR candidates:** list the A.6 decisions that still load-bear, then `afm ask refactor`. Criterion: if the operator swapped it tomorrow, would someone need a doc to explain why? Yes
251
+ means ADR, no means skip. For each chosen one: `afm adr new <slug> --title "<title>" --description "<one sentence>"`, then fill the sections from the A.6 reasoning and mark the status
252
+ `Accepted (retroactive, created by afm refactor)`. For each unchosen one: leave it out (a dead decision
253
+ does not become an ADR later).
254
+ - **C.9.5 Gotcha seeds:** the same `afm ask refactor` round asks which seeds of the detected stacks the
255
+ team has already been bitten by (read each with `afm path modules/<stack>/gotchas.seed`). Seeds are
256
+ *candidates*: they activate only if the operator confirms "this has already happened here". For each
257
+ confirmed one: `afm gotcha new <slug> --basis bitten-twice ...` (see `afm path ops/gotcha`), and drop it
258
+ from the commented block. Then ask in free text: *"Do you remember other gotchas that are not on this
259
+ list?"* and register each through `afm gotcha`.
260
+ - **C.9.6 DoD + pre-push, recommendation-first with the A.7 defaults:** the checks found in A.7 come
261
+ **already checked**. What gates today may not be the desired target, so the question is a confirmation
262
+ ("is this what *should* gate, or do I adjust it?"). `afm ask gates` fills `afm.md` § 6 and § 6.1. With A.7
263
+ empty **and** nothing checked: `[TBD]` plus the note "define before the first merge after adoption".
264
+ - **C.9.7 Code-style seeds, one round per detected stack:** for each stack, list the files
265
+ `afm index --type code-style` reports under `code-style/<stack>/` plus `code-style/_any/`. Each is a house
266
+ convention the module's author observed in one project (naming, test placement, a file-size ceiling, an
267
+ error-boundary shape, an import order), never a fact of the stack. State in one line what each decides,
268
+ then `afm ask code-style`. Materialize only the marked items, verbatim, into
269
+ `docs/code-style/<stack>/<concern>.md`. An unmarked item is written nowhere. **Default = nothing marked,
270
+ nothing applies**: the opposite default from the rubrics and modules already copied, and deliberately so.
271
+
272
+ ---
273
+
274
+ ## Part D — Forward-only rules
275
+
276
+ ### D.10 — Write `afm.md` § 3.1
277
+
278
+ From the A.5 table, materialize the section in `docs/afm.md`:
279
+
280
+ ```md
281
+ ## 3.1 Forward-only rules
282
+
283
+ Retroactive adoption through `afm refactor` on <YYYY-MM-DD>. The rules below apply to **new code from this date on** and to **files you modify** (boy-scout rule). Legacy code that violates them is tracked tech debt, not a PR blocker. **This holds even for `INALIENABLE` rules.** Inalienable means the operator cannot switch the rule off. It does **not** mean the rule rewrites legacy code. A retroactive requirement would make adoption impossible in any codebase that did not start under it.
284
+
285
+ | Rule | Why forward-only | Tech debt tracked in |
286
+ | --- | --- | --- |
287
+ | 1 — TDD | Current coverage: <X>%. A retroactive sweep would take months. | `[TBD — open an issue or an ADR]` |
288
+ | 4 — zero `any` | <N> occurrences across <M> files. Incremental migration. | `[TBD]` |
289
+
290
+ **Boy-scout criterion:** when you edit a legacy file that violates a forward-only rule, bring it into conformance in the same PR if the PR scope justifies it. Do not force a 500-line refactor to fix a typo. Otherwise open a separate issue and link it.
291
+ ```
292
+
293
+ **Granularity: autonomous default (#6), no gate.** Materialize the table with **forward-only from today +
294
+ boy-scout**, the right default in most cases, and report it with a non-blocking note: *"Forward-only from
295
+ today + boy-scout by default. If you want a mandatory sweep (with a deadline) or rule-by-rule granularity,
296
+ tell me."* The operator adjusts it in review if they want. Do not block materialization with a question.
297
+
298
+ ### D.11 — `docs/.afm-version`
299
+
300
+ Written by `afm refactor --mechanical` with the version in use. Check that it is there; do not hand-write
301
+ the version.
302
+
303
+ ### D.12 — Instruction files
304
+
305
+ `AGENTS.md` is the canonical, tool-agnostic file and `afm refactor --mechanical` wrote it, plus a stub per
306
+ answered harness that imports it. If the repo already had an `AGENTS.md`, only the managed AFM block was
307
+ merged in: never duplicate a rule. The block carries the **retroactive adaptations**: the note *"This
308
+ project adopted AFM retroactively on `<YYYY-MM-DD>`, through afm v`<VERSION>`"*, `afm.md` flagged as
309
+ including § 3.1 forward-only (inherited rules apply only to new code plus boy-scout edits), and `adr/`
310
+ flagged as including the retroactive ADRs from adoption. Add the ADR note once C.9.4 created any.
311
+
312
+ ---
313
+
314
+ ## Closing
315
+
316
+ 1. **Report the `[TBD]` items left, no gate; reconcile takes over.** List each open item (file + section,
317
+ for example `prd.md § 3 Persona`) in the closing summary and in the commit note. Do not force filling
318
+ it now: `afm reconcile` (always-on) watches the `[TBD]` items and proposes filling them as the product
319
+ evolves. If the operator wants to close one right away, they ask. It is not a gate.
320
+ 2. **Generate the indexes and check:** `afm index --materialize`, `afm index --check`, then `afm doctor`.
321
+ The PRD has § 1 + § 2 + § 3 + at least 1 RF; the ACH has a diagram + mapped component types; the AFM has
322
+ rules + § 3.1 forward-only + DoD (or `[TBD]`); the UST has at least 1 US (even from an existing test; if
323
+ not, empty with a note is fine); `.afm-version` points to the version in use; the retroactive ADRs chosen
324
+ in C.9.4 are in `docs/adr/`.
325
+ 3. **Suggested commit:**
326
+ ```
327
+ docs(afm): retroactive adoption through afm refactor — afm v<VERSION>
328
+
329
+ Materializes PRD/ACH/AFM/UST/gotchas from code archaeology + a gap interview.
330
+ Forward-only rules from <YYYY-MM-DD>: <list>.
331
+ Retroactive ADRs: <numbered list>.
332
+ Open [TBD] items: <list>.
333
+ ```
334
+ 4. **Reminder for the operator:** the refactor is closed. `docs/` is now a living source that evolves
335
+ alongside the code through passive reconcile: every session watches the signals in
336
+ `afm path interview/triggers` and proposes an edit to the right file, with no explicit command.
337
+ Forward-only in § 3.1 is not an excuse to stop: boy-scouting an edited file keeps the improvement
338
+ gradient going. The ops `afm gotcha`, `afm adr`, `afm rule` and `afm promote` stay available on demand.
339
+ The single test for memory versus doc: *if another dev needs to know it to avoid breaking things, it is
340
+ a doc.*
341
+
342
+ ---
343
+
344
+ ## Anti-patterns
345
+
346
+ - ❌ **Inferring persona or pain from code.** Code does not reveal this. Always `[TBD]` + ask in Part C.
347
+ - ❌ **Inventing an entity not in the schema.** If the schema has only 3 entities, the glossary has 3.
348
+ - ❌ **Applying a retroactive hard rule without a forward-only flag.** This will lock up PRs.
349
+ - ❌ **Writing an ADR for every inferred decision.** Only for decisions with a present symptom
350
+ (load-bearing). Does swapping it hurt? ADR. Does swapping it not hurt? A note in `ach.md`, or skip it.
351
+ - ❌ **Materializing step by step and asking for confirmation.** Bootstrap does this because the answers
352
+ come from the operator. Refactor does an autonomous scan and materializes-and-reports. Per-file
353
+ confirmation is needless friction (#6).
354
+ - ❌ **A "start?", "want to review?" or "adjust granularity?" gate.** Invoking `afm refactor` is already the
355
+ approval (#6). Announce, materialize, report. Review happens via `git diff`.
356
+ - ❌ **Asking DoD/pre-push blind.** What gates merge and push is in CI and hooks, and the report lists it.
357
+ Confirm what was found (#2). A blank selection is only for when A.7 finds nothing.
358
+ - ❌ **Forcing `[TBD]` items to be filled at closing.** Report the list and let `afm reconcile` propose it
359
+ later. `[TBD]` beats pressure for a rushed answer (#4).
360
+ - ❌ **Skipping Part A to go straight to the interview.** Without the scan this becomes a badly-run
361
+ bootstrap ("tell me what you remember about the product"). The operator adopted AFM retroactively because
362
+ the doc did not exist; they probably do not remember everything the code does, either.
363
+ - ❌ **Activating gotcha seeds without the operator's confirmation.** Seeds are *candidates*. They activate
364
+ only if the operator confirms "this has already happened here".
365
+
366
+ ---
367
+
368
+ ## Refactor success criteria
369
+
370
+ - The generated doc is useful **without** the operator having to edit it by hand (except filling `[TBD]`
371
+ and validating retroactive ADRs).
372
+ - No section contains invention beyond what the code shows or the operator answered.
373
+ - Another dev can clone the repo, read `docs/`, and understand the product and the architecture, including
374
+ the rules in force and what is forward-only, without having to ask.
375
+ - Forward-only never becomes an excuse to never improve legacy code. The boy-scout rule in § 3.1 keeps the
376
+ improvement gradient going.
377
+ - **Only genuine intent spends a turn.** Zero ceremony gates (start, want-to-review, granularity, pending
378
+ items). Nothing discoverable (stack, folders, entities, DoD, pre-push) is asked: it comes from the scan.
379
+ What is left to ask is pain, persona, problem/MVP, load-bearing ADR and lived gotcha.
@@ -0,0 +1,107 @@
1
+ ---
2
+ type: interview
3
+ description: The signals that reconcile watches to know a doc edit is due.
4
+ load: cold
5
+ ---
6
+
7
+ # Triggers — Signals for Doc Evolution
8
+
9
+ > This doc gives instructions to the agent. The agent reads it every session, detects a signal and proposes an edit. The agent does not apply the edit alone.
10
+
11
+ ---
12
+
13
+ ## Single Principle
14
+
15
+ Invariant principle #1 (see [`../PRINCIPLES.md`](../PRINCIPLES.md)): the agent's memory holds no project rule. It holds only the user's style. Here is the direct application:
16
+
17
+ Use this one hard criterion to decide where something goes:
18
+
19
+ > "If another developer (or another agent without my memory) needs this fact to avoid breaking something, it belongs in a doc, not in memory."
20
+
21
+ Memory holds only:
22
+ - The user's communication style (terse vs. verbose, no emoji, and so on).
23
+ - A durable preference (small PRs vs. large bundles).
24
+ - Personal context (role, years of experience, current focus).
25
+
26
+ Project knowledge always goes into `/docs/`.
27
+
28
+ ---
29
+
30
+ ## Trigger Table
31
+
32
+ Every session, watch for these signals. When one fires, propose the edit to the user. Do not apply it alone. The user approves, then the agent edits.
33
+
34
+ | Signal observed during the session | Affected doc | The agent's action (ready-made line) |
35
+ | --- | --- | --- |
36
+ | A new structural decision (a new layer, a new first-class component, a new cross-module contract, a folder refactor) | `ach.md` + new `adr/NNNN-*.md` | "I just proposed X, and that is an architectural decision. Do you want me to draft an ADR and update ACH before we merge?" |
37
+ | The same runtime/SDK surprise blocked us 2 times | `gotchas/` | "This behavior confused me before. I will log it in gotchas with an explicit trigger: 'If you edit X, read this first.'" |
38
+ | The user corrected the approach with a reusable rule ("no, never do Z") | `afm.md` § 3 (hard rule) or § 5 (off-track signal) | "I will add this as a hard rule. What mechanical trigger detects the violation? (`grep`, a checklist, and so on)" |
39
+ | **A catalog guardrail whose `signal` field matches this project** — run the `signal` field from `../guardrails/*.md` (it returns 0/1), and the gate is not yet installed. **One line covers the whole catalog**: the catalog grows, this row does not | `../guardrails/<id>.md` (read) + an install proposal | "This project matches guardrail `<id>`'s signal: `<the command that matched>`. Once installed, it becomes trigger `<trigger>`. Installing writes **outside `docs/`**, so I will not do it alone (bright line). I will bring you the constant to fill in and the possible surfaces, so you can choose where it runs. Want to see it?" |
40
+ | **A hard rule whose trigger is an ad hoc command where a versioned script already exists** — the `*Verification:*` field of a § 3 rule rewrites in prose what a repo `test/*.sh` already does | `afm.md` § 3 (the rule) | "Rule N verifies with a hand-written command, and `<script>` already does this in a versioned form. Should I point `*Verification:*` at the script? Rewriting the command in prose creates a second source of truth that drifts on its own." |
41
+ | The user accepted a counterintuitive approach ("the single bundled PR was right here") | `afm.md` § 5 (validated) or ADR | "Do you want me to log this as a validated decision? (So another agent or developer does not undo it.)" |
42
+ | A new component appeared (a 3rd caller of a helper, a new module, a promoted library) | `ach.md` § 3 + naming convention | "I promoted X from inline code to `lib/`. Should I update ACH § 3.2 and add a canonical example?" |
43
+ | **Primitive boilerplate grew** — the same fixed-order sequence of primitive calls repeats ≥3 times, AND the wiring hides the intent at those sites, AND a reusable grammar exists (composition, ordering, branching) | candidate `adr/NNNN-*.md` + check `rubrics/when-to-create-dsl.md` | "I noticed the same wiring sequence repeated in N places, and the boilerplate hides the intent. A DSL (builder or combinators) may help. This is an architectural change (rule 11), so **I will not build it alone**. I will bring you an API sketch and a candidate ADR for you to decide. Want to see it?" |
44
+ | **A doc gave bad guidance at apply time** (the `reflect` behavior accumulator) — I applied a rule or section from **one** core doc, and it was ambiguous (I had to reread it, or read it two ways), it led me to an error, or the user corrected me against that specific doc ≥2 times in the session. **This accumulates** (do not propose on every turn — the default threshold is ≥2 events per session, but an explicit user complaint unlocks it right away) | suggest `afm reflect` (instructiveness refinement) | "Rule/section X guided me poorly today (ambiguous, stale, or I hit this 2 times). Running `afm reflect` lets me propose making it more assertive. I add nothing new, I only refine what exists. Want me to?" |
45
+ | **A lived contradiction between docs** (Class B of evolve) — I followed **two** core docs that contradict each other in the same task | suggest `afm evolve` (health cycle) | "The docs contradict each other on X (I hit this 2 times in this session). This is not a one-off fix. Running `afm evolve` can diagnose the whole instance's health and propose a package. Want me to?" |
46
+ | **Perceived bloat at apply time** (Class B of evolve) — while loading context, a notably redundant or duplicated core doc got in the task's way | suggest `afm evolve` (health cycle) | "`afm.md` or `ach.md` looks bloated or duplicated, and it got in the way just now. If you want, `afm evolve` can audit the instance (with `wc`/grep, real evidence) and propose a trim at the gate. I apply nothing without your approval." |
47
+ | **≥2 similar gotchas accumulated** (the `generalize` mechanism) — I saw 2+ gotchas/rules in `gotchas/` that share the same abstract cause (one more general instruction would have prevented all N) | suggest `afm generalize` (semantic consolidation) | "These N gotchas say the same thing in different cases. Running `afm generalize` can merge them into one abstract rule (with a tombstone on the originals, no lost provenance). This cuts bloat at the root. Want me to?" |
48
+ | **Staleness or misplaced info** (the `restructure` mechanism) — a doc references code that changed and was not updated (likely, per `git log`), OR I searched for guidance that **exists** but sat in the wrong doc or section | suggest `afm restructure` (context architecture) | "`<doc>` may be stale versus `<path>` (it changed since the doc's last edit), or guidance X was buried where I did not look. `afm restructure` proposes an update or a move at the gate. (If the info does **not** exist anywhere, that is a case for `afm gotcha`, not restructure.)" |
49
+ | **A failure crossed the § 5.1 terminal condition** (a test/`tsc`/command returned non-zero and stayed unresolved past the retry cap, OR the user explicitly corrected the approach) | the failure store of the AFM state directory (the failure hook logs it) + suggest `afm remediate` | "This failure crossed the retry cap, or you corrected me. The failure hook already recorded it with the external signal (`sig=`). If it recurs (≥2 times) or you confirm, I will run `afm remediate` to turn it into a procedure (mechanical) or a learning (conceptual)." |
50
+ | **The same failure `sig=` recurred ≥2 times** (recurrence: `afm failures promotable` lists it) | suggest `afm remediate` (CRITIC loop) | "This failure recurred. Running `afm remediate` can resolve it for good — a runbook (`procedures/`) for a mechanical sequence, or a `learnings/` entry for future agent sessions if it is conceptual. I apply nothing without your approval." |
51
+ | **A repeatable operational sequence ran ≥2 times** (a release, deploy, or migration done by hand again) | `docs/procedures/` via `afm remediate` | "You did this sequence (release, deploy, or migration) by hand ≥2 times. I want to turn it into a `docs/procedures/` runbook with a 0/1 check per step. May I?" |
52
+ | **An artifact was written in a language other than English**, and `prd.md` § 11.1 does not say that language is the product's own | `prd.md` § 11.1 (read first) + the artifact | "I wrote `<file>` in `<language>`. Artifacts are English (the rule), and the ONE exception is the strings your users read, which `prd.md` § 11.1 declares. That field says `<value>`, so this file is not covered by it. Should I rewrite it in English, or is this a product string that belongs in the exception?" **Read § 11.1 before you fire this.** With `[TBD]` there, ask which of the two it is — never assume the file is a violation. |
53
+ | A feature started with no matching US | `ust.md` | "I found no matching US. Do you want me to create US-NNN before I start implementing?" |
54
+ | A product scope change (an RF cut or addition) | `prd.md` § 4 | "This changes RF-NN. Should I update the table and note in the PRD?" |
55
+ | The user asks to DELIVER a feature ("build feature X", "implement X", "deliver X end to end") | `deliver` flow (`afm.md` § 2.2) | "I will run the autonomous delivery: scan the code, research libraries through nasca, ask you only what I cannot infer, build the plan for one approval, and execute to the end. May I? (Say 'go' and I go straight through.)" |
56
+ | An in-progress change reaches >200 lines / >3 files, OR it crosses layers, OR it adds a new external boundary | new `docs/features/NNN-*/` via `deliver` | "Should I promote this to a feature folder and deliver it via `afm deliver`? It runs discovery, builds a plan for one approval, and executes to the end." |
57
+ | The user is about to start T001 in `tasks.md` for a feature, and `analyze` has not run this session | `analyze` (suggestion) | "Before starting T001 for this feature, should I run `afm analyze` to catch coverage gaps?" — suggest once per feature, do not repeat. |
58
+ | I learned a pattern about the user (a durable style preference) | memory | save it in the agent's memory as a durable preference |
59
+ | I learned technical knowledge about the project | doc | edit the doc (`afm`, `ach`, `prd`, `gotchas`, `adr`) |
60
+ | The learning generalizes to any project | propose a change to the AFM template content | see `promotion.md` |
61
+
62
+ ---
63
+
64
+ ## Concrete Examples (Training)
65
+
66
+ ### Example 1 — A Gotcha Emerges
67
+
68
+ **Session:** the user and the agent debug for 30 minutes: "this tsdown subprocess breaks with `type: commonjs`." They fix it. It works.
69
+
70
+ **Signal detected:** "the same runtime surprise blocked us 2 times." The user mentioned it had confused another developer before.
71
+
72
+ **Proposed action:** "I will add a `gotchas/` entry. Read it before you edit emit/package-json.ts or move the tsdown binary. `type` stays `module`, even in format=cjs. Do you also want ADR-0003 with the full decision?"
73
+
74
+ ### Example 2 — A New Rule Emerges from a Correction
75
+
76
+ **Session:** the agent implemented `domain_X`, which imports `TRPCError`. The user flags it: "Domain code never imports a transport error. Map code to TRPCError in the procedure."
77
+
78
+ **Signal detected:** "the user corrected the approach with a reusable rule."
79
+
80
+ **Proposed action:** "I will add hard rule 15 to `afm.md` § 3: 'Domain code never imports TRPCError. Use DomainError({ code: ... as const }). The procedure maps it at the boundary.' Mechanical trigger: `grep -rn 'TRPCError' {{src-path}}/server/modules/**/domain/` returns 0. Correct?" (`{{src-path}}` is the project's measured source root — see `bootstrap.md` § Step 5 "Rule constants" or `refactor.md` § A.5. Pasting this example with a literal `src/` would hardcode a house layout as a consumer's hard rule for a project whose real root is `app/` or `lib/`.)
81
+
82
+ ### Example 3 — Promotion to the Template
83
+
84
+ **Session:** a new project learned that a Stripe webhook can arrive 2 times, and it needs an idempotent UPSERT. The user confirms the rule.
85
+
86
+ **Signal detected:** "the learning generalizes to any project" — this applies to every project that uses Stripe.
87
+
88
+ **Proposed action:** "This rule (`idempotent webhook UPSERT via unique stripeSubscriptionId`) applies to any Stripe project. I just added it to `/docs/gotchas/`. Do you also want me to propagate it to the `modules/stripe-billing/gotchas.seed.md` of the AFM template content? Then your next project gets it for free."
89
+
90
+ ---
91
+
92
+ ## Anti-Patterns
93
+
94
+ - ❌ **Apply an edit without proposing it first.** The user decides what goes into the doc.
95
+ - ❌ **Save a project rule in memory.** This violates the single principle. Memory is not a doc.
96
+ - ❌ **Invent a gotcha without the 2-time trigger.** A gotcha comes from real use, not imagination.
97
+ - ❌ **Promote to the template before the user confirms.** The learning may be project-specific.
98
+ - ❌ **Propose an edit on every turn.** Accumulate signal across the session, then propose when it carries weight.
99
+
100
+ ---
101
+
102
+ ## When NOT to Propose
103
+
104
+ - A trivial change (a variable rename, a lint fix, a typo).
105
+ - A refactor with no new learning (code moves, but behavior does not change).
106
+ - A bug fix that reveals no rule (it was a typo, not a decision).
107
+ - An exploratory session that has not converged — wait for it to settle.
@@ -0,0 +1,44 @@
1
+ ---
2
+ type: module
3
+ description: 'Adds the Server/Client Component split to the materialized ACH. The folder tree, the UI-primitive location, and the route-group/handler-delegation convention are opt-in seeds — see the pointers below.'
4
+ load: cold
5
+ stack: nextjs-app-router
6
+ patches: 'docs/ach.md'
7
+ detect: |
8
+ if command -v jq >/dev/null 2>&1; then jq -e '(.dependencies//{})+(.devDependencies//{})+(.peerDependencies//{})|has("next")' package.json >/dev/null 2>&1; else grep -q '"next"' package.json 2>/dev/null; fi
9
+ ---
10
+
11
+ # Patch — ACH for Next.js App Router projects
12
+
13
+ > This patch applies to `/docs/ach.md`. Insert the sections below at the marked points.
14
+
15
+ ## §2 — Add to the folder tree
16
+
17
+ > Whether the App Router root sits at the repo root (`app/`) or under `src/` (`src/app/`) — Next.js
18
+ > accepts both — and how a route group under it gets named, are house choices, not a Next.js
19
+ > requirement. They now live as an opt-in seed at `code-style/nextjs-app-router/naming.md`
20
+ > (concern: naming). Materialize it only if the operator accepts it.
21
+
22
+ ## §3 — Add the UI primitives component
23
+
24
+ > The `src/components/` location this patch used to state as fact for UI primitives is the same
25
+ > house choice as the folder root above — Next.js has no opinion on where a component lives. It
26
+ > now lives in the same opt-in seed, `code-style/nextjs-app-router/naming.md` (concern: naming).
27
+
28
+ ## §6 — Add dashboard routing
29
+
30
+ > The route-group split this patch used to state as fact (`(protected)/` vs `auth/`) and the
31
+ > "route handlers stay thin and delegate to `server/`" rule are both house convention, not a
32
+ > framework requirement. They now live as opt-in seeds at
33
+ > `code-style/nextjs-app-router/naming.md` (concern: naming, for the route-group split) and
34
+ > `code-style/nextjs-app-router/imports.md` (concern: imports, for the delegate-to-`server/`
35
+ > rule). Materialize either only if the operator accepts it.
36
+
37
+ ## Additional hard rules
38
+
39
+ (number these starting from the next free slot in `afm.md` §3)
40
+
41
+ - **Server Component is the default. Use "use client" only where you need interactivity.**
42
+ *Verification:* `grep -rn "use client" src/app app 2>/dev/null` reviews each context. Each match must justify itself (a form, a state hook, a DOM event).
43
+ - **Do not fetch directly in a Server Component when a typed client is available**. Use the direct server client (`trpcServer`) on the server, and React Query on the client.
44
+ *Verification:* `grep -rn "fetch(" --include=page.tsx src/app app 2>/dev/null` finds no raw fetch call in a page.
@@ -0,0 +1,78 @@
1
+ ---
2
+ type: module
3
+ description: 'Seed gotchas for the App Router, starting with cookies() and headers() being valid only in a Server Component or a route handler.'
4
+ load: cold
5
+ stack: nextjs-app-router
6
+ patches: 'docs/gotchas/*.md'
7
+ detect: |
8
+ if command -v jq >/dev/null 2>&1; then jq -e '(.dependencies//{})+(.devDependencies//{})+(.peerDependencies//{})|has("next")' package.json >/dev/null 2>&1; else grep -q '"next"' package.json 2>/dev/null; fi
9
+ ---
10
+
11
+ # Gotchas seed — Next.js App Router
12
+
13
+ > Each entry below is a complete gotcha file. Copy one to `docs/gotchas/NNN-slug.md` (the first `---` of the entry as line 1) only when it bites in real use. Do not copy everything proactively. Re-date `last_bite` on copy.
14
+
15
+ ---
16
+ type: gotcha
17
+ description: 'cookies() and headers() from next/headers work only in a request context (Server Component, route handler, server action) and throw everywhere else.'
18
+ load: warm
19
+ fires_on: event
20
+ fires_when: 'you use cookies() or headers() from next/headers in a pure library or in a Client Component.'
21
+ bites: 1
22
+ last_bite: 2026-10
23
+ refs:
24
+ - 'node_modules/next/dist/docs/01-app/02-api-reference/04-functions/cookies.mdx'
25
+ ---
26
+
27
+ ## Next.js — `cookies()` / `headers()` work only in a Server Component or route handler
28
+
29
+ ## Behavior
30
+
31
+ Both functions work only in a request context: Server Component, route handler, or server action. Everywhere else, they throw an error at runtime.
32
+
33
+ ## Solution
34
+
35
+ Read cookies in the Server Component or route handler. Pass the value to the client component as a prop. Never import `next/headers` in code that can run in the browser.
36
+
37
+ ---
38
+ type: gotcha
39
+ description: 'revalidatePath and revalidateTag invalidate the Next.js cache only; React Query keeps its own client cache, so a mutation must also invalidate the client query.'
40
+ load: warm
41
+ fires_on: event
42
+ fires_when: 'you are in a route handler or server action and want to refresh the client cache.'
43
+ bites: 1
44
+ last_bite: 2026-10
45
+ ---
46
+
47
+ ## Next.js — `revalidatePath` / `revalidateTag` do not invalidate React Query
48
+
49
+ ## Behavior
50
+
51
+ `revalidatePath` invalidates the Next.js cache (RSC + fetch). React Query keeps its own cache on the client. A server action that mutates data must also invalidate the client query. This does not happen automatically.
52
+
53
+ ## Solution
54
+
55
+ Return a signal to the client that triggers `queryClient.invalidateQueries(...)`. Or use a stack client that already integrates this, for example `@trpc/tanstack-react-query`, which invalidates automatically in `onSuccess`.
56
+
57
+ ---
58
+ type: gotcha
59
+ description: 'A root layout under a dynamic segment (app/[lang]/layout.tsx) leaves the internal _not-found route with no root layout, so the build fails or serves a raw 404.'
60
+ load: warm
61
+ fires_on: event
62
+ fires_when: 'you delete app/layout.tsx and move <html>/<body> to app/[lang]/layout.tsx (an i18n pattern, for the correct lang at SSR).'
63
+ bites: 1
64
+ last_bite: 2026-10
65
+ refs:
66
+ - 'node_modules/next/dist/docs/.../file-conventions/not-found.md (section global-not-found.js)'
67
+ - 'node_modules/next/dist/docs/.../layout.md (root layout under a dynamic segment)'
68
+ ---
69
+
70
+ ## Next.js — a root layout under a dynamic segment orphans `_not-found`
71
+
72
+ ## Behavior
73
+
74
+ Next.js generates an internal `/_not-found` route that lives **outside** the `[lang]` segment. It then has no root layout to compose the document. The build fails (the `_not-found` page has no root layout) or serves a raw 404. Non-locale paths that escape the proxy redirect (for example `/foo.bar`, with a dot) fall into the same gap.
75
+
76
+ ## Solution
77
+
78
+ Add `app/global-not-found.tsx`. It returns its own complete HTML document (`<html><body>…`, default lang, provider-free, because it bypasses layouts). Enable it with `experimental.globalNotFound: true` in the Next.js config (Next.js 15.4 or later). The `notFound()` of localized routes still resolves in `app/[lang]/not-found.tsx` (inside the layout, with the correct html lang and theme).