@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,41 @@
1
+ questions:
2
+ - id: harnesses
3
+ prompt: Which harnesses should the instruction files of this project cover?
4
+ header: Harnesses
5
+ multiSelect: true
6
+ recommended: [claude-code]
7
+ options:
8
+ - label: claude-code
9
+ description: Writes a CLAUDE.md stub that imports AGENTS.md.
10
+ - label: opencode
11
+ description: Reads AGENTS.md itself, so no stub is written.
12
+ - label: agy
13
+ description: Writes a GEMINI.md stub that imports AGENTS.md.
14
+ - label: git
15
+ description: Git hooks only; no instruction file is needed.
16
+ - id: app-language
17
+ prompt: In which language does this product show its own users their strings?
18
+ header: App language
19
+ recommended: Decide later
20
+ options:
21
+ - label: English
22
+ description: User-facing strings are in English.
23
+ - label: Portuguese
24
+ description: User-facing strings are in Portuguese.
25
+ - label: Spanish
26
+ description: User-facing strings are in Spanish.
27
+ - label: Decide later
28
+ description: Records [TBD] in the PRD; the language migration stops and asks.
29
+ - id: artifact-language
30
+ prompt: In which language are the artifacts of this project written (docs, code comments, test names)?
31
+ header: Artifacts
32
+ recommended: en
33
+ options:
34
+ - label: en
35
+ description: English, the default. Nothing is recorded.
36
+ - label: pt-BR
37
+ description: Recorded with afm config set language.artifacts pt-BR; the gate skips the English-prose rules.
38
+ - label: es
39
+ description: Recorded with afm config set language.artifacts es; the gate skips the English-prose rules.
40
+ - label: other
41
+ description: Another tag. Init prints the command to run with the tag the owner names.
@@ -0,0 +1,17 @@
1
+ questions:
2
+ - id: existing-root
3
+ prompt: This folder already has an obligations root. What should the mapping do?
4
+ header: Root
5
+ options:
6
+ - label: extend
7
+ description: Keep the existing entries and add or update only what the contract changes.
8
+ - label: stop
9
+ description: Change nothing; the existing root stays as it is.
10
+ - id: install
11
+ prompt: The map passes the lint. Install the git hooks for every repository below this folder now?
12
+ header: Install
13
+ options:
14
+ - label: install-now
15
+ description: Adds one includeIf entry to the global git config; every repository below the folder runs the checks, then its own hooks.
16
+ - label: later
17
+ description: Nothing is enforced until the operator runs afm obligations install.
@@ -0,0 +1,14 @@
1
+ questions:
2
+ - id: open-markers
3
+ prompt: The spec has open NEEDS CLARIFICATION markers. How should the plan proceed?
4
+ header: Markers
5
+ recommended: clarify-first
6
+ options:
7
+ - label: clarify-first
8
+ description: Run the structured clarify scan first. It records dated answers in the spec, then planning resumes.
9
+ - label: resolve-inline
10
+ description: Quick fallback. Answer each marker in free text now; no Clarifications section is written.
11
+ - label: keep-going
12
+ description: Not recommended. The plan inherits the markers and the tasks step refuses to run until they are resolved.
13
+ - label: cancel
14
+ description: Go back to the spec and plan nothing yet.
@@ -0,0 +1,23 @@
1
+ questions:
2
+ - id: adr
3
+ prompt: Which of the inferred decisions still load-bear today and become a retroactive ADR? Would someone need a doc to explain why if it were swapped tomorrow?
4
+ header: ADRs
5
+ recommended: None
6
+ options:
7
+ - label: None
8
+ description: No retroactive ADR; a dead decision never becomes one later.
9
+ - label: Some
10
+ description: The operator names the decisions; each becomes an accepted retroactive ADR.
11
+ - label: All
12
+ description: Every listed candidate becomes an accepted retroactive ADR.
13
+ - id: gotcha-seeds
14
+ prompt: Which gotcha seeds of the detected stacks has the team here already been bitten by? Seeds are candidates, not active entries.
15
+ header: Gotchas
16
+ recommended: None
17
+ options:
18
+ - label: None
19
+ description: No seed is activated.
20
+ - label: Some
21
+ description: The operator names the seeds; each becomes its own gotcha file.
22
+ - label: All
23
+ description: Every seed is confirmed as already lived here and becomes its own gotcha file.
@@ -0,0 +1,13 @@
1
+ # One question per refinement of a doc that guided badly in the session:
2
+ # afm ask reflect --scope <item-slug>
3
+ questions:
4
+ - id: refinement
5
+ prompt: Refine this doc as proposed?
6
+ header: Refinement
7
+ options:
8
+ - label: Apply
9
+ description: Apply the refinement (rewrite, added trigger, or disambiguation) exactly as itemized.
10
+ - label: Report only
11
+ description: Do not edit the doc; keep the finding as a suggestion in the report.
12
+ - label: Skip
13
+ description: Reject it; the report records the rejection so the finding is not proposed again without new evidence.
@@ -0,0 +1,27 @@
1
+ # One pair of questions per recurring failure (the scope is the sig= as a slug):
2
+ # afm ask remediate --scope <sig>
3
+ questions:
4
+ - id: artifact
5
+ prompt: Which durable artifact should this failure become?
6
+ header: Artifact
7
+ options:
8
+ - label: Guardrail
9
+ description: A check a command can run with no judgment; takes precedence over the other two.
10
+ - label: Procedure
11
+ description: A repeatable sequence of steps with a 0/1 gate per step and a start trigger.
12
+ - label: Learning
13
+ description: A conceptual lesson whose value is in its cause.
14
+ - label: Not now
15
+ description: Leave the failure open; it waits for recurrence or for a user correction.
16
+ - id: surface
17
+ prompt: For a guardrail, where is the check installed?
18
+ header: Surface
19
+ options:
20
+ - label: Linter
21
+ description: The linter config the project already runs.
22
+ - label: CI
23
+ description: The CI workflow the project already runs.
24
+ - label: Git hook
25
+ description: A git hook (afm install git runs the gate there).
26
+ - label: Not a guardrail
27
+ description: The artifact is a procedure, a learning or nothing, so no check is installed.
@@ -0,0 +1,15 @@
1
+ # One question per staleness, findability or dead-gotcha finding:
2
+ # afm ask restructure --scope <item-slug>
3
+ questions:
4
+ - id: finding
5
+ prompt: What should be done with this finding?
6
+ header: Finding
7
+ options:
8
+ - label: Update the doc
9
+ description: Read the current code, then update the stale doc (a proposal, never an auto-fix).
10
+ - label: Relocate
11
+ description: Move the information to where it is expected, or add a pointer there; a loading-strategy ADR for a tiering finding.
12
+ - label: Archive
13
+ description: Comment the dead entry out as a tombstone; nothing is deleted.
14
+ - label: Leave as is
15
+ description: The doc is still right; the report records the review.
@@ -0,0 +1,12 @@
1
+ questions:
2
+ - id: rf
3
+ prompt: Which PRD requirement does this user story implement?
4
+ header: RF mapping
5
+ recommended: New RF
6
+ options:
7
+ - label: New RF
8
+ description: Drafts the next RF in the PRD from the story.
9
+ - label: Existing RF
10
+ description: The operator names the number or the title.
11
+ - label: Not yet
12
+ description: Records [TBD]; decided later.
@@ -0,0 +1,12 @@
1
+ questions:
2
+ - id: scope
3
+ prompt: Where does the rule enter?
4
+ header: Rule scope
5
+ recommended: forward-only
6
+ options:
7
+ - label: universal
8
+ description: Section 3, applies to all code including legacy. May produce a large cleanup change.
9
+ - label: forward-only
10
+ description: Section 3.1, new code and files touched from today on. Legacy debt is tracked, not blocking.
11
+ - label: cancel
12
+ description: Nothing is written; the decision needs more thought.
@@ -0,0 +1,12 @@
1
+ questions:
2
+ - id: surface
3
+ prompt: Where does this trigger run?
4
+ header: Surface
5
+ recommended: pre-commit
6
+ options:
7
+ - label: pre-commit
8
+ description: Blocks every commit, including one made outside an agent session. Costs the trigger's runtime on each commit.
9
+ - label: ci
10
+ description: Blocks the merge, not the local commit. Only honest when the project already has CI.
11
+ - label: agent
12
+ description: Stays in the doc and runs by judgment. Honest for a heuristic trigger, not for a precise one nobody automated.
@@ -0,0 +1,23 @@
1
+ questions:
2
+ - id: heuristic
3
+ prompt: The change is borderline for a feature folder. Open one, or go straight to the loop?
4
+ header: Feature?
5
+ recommended: open-feature
6
+ options:
7
+ - label: open-feature
8
+ description: Create docs/features/NNN-slug with a spec, then plan and tasks. Best when the change spans files or has unknowns.
9
+ - label: straight-to-loop
10
+ description: Skip the folder and run the RED, GREEN, REFACTOR, COMMIT loop of core/afm.md section 2 once.
11
+ - id: us-link
12
+ prompt: Which user story does this feature correspond to?
13
+ header: Linked US
14
+ recommended: candidate
15
+ options:
16
+ - label: candidate
17
+ description: The story the scan matched in docs/ust.md. Confirms the link.
18
+ - label: other-existing
19
+ description: A different existing story. The operator gives its number.
20
+ - label: create-first
21
+ description: Write a new story with a Gherkin criterion in docs/ust.md before the spec.
22
+ - label: later
23
+ description: No story yet. The spec records a NEEDS CLARIFICATION marker to link it.
@@ -0,0 +1,10 @@
1
+ questions:
2
+ - id: artifact-language
3
+ prompt: Migrate the artifacts (docs, code comments, test names) to English?
4
+ header: Artifacts
5
+ recommended: Migrate to English
6
+ options:
7
+ - label: Migrate to English
8
+ description: Artifacts move to English and stop paying the token cost of a second language in every context load.
9
+ - label: Keep the current language
10
+ description: Nothing moves. The choice is recorded so the next update does not ask again.
@@ -0,0 +1,14 @@
1
+ questions:
2
+ - id: app-language
3
+ prompt: In which language does this product show its own users their strings? The PRD records none yet.
4
+ header: App language
5
+ recommended: Decide later
6
+ options:
7
+ - label: English
8
+ description: User-facing strings are English; nothing is excluded from the artifact migration.
9
+ - label: Portuguese
10
+ description: User-facing strings are Portuguese and stay out of the migration.
11
+ - label: Spanish
12
+ description: User-facing strings are Spanish and stay out of the migration.
13
+ - label: Decide later
14
+ description: Records [TBD]; the artifact language migration does not run until it is set.
@@ -0,0 +1,10 @@
1
+ questions:
2
+ - id: apply
3
+ prompt: Apply the migrations the dry run listed and move the version pin?
4
+ header: Update
5
+ recommended: Apply
6
+ options:
7
+ - label: Apply
8
+ description: Applies every migration in order, proves each one, then moves the pin. A failed migration keeps the pin where it was.
9
+ - label: Not now
10
+ description: Nothing is applied and the pin stays; the dry run can be repeated later.
@@ -0,0 +1,9 @@
1
+ questions:
2
+ - id: reviewed
3
+ prompt: Did you read this document yourself and stand behind it?
4
+ header: Reviewed
5
+ options:
6
+ - label: Yes, I read it
7
+ description: Stamps the verification under your name.
8
+ - label: No
9
+ description: Nothing is stamped; a stamp asserts that a person read the content.
@@ -0,0 +1,18 @@
1
+ ---
2
+ role: executor
3
+ description: Writer of one bounded change. Makes the edit its brief names, test first, inside the files the brief grants, and reports what changed; dispatched with a brief.
4
+ capabilities: read, search, write, shell
5
+ ---
6
+ You are an executor. The message that dispatched you is your brief: follow it.
7
+
8
+ You make the change the brief names, and only that change.
9
+
10
+ - Touch only the files the brief grants. Another file you need is a question for the caller, not an edit.
11
+ - Test first: a failing test (or a type that does not compile yet), then the smallest change that
12
+ makes it pass, then the refactor. Run the tests and the type check before you report.
13
+ - Reuse what exists before you add a helper. Add no option, hook or abstraction the brief did not ask for.
14
+ - Never print, write or commit a secret.
15
+ - Never push, and never commit unless the brief says to.
16
+
17
+ Reply with the files you changed, the checks you ran with their exact result, and anything you left
18
+ undone or doubt.
@@ -0,0 +1,22 @@
1
+ ---
2
+ role: explorer
3
+ description: Read-only investigator. Answers one question from the code, the docs or the web, cites what it read, and changes nothing; dispatched with a brief.
4
+ steps: 60
5
+ capabilities: read, search, web
6
+ mcpTools: approve, config, detect, doctor, failures_promotable, feature_lint, feature_status, gate, index, lang, next_id, path, policy, preflight, read, sessions, sessions_signals, version
7
+ cliDoor: false
8
+ ---
9
+ You are an explorer. The message that dispatched you is your brief: follow it.
10
+
11
+ You only read. You never edit a file, run a command that changes state, or commit.
12
+
13
+ - Read only what the question needs: the sections you are about to use, not whole trees.
14
+ - Cite every claim: a path with the line, or a source URL with the literal quote. A claim with no
15
+ citation is a guess, and you label it a guess.
16
+ - Never invent a path, a line number, a URL or a quote. If you did not read it, you do not cite it.
17
+ - Say what you could not find. Absence is a result.
18
+
19
+ You have at most 60 steps. Write the answer whole, not a step at a time. If you run out, reply with
20
+ what you have and what is still missing.
21
+
22
+ Reply with the answer first, then the evidence, then the gaps.
@@ -0,0 +1,23 @@
1
+ ---
2
+ role: reviewer
3
+ description: Blind auditor. Checks one piece of work it did not write against its sources and rules, and returns a verdict with evidence; dispatched with a brief.
4
+ capabilities: read, search, web
5
+ mcpTools: approve, config, detect, doctor, failures_promotable, feature_lint, feature_status, gate, index, lang, next_id, path, policy, preflight, read, sessions, sessions_signals, version
6
+ cliDoor: false
7
+ ---
8
+ You are a reviewer. The message that dispatched you is your brief: follow it.
9
+
10
+ You audit work you did not write. You read it and the sources or rules it answers to. You never
11
+ write a fix.
12
+
13
+ - Judge against the rules and sources the brief names, not against taste.
14
+ - Verify, do not trust: open each cited path, line or quote and confirm it says what the work claims.
15
+ - Run the checks the brief lists that the `afm` tools offer (the gate, the doctor, the index), alone and one
16
+ at a time, and report their exact output. You have no shell: a check that needs one is a check you did
17
+ not run, and you say so.
18
+ - Report a finding only with its evidence: the path and line, the rule it breaks, and the concrete
19
+ input or state that fails. A suspicion with no evidence is not a finding.
20
+ - Say what you did not check.
21
+
22
+ End with one verdict line: PASS when no finding stands, FAIL otherwise, followed by the findings
23
+ most severe first.
@@ -0,0 +1,40 @@
1
+ ---
2
+ type: rubric
3
+ description: Chooses between an ORM enum, a literal union, a branded type and a parser schema.
4
+ load: warm
5
+ fires_on: file-shape
6
+ trigger_ext: '.ts .tsx'
7
+ trigger_grep: '(^[[:space:]]*(export[[:space:]]+)?(const[[:space:]]+)?enum[[:space:]]+[A-Za-z_]|\([[:space:]]*[a-zA-Z_][A-Za-z0-9_]*:[[:space:]]*string[[:space:]]*,[[:space:]]*[a-zA-Z_][A-Za-z0-9_]*:[[:space:]]*string[[:space:]]*[,)])'
8
+ fires_when: 'a TS `enum` is declared, or a signature takes two adjacent `string` parameters'
9
+ ---
10
+
11
+ # Rubric — enum vs literal union vs branded type vs Zod schema
12
+
13
+ ## Decision table
14
+
15
+ | Case | Choice | Anti-pattern |
16
+ | --- | --- | --- |
17
+ | Value exists in the DB (status, role, plan) | **ORM enum** (Prisma enum, etc) — the only path that survives `generate` | Pure TS enum that mirrors the ORM enum — duplication |
18
+ | ≤ 5 closed values, used only in code | **Literal union** (`"latest" \| "next" \| "beta"`) | Pure TS enum — produces transpiled waste, not tree-shakeable |
19
+ | Open string with a rule (user input, free dist-tag) | **Parser schema** (Zod) + parse at the boundary | Validation inside the domain (violates hard rule 16) |
20
+ | Primitive with a semantic invariant (sha256, userId ≠ sessionId, currency cents) | **Branded type** (`type Hash = string & { __brand: "Hash" }`) | Raw `string` — loses the check at the call site |
21
+ | Opaque value from an external SDK (Stripe price id) | SDK type + Zod at the boundary | Re-type as branded — duplicates the SDK |
22
+
23
+ ## When a branded type wins
24
+
25
+ - A function takes two strings with different meanings (`copy(from: string, to: string)`). A branded type stops you from swapping the order.
26
+ - Hash, ID, currency in cents, timestamp in ms vs s. A branded type makes the conversion explicit.
27
+ - Different domain IDs (UserId vs SessionId vs OrgId). A branded type stops you from passing a UserId where the code asked for an OrgId.
28
+
29
+ ## When a branded type does not pay off
30
+
31
+ - A string that goes to a log, a UI, or the network. The reader gains nothing.
32
+ - The type already comes from the SDK as an opaque string. Re-typing it just duplicates the SDK.
33
+ - The function has one parameter. There is no ambiguity to resolve.
34
+
35
+ ## Anti-examples
36
+
37
+ - ❌ `enum Plan { FREE = "FREE", PRO = "PRO" }` in TS when Prisma already has `enum Plan { FREE, PRO }`. Use the Prisma one directly.
38
+ - ❌ `type DistTag = string` that accepts anything. Use a literal union if the set is closed, or Zod if it is open with a rule.
39
+ - ❌ `copy(src: string, dst: string)` called by mistake as `copy(dst, src)`. Branded `SrcPath` and `DstPath` types fix this.
40
+ - ❌ Branding every `string` "for consistency". This adds overhead with no check gained.
@@ -0,0 +1,37 @@
1
+ ---
2
+ type: rubric
3
+ description: Separates what decays from what is permanent, and says where each one lives.
4
+ load: warm
5
+ fires_on: op-call
6
+ called_by: ["reconcile", "reflect"]
7
+ fires_when: 'an artifact needs a tier: does it decay or is it permanent'
8
+ ---
9
+
10
+ # Rubric — episodic vs semantic boundary (what decays vs what is permanent)
11
+
12
+ > This rubric applies invariant principle #1 ("if another agent without my memory needs to know it, it is doc") on the **time** dimension. Not every artifact in `/docs/` is permanent knowledge. v3.1.0+ (Phase 3 of the v3.2 initiative). Ancestor: CoALA (arXiv 2309.02427) — **episodic** memory (what happened) differs from **semantic** memory (what is known) and from **procedural** memory (how to do it).
13
+
14
+ ## The tiers in AFM
15
+
16
+ | Tier | What it is | Where it lives | Does it decay? | Enters diagnose axes A1-A7? |
17
+ |---|---|---|---|---|
18
+ | **Semantic** | durable knowledge: rules, architecture, decisions, surprises | `afm.md`, `ach.md`, `prd.md`, `ust.md`, `gotchas.md`, `adr/`, `learnings/`, `rubrics/` | **No** — superseded (ADR Superseded, tombstone), never deleted | **Yes** |
19
+ | **Procedural** | repeatable sequences | `procedures/` | frequency/staleness (`restructure`) | Yes (inherited coverage) |
20
+ | **Episodic** | what happened in one session: work state, handoff | handoff block in `sessions/`, `_focus.md` (current focus) | **Yes** — an aged `open` handoff decays (A2). `_focus` is OVERWRITE | **NO** (it is state, not knowledge) |
21
+ | **Telemetry** | append-only log of events/failures. **real use of the methodology** | `.afm-log/`, `.afm-log-failures/`. **timeline and `afm_findings` in `sessions/`** | only by rotation/retention. audit trail = git | **NO** (append-only) |
22
+
23
+ > **`sessions/` is dual-tier** (v4/F9). One file carries both parts. The **handoff block** decays: `state: open|consumed` governs **only that block**. `consumed` means "already read", never "file is dead". The **telemetry** part does not decay: what was asked, how AFM was used, `afm_findings`. This part is versioned and travels with the repo. It is what an agent in the plugin repo reads to improve AFM from real use. Rule 17's exclusion still applies by closed path — the file is append-per-session, never rewritten.
24
+
25
+ ## Decision criteria
26
+
27
+ - **Does another agent without my memory need this to avoid breaking something?** Then it is **semantic**: permanent, enters diagnose, never decays on its own. This is #1.
28
+ - **Is it "where I was" or "what happened in this session"?** Then it is **episodic**: it decays and stays out of diagnose. Giving this permanence fills diagnose with noise.
29
+ - **Promotion from episodic to semantic is the point of `reconcile`.** An episode can reveal a load-bearing decision, rule, or gotcha. When it does, `reconcile` proposes materializing it in the semantic tier. This proposal needs a human gate (#6). The episode is the **buffer** where evolution finds candidates, not the evolution itself.
30
+
31
+ ## Anti-patterns
32
+
33
+ - ❌ **Treating handoff or `_focus` as a normative doc.** This fills diagnose (A1-A7) with volatile state. These artifacts are episodic.
34
+ - ❌ **Reading `state: consumed` as "the file can disappear".** `state` governs only the handoff block. The telemetry from the same session stays alive and versioned.
35
+ - ❌ **Letting semantic knowledge decay.** A rule, decision, or gotcha does not decay with age. It is superseded (ADR) or consolidated (`generalize`). It is never deleted for age (#5: institutional memory).
36
+ - ❌ **Letting `_focus.md` grow.** It must stay small state that gets overwritten (rule 20), not a log.
37
+ - ❌ **Promoting an episode to semantic without checking against #1.** Not everything that "happened" is something another agent needs to know.
@@ -0,0 +1,98 @@
1
+ ---
2
+ type: rubric
3
+ description: Separates a domain error from a procedure error and from an infrastructure error.
4
+ load: warm
5
+ fires_on: file-shape
6
+ trigger_path: '*/domain/*'
7
+ trigger_grep: '(\b(TRPCError|HttpException|HTTPException|ApiError|ResponseError)\b|throw[[:space:]]+new[[:space:]]+Error\()'
8
+ fires_when: 'a transport error type or a bare `Error` is raised inside a `domain/` path'
9
+ ---
10
+
11
+ # Rubric — error classification (Domain vs. Procedure vs. Infra)
12
+
13
+ ## The 3 levels
14
+
15
+ ### Domain error — a business rule is violated
16
+
17
+ **Who throws it:** `domain_*` functions (pure business rules).
18
+
19
+ **How to represent it:**
20
+
21
+ ```ts
22
+ // Option A: Result<T, E> (preferred for clean flow control)
23
+ type Result<T, E> =
24
+ | { ok: true; value: T }
25
+ | { ok: false; code: E };
26
+
27
+ const result = await domain_createUserAuth({ ctx, input });
28
+ if (!result.ok) {
29
+ switch (result.code) {
30
+ case "EMAIL_TAKEN": ...
31
+ case "WEAK_PASSWORD": ...
32
+ default: {
33
+ const _exhaustive: never = result.code;
34
+ throw new Error(`unhandled domain code: ${_exhaustive}`);
35
+ }
36
+ }
37
+ }
38
+
39
+ // Option B: throw DomainError when the caller rarely handles each case
40
+ class DomainError<C extends string> extends Error {
41
+ constructor(public readonly code: C, message?: string) { super(message); }
42
+ }
43
+ throw new DomainError("MAGIC_LINK_INVALID");
44
+ ```
45
+
46
+ **The code must be a literal `as const`.** The switch then guarantees coverage in the caller, as long as `default` assigns the rest to `never` (see example). Without a literal code, a refactor breaks silently.
47
+
48
+ ### Procedure error — transport boundary
49
+
50
+ **Who throws it:** procedures (tRPC handlers, route handlers, controllers).
51
+
52
+ **How to represent it:** `TRPCError` (or the framework equivalent — `HTTPException` in FastAPI, `BadRequestException` in Nest).
53
+
54
+ **The boundary is one-way.** The procedure knows Domain and maps code to HTTP status. Domain never imports `TRPCError` (hard rule 15).
55
+
56
+ ```ts
57
+ // the procedure does the translation
58
+ const result = await domain_createUserAuth({ ctx, input });
59
+ if (!result.ok) {
60
+ switch (result.code) {
61
+ case "EMAIL_TAKEN":
62
+ throw new TRPCError({ code: "CONFLICT", message: "Email já cadastrado" });
63
+ case "WEAK_PASSWORD":
64
+ throw new TRPCError({ code: "BAD_REQUEST", message: "Senha fraca" });
65
+ default: {
66
+ const _exhaustive: never = result.code;
67
+ throw new Error(`unhandled domain code: ${_exhaustive}`);
68
+ }
69
+ }
70
+ }
71
+ ```
72
+
73
+ ### Infra error — external resource failure
74
+
75
+ **Who throws it:** no one on purpose. It rises from the HTTP client, the ORM, or the queue.
76
+
77
+ **How it propagates:**
78
+ - In a **Task-like** context (Trigger.dev, BullMQ): let it rise. The orchestrator's retry policy handles it.
79
+ - In a **Procedure-like** context: catch at the final boundary, log it, and map it to `INTERNAL_SERVER_ERROR`. Never leak the stack trace to the client.
80
+
81
+ ## Anti-patterns
82
+
83
+ - ❌ **Domain imports `TRPCError`.** This couples Domain to the transport layer. Hard rule 15 checks it: `grep -rn "TRPCError" {{src-path}}/server/modules/**/domain/` must return 0.
84
+ - ❌ **`throw new Error("generic string")` in domain code.** Without a literal code, the caller cannot handle the error specifically. Use `DomainError({ code: "..." as const })` instead.
85
+ - ❌ **A generic try/catch around every `await`.** Typed errors beat a generic catch. Catch only when you will act on the error — map it, log it specifically, or apply a deliberate fallback. Otherwise let it rise.
86
+ - ❌ **A procedure that returns `{ error: "..." }` instead of throwing.** This breaks the framework contract and forces the client to check `data.error` instead of using the standard mechanism.
87
+ - ❌ **Mixing Domain error and Infra error in the same switch.** Domain code is closed — you know every case. Infra is open — the network can fail in N ways. Handle them separately.
88
+ - ❌ **An "exhaustive" switch with no `never` branch.** When a new code is added to a Domain error, existing callers still compile. They silently ignore the new case. Hard rule 4 catches this only when `default` assigns the rest to `never`.
89
+
90
+ ## Decision flow
91
+
92
+ ```
93
+ Where am I?
94
+ ├── domain function → Result<T, E> with a literal `as const` code
95
+ ├── procedure → maps Domain code to TRPCError; lets Infra rise
96
+ ├── task → carries idempotency; lets Infra rise (retry handles it)
97
+ └── pure library → Result<T, E> or DomainError with a discriminant code
98
+ ```
@@ -0,0 +1,111 @@
1
+ ---
2
+ type: rubric
3
+ description: Routes a recognized failure to a guardrail, a procedure, a learning or to nothing.
4
+ load: warm
5
+ fires_on: op-call
6
+ called_by: ["remediate", "reflect"]
7
+ fires_when: 'a failure was recognized by an external signal and needs a destination'
8
+ ---
9
+
10
+ # Rubric — failure classification (mechanizable → guardrail | mechanical → procedure | conceptual → learning | transient → nothing)
11
+
12
+ > The CRITIC loop (`ops/remediate.md`) uses this rubric to remediate a failure recognized and recorded in the state store (`afm failures record`). The discriminator is **executable**. It is not a "feeling". Ancestor: CRITIC (arXiv 2305.11738) — recognize a failure only by external signal. Self-criticism without a tool degrades (PRINCIPLES #3).
13
+
14
+ ## Entry gate (common to all three)
15
+
16
+ A failure **exists only** if an **external signal** recognized it.
17
+
18
+ Signals: a test stays red (cap of §5.1 used up), or `tsc`/type-check returns non-zero.
19
+
20
+ Other signals: a step command returns non-zero, or a hard rule breaks after the fact (trigger fired on the wrong side).
21
+
22
+ A user's explicit correction is also a valid signal. "I think I made a mistake" is **not** a failure (CRITIC).
23
+
24
+ Every failure becomes **one record** in the state store, written by `afm failures record --sig <signature>` (the recurrence key).
25
+
26
+ ## The four destinations
27
+
28
+ ### Mechanizable → `docs/guardrails/<slug>.md` (**takes precedence**)
29
+
30
+ **Both conditions apply:** (1) a **0/1 check can detect the failure without judgment** — a lint rule, type-check, `grep`, test, or verification script. (2) It recurred (same promotion gate as the other destinations: `sig=` appears ≥2 times **OR** the user gave 1 explicit correction).
31
+
32
+ **Why this destination takes precedence over procedure and learning.** The two destinations below produce **documents that inform a reader**. They depend on someone remembering to open the runbook or having read the lesson. A guardrail **does not depend on memory**. The gate fires on its own, in the development environment, before the error reaches review. When a failure fits both categories, choose guardrail. A repeated error fixed by non-mechanical analysis fits exactly this case: the analysis costs context every time, but the check costs effort only once.
33
+
34
+ *Examples:* a broken boundary between modules (an import crossing a layer). A union of literals that does not break code that skips the new case. A required order in an internal DSL. An identifier outside the language required by rule 21.
35
+
36
+ **Where the check lands — discovery is mandatory before any proposal.** Before you propose an installation, **read the verification surfaces the project already has**.
37
+
38
+ Examples: linter config, `tsconfig`/type-check, CI steps, git hooks, test scripts.
39
+
40
+ The proposal **extends an existing surface** — a new rule in the linter that already runs, a step in the workflow that already exists. **Introducing a new tool is a last resort.** State that choice explicitly in the proposal, with its cost. A guardrail that forces the operator to adopt an extra tool to catch one error is often more expensive than the error.
41
+
42
+ **Installing writes outside `docs/`.** So it is a **proposal to the operator**, with surface options (linter · CI · git hook · free text).
43
+
44
+ AFM materializes only the record at `docs/guardrails/<slug>.md`, from [`../templates/guardrail.template.md`](../templates/guardrail.template.md). The record holds `signal:`, `trigger:` once installed, and the chosen `surface:` — the same frontmatter keys the catalog uses.
45
+
46
+ It also holds `origin: recurring-failure`, `Origin: sig=`, and the required **`## What would refute this`** (What would refute this) section.
47
+
48
+ > **There is one procedure for installation**, in [`../../ops/rule.md` § Install the gate](../ops/rule.md) — it covers finding the existing surface, building the runner from the template, measuring HEAD before you turn it on, cost, doc-to-runner sync, and the record. This destination **composes** that procedure. It does not repeat it (rule 34).
49
+ >
50
+ > **`docs/guardrails/` has two origins, and this rubric produces one of them.** `origin: recurring-failure` starts here, from a recurring `sig=`. The other, `origin: hard-rule`, starts from a hard rule already written in `afm.md § 3` whose 0/1 trigger nobody ran. Same artifact, same burden of refutation, different entry point. These are not two families. Describing the same object in two vocabularies is the drift that rule 34 exists to prevent.
51
+
52
+ > **Why the rationale is mandatory.** A future agent who finds the check inconvenient will want to loosen it. The `## What would refute this` section reverses that burden. Changing the guardrail requires **refuting the recorded reason**, not just claiming friction. This is the same discipline as "a broken rule is not a wrong rule" (`ops/reflect.md § 2`), applied to the gate instead of the text.
53
+
54
+ ### Mechanical → `docs/procedures/<slug>.md`
55
+
56
+ **All three conditions apply:** (1) it is a **repeatable sequence of steps** with a 0/1 gate per step. (2) It recurred: `afm failures promotable` lists `sig=<hash>` with a count ≥2.
57
+
58
+ A user correction also counts as recurrence, because the user is the oracle. (3) It has a **mechanical start trigger** ("when X, run this runbook").
59
+
60
+ *Example:* the build breaks with `type:module` in tsdown, and this recurred. It became a runbook: "when you edit the emit step, do A, then B, then C, and check 0/1".
61
+
62
+ ### Conceptual → `docs/learnings/<slug>.md`
63
+
64
+ **Condition:** the value is in the **cause** (a counterintuitive lesson), not in a mechanical sequence of steps. Same promotion gate (1 user correction OR ≥2 mechanical recurrences). It carries a `**Trigger:**` (trigger) by path, and `afm-pre-edit.sh` injects it for anyone who edits that area.
65
+ *Example:* "I assumed the webhook arrives once. It arrived twice. Always handle it as idempotent." This became a learning with trigger `webhook`.
66
+
67
+ ### Transient → nothing (only evidence stays in the log)
68
+
69
+ **Condition:** the retry in §5.1 resolved it (it never reached the terminal). Or no durable fix exists. Or the claim **does not survive a fix to its cause**.
70
+
71
+ Example of the last case: "tool X is broken" hardens into a future refusal even after the tool is fixed — a negative filter.
72
+
73
+ It stays as a line in `.afm-log-failures/`. It does **not** become an artifact. This is principle #5 (do not invent a constraint without a durable case) and the negative filter from Phase 4.
74
+
75
+ ## Decision flow
76
+
77
+ ```
78
+ Failure recognized by an external signal? ── no → NOT a failure (CRITIC). Stop.
79
+ │ yes
80
+ ▼
81
+ Record it in the state store (afm failures record, sig=).
82
+ │
83
+ Resolved by the §5.1 retry / no durable antidote / claim dies when the cause is fixed?
84
+ ├── yes → TRANSIENT: stays as evidence, is not promoted.
85
+ └── no
86
+ │
87
+ 1 user correction OR sig= recurred ≥2×?
88
+ ├── no → still only evidence (waits for recurrence).
89
+ └── yes
90
+ │
91
+ Detectable by a 0/1 check without judgment (lint/type/grep/test)?
92
+ ├── yes → GUARDRAIL (docs/guardrails/ + installation proposal)
93
+ └── no
94
+ │
95
+ Repeatable step sequence with 0/1 gates + a start trigger?
96
+ ├── yes → PROCEDURE (docs/procedures/)
97
+ └── no → LEARNING (docs/learnings/)
98
+ ```
99
+
100
+ ## Anti-patterns
101
+
102
+ - ❌ **Recognizing a failure by self-judgment** (with no external signal). CRITIC: this degrades results.
103
+ - ❌ **Promoting one mechanical failure** to an artifact (creates noise, a dead constraint). Wait for ≥2 recurrences, except a user correction, which counts as 1.
104
+ - ❌ **Promoting a transient failure** resolved in §5.1. It never reaches the terminal, so it is not logged as a failure.
105
+ - ❌ **Sending everything to `procedures/`**. A procedure is a *mechanical sequence*. A conceptual lesson is a `learning`.
106
+ - ❌ **Sending everything to `learnings/`**. A repeatable runbook is a `procedure`.
107
+ - ❌ **Writing a procedure or learning for what a check can catch** — this is the central anti-pattern of this rubric. A document that depends on memory loses to a gate that fires on its own. If the check exists, the destination is guardrail.
108
+ - ❌ **Proposing a new tool without reading what the project already runs** — the existing surface comes first. A new tool is a last resort, and you must state its cost.
109
+ - ❌ **A guardrail with no `## What would refute this`** — without the recorded burden of refutation, the next agent loosens the gate by claiming friction.
110
+ - ❌ **Installing the guardrail alone** — installing writes outside `docs/`, so it is a proposal to the operator (#6).
111
+ - ❌ **A procedure, learning, or guardrail with no source `sig=` cited** (traceability — hard rule 19 / R3).