@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,317 @@
1
+ ---
2
+ type: op
3
+ description: 'Runs the self-evolution cycle: five mechanisms plus update, under one gate.'
4
+ load: warm
5
+ writes: ["docs/evolution/*.md"]
6
+ composes: ["diagnose", "reflect", "generalize", "restructure", "update", "remediate"]
7
+ ---
8
+ # Sub-flow: orchestrator for the AFM local documentation self-evolution cycle (`evolve`)
9
+
10
+ > **In this file:** What `evolve` is / is not · Pre-check · Phase 1 — Evidence collection · Proposal discipline · Phase 2 — Proposal · Phase 3 — Single gate (≈ Commit κ) — always ha… · Phase 4 — Application + postconditions · Phase 5 — Record + promote · Whitelist — evolvable vs. protect… · Suppression contract · Anti-patterns
11
+
12
+
13
+ > **Form** — effect: `docs/evolution/<date>-NNN` · trigger: `afm evolve`, **cadence** · precondition: `.afm-version`, cooldown 14d · composed of: — (orchestrator) · **degree of freedom: medium**
14
+
15
+ Triggers:
16
+ - `afm evolve`.
17
+ - Natural language about **the health of the AFM docs in this project**, for example:
18
+ - "audit the methodology"
19
+ - "AFM here is not at 100%"
20
+ - "the docs are a mess"
21
+ - "the rules do not fire anymore"
22
+ - "clean up the docs"
23
+
24
+ > ## ⚠ The target of evolution: the local docs, NEVER the plugin
25
+ >
26
+ > **"Methodology self-evolution" does NOT mean evolving the AFM plugin.** It means refining the **materialized instance** of the methodology **in this project** — the files in `<consumer>/docs/` (`afm.md`/`ach.md`/`gotchas/`/rubrics/ADRs/…) — to make them **leaner, clearer, current, and efficient**.
27
+ >
28
+ > - **Evolves:** only `<consumer>/docs/` (the local docs of this repo). This is the only write target of the whole cycle and of the 4 mechanisms.
29
+ > - **NEVER touches:** the bundled content (the AFM package: the canonical framework). This is bright line #7. The mechanical boundary postcondition (Phase 4.3) exists to prove the cycle did not dirty the plugin. It has **two branches**, because in a consumer project the plugin root is not a git repo.
30
+ > - **To the plugin, only RECORDS:** if a lesson applies to **any** instance (not only this project), the cycle suggests `afm promote`. That op **records the finding** with `afm findings record`, in the project state, with mechanical evidence. No one applies it to the plugin from here. The boundary is absolute (#7). The maintainer applies it, in the plugin repo.
31
+ >
32
+
33
+ > **The name.** `evolve` is a codename (not descriptive of purpose) — chosen by the framework owner. Natural-language activation does **not** depend on the name: it lives in the skill's `when_to_use`. Renaming it is a **major** change (moves a file under `ops/` and `skills/`).
34
+ >
35
+ > **The `composes:` list has six entries and the cycle has five mechanisms. Both are right.**
36
+ > `diagnose`, `reflect`, `generalize`, `restructure` and `remediate` are the mechanisms.
37
+ > `update` is composed as well, on axis A3, and it is not a mechanism — it syncs the instance
38
+ > with the plugin. Do not "correct" either number into the other.
39
+
40
+ > **`evolve` is a conductor, not an executor** (same pattern as `deliver`). It has **3 things no atomic mechanism has** — (1) the **evidence-collection driver** for the whole instance (composes `diagnose` + `reflect`), (2) the **split into buckets + the single gate**, (3) the **application driver + mechanical postconditions** plus the record and lineage. It **reads and follows** everything else from the mechanisms (`diagnose`/`reflect`/`generalize`/`restructure`/`update`) and from the write ops (`rule`/`gotcha`/`adr`), through the **suppression contract** at the end of this file. **The logic to downgrade, archive, or merge a doc originates here** (no canonical op covers it) — only the orchestrator has this logic. (The **version-drift migration**, which used to originate here, became the `update` op in rc.13. `evolve` now composes it in axis A3.)
41
+ >
42
+ > This materializes, with no new principle, the combination of invariants #2 (discover-first: diagnose with evidence before proposing), #3 (mechanize-or-downgrade: the invocation signals themselves pass the test that evolve audits in others), #6 (autonomy-first with self-check: *produce → self-check → report*, with the gate as the load-bearing residue), and #8 (earned question, recommendation-first). See [`../PRINCIPLES.md`](../PRINCIPLES.md).
43
+ >
44
+ > **Ancestors:** the Reflect→Select→Improve→Evaluate→Commit loop from Autogenesis (arXiv 2604.15034), and the Weakness-Mining→Proposal→Validation loop from Self-Harness (arXiv 2606.09498).
45
+ >
46
+ > Commit(proposal):
47
+ > 1. ε := Evaluate(proposal) # measured, per the Autogenesis order: ε before κ
48
+ > 2. HeldOutSet := a re-runnable set that scores ε empirically
49
+ > 3. HasHeldOutSet := HeldOutSet exists for this proposal # AFM: never, for a process change
50
+ > 4. if not HasHeldOutSet -> κ := the human # unconditional: see Phase 3, "never skippable"
51
+ > 5. # Self-Harness says the same from the other side: high-risk work needs
52
+ > 5. # "gates stronger than pass rate". Here EVERY process change is that work.
53
+ >
54
+ > In AFM, κ always resolves to the human. Every `Commit κ` in this file names this step.
55
+
56
+ ---
57
+
58
+ ## What `evolve` is NOT
59
+
60
+ The conductor block above says what it is. Four things it is deliberately not, each one a rejected
61
+ design and not an omission:
62
+
63
+ - An atomic mechanism. `diagnose`/`reflect`/`generalize`/`restructure` run à la carte. For a health
64
+ report alone use `afm diagnose`. To refine one doc that misled you, use `afm reflect`.
65
+ - An autonomous optimizer that self-applies changes and relies on rollback. This is the Autogenesis runtime model. AFM rejects it here, because the evolved object is a Markdown doc, not model weights.
66
+ - A daemon or periodic ritual. It runs by **signal**, never by calendar (Self-Harness: "on a saturated benchmark, an adaptive trigger beats a fixed budget").
67
+ - A resolver of `[TBD]`. Age is a signal to *ask the human if this is still a deliberate stance*. It is never a reason to invent an answer (#4/#5).
68
+
69
+ ---
70
+
71
+ ## Pre-check
72
+
73
+ 1. **Does `<consumer>/docs/.afm-version` exist?** If not, stop. Suggest `afm init` (greenfield) or `afm refactor` (brownfield) first.
74
+ 2. **Does `afm preflight` exit 0?** A non-zero exit says why: the docs are not bootstrapped, the bundled content does not resolve, or the pin does not match. Report it to the user. Do not fail silently.
75
+ 3. **Capture the stated symptom** from the trigger. This is what the user said after invoking the command. Examples: "the rules do not fire", "confusion between docs". This becomes the focus of the evidence collection. It also **counts as a "new signal"** for the cooldown check (step 5).
76
+ 4. **Resumability:** find the newest report with `mechanism: evolve` in `<consumer>/docs/evolution/`. A package is open when its findings carry no recorded gate decision. Resume from Phase 3 with that package. Otherwise start at Phase 1. The state lives in the report on disk. There is no separate state file.
77
+ 5. **Cooldown (mechanical refusal):** run **`afm evolve gate-check`**. Pass `--symptom "<what the user said>"` when step 3 captured one, and `--signal` when a `diagnose` delta since the last cycle is on file (see below). Its exit code is the decision: **0** run, **1** refuse, **3** not an AFM project, **4** could not decide (never read a crash as exit 1). It refuses when both are true:
78
+ - The last cycle **with `mechanism: evolve`** in `docs/evolution/` is **recent** (default under 14 days). Override this with `cooldown-days=` on the `<!-- evolve: ... -->` line of `docs/.afm-version`.
79
+ - **No new signal** appeared since then.
80
+
81
+ "New signal" means either:
82
+ - (a) a delta in the `diagnose` checks (Class A/A7) since the last cycle date. Verify this with the findings of `afm doctor --json` against the date of the newest report in `docs/evolution/`, **never** with self-written content. Pass `--signal` only when that delta is real.
83
+ - (b) the stated symptom from step 3 (`--symptom`).
84
+
85
+ With no new signal inside the window, the cycle **does not run**. Autogenesis: a cycle on a healthy instance yields near zero gain. Outside the window (14 days or more), the cycle runs normally.
86
+
87
+ This does **not** contradict "invocation is consent" (#6). There is precedent for mechanical op refusal. And **a stated user symptom always unlocks the cycle**, even inside the window.
88
+
89
+ ---
90
+
91
+ ## Phase 1 — Evidence collection (composes `diagnose` + `reflect`)
92
+
93
+ `evolve` **does not reimplement** the scan or the reflection. It runs them through the suppression contract and consolidates the bundles. This is gap-driven: the symptom from the pre-check sets the depth.
94
+
95
+ 0. **Capture `T0=$(date +%s)`** before any read. This is the baseline for the boundary postcondition (Phase 4.3) when the content root is not a git repo. Without it, the no-git branch has nothing to compare against.
96
+
97
+ 1. **Run `diagnose`** (**mechanical** evidence): `afm doctor --json` for A1-A6, staleness and dead gotchas, plus the A7 paired reading, as `diagnose.md` describes (Phase 0 scan of the 7 axes, plus Phase 1 φ/addressability/severity diagnosis). It returns the evidence bundle. (Run à la carte, `diagnose` prints the bundle. Here it feeds the cycle. `diagnose` does not write `docs/evolution/` — that is Phase 5.)
98
+ 2. **Run `reflect`** (**behavioral** evidence). Follow `reflect.md` §§ 1-2 (collect the φ_b signatures seen in the session, plus the self-check "was it me, not the doc"). Suppress `reflect`'s own gate — it moves to the single gate. With no friction in the session, the behavioral axis stays empty. That is a valid result.
99
+ 3. **On-demand proposal mechanisms** (through suppression, own gate suppressed, gap-driven — with no signal, they do not run):
100
+ - `diagnose` axis A3 flags **version drift** (pinned instance ≠ plugin `VERSION`). This composes `update` — a delta-by-delta migration proposal for consumer-facing changes (see Phase 2.2).
101
+ - `diagnose` axis A6 flags **2 or more redundant gotchas** → composes `generalize` (merge proposal).
102
+ - `diagnose` axis A6 flags a **doc bloated with deep reference material** → composes `restructure` (temperature-tier proposal).
103
+ - Also run the **`restructure` staleness scan** (`restructure.md § 1`, cheap with git) as part of the evidence. This does **not** depend on a prior `diagnose` signal. Staleness is **not** one of the 7 axes — it is `restructure`'s own, complementary detection. A staleness finding becomes a `restructure` proposal.
104
+ - **2 or more repeats of the same failure** compose `remediate` (`remediate.md`). `afm failures promotable` lists them: each `sig=` that recurred in the state store and that no failure record or `afm failures close` has closed. Hard rule 19 flags the orphan. `remediate` classifies the failure. It proposes the **definitive remediation** — a procedure (mechanical) or a learning (conceptual).
105
+
106
+ This is the cycle's "self-reflection on failures". `diagnose`/rule 19 **flag** the unfixed repeat failure. The cycle **resolves** it at the gate. `remediate`'s own gate is suppressed — it moves to the single gate. This is gated by #5 (negative filters — a transient failure does not get promoted).
107
+
108
+ 3.5. **Guardrail axis — what is still caught by hand, and should be caught by a command**. This axis joins two sources that no one cross-checks today:
109
+ - the **guardrail candidates** from `reflect § 1.2` — a defect the agent fixed by hand 2 or more times in the session.
110
+ - the failures of `afm failures promotable` that the rubric classified as **mechanizable** — a precedence destination.
111
+
112
+ For each one, run the **surface discovery** from `remediate.md` step 3.5. Look at the linter, type check, CI, or git hooks the project **already** runs. Propose where the check should land.
113
+
114
+ The output has two parts. The first is the durable record in `docs/guardrails/<slug>.md`, which the cycle materializes. The second is the **install proposal** to the operator, with surface options: linter, CI, git hook, or free text. Installing writes outside `docs/`, so it is always bucket (b). It is never auto-applied.
115
+
116
+ > **Why this axis belongs to the cycle, not only to `remediate`.** `remediate` acts failure by failure, reactively. The cycle sees the **pattern across failures**. Three different defects that share the same missing surface — no boundary check exists at all — form one finding that none of the three isolated failures reveals alone. This is the same logic `generalize` applies to gotchas, applied to gates.
117
+ >
118
+ > This axis also has the best cost-to-return ratio. Each installed guardrail turns a recurring analysis — one that spends context every time the code is touched — into a command that runs free in the development environment.
119
+
120
+ 4. **Consolidate** the bundles into one set of findings (mechanical, behavioral, merge/structure, and guardrail). Preserve the axis, φ, evidence, severity, and addressability of each one.
121
+
122
+ > **An empty diagnosis is a valid result.** If `diagnose` and `reflect` find nothing addressable, the cycle reports "100%", records the outcome with `afm cadence close --arm evolve --reason "empty diagnosis"` (the durable record that resets the evolve cadence counter), and stops. It does not invent a problem to justify the invocation.
123
+
124
+ ---
125
+
126
+ ## Proposal discipline (shared)
127
+
128
+ > **Single canonical source of the IMPROVER discipline.** The mechanisms that **propose** edits (`reflect`, `generalize`, `restructure`) **link to this section and follow it** — they do not copy it. (`diagnose` is read-only and does not use it.) A change here changes it for all of them.
129
+
130
+ For each **addressable** finding, before it reaches the gate:
131
+
132
+ 1. **Retrieval-before-create** (Autogenesis `tool_generator`): before proposing a new doc, section, rule, or gotcha, **prove with grep that no equivalent exists**. This is a direct antidote to bloat — the cycle cannot cure bloat by creating more docs. *(This anchor is reused on the **product** side, by `deliver.md § Phase 0.A0` and `specify.md` step 2.5. It is retrieval-before-**generate** (Voyager/AWM): build from an existing feature or ADR instead of regenerating. A change here also applies there.)*
133
+ 2. **Minimal change + diff per surface** (Autogenesis: "edit only what is on the whitelist"). Touch only files the diagnosis cited. Do not create an artifact the diagnosis did not name.
134
+ 3. **4-field audit record** per proposal (Self-Harness — structurally an ADR). Fields: *targeted pattern / edited surface / expected behavior effect / regression risk*.
135
+ 4. **Inventory to preserve** (Self-Harness "passing behaviors to preserve"). Each proposal lists what is **healthy and must not regress** on the touched surface. The gate sees what the change risks.
136
+ 5. **Attempt memory + per-surface lineage** (anti-oscillation):
137
+ - Re-proposing something **rejected** in an earlier cycle needs **new evidence** (Self-Harness "summaries of previously attempted edits").
138
+ - Re-proposing something **approved and later reverted** needs the same care. So does touching a surface with a tombstone `*(removed — lives in §X)*`. So does touching a surface changed in the opposite direction in an earlier cycle. In each case, the proposal **must cite the history and explain why the situation is different now**. The item then carries a **flip-flop flag** for the gate. The flag reads: "⚠ this surface already changed in the opposite direction in cycle NNN".
139
+ 6. **Validation dry run BEFORE the gate.** This fixes the Autogenesis ε→κ order — Evaluate comes before Commit. Apply each proposed edit **to a copy**. **Measure** its postconditions. Do not predict them.
140
+
141
+ Does the edited trigger still parse (`afm doctor` axis A5 stays clean on the copy)? Does `afm detect --for <file>` still select the touched doc, and does `afm index --check` stay green? The gate shows **"before (measured)"** and **"after (measured in the dry run)"**.
142
+
143
+ Each item must prove it **clears the signal that motivated it**. This is like the Self-Harness `max(Δ_in,Δ_ho)>0` rule. "Does not make it worse" is not enough — the edit must improve the signal.
144
+ 7. **Split into 3 buckets** (a verification corollary of #6):
145
+ - **(a) auto-applicable — NARROW.** Only a **non-semantic restorative** fix with a **target proven** by git/FS:
146
+ - a dead path reference → the correct path **proven** by `git log --follow` (a traceable rename).
147
+ - a broken ADR link → fixed to point at an NNNN that **exists** in `adr/`.
148
+ - **NEVER (a), always (b)** — even when the target is git-restorable. This covers two surfaces:
149
+ - any edit to a `*Verification:*` command in **`afm.md § 3`**.
150
+ - any edit to a path the hooks parse (gotcha `trigger_path`, `afm.md § 3` blocks).
151
+
152
+ Narrowing your own oversight outweighs restoring the reference. *Why:* these are the rc.5 enforcement guardrails. "Fixing" a trigger can narrow what it catches — for example, a regex that drops `.tsx`. Narrowing a path also reduces the injection coverage of the pre-edit hook. (A `## 3.` header in `ach.md` or other docs is prose, **not** this surface. A git-restorable dead reference there can still be (a).)
153
+
154
+ The boundary test for (a): if the fix changes *what the rule catches* (semantics), it is (b). If it only restores *what the doc already states*, it is (a).
155
+ - **NOT RESTORABLE = ALWAYS (b), never invent the target.** This applies to:
156
+ - a dead reference **with no** path proven by git.
157
+ - an ADR chain **with no** existing NNNN target.
158
+ - a trigger **with no** historical path in git.
159
+
160
+ In each case, the agent **does not invent** a path, ADR, or directory. It goes to the gate as earned options: `archive with a tombstone` / `redirect to the real target (if the user knows it)` / `recreate the missing artifact`. Inventing a plausible target is fabricating a fix with no proof (#5) — forbidden.
161
+ - **"Recreate" applies only to a DOC artifact inside `/docs/`** — a missing ADR, a gotcha. **It never applies to the CODE target of a trigger.** Recreating `src/old/sync.ts` is **out of scope**. The cycle evolves the methodology. It does not write product code. For a dead code reference, the only options are `archive`/`redirect`.
162
+ - **(b) load-bearing → gate.** The rc.5 structural test: does the change alter the inventory or the process? Examples:
163
+ - downgrading a rule to § 1.3.
164
+ - archiving a doc.
165
+ - merging gotchas (via `generalize`).
166
+ - a new hygiene rule.
167
+ - drift migration.
168
+ - instructiveness refinement (via `reflect`).
169
+ - temperature-tier repartitioning (via `restructure`).
170
+ - **every trigger/hook-path edit**.
171
+
172
+ This is most of the package.
173
+ - **Exception to "no undiagnosed artifact" (item 2):** creating the **missing artifact that the diagnosis itself pointed to** is legitimate. This holds IF it is itemized in Phase 3. Example: A4 has a broken chain with no NNNN target. The proposal can **create the replacement ADR** (title and status at the gate). Creating an artifact **no finding** motivated is still forbidden.
174
+ - **(c) cosmetic/deferrable → defer** it, with a note in the report (becomes `[TBD]` or a note, not an edit now).
175
+
176
+ > **Severity and bucket are ORTHOGONAL.** Severity (from `diagnose`) is the impact of the **symptom**. Bucket is the friction of the **fix**. A finding can be **HIGH and bucket (a)** at once (example: a dead reference in `ach.md`'s component map — the symptom matters, so HIGH, but the fix is git-restorative, so (a)). Severity orders what rises within the cap. Bucket decides *how* the item is handled.
177
+
178
+ ---
179
+
180
+ ## Phase 2 — Proposal (IMPROVER role, in staging)
181
+
182
+ Apply the **Proposal discipline (shared)** above to each consolidated finding from Phase 1. The mechanisms that already propose changes (`reflect`/`generalize`/`restructure`) bring their proposals ready — they already passed the discipline. `evolve` adds the proposals for the purely mechanical `diagnose` findings — downgrade, archive, merge. This is the logic that **originates here**. `evolve` consolidates everything into one package.
183
+
184
+ 1. **Package cap:** the cap counts **only (b) questions**. It is measured **per cycle** (8 (b) questions total, maximum). `afm evolve gate-check --critical <n> --high <n> --medium <n> --low <n>` computes it: it prints how many to ask now, in how many calls (for example `2 calls (4+4)`), and how many to stage. Present them in **at most 2 calls of at most 4 questions each** (NEVER more than 4 in one call). One **(b) item equals one `multiSelect` option** (including the A2 stance question and the A3 migration). Listed **(a) items do not use a slot**. They are seen, not asked — the user confirms the batch at the same gate.
185
+ - **5 to 8 (b) items are NOT an "overflow"**. They fit in up to 2 calls (4 plus the rest). Staging is required only **above 8**.
186
+ - **Staging priority (ascending severity):** what gets staged goes **LOW before MEDIUM before HIGH**. **CRITICAL and HIGH are never staged** (they rise in the current cycle). **(b) LOW/MEDIUM items are staged by default** (recorded in Phase 5). This holds unless (i) the user's stated symptom touches them, or (ii) cap room is left after CRITICAL/HIGH. (The A2 stance question is LOW, so it is staged by default unless there is room.)
187
+ - Any surplus is **staged for the next cycle** (recorded in the report), never dumped into one oversized gate.
188
+ 2. **Drift migration (A3) — composes `update.md`** (since rc.13, the procedure used to originate here). `evolve` **reads and follows** `update.md` end to end.
189
+
190
+ It finds the consumer-facing deltas between the pinned version and the current one. It builds the migration as **ONE umbrella item** — a `multiSelect` option with sub-bullets per approvable delta. It applies each delta. It **bumps `docs/.afm-version`** at the end.
191
+
192
+ It suppresses only `update`'s **own gate** — the migration item moves to the single gate (step 3.B). The protected surfaces (the cycle's own rubric, the evolution entries in `triggers.md`, `[TBD]`) live in `update`'s whitelist, which mirrors evolve's. "Missing materialized rubrics" is not a separate finding — it is subordinate to this A3 `update` item.
193
+
194
+ ---
195
+
196
+ ## Phase 3 — Single gate (≈ Commit κ) — **always happens, never skippable**
197
+
198
+ `evolve` **requires a gate under every protocol**. It is a first-class exception alongside the bright lines ([`core/protocol.md`](../core/protocol.md) § 4), not the absence of a flag.
199
+
200
+ The safety valve that makes "go" safe in `deliver` **does not exist here**. That valve halts on the first task that depends on an assumption. There is no execution phase in `evolve`. The doc edit *is* the effect. There is no future boundary where the human would catch drift. So the gate cannot be skipped.
201
+
202
+ Even a package with **only (a) items** opens the gate. The ceremony cost is the same: 1 gate per cycle. (a) items only change what is inside that gate.
203
+
204
+ - **3.A — Build the consolidated package**. Include before/after vital signs (measured in the discipline's § 6 dry run), the buckets, and the audit records. (a) items are entered **as a list** (they auto-apply only after the gate sees them). (b) items are entered as **earned questions** (#8). Each carries evidence, a `(Recommended)` tag, and **"what changes in the structure if this is wrong"**.
205
+
206
+ ADRs to be created are **itemized here** (title and proposed status). Nothing materializes after the gate that the gate did not see.
207
+ - **3.B — Present it through `afm ask evolve`, item by item**. Each (b) item is one scope: show its evidence, recommendation and "what changes if this is wrong" in the package, then run `afm ask evolve --scope <item-slug> --recommend <label>` with the label of your recommendation, so the picker marks it recommended, the default (the question is `apply` in `questions/evolve.questions.yaml`: apply, skip, or stage for the next cycle). The harness may render the scopes of one call together, at most 4. A subset can be approved in one call (#8 supports this). **Do not** use a monolithic plan-approve: the edits are **independent** (unlike `deliver`, where they form one interdependent plan). An all-or-nothing block dilutes attention, and the merge item (which loses provenance) can slip through by dilution.
208
+ - **3.C — Items that always get their own question, even in a large package**. Examples: downgrading or removing a hard rule, and deleting a doc. Each always gets a separate question (deletion is bright line (a) of #6).
209
+
210
+ **Never renumber a rule** — a removed one becomes `*(removed — lives in §X now)*`. Renumbering breaks every external reference and every trigger that cites the number. Items with a flip-flop flag show the warning.
211
+ - **3.D — Record the decision** (approved or rejected, per item) in the Phase 5 report before applying it.
212
+
213
+ ---
214
+
215
+ ## Phase 4 — Application + postconditions (≈ Commit κ applied)
216
+
217
+ 1. **Apply** the (a) items and the approved (b) items, through the **suppression contract**:
218
+ - A rule edit follows `rule.md`.
219
+ - A gotcha follows `gotcha.md`.
220
+ - An ADR follows `adr.md`.
221
+ - A refinement follows `reflect.md`.
222
+ - A merge follows `generalize.md`.
223
+
224
+ Only their own per-artifact `afm ask`/gate is suppressed — it moved to the single gate. **Downgrade, archive, merge** have no canonical op, so the procedure originates here. Archiving moves content to a history section or file, with a tombstone. It never deletes without the deletion gate item.
225
+ 2. **Mechanical postcondition #1 — parseable format:** re-run `afm doctor --json` (axis A5 for the edited triggers), `afm detect --for <file>` and `afm index --check` on the touched docs. The format the hooks parse must stay preserved, **or the edit rolls back**. A rollback is **reported as a cycle failure** in the report — never silently. It flags any item that depends on the reverted one.
226
+ 3. **Mechanical postcondition #2 — the instance/plugin boundary is MECHANICAL, not a matter of discipline**. The content root `afm path` resolves (the installed package) is **writable** on most installs, so the boundary needs a trigger, not discipline. Any dirt there means **rollback plus a CRITICAL report**.
227
+
228
+ > **A universal assertion, not just a guard for this cycle.** Under the absolute boundary (#7), **no** AFM op writes to the plugin — not even `promote`, which only records. So this check is the postcondition for **any** op that writes to `docs/`. The other ops (`reflect`, `generalize`, `restructure`, `update`) point here instead of repeating the same check.
229
+
230
+ **Two checks, because the content root has two natures.** In AFM's own repo, it is a git checkout. In a consumer project, it is the directory of the installed package, which **is not a git repo**. Pick the check by testing, never by assuming:
231
+
232
+ ```sh
233
+ P="$(dirname "$(dirname "$(afm path ops/evolve.md)")")" # the content root
234
+ if git -C "$P" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
235
+ [ -z "$(git -C "$P" status --porcelain)" ] || FALHA
236
+ else
237
+ # No git: `T0` is the epoch captured at the start of Phase 1 (`date +%s`).
238
+ [ "$(find "$P" -type f -newermt "@$T0" -print -quit)" = "" ] || FALHA
239
+ fi
240
+ ```
241
+
242
+ > **Why the `if` is load-bearing:** `git -C <non-repo> status --porcelain` exits with **exit code 128 and empty stdout**. A naive "empty output" test therefore **passes** — and it passes exactly in the case that matters, the consumer. The only executable defense of the boundary was inert in production, and green in the plugin's own repo, which is where it is needed least.
243
+
244
+ ---
245
+
246
+ ## Phase 5 — Record + promote (auditable lineage)
247
+
248
+ 1. **Materialize or close** `<consumer>/docs/evolution/<date>-NNN.md` (`afm next-id evolution` prints the free NNN), with `afm new evolution-report --mechanism <...>` (fix findings with `afm lint --fix`). Include the φ findings (mechanical and behavioral), the buckets, and the audit records. Include the **rejected AND approved-then-reverted items** too — the attempt memory for future cycles. Include the before/after vital signs, and the date (`afm evolve gate-check` reads it for the cooldown). This is the Self-Harness h₀→h₁ lineage.
249
+ 2. **Does it generalize?** If a finding applies to any instance ("every pre-rc.5 instance has this drift"), **suggest** `afm promote`. Never skip its own gate (#7) — `evolve` only suggests.
250
+ 3. **Hand off to `reconcile`** to watch the effect of the changes in later sessions. This is AFM's possible form of "re-run". With no held-out set, real validation is observed future behavior.
251
+
252
+ > **The report name is `YYYY-MM-DD-NNN.md` and its frontmatter MUST carry `mechanism: evolve`.**
253
+ > Three mechanisms write into `docs/evolution/`, and each one's cadence window is "since MY last
254
+ > report". A report with no `mechanism:` is invisible to every window, and an ordinal-first name
255
+ > makes the selector order by ordinal before date. Both were live defects until 3.13.0.
256
+
257
+ ---
258
+
259
+ ## Whitelist — evolvable vs. protected surfaces
260
+
261
+ **Evolvable** (a cycle can propose an edit here, following the buckets):
262
+ - `gotchas/`.
263
+ - the instance's `afm.md § 3`/`§ 1.3` (with the (a)/(b) restrictions).
264
+ - materialized rubrics **other than the evolution cycle's own**.
265
+ - ADR status.
266
+ - the doc-map bridge in the consumer's instruction file (`AGENTS.md`), outside the managed markers.
267
+ - `docs/guardrails/` (the **record**). The config installed outside `docs/` is a proposal, not an evolvable surface.
268
+
269
+ **Protected** (never evolvable by a cycle — only through the plugin, through `promote`, or by human decision outside the cycle):
270
+ - `PRINCIPLES.md` (link) and all of the bundled content (#7).
271
+ - The content of `[TBD]` (the user's stance — #4).
272
+ - The format the hooks parse.
273
+ - **The evolution cycle's own rubric** (`when-to-evolve-methodology.md`) is protected. So are **the `triggers.md` entries that fire any evolution-mechanism skill** (`evolve`/`reflect`/`diagnose`/`generalize`/`restructure`). Otherwise, the cycle would edit the document that decides when it runs — self-reference.
274
+ - **The evolution-report template.**
275
+ - **`docs/.afm-version`** — the activation key for every skill and hook. Change it only through an explicit migration (finding A3), approved item by item at the gate.
276
+
277
+ ---
278
+
279
+ ## Suppression contract (the honest DRY guarantee)
280
+
281
+ `evolve` reads the op and follows it. It does not copy the procedure. Where the procedure **does not exist**, it originates here (legitimate — orchestrator logic).
282
+
283
+ | Op | Reuses | Suppresses / originates here | Why it is safe |
284
+ | --- | --- | --- | --- |
285
+ | `diagnose.md` | The whole 7-axis scan plus the φ/addressability/severity diagnosis (Phase 1.1) | Nothing suppressed (read-only). `diagnose` does not write `docs/evolution/` — that is Phase 5 | Read-only scope. It only produces evidence |
286
+ | `reflect.md` | φ_b collection plus self-check (Phase 1.2), plus guardrail candidates (reflect § 1.2 → Phase 1.3.5) | reflect's **own gate** (moves to the single gate); the record (moves to Phase 5) | Consolidated gate. The behavioral finding enters the same package |
287
+ | `generalize.md` | Gotcha merge proposal | Own gate (moves to the single gate) | A merge is an unavoidable (b) item at the gate |
288
+ | `restructure.md` | Repartitioning/staleness proposal | Own gate (moves to the single gate) | Repartitioning is a (b) item |
289
+ | `update.md` | The whole A3 drift migration (finds deltas, builds the package, applies it, bumps `.afm-version`) | Own gate (moves to the single gate) | Migration is ONE umbrella (b) item. It only reads the plugin, and writes only to the instance |
290
+ | `rule.md` | Rule-writing procedure, and the executable-trigger requirement (#3) | Per-artifact `afm ask`. **Downgrading/archiving a rule originates here** | Approval at the gate. Downgrading is an unavoidable (b) item |
291
+ | `gotcha.md` | Append procedure plus entry validation | Per-artifact `afm ask` | The gate sees the merge item by item |
292
+ | `adr.md` | Template, numbering, and the load-bearing guardrail (#9) | Status question of `afm ask adr` (itemized in 3.A) | An ADR materializes only after it passes the gate |
293
+ | `remediate.md` | Classification, plus the procedure/learning proposal for a repeat failure (`afm failures promotable`: a `sig=` seen 2 or more times) | Own gate (moves to the single gate) | The **definitive** remediation for the repeat failure. Gated by #5 (negative filters) |
294
+ | `reconcile.md` | The memory-vs-doc criterion, and its triggers | Nothing (it only consumes at the handoff) | — |
295
+ | `promote.md` | Nothing suppressed | — | Absolute boundary #7. `promote` **records** the finding. No one applies it to the plugin from here |
296
+
297
+ > **Recursion guard.** Phase 1.2 composes only `reflect.md §§ 1-2` — never `reflect.md § 5`. That scoping is what stops the cycle from calling itself: `reflect § 5` step 3 is the step that can propose `afm evolve`, and Phase 1.2 never reaches it. **`reflect` running UNDER `evolve` never escalates. `reflect` running à-la-carte may.** This was accidental scoping until now — stated here as the explicit rule, not left implicit in how far Phase 1.2 happens to read.
298
+
299
+ ---
300
+
301
+ ## Anti-patterns
302
+
303
+ - ❌ **Running by ritual or calendar** — it runs by signal. A cycle with no new signal gets a cooldown refusal (Autogenesis: an adaptive trigger beats a fixed budget).
304
+ - ❌ **Reimplementing the scan or the reflection** — `evolve` composes `diagnose`/`reflect` through suppression. It does not duplicate their procedure.
305
+ - ❌ **Treating an empty diagnosis as a failure** — a healthy instance means the cycle reports "100%" and stops. It never invents a problem to justify the invocation.
306
+ - ❌ **Inventing the target for a non-restorable fix**. Examples: a dead reference with no proven rename, an ADR with no NNNN target, a trigger with no historical path. These go to the gate as options — archive, redirect, recreate. Never guess a path or ADR (#5).
307
+ - ❌ **Classifying a trigger/hook-path edit as (a)** — it is always (b). This is the agent reducing its own oversight.
308
+ - ❌ **Skipping the gate** — there is no "go" in `evolve`. Even a package with only (a) items opens the gate.
309
+ - ❌ **A monolithic plan-approve** — the gate is item by item, one `afm ask evolve` scope per (b) item (the edits are independent).
310
+ - ❌ **Downgrading a rule because it was violated** — a violation does not mean the rule is wrong. Downgrading needs proof the rule is *wrong* (a false positive, impossible to satisfy, or an intent proven obsolete by git). Consider "the agent was non-compliant" as the rival explanation first.
311
+ - ❌ **Deleting** — archive it instead, with a tombstone. Deletion is a bright line and gets its own gate item. A superseded ADR, a dead gotcha, or an old marker stay institutional memory until the human says otherwise.
312
+ - ❌ **Renumbering a rule** — a removed one becomes `*(removed — lives in §X)*`.
313
+ - ❌ **Materializing after the gate what the gate did not see**. ADRs and edits must be itemized in Phase 3, or they do not happen.
314
+ - ❌ **Editing the bundled content** — the Phase 4.3 boundary postcondition (two branches) catches this. Any dirt means rollback plus CRITICAL. A generalization is **recorded** through `promote`, never applied from here (#7).
315
+ - ❌ **Re-proposing a rejected or reverted item with no new evidence**. Attempt memory, plus the per-surface flip-flop flag, catch this.
316
+ - ❌ **Resolving `[TBD]` alone**. Age is a signal to ask if the stance still holds. It is not a reason to invent an answer (#4/#5).
317
+ - ❌ **Composing `reflect.md` past § 2 in Phase 1.2**. Reading further would reach the § 5 escalation step and let `reflect` propose `afm evolve` from inside the very cycle running it. The recursion guard depends on Phase 1.2 stopping at §§ 1-2 — see `§ Suppression contract`.
@@ -0,0 +1,97 @@
1
+ ---
2
+ type: op
3
+ description: Turns a bootstrapped project into a reusable architectural template.
4
+ load: warm
5
+ writes: ["docs/.template"]
6
+ composes: []
7
+ ---
8
+ # Sub-flow: export project as architectural template (`export-template`)
9
+
10
+ > **Form** — effect: `docs/.template`; deletes product content · trigger: `afm export-template` · pre-condition: `.afm-version` · composed by: — · **degree of freedom: low**
11
+
12
+ Triggers: `afm export-template`, or natural language ("export as template", "turn into architectural
13
+ template", "turn this project into a starter").
14
+
15
+ > **Bright line of #6:** this op **deletes files**, an irreversible operation outside git. It is an
16
+ > exception to autonomy-first: it ALWAYS shows the full diff (the list of what will be deleted) and
17
+ > confirms with the operator before deleting. The command enforces it: `afm template export` refuses to
18
+ > run without `--dry-run` or `--yes`.
19
+
20
+ Converts a bootstrapped project into a reusable architectural template. Deletes product-specific
21
+ content (PRD, US, features). Keeps architecture, rules, technical gotchas, ADRs, rubrics, patterns and
22
+ the accepted code-style files, because a template exists to carry architecture forward. Writes the
23
+ `docs/.template` marker. The next `afm init` on a clone of the template detects the marker and runs a
24
+ branch focused on product (`afm path interview/bootstrap` § Alternate branch).
25
+
26
+ The CLI owns the plan: which `docs/` entries go, the diff, the marker JSON, the coherence warnings, the
27
+ clean-worktree check and the idempotency check. This op owns what is intent: the metadata, the choice of
28
+ what to keep, the task-template induction and the final confirmation.
29
+
30
+ ## Procedure
31
+
32
+ 1. **Pre-check.** The project must be bootstrapped. `afm template export --dry-run` reports a project
33
+ with no `.afm-version` and no marker as *not bootstrapped yet*: tell the operator to run `afm init`
34
+ first, then export.
35
+ - **Anti-rot gate + pre-freeze consolidation.** A frozen (offline) architectural template must load
36
+ architecture only from a **green** (tests pass) and **committed** project. The dry run warns when
37
+ the worktree is not clean. Show that warning as a line in the confirmation, not as a second prompt:
38
+ an unclean state means the template would inherit unvalidated architecture.
39
+ - **Before freezing**, suggest `afm generalize` over the accumulated streaming learnings. `afm reconcile`
40
+ appends gotchas and rules through the project's life. Consolidate those learnings
41
+ **into** the template instead of freezing a partial layer, which later collides with the
42
+ consumer's reconcile. Precedence rules for that collision:
43
+ `afm path rubrics/template-vs-streaming-precedence`.
44
+ - **Idempotency.** If `docs/.template` already exists the dry run says it will be overwritten: ask
45
+ whether to update the metadata, just reapply the deletion, or cancel.
46
+ 2. **Collect the metadata as free text** (free-form identifiers, not closed options): the template
47
+ **name** (kebab-case suggested, for example `nextjs-trpc-prisma-starter`) and its **version** (semver
48
+ suggested, for example `1.0.0`). Never derive the name from the repo folder (#5). A blank answer
49
+ stays `[TBD]` in the marker (#4/#5: do not invent).
50
+ 3. **Ask what to keep:** `afm ask export-template` (questions in
51
+ `content/questions/export-template.questions.yaml`). By default an export deletes the four
52
+ product artifacts (`prd`, `ust`, `features`, `afm-version`) and keeps everything else; the answers
53
+ become `--keep <item>` (once per item) and `--delete-research` when `docs/research/` goes.
54
+ - **Why `code-style/` is not a question.** It is a real directory that `afm init` and `afm refactor`
55
+ fill only with what the operator accepted. An export keeps it: the conventions the operator
56
+ deliberately accepted are architecture, and dropping them hands the next project an `ach.md`
57
+ without the naming and placement decisions behind its vocabulary. `patterns/` and `rubrics/` stay
58
+ for the same reason: reference libraries that name no product entity.
59
+ 4. **Check coherence.** The dry run warns when one of `prd.md` / `ust.md` is kept and the other deleted
60
+ (partial product content), and when both are kept (the template embeds product content every
61
+ consumer must edit by hand). Put each warning to the operator and reopen step 3 if they want to change
62
+ the selection.
63
+ 5. **Induce a task template before `features/` goes (AWM, from a green trajectory).** Run this step only
64
+ when the dry run lists `docs/features/`. Take the **most recent** `docs/features/NNN-*/tasks.md` with
65
+ **ALL tasks `- [X]`**: it passed its own test, and never induce from incomplete work. The dry run
66
+ names the feature, or says there is none, in which case skip the step. Turn concrete values into named
67
+ variables (product, entity, procedure, domain become `{product-name}`, `{entity}`,
68
+ `{boundary-procedure}`, `{domain}`), following `afm path templates/feature-tasks.induced.template`, and
69
+ save it as `docs/templates/feature-tasks.induced.md`. **Order matters:** induce **before** the
70
+ deletion. This lets the next consumer compose from an already-validated task shape.
71
+ 6. **Show the full diff, then ask for confirmation** (destructive bright line):
72
+ - `afm template export --dry-run --name <name> --template-version <version> [--keep <item>] [--delete-research]` prints the exact files to delete with their sizes, the proposed `docs/.template`
73
+ JSON (`template-name`, `template-version`, `exported-from-afm`, `exported-at`), what stays untouched
74
+ and the warnings.
75
+ - Then `afm ask export-template-apply` (questions in
76
+ `content/questions/export-template-apply.questions.yaml`). `Adjust` goes back to step 3. `Cancel`
77
+ touches nothing.
78
+ 7. **Apply** with the same flags and `--yes`. The command writes the marker first, so a deletion that
79
+ fails midway leaves a project the pre-check still accepts, then removes the selected entries. It
80
+ touches `docs/` only.
81
+ 8. **Report to the operator:** what was deleted, the path of the created `docs/.template`, the final
82
+ state of `docs/`, the suggested commit message (``docs(afm): convert <name> to architectural template
83
+ v<version>``) and the next step: package the repo as a starter (degit, tiged or a git template). Next
84
+ time it is cloned for a new project, `afm init` detects the `docs/.template` marker automatically and
85
+ offers a from-template branch focused on product.
86
+
87
+ ## Anti-patterns
88
+
89
+ - ❌ Touching code (`src/`, a schema, a manifest). This op only touches `docs/`. An architectural
90
+ template is "architecture + rules", not "the whole repo cleaned up".
91
+ - ❌ Deleting files without showing the diff and confirming first (#6 destructive bright line).
92
+ Autonomy-first does NOT apply to irreversible deletes.
93
+ - ❌ Inventing metadata when the operator left it blank. Use `[TBD]` in the JSON (#4 and #5).
94
+ - ❌ Overwriting an existing `docs/.template` without asking.
95
+ - ❌ Deleting `docs/.afm-version` when the operator marked it as kept. The default is to delete it (a
96
+ template is not an instance), but the operator can opt out.
97
+ - ❌ Auto-deriving the template name from the repo folder name. Ask explicitly (#5).
@@ -0,0 +1,120 @@
1
+ ---
2
+ type: op
3
+ description: Merges several gotchas that repeat into one abstract rule.
4
+ load: warm
5
+ writes: ["docs/gotchas/*.md", "docs/rules/*.md", "docs/afm.md", "docs/evolution/*.md"]
6
+ composes: []
7
+ ---
8
+ # Sub-flow: semantic consolidation of gotchas into an abstract rule (`generalize`)
9
+
10
+ > **In this file:** What `generalize` is / is not · Pre-check · 1. Identify the batch (clustering, ≥2) · 2. MetaReflect: propose the abstract rule (follow the shared discipline) · 3. ShowsImprovement + backtracking (validation before the gate) · 4. Own gate (à la carte) — suppressed under `evolve` · 5. Registration + handoff · Suppression contract (back-pointer) · Anti-patterns
11
+
12
+ > **Form** — effect: rule + tombstones · trigger: `afm generalize`, composition · precondition: ≥2 similar gotchas · composed by: `evolve` 1.3 · **degree of freedom: medium**
13
+
14
+ Triggers: `afm generalize`. Also natural-language **consolidation** requests. Examples: "these gotchas are all the same thing", "merge these rules". Also: "this became a pattern — generalize it", "I have 3 gotchas that say the same thing".
15
+
16
+ > **Target = this project's local docs (`<consumer>/docs/`), never the plugin.** The merge of N gotchas into 1 rule happens **inside this repo's materialized instance** (the same `/docs/`) — never inside the canonical framework (the bundled content, bright line #7). An abstract rule that applies to any instance is only **registered** through `afm promote` (a finding with evidence). See [`evolve.md § The target of evolution`](./evolve.md).
17
+ >
18
+ > **Mechanism, not conductor.** `generalize` is the mechanism-skill that **merges a batch of similar gotchas/reflections into one abstract rule** (episodic memory → semantic memory). It runs **à la carte** (its own gate) OR inside the `evolve` cycle (which composes it when `diagnose` flags inflation from redundant gotchas, and its own gate is suppressed).
19
+ >
20
+ > **Ancestor:** the *MetaReflect* step of MetaReflection (arXiv 2405.13009).
21
+ >
22
+ > Generalize(gotchas, batch):
23
+ > 1. read the current gotchas and the batch # |batch| >= 2
24
+ > 2. emit one abstract rule that covers the batch — ADD it, and MERGE the batch into tombstones
25
+ > 3. ShowsImprovement := the rule covers every case in the batch
26
+ > AND loses no case the gotchas separately caught
27
+ > 4. if not ShowsImprovement -> backtrack: keep the gotchas separate, emit nothing
28
+ >
29
+ > A larger batch produces a more general rule. This maps to three principles. #1: episodic
30
+ > memory in `gotchas/` becomes semantic memory in `afm.md`. #3: the rule needs an executable
31
+ > 0/1 trigger, or it stays a principle. #6/#8: self-check happens before the gate. See
32
+ > [`../PRINCIPLES.md`](../PRINCIPLES.md).
33
+
34
+ ---
35
+
36
+ ## What `generalize` is / is not
37
+
38
+ **It is:** the act of taking **≥2 similar gotchas/reflections** (the AFM "bit twice" threshold = the MetaReflection **batch**). It proposes **one abstract, non-case-specific rule** that covers them. It reduces N isolated entries to 1 — the root antidote to inflation. This is the episodic-to-semantic step AFM already does by hand, now mechanized.
39
+
40
+ **It is NOT:**
41
+ - `promote` **registers** a finding meant for the plugin, #7. It never writes to the plugin. `generalize` stays **inside the instance** (`<consumer>/docs/`). N gotchas become 1 rule in the same `/docs/`. (Later, the abstract rule can become a registered finding. That is a separate step, with its own gate.)
42
+ - `reconcile` (adds **one** new gotcha/rule from a fact just learned). `generalize` **merges what already exists**.
43
+ - `reflect` (refines the **clarity of one specific doc** that gave bad guidance). `generalize` **consolidates many** into one abstraction.
44
+ - Do not invent a rule "because it feels general". An abstract rule **must come from a real batch** of ≥2 concrete cases (#5). Generalizing from 1 case fabricates an abstraction without evidence.
45
+
46
+ ---
47
+
48
+ ## Pre-check
49
+
50
+ 1. **Does `<consumer>/docs/.afm-version` exist?** If not, stop and suggest `afm init` or `afm refactor`.
51
+ 2. **Does `afm preflight` exit 0?** A non-zero exit says why: the docs are not bootstrapped, the bundled content does not resolve, or the pin does not match. Report it. Do not fall back silently.
52
+ 3. **Is there a batch of ≥2** plausibly similar gotchas/reflections? If the trigger does not name the batch, run a light clustering pass over `gotchas/`. Grep for common terms and surfaces. **Fewer than 2 similar candidates means there is nothing to generalize.** Report this and stop. Rule #5 forbids a rule from 1 case.
53
+
54
+ ---
55
+
56
+ ## 1. Identify the batch (clustering, ≥2)
57
+
58
+ Group candidates by **shared signature** — same surface/area, same normative verb, same failure mechanism. Cite each member with `file:line` (for example, `gotchas/` entries X, Y, Z). The batch is the set that **shares the abstract cause**, not just similar wording. The test is: "would one more general instruction have prevented all N cases?"
59
+
60
+ > **A larger batch produces a more abstract rule** (Table 6 of MetaReflection). Do not force a merge of 2 cases that barely resemble each other. But 3-4 cases that clearly share the cause produce a stronger abstraction. Members that do **not** match the cause stay out of the batch — do not dilute the rule with them.
61
+
62
+ ---
63
+
64
+ ## 2. MetaReflect: propose the abstract rule (follow the shared discipline)
65
+
66
+ Follow the **shared proposal discipline** in `evolve.md § Proposal discipline (shared)`. **Read it there and follow it.** Do not copy it here — the numbered procedure lives only there. The proposal:
67
+
68
+ 1. **Draft the generalized rule.** Make it non-case-specific, and make it cover the batch. The paper gives a HotpotQA example. "When searching for people, add profession" plus "add a date for movies" become "increase primary terms with secondary entity keywords". Make it concrete enough to act on. Make it abstract enough to cover all N cases. The original cases become **examples** of the rule.
69
+ 2. **Retrieval-before-create, reversed:** `generalize` **reduces**, it does not create a parallel entry. Never leave the N gotchas **and** the new rule side by side (that is inflation, the opposite of the goal). The merged members become tombstones (step 4).
70
+
71
+ ---
72
+
73
+ ## 3. ShowsImprovement + backtracking (validation before the gate)
74
+
75
+ Before the gate, check the rule — this step is the analog of the paper's `ShowsImprovement`:
76
+
77
+ - **Coverage:** re-apply the abstract rule mentally to **each** member of the batch. Does it cover all N? If it leaves one out, refine the abstraction. Or drop that member from the batch instead. **If the merged rule cannot cover the cases without becoming too vague, backtrack.** Keep the gotchas separate. Report "not generalizable without loss" (Self-Harness: "no worse" is not enough, the rule must cover the cases).
78
+ - **Mechanization (#3 — the paper's binary reward):** the merged rule moves up to `afm.md § 3` (hard rule). This needs an executable 0/1 trigger (`grep`/`wc`/`git diff`/`tsc`). Without an executable trigger, it is **not a hard rule.** It moves down to `afm.md § 1.3` as a **principle**, for guidance only. Never write a "hard rule" without a `*Verification:*` line. It would fail the same test `diagnose` runs under A5.
79
+
80
+ ---
81
+
82
+ ## 4. Own gate (à la carte) — suppressed under `evolve`
83
+
84
+ The merge is **load-bearing**: it changes the inventory from N entries to 1. It **loses provenance** if done wrong. It goes to the gate as an **unavoidable item (b)**, one `afm ask generalize` question per merge (`questions/generalize.questions.yaml`), earned. The evidence is the cited batch, the proposed rule, and "what is lost if the abstraction is wrong". À la carte, `generalize` opens its own gate: `afm ask generalize --scope <rule-slug>`, where the scope is the slug of the proposed rule. Under `evolve`, the single gate absorbs this gate.
85
+
86
+ On approval:
87
+ 1. **Write the rule** through `rule.md` (`afm rule new <slug>` for a § 3 rule with a trigger, which the CLI refuses without a 0/1 `*Verification:*` line; or edit § 1.3 for a principle). Suppress only its `afm ask` step.
88
+ 2. **Archive the merged members with a tombstone.** Never delete. Each merged gotcha becomes `*(consolidado na regra N de afm.md § 3 — ver ciclo NNN)*` (institutional memory + preserved provenance). Deletion is a bright line (#6) — it needs its own gate item.
89
+ 3. **Postcondition:** `afm doctor --json` (axes A1, A4 and A5), `afm index --check` and `afm detect --for <file>` over `afm.md`, `rules/` and `gotchas/` must preserve the format the hooks parse. If not, report a rollback. The two-branch check in [`evolve.md § Phase 4.3`](./evolve.md#phase-4--application--postconditions--commit-κ-applied) must also show a green instance/plugin boundary. The naive empty-output test passes in a non-git directory, which is the consumer's case.
90
+
91
+ ---
92
+
93
+ ## 5. Registration + handoff
94
+
95
+ 1. **Materialize/append** to `docs/evolution/<date>-NNN.md` (create it with `afm new evolution-report --mechanism <...>`; fix findings with `afm lint --fix`): the merged batch, the resulting rule, the tombstones, and the ShowsImprovement result (covered / backtrack).
96
+
97
+ > **The report name is `YYYY-MM-DD-NNN.md` and its frontmatter MUST carry `mechanism: generalize`.**
98
+ > Four mechanisms write into `docs/evolution/`, and each one's cadence window is "since MY last
99
+ > report". A report with no `mechanism:` is invisible to every window, and an ordinal-first name
100
+ > makes the selector order by ordinal before date. Both were live defects until 3.13.0.
101
+ 2. **Does this generalize beyond the instance?** If the abstract rule applies to any project, **register** it through `afm promote`. Pass a finding with evidence. Never apply it directly — #7.
102
+ 3. **Hand off to `reconcile`** to watch whether the merged rule actually replaces the N originals in later sessions.
103
+
104
+ ---
105
+
106
+ ## Suppression contract (back-pointer)
107
+
108
+ `generalize` **reuses** the proposal discipline, bucket partition, and postconditions of `evolve.md` (read and follow them) and `rule.md` (suppress its `afm ask`). Under `evolve`, the § 4 gate is suppressed and folded into the single gate. The authoritative table is in `evolve.md § Suppression contract`.
109
+
110
+ ---
111
+
112
+ ## Anti-patterns
113
+
114
+ - ❌ **Generalizing from 1 case** — without a batch (≥2), there is no generalization. It is fabricating an abstraction without evidence (#5).
115
+ - ❌ **Leaving the N gotchas AND the rule coexisting** — this is inflation, the opposite of the goal. Merged members become tombstones.
116
+ - ❌ **Deleting the merged gotchas** — archive with a tombstone (provenance + institutional memory). Deletion is a bright line, and needs its own gate item.
117
+ - ❌ **Merging cases that do not share the cause** — the abstract rule becomes too vague and covers nothing well. The test is: "would one instruction have prevented all N cases?"
118
+ - ❌ **A hard rule without an executable trigger** — a rule without a `*Verification:*` 0/1 line becomes a § 1.3 principle. It does not become a § 3 rule. This is #3, the paper's ShowsImprovement.
119
+ - ❌ **Skipping the backtrack** — if the abstraction cannot cover the cases without becoming vague, keep the cases separate. Report "not generalizable without loss".
120
+ - ❌ **Editing the bundled content** — a generalization meant for the plugin is **registered** through `promote`, never applied directly (absolute boundary #7). The boundary postcondition is in `evolve.md § Phase 4.3`.
@@ -0,0 +1,46 @@
1
+ ---
2
+ type: op
3
+ description: Records a surprise that cost time, with the trigger that makes it fire again.
4
+ load: warm
5
+ writes: ["docs/gotchas/*.md"]
6
+ composes: []
7
+ ---
8
+ # Sub-flow: register a gotcha
9
+
10
+ > **Form** — effect: one file under `docs/gotchas/` · trigger: `afm gotcha`, composition · pre-condition: gate ≥2× or external SDK · composed by: `reconcile`, `evolve`, `reflect` · **degree of freedom: low**
11
+
12
+ Triggers: `afm gotcha`, or natural language ("register a gotcha", "this confused me before").
13
+
14
+ Identical in a greenfield or a refactored project. The CLI refuses an entry that did not pass the
15
+ gate, numbers the file, writes the frontmatter the trigger index reads and refreshes the index.
16
+
17
+ ## Procedure
18
+
19
+ 1. `afm preflight`. Exit 3: no instance, run `afm init` or `afm refactor` first.
20
+ 2. **Validate the entry rule before you collect content.** Ask `afm ask gotcha` (questions in
21
+ `content/questions/gotcha.questions.yaml`). The answer is the operator's confirmation that the
22
+ case is real; it is not discoverable state.
23
+ - `bitten-twice` or `documented-sdk` continues, and the answer is the `--basis` of step 4.
24
+ - `neither` stops. Register nothing (invariant principle #5: do not invent a gotcha without a real
25
+ case).
26
+ 3. **Collect the descriptive fields as free text**, because they are open descriptions: the **area**,
27
+ the **trigger** ("if you edit X..."), the **counterintuitive behavior**, the **solution** and the
28
+ **references**.
29
+ 4. **Pick how it fires, then write it:**
30
+ - `afm gotcha new <slug> --basis <bitten-twice|documented-sdk> --area A --title T --trigger X --behavior B --solution S --ref R --description "<what the reader LEARNS, not what the file is>"`
31
+ - **The frontmatter is the delivery mechanism, not decoration.** The trigger index reads
32
+ `fires_on` and, for a file shape, `trigger_path`. An entry without a way to fire never reaches
33
+ anybody.
34
+ - **Prefer `--fires-on event` (the default) over a bad file shape.** Use `--fires-on file-shape --trigger-path "<glob>"` only when a narrow glob names the files. "Most of the repository"
35
+ means there is no trigger. A guessed trigger fires on the wrong file, which is worse than one
36
+ that never fires (#5).
37
+ - The command fills the frontmatter `bites` from the basis and `last_bite` with the current month, prints the path
38
+ and runs `afm index --materialize`.
39
+ 5. **Report the path.** Review happens through `git diff` (invariant principle #6).
40
+
41
+ ## On a later re-bite
42
+
43
+ The gotcha exists and it hit again: `afm gotcha bite <id>`. It bumps `bites` and sets `last_bite` to the
44
+ current month. That is the incidence signal `afm restructure` reads to prune dead gotchas (an old
45
+ `last_bite` plus a stalled `bites`). Do not register "avoided" cases: avoidance is an unfalsifiable
46
+ counterfactual, so only observable incidence counts.