@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,38 @@
1
+ ---
2
+ type: rubric
3
+ description: Rejects what must not become a durable doc, because a false constraint is poison.
4
+ load: warm
5
+ fires_on: op-call
6
+ called_by: ["remediate", "reconcile"]
7
+ fires_when: 'something is about to become a durable doc'
8
+ ---
9
+
10
+ # Rubric — negative-filters (what NOT to promote to durable doc)
11
+
12
+ > This is a rejection checklist for the entry gate of `gotcha`/`reconcile`/`remediate`. It is the negative side of principle #5 ("do not invent"): **a false constraint is poison**. It is worse than no doc, because it hardens into a future wrong refusal or error. This applies from v3.1.0 (Phase 4 of the v3.2 initiative). Field evidence (ai-memory): in one real corpus, about 28% of pages were low-signal sessions that only polluted retrieval.
13
+
14
+ ## Reject (this does NOT become a gotcha, learning, rule, or procedure)
15
+
16
+ | Anti-pattern | Why it is poison | What to do instead |
17
+ |---|---|---|
18
+ | **Negative claim about a tool** ("tool X is broken", "library Y does not work") | It hardens into a **fossil refusal**. After the tool is fixed, the doc still makes the next agent avoid it for no reason. | Record the concrete *workaround*, if it is durable. Do not record the verdict "it is broken". Remove the entry when the cause is fixed, because it is transient. |
19
+ | **Transient failure** (fixed on retry, see § 5.1, a missing credential or binary at that moment, a setup state) | It becomes a **dead constraint**. The condition no longer exists, so the doc lies to the future reader. | Keep it as evidence in the state store, not as an artifact. Capture the *retry or fix pattern*, not the temporary failure. |
20
+ | **One-off narrative** ("in this session I did A, B, C") | The timeline already lives in the event ledger and the session handoffs, in the state store. As a normative doc, it is only noise. | Use an episodic handoff, not a semantic doc. |
21
+ | **User-visible status** ("the build passes now", "deploy ok") | This is a momentary state, not knowledge. | Use `_focus.md` (state) or a handoff. Do not use `gotcha` or `adr`. |
22
+ | **Release marker or smoke test** ("v0.1.1 published", "echo ok") | This is operational, not a reusable lesson. | Use `notes` or a log. Never a rule or gotcha. |
23
+ | **Vibe-rule with no trigger** (KISS, DRY treated as a "rule") | Without an executable 0/1 trigger, it is not a hard rule (see #3). | Record it as a principle in `afm.md § 1.3`, not in § 3. |
24
+
25
+ ## Promotion test (pass the gate IF)
26
+
27
+ 1. **Does it have a durable antidote?** It must be a concrete action that prevents the problem, not just a verdict.
28
+ 2. **Does the claim survive a fix to its cause?** If it "goes away when X is fixed", it is transient. Reject it.
29
+ 3. **Does another agent without my memory need this to avoid breaking something?** (#1 — otherwise it is memory or state, not doc.)
30
+ 4. **Did it happen ≥2 times?** Or is it a user correction? Or is it external SDK documentation? (#5 — otherwise it is evidence, not yet an artifact.)
31
+
32
+ All four **yes** answers promote the item. Any structural **no** keeps it as evidence or state, not a durable doc.
33
+
34
+ ## Anti-patterns (of the gate itself)
35
+
36
+ - ❌ **Do not promote out of caution** ("better to record it just in case"). A false constraint is worse than nothing (#5).
37
+ - ❌ **Do not confuse transient with durable.** The test is always "does it survive a fix to its cause?".
38
+ - ❌ **Do not treat every error as a gotcha.** A recognized error goes to the CRITIC loop (`remediate`), which applies this filter.
@@ -0,0 +1,119 @@
1
+ ---
2
+ type: rubric
3
+ description: Turns each SOLID principle into a mechanical trigger instead of folklore.
4
+ load: warm
5
+ fires_on: file-shape
6
+ trigger_basename: 'utils.* helpers.* util.* helper.* *-utils.* *-helpers.* *_utils.* *_helpers.* *-manager.* *_manager.* manager.* *-and-*'
7
+ trigger_any: yes
8
+ trigger_grep: 'switch[[:space:]]*\([[:space:]]*[a-zA-Z_.]*(provider|adapter|driver|backend|strategy|channel|kind|variant)'
9
+ fires_when: 'a file name collects unrelated responsibilities, or a provider `switch` is spread across files'
10
+ ---
11
+
12
+ # Rubric — SOLID as a concrete trigger (not folklore)
13
+
14
+
15
+ SOLID is easy to use as an argument and hard to use as a trigger. This rubric converts each principle into a **mechanical trigger** — when to apply it, the anti-pattern, an example.
16
+
17
+ ## SRP — Single Responsibility (already hard rule 5)
18
+
19
+ **Trigger:** the file or function name has "and" / "manager" / "utils" / "helpers" without a domain prefix.
20
+
21
+ **Apply:** split it. One file, one responsibility.
22
+
23
+ Anti-pattern: `notification-and-billing.ts`, `user-manager.ts`, `helpers.ts`.
24
+
25
+ ## OCP — Open/Closed: extend without modifying
26
+
27
+ **Trigger:** you are about to add a **new provider**. Examples: registry NPM/GitHub/Custom, storage S3/R2/MinIO, a new plan, a new payment method, a new notification channel.
28
+
29
+ **Apply:** add a **new file** that implements a typed port. A central registry injects it. **No** `switch (provider)` spread across 2+ files.
30
+
31
+ ```ts
32
+ // ✅ port + adapters + registry
33
+ type RegistryAdapter = {
34
+ publish(tarball: Buffer, opts: PublishOpts): Promise<PublishResult>;
35
+ };
36
+ const adapters: Record<RegistryKind, RegistryAdapter> = {
37
+ npm: npmAdapter,
38
+ github: githubAdapter,
39
+ custom: customAdapter,
40
+ };
41
+
42
+ // ❌ switch spread across 3 files
43
+ function publish(kind: RegistryKind, ...) {
44
+ if (kind === "npm") { /* npm logic */ }
45
+ else if (kind === "github") { /* github logic */ }
46
+ // ... and again in other functions
47
+ }
48
+ ```
49
+
50
+ ## LSP — Liskov Substitution: interchangeable implementations
51
+
52
+ **Trigger:** you have **2+ implementations of the same port** (RegistryAdapter, StorageAdapter, EmailAdapter).
53
+
54
+ **Apply:** all implementations return the **same classified result shape**. Adapter A must not return `null` on conflict while adapter B throws an exception.
55
+
56
+ ```ts
57
+ // ✅ every implementation returns the same discriminated Result
58
+ type PublishResult =
59
+ | { code: "PUBLISHED"; version: string }
60
+ | { code: "CONFLICT"; existingVersion: string }
61
+ | { code: "FAILED"; reason: string };
62
+
63
+ // ❌ adapter A: returns null on conflict
64
+ async function publishNpm(): Promise<{ version: string } | null> { ... }
65
+ // ❌ adapter B: throws an exception
66
+ async function publishGithub(): Promise<{ version: string }> {
67
+ throw new ConflictError(...);
68
+ }
69
+ ```
70
+
71
+ ## ISP — Interface Segregation: minimal port
72
+
73
+ **Trigger:** a domain function receives the whole `ctx: TRPCContext` but uses only `ctx.db` and `ctx.log`.
74
+
75
+ **Apply:** declare only what you use: `ctx: Pick<TRPCContext, "db" | "log">`. Otherwise the test must mock everything.
76
+
77
+ ```ts
78
+ // ✅ minimal port
79
+ async function domain_createSessionAuth({
80
+ ctx,
81
+ input,
82
+ }: {
83
+ ctx: Pick<TRPCContext, "db" | "log">;
84
+ input: { userId: string };
85
+ }): Promise<Result<IssuedSession, "USER_NOT_FOUND">> { ... }
86
+
87
+ // ❌ whole ctx, hides the real dependency
88
+ async function domain_createSessionAuth({ ctx, input }: DomainInput<...>) {
89
+ // uses only ctx.db, but the test must mock ctx.user, ctx.session, ctx.headers, ...
90
+ }
91
+ ```
92
+
93
+ ## DIP — Dependency Inversion: domain does not know infra
94
+
95
+ **Trigger:** a domain function or pure lib is about to import something from a framework (`TRPCError`, `req.headers`, a direct ORM client with no abstraction).
96
+
97
+ **Apply:** invert the direction. Domain defines the interface. Infra implements it. Domain imports only from layers below it (pure lib, types).
98
+
99
+ ```
100
+ ✅ correct direction (all paths rooted at {{src-path}}/):
101
+ app/ → server/ → server/modules/X/ → domain/X/ → lib/ → types
102
+
103
+ Each layer knows the layer below it, never the layer above it.
104
+
105
+ ❌ common inversions:
106
+ - {{src-path}}/domain/X/ importing TRPCError (transport leaks up into domain)
107
+ - {{src-path}}/lib/Y/ importing from server (lib is no longer publishable)
108
+ - {{src-path}}/lib/Y/ importing an ORM type (couples lib to infra)
109
+ ```
110
+
111
+ ## Summary — what to ask when
112
+
113
+ | Symptom | Principle | Fix |
114
+ | --- | --- | --- |
115
+ | File is growing, doing 2+ things | SRP | Split it |
116
+ | You are adding a 4th variant of something | OCP | Port + adapters, not a switch |
117
+ | 2 implementations of the same thing return different shapes | LSP | Standardize on a discriminated Result |
118
+ | Function receives a giant ctx but uses 2 fields | ISP | Pick / minimal interface |
119
+ | Domain wants to import something from above | DIP | Invert: domain defines, infra implements |
@@ -0,0 +1,34 @@
1
+ ---
2
+ type: rubric
3
+ description: Picks one source when the frozen template and the streaming learning disagree.
4
+ load: warm
5
+ fires_on: op-call
6
+ called_by: ["export-template", "reconcile"]
7
+ fires_when: 'frozen template knowledge and a streaming learning are in conflict'
8
+ ---
9
+
10
+ # Rubric — frozen template (offline) vs. streaming learning (online): precedence, never sum
11
+
12
+ > **Load-bearing finding from AWM (arXiv:2409.07429):** offline knowledge (the frozen architectural template from `export-template`) and online knowledge (the learning that `reconcile`/`restructure` accumulate in streaming during the project life) are **non-additive**. Combining the two hurts. The combined result falls *between* the two and matches neither. AFM has both layers. AFM needs an explicit rule of **precedence + tombstone**. AFM must never merge the two.
13
+
14
+ The single rule: when offline and online conflict, **pick ONE and tombstone the other**. Keep the provenance. Never keep both as a "sum". Never merge the content.
15
+
16
+ ## Decision table
17
+
18
+ | Situation | Rule |
19
+ | --- | --- |
20
+ | The project has a **template origin** (`docs/.template` was the seed) AND `reconcile` proposes a rule or gotcha that **contradicts** an artifact inherited from the template | **Streaming wins locally.** Apply the new rule or gotcha. Mark the inherited artifact with `*(overridden — see reconcile NNN / cycle NNN)*`. **Do not merge** the two. Non-additivity means mixing is worse than either alone. |
21
+ | The **same knowledge** exists in the frozen template **and** in a streaming learning (a duplicate, not a conflict) | **Pick ONE** (usually the more recent, local copy). Tombstone the other. Do not keep both copies as a "sum". That creates the inflation `diagnose A6` later flags. |
22
+ | `export-template` is about to **freeze** a project that already accumulated streaming learnings | Consolidate the streaming learnings **via `afm generalize` BEFORE** the export. They become part of the frozen template (offline), not a parallel layer. This avoids freezing half the knowledge and leaving the other half to collide with the consumer's own reconcile later. |
23
+
24
+ ## Why not merge
25
+
26
+ - **AWM measured this:** combined offline and online knowledge lands *between* the two and matches neither. Silent fusion is the worst outcome.
27
+ - **Tombstone, not deletion:** precedence preserves provenance. The losing artifact becomes a note. It does not disappear. This matches the discipline of `generalize` (a merged gotcha becomes a tombstone) and principle #6 (deletion is a bright line).
28
+ - **`reflect` and `generalize` stay valid** *within* each layer. This rubric forbids only mixing **between** layers without deciding precedence.
29
+
30
+ ## Counter-examples
31
+
32
+ - ❌ Do not keep the inherited template rule **and** the new reconcile rule that contradicts it, hoping "both count". This violates non-additivity. Decide the precedence instead.
33
+ - ❌ Do not let `export-template` freeze a project with pending streaming learnings unconsolidated. The consumer then inherits a partial layer that will fight its own reconcile.
34
+ - ❌ Do not merge the text of both into a third "combined" version. That is exactly the *between-the-two* result AWM showed to be worse.
@@ -0,0 +1,94 @@
1
+ ---
2
+ type: rubric
3
+ description: Says where the parser goes, so the domain never validates its own input.
4
+ load: warm
5
+ fires_on: file-shape
6
+ trigger_path: '*/domain/*'
7
+ trigger_grep: '(from[[:space:]]+[''"]zod[''"]|require\([''"]zod[''"]\)|\bz\.(object|string|number|enum|array)\()'
8
+ fires_when: 'a schema parser is used inside a `domain/` path'
9
+ ---
10
+
11
+ # Rubric — where Zod (or the parser) goes
12
+
13
+ ## The single rule
14
+
15
+ The schema parser (Zod or the stack equivalent) **validates in exactly 2 places**:
16
+
17
+ 1. **Procedure input / transport handler** — request to validated type.
18
+ 2. **External payload parsing** — webhook, crawled source, env var, queue message, DB JSON with unknown shape.
19
+
20
+ **Domain receives an already validated, typed shape.** Pure lib code does too. Re-validating inside domain "for safety" duplicates the schema's source of truth.
21
+
22
+ ## Why this rule exists
23
+
24
+ - **Validating twice wastes effort** (CPU cost, plus a schema kept in 2 places).
25
+ - **Domain tests logic, not parsing.** A mock input with the wrong type does not compile. TS is already the barrier.
26
+ - **Schema lives near the boundary** where external data arrives, not wherever "seemed like a good idea."
27
+
28
+ ## Examples
29
+
30
+ ### ✅ Correct: procedure validates input before it calls domain
31
+
32
+ ```ts
33
+ const router_apps = router({
34
+ procedure_createApps: publicProcedure
35
+ .input(z.object({
36
+ packageName: z.string().min(1),
37
+ schemaUrl: z.string().url(),
38
+ }))
39
+ .mutation(async ({ ctx, input }) => {
40
+ // input is already { packageName: string; schemaUrl: string }
41
+ const result = await domain_createApps({ ctx, input });
42
+ // ...
43
+ }),
44
+ });
45
+ ```
46
+
47
+ ### ✅ Correct: webhook handler validates the external payload
48
+
49
+ ```ts
50
+ export async function POST(req: Request) {
51
+ const raw = await req.text();
52
+ const event = stripe_verifyWebhook(raw, signature); // validates the signature
53
+ const payload = zStripeEvent.parse(event); // validates the shape
54
+ await domain_handleStripeEventBillings({ ctx, input: payload });
55
+ }
56
+ ```
57
+
58
+ ### ❌ Wrong: domain re-validates "for safety"
59
+
60
+ ```ts
61
+ async function domain_createApps({ ctx, input }: DomainInput<{ packageName: string; schemaUrl: string }>) {
62
+ // ❌ Wrong: the procedure already validated this. It adds noise and duplicates the schema.
63
+ const validated = z.object({
64
+ packageName: z.string().min(1),
65
+ schemaUrl: z.string().url(),
66
+ }).parse(input);
67
+ }
68
+ ```
69
+
70
+ ### ✅ Correct: pure lib receives the shape and does not validate
71
+
72
+ ```ts
73
+ // lib/sdk-generator/index.ts
74
+ export function generateSdk({ schema, options }: { schema: OpenApiV3; options: GenOpts }): SdkFiles {
75
+ // No z.parse call here. The schema arrives already validated from the caller.
76
+ // If the caller passed the wrong shape, that is the caller's bug, not something the lib must guard against.
77
+ }
78
+ ```
79
+
80
+ ## When "validate at the boundary" grows
81
+
82
+ Suppose 6 similar procedures all validate the same `apps` shape.
83
+
84
+ - Extract the schema to `{{src-path}}/server/modules/apps/schemas.ts`.
85
+ - Each procedure imports it: `.input(zCreateAppsInput)`.
86
+ - The schema is still declared **once**, but reused across procedures.
87
+ - This stays a boundary pattern. Only the duplication is gone.
88
+
89
+ ## More anti-patterns
90
+
91
+ - ❌ Wrong: validating input inside a domain function "for DI" or "for defense in depth." TS plus the boundary schema already cover this.
92
+ - ❌ Wrong: declaring a schema inside the domain file. Move it to `schemas.ts` or `*.types.ts` in the module (hard rule 7).
93
+ - ❌ Wrong: `z.unknown().parse(...)` to dodge a type. This validates nothing and gives false safety. Use a real `z.object({...})` or accept the upstream type.
94
+ - ❌ Wrong: validating env vars with scattered `process.env.X || throw` calls. Centralize this in `{{src-path}}/server/env.ts` with Zod, and validate once at boot.
@@ -0,0 +1,65 @@
1
+ ---
2
+ type: rubric
3
+ description: Decides when a DSL is worth suggesting, and when it is premature.
4
+ load: warm
5
+ fires_on: repo-shape
6
+ detector: dsl
7
+ fires_when: 'three or more call sites repeat one fixed-order sequence'
8
+ ---
9
+
10
+ # Rubric — when to create a DSL (suggest, do not build)
11
+
12
+ > DSL here means any domain mini-language that collapses repeated boilerplate of primitive calls: a fluent builder, a combinator pipeline, a declarative object that gets interpreted, or a parsed language. **DSL-first is the complement of the Rule of Three, not the opposite of KISS.** The agent does not abstract early. But when primitive boilerplate scales AND has grammar, a DSL pays for itself. The agent **suggests** (proposes and sketches). The agent **does not build alone** (hard rule 11 — a DSL is a first-class layer or abstraction, so it stops and asks).
13
+
14
+ ## Binary decision
15
+
16
+ **Suggest a DSL only when BOTH signals are true:**
17
+
18
+ - ✅ **Repetition (Rule of Three of sequence):** 3 or more call sites repeat the same sequence of N or more primitive calls, in fixed order. This is not 3 loose calls. The *sequence* itself repeats. Only the parameters vary, not the structure.
19
+ - ✅ **Boilerplate dominates the intent (ratio):** at these sites, most lines are mechanical wiring, setup, or glue, not real business logic. The reader cannot see *what* the code wants through *how* it wires the primitives together.
20
+
21
+ **A third condition tells a DSL apart from "extract a function":**
22
+
23
+ - ✅ **Reusable grammar exists** — composition, required ordering, branching, or chaining that repeats. This is what makes a DSL pay more than a helper. Without grammar (just "call 5 functions in the same fixed sequence"), **a named helper wins.** That case is not a DSL.
24
+
25
+ **Do NOT suggest a DSL when:**
26
+
27
+ - ❌ **Fewer than 3 repeated sequences.** The Rule of Three has not been met. Wait for the third case (YAGNI).
28
+ - ❌ **A simple helper or builder already collapses the boilerplate.** KISS beats DSL here. A named function (`stripe_createCheckoutSession`) or a one-level builder wins over a mini-language. Use a DSL only when the helper cannot capture the grammar.
29
+ - ❌ **The "boilerplate" is real per-site logic.** Genuine variation between sites is not boilerplate. Abstracting it would hide a difference that matters.
30
+ - ❌ **"This will scale" or "we can parametrize everything."** This is YAGNI. Do not build a speculative DSL for the general case before 3 real cases exist.
31
+
32
+ ## Why these rules
33
+
34
+ - **Both signals together, not one.** Repetition without dominant boilerplate: a helper solves it. High boilerplate without repetition (1 site): it is just a large function — split it or inline it. A DSL is expensive (new layer, indirection, a learning curve, debugging through the abstraction). It pays off only at the intersection of both signals.
35
+ - **Grammar is the DSL-versus-helper discriminator.** Extracting a function removes duplication. A DSL gives you a *language* to express the intent. If there is nothing to "compose," a function is enough, and cheaper.
36
+ - **Suggest, do not build (rule 11 / autonomy principle 6, bright line d).** Creating a DSL introduces a first-class layer or abstraction. This is a load-bearing architectural decision. The agent brings the proposal, with an API sketch and a candidate ADR. The architecture owner decides. Building a DSL on its own would cross the bright line.
37
+
38
+ ## Form — pick the lightest one that removes the boilerplate (KISS inside the DSL)
39
+
40
+ In increasing order of cost — **stop at the first form that captures the grammar:**
41
+
42
+ 1. **Fluent builder / factory function** — simple chaining (`q().where().limit()`). This is the cheapest form. It covers most cases.
43
+
44
+ **Purity:** chain methods only assemble immutable data. IO stays in one terminal call (`.exec()` or `.run()`). A side effect in the middle of the chain forces you to mock the world to test a pure rule. This is the "mock that simulates more than needed" smell (see § 5). **Hard rule 7** separates pure domain from glue for this exact reason. A builder placed outside `{{src-path}}/<domain>/` escapes that separation.
45
+
46
+ Counter-example: `checkout().comValor(v).cobrarNoStripe().comDesconto(d)`. Here `cobrarNoStripe()` sits mid-chain and mixes IO with data assembly.
47
+ 2. **Combinators / pipeline** — small functions that compose (`pipe(parse, validate, persist)`). Use when the grammar is composition.
48
+ 3. **Declarative interpreted object** — data-driven config that a runner walks through. Use when the "language" is a data structure.
49
+ 4. **Parsed mini-language** (string to AST to exec) — **last resort**, rarely justified in a product app. It needs a parser, error handling, and tests for the parser itself. Use it only when the 3 forms above genuinely cannot express the grammar.
50
+
51
+ ## Before proposing — self-check (verification corollary 6)
52
+
53
+ 1. Do the 3 sites repeat the same *sequence*, or do they just use the same primitives in different orders? (Different orders mean it is not one DSL.)
54
+ 2. Would a one-level helper collapse 80% of the boilerplate? If yes, propose the helper, not the DSL.
55
+ 3. Does the proposed DSL hide a real difference between the sites? If yes, it will leak — rethink the boundary.
56
+ 4. Which form above is the lightest one that captures the grammar? Do not propose a parser if a builder solves it.
57
+ 5. Is there a required order between chain steps? If yes, the proposed form must reject the wrong order at **compile time**, not a runtime `throw`. Use type-state: each method returns a type that exposes only the next legal methods. **If type-state gets expensive, do not propose the builder.** A single function with all required arguments solves the same problem without the technique.
58
+
59
+ ## Counter-examples
60
+
61
+ - ❌ Building a standalone query DSL at the 2nd call site — the Rule of Three has not been met. Wait for the third case, or use a helper.
62
+ - ❌ Proposing a parsed mini-language for 3 sequences that a 20-line fluent builder would solve — too expensive a form (use level 1 instead).
63
+ - ❌ Calling 3 handlers that check different things "boilerplate" — this is per-site logic, not repeated wiring. A DSL would hide the difference.
64
+ - ❌ Building the DSL alone because "it is obviously needed" — this is rule 11. Propose it, sketch the API, and open a candidate ADR. The human approves the new layer.
65
+ - ❌ A DSL for the general case ("supports any future provider") built from 3 real providers — this is YAGNI. Model the 3 real cases and generalize when a 4th case actually diverges.
@@ -0,0 +1,49 @@
1
+ ---
2
+ type: rubric
3
+ description: Decides when code earns its own library directory.
4
+ load: warm
5
+ fires_on: file-shape
6
+ trigger_min_lines: 150
7
+ trigger_max_consumers: 1
8
+ fires_when: 'a file passes 150 lines of logic and at most one other file imports it'
9
+ ---
10
+
11
+ # Rubric — when to create `{{src-path}}/lib/<x>/`
12
+
13
+ ## Binary decision
14
+
15
+ **Create a lib when ANY of these is true:**
16
+
17
+ - ✅ You already have **3 callers** of the same inline helper (confirmed Rule of Three).
18
+ - ✅ It is a **nameable external integration** (Stripe, S3, Resend, Slack, GitHub). It becomes `lib/<provider>/`.
19
+ - ✅ It has **more than ~150 lines** of pure logic coupled to one consumer. Extract it to reduce reading load.
20
+
21
+ **Do NOT create a lib when:**
22
+
23
+ - ❌ You have 1 caller. Keep it inline. Wait for the second caller.
24
+ - ❌ It mixes I/O with the ORM. Put it in `infra/` or inline in the procedure.
25
+ - ❌ The helper has fewer than 10 lines and 2 callers. Simple duplication wins (KISS beats DRY here).
26
+ - ❌ The reason is "I will need it later". This is YAGNI. Keep it inline until you need it.
27
+
28
+ ## Why these rules exist
29
+
30
+ - **3 callers means a real pattern, not a coincidence.** Two callers can be a false convergence.
31
+ - **An external integration deserves its own name** (`stripe_createCustomer`, not `createCustomer`). The reader then knows at once that this is a network call. This lowers the cognitive cost of scanning the code.
32
+ - **At 150 lines, "read the whole file" costs more than "follow the call to the helper."** Below that size, inline code is cheaper.
33
+ - The reader pays this cost either way. Extraction just moves it to the cheaper side.
34
+
35
+ ## Where to place it when you create it
36
+
37
+ Decide in this order:
38
+
39
+ 1. **Is it a pure lib with no dependency on the app framework?** Use `{{src-path}}/lib/<x>/`. It must be publishable, with zero ORM, web framework, or orchestrator code.
40
+ 2. **Does it hold business logic for module X?** Use `{{src-path}}/server/modules/<X>/domain/`.
41
+ 3. **Does it serve 3 or more modules?** Use `{{src-path}}/domain/shared/`.
42
+ 4. **Is it a wrapper for an external client (a singleton with config)?** Use `{{src-path}}/server/infra/`.
43
+
44
+ ## Bad examples
45
+
46
+ - ❌ `{{src-path}}/lib/utils/format-date.ts` with 1 caller. Keep it inline in the page that needs it.
47
+ - ❌ `{{src-path}}/lib/auth/get-user.ts` that imports the ORM. Move it to `{{src-path}}/server/modules/auth/`. It is not a pure lib.
48
+ - ❌ `{{src-path}}/lib/email-and-notifications/` mixes two responsibilities. Split it into `{{src-path}}/lib/email/` and `{{src-path}}/lib/slack/`.
49
+ - ❌ `{{src-path}}/lib/stripe/` with `class StripeManager { 12 methods }`. Split it into `{{src-path}}/lib/stripe/checkout.ts`, `{{src-path}}/lib/stripe/portal.ts`, and so on, using named functions such as `stripe_createCheckoutSession`.
@@ -0,0 +1,39 @@
1
+ ---
2
+ type: rubric
3
+ description: Decides when a feature earns a top-level module.
4
+ load: warm
5
+ fires_on: file-shape
6
+ trigger_new_module: 'modules'
7
+ fires_when: 'the file would be the first one in a new top-level module directory'
8
+ ---
9
+
10
+ # Rubric — when to create a top-level module in `{{src-path}}/server/modules/`
11
+
12
+ ## Binary decision
13
+
14
+ **Create a new module when ALL of these are true:**
15
+
16
+ - ✅ It has its **own entity** (a new model, not a field on an existing model).
17
+ - ✅ It already has **2 or more planned procedures** (not one isolated procedure).
18
+ - ✅ It has its **own state with a lifecycle** (not just a static lookup table).
19
+
20
+ **Otherwise it is a sub-feature of an existing module.** Example: `notifications` that serves only `auth` belongs at `{{src-path}}/server/modules/auth/notifications/`, not as a top-level module.
21
+
22
+ ## Why these rules exist
23
+
24
+ - **Its own entity** defines the module's natural boundary. Without an entity, it is just a feature of another module (a field, extra behavior).
25
+ - **2 or more procedures** confirms the module has enough usage surface. One isolated procedure does not justify its own directory, router, and domain.
26
+ - **Lifecycle** separates "a domain with state" from "static configuration." A plan (FREE/PRO) is an enum plus a lookup table. It is not a `plans/` module. It is part of `billings/`.
27
+
28
+ ## Review questions before you create a module
29
+
30
+ 1. Does this concept already exist in a current module? If yes, it is a sub-feature.
31
+ 2. Will it share `domain/`, `infra/`, or types with another module? If yes, consider `{{src-path}}/domain/shared/` instead of a new module.
32
+ 3. Will it stay untouched for more than 6 months? If yes, and it does not grow, it may be a helper, not a module.
33
+
34
+ ## Anti-examples
35
+
36
+ - ❌ Do not create `modules/notifications/` when only `auth` sends notifications. Use `modules/auth/notifications/`.
37
+ - ❌ Do not create `modules/plans/` to hold the `PLAN_CONFIG` constant. Use `modules/billings/plan-config.ts`.
38
+ - ❌ Do not create `modules/utils/` to collect cross-module helpers. No `utils` module exists. Put helpers in `lib/` or inline.
39
+ - ❌ Do not create `modules/admin/` early "because an admin panel is coming later." This is YAGNI. Wait for the first admin procedure to appear.
@@ -0,0 +1,62 @@
1
+ ---
2
+ type: rubric
3
+ description: Chooses between the full cycle, one mechanism and a point fix.
4
+ load: warm
5
+ fires_on: op-call
6
+ called_by: ["evolve", "reflect"]
7
+ fires_when: 'a methodology finding needs a path: cycle, one mechanism, or a point fix'
8
+ ---
9
+
10
+ # Rubric — the `evolve` cycle vs. a single mechanism vs. a point fix
11
+
12
+ > **What "evolution" means here:** it means refining the **local documentation of this project** (the methodology instance materialized in `<consumer>/docs/`). It makes that doc leaner, clearer, current, and efficient. It is **never** AFM itself (the bundled content). For the plugin, you only **suggest** a change, through `afm promote`. Every mention of "methodology" or "methodology health" below means the local doc.
13
+
14
+ > This is a **3-way decision**. Does the finding call for (1) the **full cycle** of `afm evolve` (an orchestrator: gather evidence → propose → one gate → apply → record), (2) **one mechanism à la carte** (`afm diagnose`, `afm reflect`, `afm generalize`, `afm restructure`), or (3) **a point fix** that `reconcile` proposes directly through an atomic skill (`afm gotcha`, `afm rule`, `afm adr`)? Cost decreases in that order. The cycle costs the most: it composes several mechanisms, one consolidated gate, and a record in `docs/evolution/`. A single mechanism is scoped to one axis. A point fix is cheap. Do not run the cycle for what one mechanism can fix. Do not run a mechanism for what one edit can fix.
15
+
16
+ ## The 3 paths
17
+
18
+ ### 1. The `evolve` cycle — use it when BOTH of these are true:
19
+
20
+ - ✅ **The problem affects the whole instance, not one isolated axis.** You see several health findings. Or the findings cross categories: dead references **and** a rule that misled someone **and** inflation spread across files. This is a *health sweep*. It benefits from one consolidated gate and one lineage record.
21
+ - ✅ **You have observable evidence that something is below 100%.** The evidence can be mechanical (from `diagnose`). It can be behavioral (from `reflect`). It can be a symptom the user states directly, such as "these docs are a mess." Without a signal, do not run the cycle. A healthy instance gains almost nothing from it. The cooldown refuses to run it.
22
+
23
+ > **Second entry point — ex-post, from inside `reflect`.** The two criteria above are normally applied ex-ante, before acting, to pick a path. `reflect.md § 5` applies the same two criteria ex-post — after the mechanism already ran, over the findings it already collected in its own §§ 1-2 — to discover that what it found exceeds its own scope. Same criteria, no new test, no restatement. It only proposes; the user still invokes `afm evolve`. See `ops/reflect.md § 5`.
24
+
25
+ ### 2. A single mechanism à la carte — use it when you know exactly which lens you need:
26
+
27
+ - 🔍 **`afm diagnose`** — only the **health report** (a mechanical scan of the 7 axes, read-only). Use it to answer "how healthy is the methodology here?" without proposing or applying anything.
28
+ - 🪞 **`afm reflect`** — use it when **one specific doc misled you** at apply time (an ambiguous rule, a section that gave no guidance). It refines instructiveness, based on behavioral evidence from the session.
29
+ - 🧬 **`afm generalize`** — use it when **2 or more similar gotchas** have piled up and should merge into one abstract rule (episodic to semantic). This is anti-inflation at the root.
30
+ - 🗂️ **`afm restructure`** — use it for **staleness**, where a doc no longer matches the code. Use it also for **findability and partitioning**: information in the wrong place, or a doc that outgrew its shape.
31
+
32
+ > A single mechanism still **self-checks and gates** what it proposes. `reflect`, `generalize`, and `restructure` each have their own gate. `diagnose` is read-only. What sets a single mechanism apart from the cycle is **scope**. It uses one lens, not the full sweep. It skips the overhead of composing every mechanism plus a cycle record.
33
+
34
+ ### 3. A point fix (reconcile → an atomic skill) — use it when the change is additive and local:
35
+
36
+ - ❌ **You learned a new fact, decision, or gotcha.** Use `afm adr` for an architecture decision. Use `afm rule` for a rule from one correction. Use `afm gotcha` for a surprise that has bitten you 2 or more times. `reconcile` already covers this at the end of the turn. Opening a mechanism or the cycle is overhead here.
37
+
38
+ Distinction: `reconcile`, `gotcha`, and `rule` **add** knowledge. `reflect`, `generalize`, and `restructure` **refine, consolidate, or reorganize** knowledge that already exists.
39
+ - ❌ **You need to validate ONE feature.** For coverage or consistency across spec, plan, and tasks, use `afm analyze` (read-only, per feature).
40
+ - ❌ **You need to deliver a feature.** Use `afm deliver`.
41
+ - ❌ **You need to promote a lesson to the plugin.** Use `afm promote`.
42
+
43
+ ## Why these rules exist
44
+
45
+ - **An observable signal is mandatory** for paths 1 and 2. A claimed systemic problem with no evidence turns the agent into an auditor of text using only text — a self-reference loop. This is forbidden. Mechanical evidence (`diagnose`) and behavioral evidence (`reflect`) are the two valid kinds of evidence — the two sides of the Self-Harness φ. Both count.
46
+ - **Signal beats ritual** (Self-Harness / Autogenesis). In healthy docs, the cycle returns almost nothing. An evidence-based trigger beats a fixed budget or calendar. The `evolve` cooldown refuses to run the cycle without a new signal. A single mechanism, being scoped and — for `diagnose` — read-only, carries no cooldown.
47
+ - **Scope decides the path** (cycle vs. mechanism). If you know the lens, use the mechanism. If the problem is a multi-category sweep that deserves one consolidated gate, use the cycle. Do not compose every mechanism (`evolve`) to fix a single axis.
48
+ - **An empty diagnosis is a valid result.** If the scan or reflection finds nothing, it reports "100%" and stops. It must **never** invent a problem to justify having run.
49
+ - **Doc size is a signal to consolidate, never a signal to cut** (ACE vs. Configuring). A core doc above about 500 lines (the `afm doctor` A6 inflation threshold) routes to a **consolidation review**. `afm generalize` merges redundancy. `afm restructure` partitions by temperature. Neither ever cuts content based on line count alone.
50
+
51
+ ACE prunes redundancy, not lines. Brevity bias discards load-bearing detail. The line count triggers a review. It never dictates a deletion.
52
+
53
+ ## Counterexamples
54
+
55
+ - ❌ **Running `afm evolve` weekly by ritual.** Run it on a signal, never on a calendar.
56
+ - ❌ **Opening the cycle to log one new gotcha.** This is additive and local. `afm gotcha` (or `reconcile` proposing it) is enough.
57
+ - ❌ **Running the full cycle just to check health.** Use `afm diagnose` instead (read-only, no gate).
58
+ - ❌ **Claiming "this doc looks inflated" without a `wc -l` or a grep for duplication.** Without observable evidence, this is not a finding (see rule 5 above).
59
+ - ❌ **Running `generalize` from 1 gotcha.** Without a batch of 2 or more, there is no generalization — only an invented abstraction with no evidence.
60
+ - ❌ **Using `reflect` to soften a rule because it embarrassed you.** A violation does not mean the rule is wrong. "The agent was non-compliant" is a mandatory rival hypothesis.
61
+ - ❌ **Using `restructure` to force tiering on a small doc.** Partitioning by temperature is opt-in. Use it only when a doc has actually grown large (YAGNI).
62
+ - ❌ **Running the cycle again when nothing has changed.** The cooldown blocks the cycle. Running a mechanism with no new signal is theater.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: adr
3
+ description: |
4
+ Writes an Architecture Decision Record to `<consumer>/docs/adr/NNNN-slug.md`. It records context, decision, alternatives and consequence. In a refactored project, write a retroactive ADR only when it is load-bearing.
5
+ Activates: `afm adr`, "create ADR", "architectural decision", "record this architecture choice".
6
+ ---
7
+
8
+ # AFM — ADR
9
+
10
+ The CLI owns the number, the template, the frontmatter, the supersede link and the index. This skill keeps
11
+ only the judgment.
12
+
13
+ ## When NOT to activate
14
+
15
+ This is a disambiguation for a skill that already activated. It does not control activation itself. A
16
+ counterintuitive surprise belongs in `afm gotcha`. A rule with an executable trigger belongs in `afm rule`.
17
+
18
+ ## Pre-check
19
+
20
+ `afm preflight`. Exit 3 means there is no instance: stop and suggest `afm init` (greenfield) or
21
+ `afm refactor` (brownfield) first. Exit 4 means the shipped content does not resolve: report it, do not
22
+ fall back silently.
23
+
24
+ ## Procedure (judgment only)
25
+
26
+ 1. Ask the status: `afm ask adr`. Collect the title, context, decision, alternatives, consequence and refs
27
+ as free text, because these fields carry intent.
28
+ 2. Run `afm adr new <slug> --title "<title>" --description "<one sentence>"`, with `--supersedes N` when
29
+ the decision replaces ADR N.
30
+ 3. Fill the sections of the printed file with what the operator said, and leave the rest `[TBD]`. Report the
31
+ path (#6).
32
+
33
+ The "Additional step in a refactored project" in the op applies ONLY when `afm refactor` adopted the
34
+ project (signal: `afm.md` § 3.1 forward-only exists). A greenfield project forbids a retroactive ADR.
35
+
36
+ ## Invariant principles
37
+
38
+ Additional #9 (a retroactive ADR is
39
+ load-bearing-only) applies ONLY in a refactored project.
40
+
41
+ Passive mode (`afm reconcile`) is always on and can propose `afm adr` when it detects a "novel structural
42
+ decision" signal. This skill covers only the active creation.
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: analyze
3
+ description: |
4
+ Cross-checks one feature against the instance. It compares `docs/features/NNN-*/{spec,plan,tasks}.md` with prd, ust, ach, afm § 3 and PRINCIPLES. It reports findings by severity in chat and writes no file.
5
+ Activates: `afm analyze [<feature>]`, "audit feature", "check coverage", "validate consistency before implementation".
6
+ ---
7
+
8
+ # AFM — Analyze
9
+
10
+ ## When NOT to activate
11
+
12
+ Use `afm clarify` to resolve markers interactively. Use `afm deliver` for end-to-end delivery: it runs analyze underneath, in gating mode. Use `afm diagnose` for the health of the whole doc set.
13
+
14
+ ## Pre-check
15
+
16
+ Run `afm preflight` (exit 3: no `docs/.afm-version`, stop and suggest `afm init` or `afm refactor`).
17
+
18
+ ## Procedure
19
+
20
+ Start from the mechanical findings: `afm feature lint <NNN> --json` covers the passes A, C, D, E and the structure of `tasks.md`. Add the judgment on top (constitution violations, duplication, the semantic side of inconsistency and ambiguity), build the coverage table, assign severities by the matrix, and report in chat with metrics. Close with the `remediation` question (`afm ask analyze`); a remediation that adds a task runs `afm task add`, never a hand edit of the `tasks:` list, and a task is closed only with `afm task done`. Gating mode sorts findings into buckets instead of reporting.
21
+
22
+ ## Invariant principles
23
+
24
+ Most relevant here: #2 (detection is an autonomous scan, not a question), #5 (no finding without evidence) and #6 (analyze is read-only: it reports in chat, writes no file, and remediates only on request).
25
+
26
+ ## Continuous doctrine
27
+
28
+ Passive mode (`afm reconcile`) is always on. This skill covers only active auditing.
@@ -0,0 +1,28 @@
1
+ ---
2
+ name: clarify
3
+ description: |
4
+ Scans one feature for ambiguity. It asks the irreducible questions, recommendation first, and writes the answers to `spec.md § 7 Clarifications`.
5
+ Activates: `afm clarify [<feature>]`, "resolve markers", "clear up ambiguity in feature X", "clarify the spec".
6
+ ---
7
+
8
+ # AFM — Clarify
9
+
10
+ ## When NOT to activate
11
+
12
+ Use `afm analyze` for a read-only, multi-artifact validation that does not resolve markers. Use `afm deliver` for end-to-end delivery: it calls clarify underneath when needed.
13
+
14
+ ## Pre-check
15
+
16
+ Run `afm preflight` (exit 3: no `docs/.afm-version`, stop and suggest `afm init` or `afm refactor`). `afm feature status <NNN> --json` lists the open markers of a feature in `blockers`.
17
+
18
+ ## Procedure
19
+
20
+ Judgment only: a 9-category scan of the spec, a prioritized queue (at most 5 questions), auto-resolution from the code and docs before any question, then one recommendation-first question per turn. The questions come from the spec, so they are dynamic; the one fixed decision (`underspecified`) is in `afm ask clarify`. Integrate each answer into `spec.md` at once, remove the marker, and finish with the coverage summary.
21
+
22
+ ## Invariant principles
23
+
24
+ Most relevant here: #2 is discover-first: resolve each question yourself through the scan or the docs, then ask. #4 says `[TBD]` beats invention, and a recommendation is a rejectable hypothesis, not a guess. #6 is autonomy-first: write the integration into spec § 7 and report. #8 is recommendation-first questions.
25
+
26
+ ## Continuous doctrine
27
+
28
+ Passive mode (`afm reconcile`) is always on. This skill covers only the active resolution of ambiguity.
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: deliver
3
+ description: |
4
+ Delivers one feature from discovery to reconciliation. It takes one recorded approval (`afm approve`), writes spec, plan and tasks, then runs each task as RED, GREEN, REFACTOR, COMMIT. It resumes from the correct phase when those files exist. Orchestrator: it composes specify, plan, tasks, clarify, analyze and reconcile. External research is not an AFM op; it routes to nasca.
5
+ Activates: `afm deliver [<feature>]`, "build feature X", "implement X end to end", "the tasks already exist, run them", "continue the delivery of feature N".
6
+ ---
7
+
8
+ # AFM — Deliver (orchestrated autonomous delivery)
9
+
10
+ The **orchestrator** of the delivery loop. One request takes "build feature X" from discovery to a delivered feature. It does not duplicate the sub-steps: it reads and follows `afm specify`, `afm plan`, `afm tasks`, `afm clarify`, `afm analyze` and `afm reconcile` through a suppression contract. External unknowns go through {{host:nasca-research}}, or {{host:nasca-campaign}} for a deep study; ask the operator if nasca is missing.
11
+
12
+ ## When NOT to activate
13
+
14
+ An isolated step ("just open the spec", "just generate the tasks") is the matching atomic skill. A trivial change goes straight to the `afm.md § 2` loop.
15
+
16
+ ## Pre-check
17
+
18
+ Run `afm preflight`. Exit 0 continues. Exit 3 means no `docs/.afm-version`: stop and suggest `afm init` (greenfield) or `afm refactor` (brownfield). Exit 4 or 5: report the line it printed. Do not fall back silently.
19
+
20
+ ## Most relevant here
21
+
22
+ **#2** (discover-first: resolve unknowns by scan and research, ask only the irreducible part, never guess product or criteria) and **#6** (autonomy-first: approval at checkpoint granularity, the consolidated plan IS the proposal).
23
+
24
+ ## Continuous doctrine
25
+
26
+ Passive mode (`afm reconcile`) is always on. It runs in parallel with `afm deliver` and takes the closing turn of Phase 4 (`core/afm.md` § 8.5 plus a passive sweep).