@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.
- package/bin/afm +4 -0
- package/content/.coupling-baseline.tsv +1 -0
- package/content/.pending-commands.txt +2 -0
- package/content/CHANGELOG-archive.md +806 -0
- package/content/CHANGELOG.md +4330 -0
- package/content/PRINCIPLES.md +119 -0
- package/content/README-light.md +158 -0
- package/content/README.md +150 -0
- package/content/code-style/_any/file-size.md +62 -0
- package/content/code-style/_any/imports.md +68 -0
- package/content/code-style/_any/naming.md +72 -0
- package/content/code-style/_any/test-placement.md +57 -0
- package/content/code-style/nextjs-app-router/imports.md +50 -0
- package/content/code-style/nextjs-app-router/naming.md +50 -0
- package/content/code-style/prisma-postgres/error-boundary.md +55 -0
- package/content/code-style/prisma-postgres/imports.md +61 -0
- package/content/code-style/shadcn-ui/naming.md +48 -0
- package/content/code-style/stripe-billing/naming.md +76 -0
- package/content/code-style/trigger-dev-v4/imports.md +58 -0
- package/content/code-style/trigger-dev-v4/naming.md +49 -0
- package/content/code-style/trigger-dev-v4/test-placement.md +61 -0
- package/content/code-style/trpc-v11/error-boundary.md +51 -0
- package/content/code-style/trpc-v11/file-size.md +44 -0
- package/content/code-style/trpc-v11/naming.md +60 -0
- package/content/code-style/trpc-v11/test-placement.md +52 -0
- package/content/core/ach.md +260 -0
- package/content/core/afm.md +514 -0
- package/content/core/gotchas.md +18 -0
- package/content/core/prd.md +141 -0
- package/content/core/protocol.md +158 -0
- package/content/core/ust.md +65 -0
- package/content/guardrails/README.md +55 -0
- package/content/guardrails/dsl-com-ordem-obrigatoria.md +47 -0
- package/content/guardrails/exaustividade-de-union.md +48 -0
- package/content/guardrails/fronteira-de-import.md +57 -0
- package/content/hooks/README.md +70 -0
- package/content/interview/bootstrap.md +417 -0
- package/content/interview/promotion.md +115 -0
- package/content/interview/refactor.md +379 -0
- package/content/interview/triggers.md +107 -0
- package/content/modules/nextjs-app-router/ach.patch.md +44 -0
- package/content/modules/nextjs-app-router/gotchas.seed.md +78 -0
- package/content/modules/nextjs-app-router/rules.patch.md +35 -0
- package/content/modules/prisma-postgres/ach.patch.md +65 -0
- package/content/modules/prisma-postgres/rules.patch.md +28 -0
- package/content/modules/shadcn-ui/ach.patch.md +42 -0
- package/content/modules/stripe-billing/ach.patch.md +46 -0
- package/content/modules/stripe-billing/gotchas.seed.md +73 -0
- package/content/modules/stripe-billing/rules.patch.md +30 -0
- package/content/modules/trigger-dev-v4/ach.patch.md +64 -0
- package/content/modules/trigger-dev-v4/gotchas.seed.md +53 -0
- package/content/modules/trigger-dev-v4/rules.patch.md +35 -0
- package/content/modules/trpc-v11/ach.patch.md +56 -0
- package/content/modules/trpc-v11/rules.patch.md +34 -0
- package/content/modules/vireya-ui/ach.patch.md +85 -0
- package/content/modules/vireya-ui/gotchas.seed.md +98 -0
- package/content/modules/vireya-ui/rules.patch.md +36 -0
- package/content/ops/adr.md +54 -0
- package/content/ops/analyze.md +130 -0
- package/content/ops/clarify.md +86 -0
- package/content/ops/deliver.md +209 -0
- package/content/ops/diagnose.md +143 -0
- package/content/ops/evolve.md +366 -0
- package/content/ops/export-template.md +97 -0
- package/content/ops/generalize.md +117 -0
- package/content/ops/gotcha.md +46 -0
- package/content/ops/obligations.md +145 -0
- package/content/ops/plan.md +61 -0
- package/content/ops/policy.md +61 -0
- package/content/ops/promote.md +72 -0
- package/content/ops/protocol.md +51 -0
- package/content/ops/reconcile.md +44 -0
- package/content/ops/reflect.md +182 -0
- package/content/ops/remediate.md +143 -0
- package/content/ops/restructure.md +142 -0
- package/content/ops/rule.md +170 -0
- package/content/ops/specify.md +62 -0
- package/content/ops/tasks.md +67 -0
- package/content/ops/update.md +252 -0
- package/content/ops/verify.md +67 -0
- package/content/patterns/adapter.md +46 -0
- package/content/patterns/facade.md +47 -0
- package/content/patterns/factory.md +46 -0
- package/content/patterns/null-object.md +55 -0
- package/content/patterns/result-vs-exception.md +52 -0
- package/content/patterns/strategy.md +45 -0
- package/content/patterns/template-method-vs-composition.md +50 -0
- package/content/questions/adr.questions.yaml +14 -0
- package/content/questions/analyze.questions.yaml +12 -0
- package/content/questions/bootstrap-mapping.questions.yaml +14 -0
- package/content/questions/bootstrap-rules.questions.yaml +10 -0
- package/content/questions/bootstrap-stack.questions.yaml +23 -0
- package/content/questions/clarify.questions.yaml +10 -0
- package/content/questions/code-style.questions.yaml +12 -0
- package/content/questions/confirm.questions.yaml +12 -0
- package/content/questions/deliver.questions.yaml +23 -0
- package/content/questions/evolve.questions.yaml +15 -0
- package/content/questions/export-template-apply.questions.yaml +11 -0
- package/content/questions/export-template.questions.yaml +23 -0
- package/content/questions/gates.questions.yaml +27 -0
- package/content/questions/generalize.questions.yaml +13 -0
- package/content/questions/gotcha.questions.yaml +11 -0
- package/content/questions/init-template.questions.yaml +10 -0
- package/content/questions/init.questions.yaml +41 -0
- package/content/questions/obligations.questions.yaml +17 -0
- package/content/questions/plan.questions.yaml +14 -0
- package/content/questions/refactor.questions.yaml +23 -0
- package/content/questions/reflect.questions.yaml +13 -0
- package/content/questions/remediate.questions.yaml +27 -0
- package/content/questions/restructure.questions.yaml +15 -0
- package/content/questions/rf-mapping.questions.yaml +12 -0
- package/content/questions/rule-scope.questions.yaml +12 -0
- package/content/questions/rule.questions.yaml +12 -0
- package/content/questions/specify.questions.yaml +23 -0
- package/content/questions/update-artifacts.questions.yaml +10 -0
- package/content/questions/update-strings.questions.yaml +14 -0
- package/content/questions/update.questions.yaml +10 -0
- package/content/questions/verify.questions.yaml +9 -0
- package/content/roles/executor.md +18 -0
- package/content/roles/explorer.md +22 -0
- package/content/roles/reviewer.md +23 -0
- package/content/rubrics/enum-vs-union-vs-branded.md +40 -0
- package/content/rubrics/episodic-vs-semantic-boundary.md +37 -0
- package/content/rubrics/error-classification.md +98 -0
- package/content/rubrics/failure-classification.md +111 -0
- package/content/rubrics/negative-filters.md +38 -0
- package/content/rubrics/solid-triggers.md +119 -0
- package/content/rubrics/template-vs-streaming-precedence.md +34 -0
- package/content/rubrics/validation-boundary.md +94 -0
- package/content/rubrics/when-to-create-dsl.md +65 -0
- package/content/rubrics/when-to-create-lib.md +49 -0
- package/content/rubrics/when-to-create-module.md +39 -0
- package/content/rubrics/when-to-evolve-methodology.md +62 -0
- package/content/skills/adr.md +42 -0
- package/content/skills/analyze.md +28 -0
- package/content/skills/clarify.md +28 -0
- package/content/skills/deliver.md +26 -0
- package/content/skills/diagnose.md +42 -0
- package/content/skills/evolve.md +43 -0
- package/content/skills/export-template.md +37 -0
- package/content/skills/generalize.md +31 -0
- package/content/skills/gotcha.md +40 -0
- package/content/skills/init.md +77 -0
- package/content/skills/obligations.md +27 -0
- package/content/skills/plan.md +28 -0
- package/content/skills/policy.md +25 -0
- package/content/skills/promote.md +39 -0
- package/content/skills/protocol.md +41 -0
- package/content/skills/reconcile.md +45 -0
- package/content/skills/refactor.md +79 -0
- package/content/skills/reflect.md +43 -0
- package/content/skills/remediate.md +33 -0
- package/content/skills/restructure.md +46 -0
- package/content/skills/rule.md +43 -0
- package/content/skills/specify.md +28 -0
- package/content/skills/tasks.md +24 -0
- package/content/skills/update.md +58 -0
- package/content/skills/verify.md +29 -0
- package/content/templates/adr.template.md +51 -0
- package/content/templates/evolution-report.template.md +132 -0
- package/content/templates/feature-plan.template.md +84 -0
- package/content/templates/feature-research.template.md +56 -0
- package/content/templates/feature-spec.template.md +86 -0
- package/content/templates/feature-tasks.induced.template.md +91 -0
- package/content/templates/feature-tasks.template.md +82 -0
- package/content/templates/focus.template.md +30 -0
- package/content/templates/gotcha.template.md +31 -0
- package/content/templates/guardrail-runner.template.md +97 -0
- package/content/templates/guardrail.template.md +63 -0
- package/content/templates/learning.template.md +40 -0
- package/content/templates/procedure.template.md +47 -0
- package/content/templates/protocols/p1.md +29 -0
- package/content/templates/protocols/p2.md +28 -0
- package/content/templates/protocols/p3.md +47 -0
- package/content/templates/research.template.md +50 -0
- package/content/templates/session-handoff.template.md +58 -0
- package/content/templates/us.template.md +39 -0
- package/content/tools/gate/core-rules/PLUGIN-13-secrets.sh +36 -0
- package/content/tools/gate/core-rules/PLUGIN-21-code-language.sh +27 -0
- package/content/tools/gate/core-rules/PLUGIN-35-gate-complete.sh +19 -0
- package/content/tools/gate/core-rules/PLUGIN-36-absolute-path.sh +38 -0
- package/content/tools/gate/core-rules/PLUGIN-37-prose-language.sh +56 -0
- package/content/tools/gate/core-rules/PLUGIN-38-parser-marker.sh +82 -0
- package/content/tools/gate/core-rules/PLUGIN-39-frontmatter-ops.sh +325 -0
- package/content/tools/gate/core-rules/PLUGIN-40-dead-reference.sh +74 -0
- package/content/tools/gate/core-rules/README.md +55 -0
- package/content/tools/gate/guardrails.sh +740 -0
- package/content/tools/gate/lib/ratchet.sh +119 -0
- package/content/tools/gate/lib/scope.sh +85 -0
- package/content/tools/gate/ratchet.seed.tsv +1 -0
- package/content/tools/gate/rules/README.md +50 -0
- package/package.json +19 -5
- package/plugin/agy/hooks.json +29 -0
- package/plugin/agy/mcp_config.json +7 -0
- package/plugin/agy/plugin.json +6 -0
- package/plugin/agy/skills/afm-adr/SKILL.md +48 -0
- package/plugin/agy/skills/afm-analyze/SKILL.md +34 -0
- package/plugin/agy/skills/afm-clarify/SKILL.md +34 -0
- package/plugin/agy/skills/afm-deliver/SKILL.md +30 -0
- package/plugin/agy/skills/afm-diagnose/SKILL.md +46 -0
- package/plugin/agy/skills/afm-evolve/SKILL.md +49 -0
- package/plugin/agy/skills/afm-export-template/SKILL.md +43 -0
- package/plugin/agy/skills/afm-generalize/SKILL.md +37 -0
- package/plugin/agy/skills/afm-gotcha/SKILL.md +46 -0
- package/plugin/agy/skills/afm-init/SKILL.md +81 -0
- package/plugin/agy/skills/afm-obligations/SKILL.md +31 -0
- package/plugin/agy/skills/afm-plan/SKILL.md +34 -0
- package/plugin/agy/skills/afm-policy/SKILL.md +29 -0
- package/plugin/agy/skills/afm-promote/SKILL.md +43 -0
- package/plugin/agy/skills/afm-protocol/SKILL.md +45 -0
- package/plugin/agy/skills/afm-reconcile/SKILL.md +49 -0
- package/plugin/agy/skills/afm-refactor/SKILL.md +83 -0
- package/plugin/agy/skills/afm-reflect/SKILL.md +49 -0
- package/plugin/agy/skills/afm-remediate/SKILL.md +39 -0
- package/plugin/agy/skills/afm-restructure/SKILL.md +52 -0
- package/plugin/agy/skills/afm-rule/SKILL.md +49 -0
- package/plugin/agy/skills/afm-specify/SKILL.md +34 -0
- package/plugin/agy/skills/afm-tasks/SKILL.md +28 -0
- package/plugin/agy/skills/afm-update/SKILL.md +64 -0
- package/plugin/agy/skills/afm-verify/SKILL.md +35 -0
- package/plugin/claude-code/.claude-plugin/marketplace.json +15 -0
- package/plugin/claude-code/.claude-plugin/plugin.json +9 -0
- package/plugin/claude-code/.mcp.json +7 -0
- package/plugin/claude-code/agents/afm-executor.md +18 -0
- package/plugin/claude-code/agents/afm-explorer.md +20 -0
- package/plugin/claude-code/agents/afm-reviewer.md +21 -0
- package/plugin/claude-code/hooks/hooks.json +85 -0
- package/plugin/claude-code/skills/adr/SKILL.md +48 -0
- package/plugin/claude-code/skills/analyze/SKILL.md +34 -0
- package/plugin/claude-code/skills/clarify/SKILL.md +34 -0
- package/plugin/claude-code/skills/deliver/SKILL.md +30 -0
- package/plugin/claude-code/skills/diagnose/SKILL.md +46 -0
- package/plugin/claude-code/skills/evolve/SKILL.md +49 -0
- package/plugin/claude-code/skills/export-template/SKILL.md +43 -0
- package/plugin/claude-code/skills/generalize/SKILL.md +37 -0
- package/plugin/claude-code/skills/gotcha/SKILL.md +46 -0
- package/plugin/claude-code/skills/init/SKILL.md +81 -0
- package/plugin/claude-code/skills/obligations/SKILL.md +31 -0
- package/plugin/claude-code/skills/plan/SKILL.md +34 -0
- package/plugin/claude-code/skills/policy/SKILL.md +29 -0
- package/plugin/claude-code/skills/promote/SKILL.md +43 -0
- package/plugin/claude-code/skills/protocol/SKILL.md +45 -0
- package/plugin/claude-code/skills/reconcile/SKILL.md +49 -0
- package/plugin/claude-code/skills/refactor/SKILL.md +83 -0
- package/plugin/claude-code/skills/reflect/SKILL.md +49 -0
- package/plugin/claude-code/skills/remediate/SKILL.md +39 -0
- package/plugin/claude-code/skills/restructure/SKILL.md +52 -0
- package/plugin/claude-code/skills/rule/SKILL.md +49 -0
- package/plugin/claude-code/skills/specify/SKILL.md +34 -0
- package/plugin/claude-code/skills/tasks/SKILL.md +28 -0
- package/plugin/claude-code/skills/update/SKILL.md +64 -0
- package/plugin/claude-code/skills/verify/SKILL.md +35 -0
- package/plugin/opencode/afm/index.js +245 -0
- package/plugin/opencode/afm/tui.js +21 -0
- package/plugin/opencode/agents/afm-executor.md +39 -0
- package/plugin/opencode/agents/afm-explorer.md +92 -0
- package/plugin/opencode/agents/afm-reviewer.md +93 -0
- package/plugin/opencode/skills/afm-adr/SKILL.md +48 -0
- package/plugin/opencode/skills/afm-analyze/SKILL.md +34 -0
- package/plugin/opencode/skills/afm-clarify/SKILL.md +34 -0
- package/plugin/opencode/skills/afm-deliver/SKILL.md +30 -0
- package/plugin/opencode/skills/afm-diagnose/SKILL.md +46 -0
- package/plugin/opencode/skills/afm-evolve/SKILL.md +49 -0
- package/plugin/opencode/skills/afm-export-template/SKILL.md +43 -0
- package/plugin/opencode/skills/afm-generalize/SKILL.md +37 -0
- package/plugin/opencode/skills/afm-gotcha/SKILL.md +46 -0
- package/plugin/opencode/skills/afm-init/SKILL.md +81 -0
- package/plugin/opencode/skills/afm-obligations/SKILL.md +31 -0
- package/plugin/opencode/skills/afm-plan/SKILL.md +34 -0
- package/plugin/opencode/skills/afm-policy/SKILL.md +29 -0
- package/plugin/opencode/skills/afm-promote/SKILL.md +43 -0
- package/plugin/opencode/skills/afm-protocol/SKILL.md +45 -0
- package/plugin/opencode/skills/afm-reconcile/SKILL.md +49 -0
- package/plugin/opencode/skills/afm-refactor/SKILL.md +83 -0
- package/plugin/opencode/skills/afm-reflect/SKILL.md +49 -0
- package/plugin/opencode/skills/afm-remediate/SKILL.md +39 -0
- package/plugin/opencode/skills/afm-restructure/SKILL.md +52 -0
- package/plugin/opencode/skills/afm-rule/SKILL.md +49 -0
- package/plugin/opencode/skills/afm-specify/SKILL.md +34 -0
- package/plugin/opencode/skills/afm-tasks/SKILL.md +28 -0
- package/plugin/opencode/skills/afm-update/SKILL.md +64 -0
- package/plugin/opencode/skills/afm-verify/SKILL.md +35 -0
- package/README.md +0 -3
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: pattern
|
|
3
|
+
description: Wraps a vendor SDK type or payload shape at the boundary so domain and lib code depend on an owned interface instead of the vendor's.
|
|
4
|
+
load: cold
|
|
5
|
+
smell: 'a vendor SDK type (a Stripe object, an S3 response, an ORM row) is imported and used directly inside domain or lib code, past the boundary it arrived at'
|
|
6
|
+
when_to_use: the vendor type crosses more than one file, or it is expected to change independently of the domain model that consumes it
|
|
7
|
+
when_not_to_use: the vendor call happens in exactly one file and its result is consumed nowhere else
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Pattern — Adapter
|
|
11
|
+
|
|
12
|
+
> Suggestion only. This pattern does not become project convention by existing here — it
|
|
13
|
+
> materializes into `code-style/`, `ach.md`, or an ADR only when the operator accepts it for
|
|
14
|
+
> this codebase.
|
|
15
|
+
|
|
16
|
+
Continues DIP in `rubrics/solid-triggers.md` (domain must not import infra) and
|
|
17
|
+
`rubrics/validation-boundary.md` (the parser lives at exactly 2 places). Adapter is what sits at
|
|
18
|
+
that same boundary for a *type*, not a schema: it converts the vendor's shape to an owned one on
|
|
19
|
+
the way in, once.
|
|
20
|
+
|
|
21
|
+
## Decision
|
|
22
|
+
|
|
23
|
+
| Situation | Verdict | Anti-pattern |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| `Stripe.Customer` (or equivalent) is read in 2+ files | Adapter: one function maps it to an owned `Customer` type at the boundary, everything past that line uses the owned type | Passing the SDK type through domain and re-reading its fields in each consumer |
|
|
26
|
+
| The SDK's field names or nesting are unstable across major versions (checked: it has broken before) | Adapter absorbs the next breaking change in 1 file | The breaking change ships and touches every call site that read the SDK type directly |
|
|
27
|
+
| The SDK call and its one consumer live in the same file, never exported | No adapter yet — see `when-to-create-lib.md`, one caller does not earn extraction | A `StripeCustomerAdapter` class for a value read once and discarded |
|
|
28
|
+
| The domain needs to call back into the vendor (not just read its output) | Wrap the vendor client behind a port your domain defines (this is DIP, Adapter's usual partner) | Domain importing the vendor SDK client directly to make the call itself |
|
|
29
|
+
|
|
30
|
+
## Why this works
|
|
31
|
+
|
|
32
|
+
A vendor's shape is out of your control; a domain model is not. Every field of the vendor type
|
|
33
|
+
read directly in domain code is a place a vendor upgrade can break — with the adapter, an upgrade
|
|
34
|
+
that renames or restructures the vendor type is absorbed in the 1 function that does the mapping,
|
|
35
|
+
never in the N places that use the resulting owned type.
|
|
36
|
+
|
|
37
|
+
## Anti-patterns
|
|
38
|
+
|
|
39
|
+
- ❌ An adapter that just renames fields 1:1 and adds no real translation, guarding a type used in
|
|
40
|
+
exactly one place. That's indirection with no boundary to protect — see `when-to-create-lib.md`.
|
|
41
|
+
- ❌ The adapter returns the vendor's own error type unchanged. Errors need the same translation as
|
|
42
|
+
data — see `error-classification.md` for what the domain-facing shape should be.
|
|
43
|
+
- ❌ Two adapters for the same vendor type, one per module, silently drifting. Vendor type → owned
|
|
44
|
+
type is a boundary fact, not a per-module preference; it belongs in one shared place.
|
|
45
|
+
- ❌ Calling the adapter function conditionally, so some call sites still see the raw vendor type.
|
|
46
|
+
A boundary that is optional is not a boundary.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: pattern
|
|
3
|
+
description: Bundles a repeated sequence of calls across 3 or more collaborators, that always represents one business step, behind a single function.
|
|
4
|
+
load: cold
|
|
5
|
+
smell: 'a call site wires 3 or more collaborators in the same order, in more than one place, to carry out one coherent business step'
|
|
6
|
+
when_to_use: the same sequence of calls across 3+ collaborators repeats at 2+ call sites and always represents one step
|
|
7
|
+
when_not_to_use: the collaborators are used independently at each call site — a different subset, or a different order, each time
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Pattern — Facade
|
|
11
|
+
|
|
12
|
+
> Suggestion only. This pattern does not become project convention by existing here — it
|
|
13
|
+
> materializes into `code-style/`, `ach.md`, or an ADR only when the operator accepts it for
|
|
14
|
+
> this codebase.
|
|
15
|
+
|
|
16
|
+
Continues ISP in `rubrics/solid-triggers.md`, from the other direction: ISP narrows what a single
|
|
17
|
+
function receives; Facade narrows what a *caller* must know to perform one step, by hiding the
|
|
18
|
+
fan-out to several collaborators behind one call.
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
| Situation | Verdict | Anti-pattern |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| 2+ call sites each wire the same 3+ collaborators, in the same order, for the same outcome | Extract a facade function; the call sites call it once and stop knowing the collaborators exist | Each call site re-derives the correct order, one of them getting it wrong under time pressure |
|
|
25
|
+
| One of the wired collaborators is itself a vendor SDK crossing a boundary | Apply Adapter to that one collaborator first, then wrap the sequence in the Facade | The Facade re-exports the raw vendor type through its own return value, leaking the boundary it should hide |
|
|
26
|
+
| The call sites use *different* subsets or orders of the same collaborators | Do not extract — that variation is the actual logic, and a facade would hide it, not simplify it | A facade with a boolean flag per caller's variant — the flags are the switch this pattern was meant to avoid |
|
|
27
|
+
| Only one call site exists | No facade yet — inline the sequence until a 2nd real caller needs the same one | A `CheckoutFacade` built for a single call site "to keep the handler short" |
|
|
28
|
+
|
|
29
|
+
## Why this works
|
|
30
|
+
|
|
31
|
+
A caller wiring C collaborators must know all C APIs, their call order, and how errors from each
|
|
32
|
+
propagate — that knowledge is repeated at every call site that performs the same step. A facade
|
|
33
|
+
moves it to 1 place: each call site's coupling drops from C collaborators to 1 function, and a
|
|
34
|
+
change to the internal wiring (a 4th collaborator added, the order changed) touches that 1 place.
|
|
35
|
+
|
|
36
|
+
## Anti-patterns
|
|
37
|
+
|
|
38
|
+
- ❌ A facade over collaborators that are each already simple to call alone. If wiring them takes
|
|
39
|
+
1 line each, the facade adds a name to remember without reducing real complexity.
|
|
40
|
+
- ❌ A "God facade" that grows to wrap every collaborator in the module, becoming the module's only
|
|
41
|
+
entry point for unrelated steps. Facade wraps *one* coherent business step, not the whole module
|
|
42
|
+
— see `rubrics/solid-triggers.md` § SRP if it starts doing 2+ things.
|
|
43
|
+
- ❌ Swallowing or generically catching every collaborator's error inside the facade. Each
|
|
44
|
+
collaborator's failure still needs its own classification — see `error-classification.md`;
|
|
45
|
+
a facade changes who calls, not how errors are represented.
|
|
46
|
+
- ❌ Building the facade before the 2nd call site exists, on the belief the sequence will repeat.
|
|
47
|
+
That is the same premature-extraction risk `when-to-create-lib.md` names for helpers in general.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: pattern
|
|
3
|
+
description: Centralizes a multi-step object construction that is copy-pasted at 2 or more call sites into one named function.
|
|
4
|
+
load: cold
|
|
5
|
+
smell: 'the same multi-step construction (apply defaults, validate, wire 2+ collaborators) is copy-pasted at 2 or more call sites to build the same kind of object'
|
|
6
|
+
when_to_use: constructing the object takes more than one step, and that construction already repeats at 2+ call sites
|
|
7
|
+
when_not_to_use: the value is a single-field object literal, or only one call site builds it today
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Pattern — Factory
|
|
11
|
+
|
|
12
|
+
> Suggestion only. This pattern does not become project convention by existing here — it
|
|
13
|
+
> materializes into `code-style/`, `ach.md`, or an ADR only when the operator accepts it for
|
|
14
|
+
> this codebase.
|
|
15
|
+
|
|
16
|
+
Continues the Rule-of-Three trigger already used in `rubrics/when-to-create-lib.md`: that rubric
|
|
17
|
+
extracts a helper on the 3rd caller. Factory is the same threshold applied specifically to
|
|
18
|
+
*construction* logic — defaults, validation, wiring 2+ collaborators into one object.
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
| Situation | Verdict | Anti-pattern |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| 2+ call sites build the same kind of object with the same defaults and the same wiring steps | Extract a `create<X>()` factory function; call sites pass only what varies | Each call site re-applies the same defaults, one of them drifting when a default changes |
|
|
25
|
+
| The object needs 1+ collaborator injected (a clock, an id generator, a config) to be testable | Factory takes the collaborators as parameters, with production defaults | The object reaches for `Date.now()` or a singleton internally — untestable without mocking modules |
|
|
26
|
+
| Construction is a single field literal (`{ id, name }`) | No factory. A function that returns its own argument is ceremony | `createUser({ id, name })` that does nothing `{ id, name }` didn't already do |
|
|
27
|
+
| Only one call site exists today | No factory yet — wait for the 2nd real caller, per `when-to-create-lib.md` | A `UserFactory` class built ahead of the 2nd caller, on the promise it is coming |
|
|
28
|
+
|
|
29
|
+
## Why this works
|
|
30
|
+
|
|
31
|
+
Construction logic duplicated at K call sites means a changed default, a new required field, or a
|
|
32
|
+
new invariant must be applied K times — and K-1 of those edits are typically missed. A factory
|
|
33
|
+
collapses that to 1 place: the invariant is enforced once, and every call site that changes still
|
|
34
|
+
compiles because they pass arguments to a function, not fields to a literal.
|
|
35
|
+
|
|
36
|
+
## Anti-patterns
|
|
37
|
+
|
|
38
|
+
- ❌ A factory with a config object with 12 optional fields, most unused by every caller. That is
|
|
39
|
+
the object's own complexity leaking into the factory's signature — fix the object first.
|
|
40
|
+
- ❌ A factory that also performs I/O (saves to the DB, calls an API) as a side effect of
|
|
41
|
+
"constructing." Construction builds a value; persistence is a separate step the caller invokes.
|
|
42
|
+
- ❌ A factory function per call site (`createUserForSignup`, `createUserForAdmin`) that each
|
|
43
|
+
duplicate 90% of the same logic. That is the smell this pattern exists to remove, reintroduced
|
|
44
|
+
one layer down — collapse them into one factory with a parameter for the 10% that differs.
|
|
45
|
+
- ❌ Naming it `UserFactory.getInstance()` to imitate a singleton when nothing requires only one
|
|
46
|
+
instance to exist. A plain exported function is the smaller design (KISS).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: pattern
|
|
3
|
+
description: Replaces a null guard repeated at 3 or more call sites with a default implementation that behaves like the absent case's known, safe outcome.
|
|
4
|
+
load: cold
|
|
5
|
+
smell: 'the same `if (x == null) { ...default behavior... }` guard, followed by using `x`, is repeated at 3 or more call sites'
|
|
6
|
+
when_to_use: the absent case has one well-known default behavior and every caller currently branches on null to reach it
|
|
7
|
+
when_not_to_use: callers must react differently to absence, or must distinguish absent from present-but-default
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Pattern — Null Object
|
|
11
|
+
|
|
12
|
+
> Suggestion only. This pattern does not become project convention by existing here — it
|
|
13
|
+
> materializes into `code-style/`, `ach.md`, or an ADR only when the operator accepts it for
|
|
14
|
+
> this codebase.
|
|
15
|
+
|
|
16
|
+
A narrower cousin of Strategy in this same library: instead of one implementation per real case,
|
|
17
|
+
it adds exactly one extra implementation standing in for "nothing here" — so the caller's `switch`
|
|
18
|
+
or `if (x == null)` collapses to zero branches, not one fewer.
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
- ✅ 3+ call sites do `if (x == null) return fallbackValue` (or an equivalent guard) right before
|
|
23
|
+
using `x`, and `fallbackValue` is the same at every one → give the absent case a real
|
|
24
|
+
implementation of the same interface (an empty cart, a no-op logger, a zero-total invoice) and
|
|
25
|
+
stop returning `null` in the first place.
|
|
26
|
+
- ✅ The type already has a real interface with 1+ methods (a `Logger`, a `Cart`) → the Null Object
|
|
27
|
+
implements that interface with safe, inert behavior (`NullLogger.log()` does nothing).
|
|
28
|
+
- ❌ Fewer than 3 call sites guard the same way, or two callers want a *different* fallback → a
|
|
29
|
+
shared Null Object would force one fallback where callers legitimately need their own; keep the
|
|
30
|
+
guards local, or pass the fallback in per caller instead.
|
|
31
|
+
- ❌ The caller must tell "absent" apart from "present with the default value" (e.g. a form field
|
|
32
|
+
the user explicitly cleared vs. one never touched) → collapsing both into one Null Object erases
|
|
33
|
+
that distinction; `Result`/`Option` is the honest fit — see `result-vs-exception.md`.
|
|
34
|
+
|
|
35
|
+
## Why this works
|
|
36
|
+
|
|
37
|
+
Every `if (x == null)` guard is a branch a reader and the compiler must both track; N call sites
|
|
38
|
+
with the same guard is N places that branch identically and N places a future change to the
|
|
39
|
+
fallback must be kept in sync. A Null Object moves the branch inside the 1 place that decides
|
|
40
|
+
"use the real thing or the null thing" (usually the factory or lookup that produces `x`), so the
|
|
41
|
+
N call sites go back to unconditional code — 1 branch total instead of N.
|
|
42
|
+
|
|
43
|
+
## Anti-patterns
|
|
44
|
+
|
|
45
|
+
- ❌ A Null Object that throws when any of its methods is called. That is not a null object, it is
|
|
46
|
+
a differently-shaped exception — it defeats the purpose, which is *safe* default behavior.
|
|
47
|
+
- ❌ Using Null Object where the caller actually needs to know absence happened (an audit log that
|
|
48
|
+
must record "no discount was found," not silently apply a $0 discount and look identical to a
|
|
49
|
+
real $0 discount). Prefer an explicit `Option`/`Result` there instead.
|
|
50
|
+
- ❌ A Null Object with mutable shared state (`NullCart` that collects items across unrelated
|
|
51
|
+
calls). The point of the pattern is a stateless, inert stand-in — shared mutable state turns it
|
|
52
|
+
into a hidden singleton bug.
|
|
53
|
+
- ❌ Silently swapping `null` for a Null Object across a serialization boundary (DB, API response).
|
|
54
|
+
Null Object is an in-process convenience; a stored `null` still means "absent" to every reader
|
|
55
|
+
outside this process, so translate at that boundary instead of upstream.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: pattern
|
|
3
|
+
description: Replaces a thrown exception for an expected, listable failure with a typed Result value the immediate caller must handle.
|
|
4
|
+
load: cold
|
|
5
|
+
smell: 'a function throws for an outcome the caller already anticipates and branches on (validation failure, not-found, conflict), and the caller wraps the call in try/catch to recover that one branch'
|
|
6
|
+
when_to_use: the failure modes are known, finite, and the immediate caller needs to react differently to each one
|
|
7
|
+
when_not_to_use: the failure is unexpected or unrecoverable — a network drop, a timeout, a bug
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Pattern — Result / Either over exception-as-control-flow
|
|
11
|
+
|
|
12
|
+
> Suggestion only. This pattern does not become project convention by existing here — it
|
|
13
|
+
> materializes into `code-style/`, `ach.md`, or an ADR only when the operator accepts it for
|
|
14
|
+
> this codebase.
|
|
15
|
+
|
|
16
|
+
`rubrics/error-classification.md` already prescribes the shape (`Result<T, E>` with a literal
|
|
17
|
+
`as const` code) for the Domain layer specifically. This pattern generalizes the same call: apply
|
|
18
|
+
it to *any* function, domain or not, where a `try { } catch { }` exists only to recover one
|
|
19
|
+
specific, anticipated branch — not to handle a genuine surprise.
|
|
20
|
+
|
|
21
|
+
## Decision
|
|
22
|
+
|
|
23
|
+
- ✅ The function has 2 or more named, expected outcomes (`EMAIL_TAKEN`, `NOT_FOUND`,
|
|
24
|
+
`WEAK_PASSWORD`) → return `Result<T, E>` with `E` a literal union, and force the caller to
|
|
25
|
+
`switch` with an exhaustive `never` default (see `error-classification.md`).
|
|
26
|
+
- ✅ Today's code throws a custom error class only to `catch (e) { if (e instanceof X) }` one line
|
|
27
|
+
above the call → that `catch` is the tell; replace both sides with `Result`.
|
|
28
|
+
- ❌ The failure is a bug, a timeout, or anything the immediate caller cannot meaningfully act on
|
|
29
|
+
→ let it rise. Wrapping every infra call in `Result` just relocates the `try/catch`, it does not
|
|
30
|
+
remove it — see `error-classification.md`'s Infra-error row.
|
|
31
|
+
- ❌ The function is called in exactly one place and that place already has a correct
|
|
32
|
+
`try/catch` → converting it buys nothing; the try/catch already IS the handling.
|
|
33
|
+
|
|
34
|
+
## Why this works
|
|
35
|
+
|
|
36
|
+
An exception's type is invisible at the call site — nothing in a function's signature says it can
|
|
37
|
+
throw, so the caller either wraps every call defensively or misses a case entirely. A `Result<T,
|
|
38
|
+
E>` return type puts the failure in the signature: TypeScript's exhaustiveness check on the
|
|
39
|
+
`switch` (the `never` default) then makes an unhandled case a compile error instead of a runtime
|
|
40
|
+
surprise, at zero added `try/catch` blocks.
|
|
41
|
+
|
|
42
|
+
## Anti-patterns
|
|
43
|
+
|
|
44
|
+
- ❌ Wrapping infra failures (DB down, network drop) in `Result` "for consistency." Those are not
|
|
45
|
+
anticipated outcomes — see `error-classification.md`: infra errors rise and get caught once at
|
|
46
|
+
the process boundary, they do not become a case in every caller's switch.
|
|
47
|
+
- ❌ A `Result<T, string>` with a free-text message instead of a literal code. The caller cannot
|
|
48
|
+
`switch` on a string; the whole benefit (exhaustiveness) is gone. The code must be `as const`.
|
|
49
|
+
- ❌ Mixing `Result` and exceptions in the same function — return `Result` for the expected branch,
|
|
50
|
+
then also `throw` for another branch of the same function. Callers must handle two mechanisms.
|
|
51
|
+
- ❌ A generic `try/catch` around a `Result`-returning call "just in case." If the function no
|
|
52
|
+
longer throws for its expected failures, the surrounding `try` should not exist either.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: pattern
|
|
3
|
+
description: Replaces a branching conditional keyed on a kind, type, or provider field with one interface and one implementation per case, selected through a registry.
|
|
4
|
+
load: cold
|
|
5
|
+
smell: 'a `switch` or `if`/`else if` chain keyed on a kind, type, or provider field, duplicated across 2+ files or functions'
|
|
6
|
+
when_to_use: a new case of the same kind arrives on a predictable cadence and every case can share one call shape
|
|
7
|
+
when_not_to_use: only one implementation exists today, or the cases would return incompatible shapes
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Pattern — Strategy
|
|
11
|
+
|
|
12
|
+
> Suggestion only. This pattern does not become project convention by existing here — it
|
|
13
|
+
> materializes into `code-style/`, `ach.md`, or an ADR only when the operator accepts it for
|
|
14
|
+
> this codebase.
|
|
15
|
+
|
|
16
|
+
Continues the OCP trigger in `rubrics/solid-triggers.md`: that rubric tells you a `switch` on a
|
|
17
|
+
provider is a problem the moment a 2nd `switch` on the same field appears elsewhere. Strategy is
|
|
18
|
+
the concrete extraction once that trigger fires.
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
| Situation | Verdict | Anti-pattern |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| A `switch(kind)` selects behavior, and a second `switch(kind)` on the same field lives in another function or file | Apply Strategy: one file per case implementing a shared interface, wired through a lookup table | Adding a 4th `case` to both switches and hoping they stay in sync |
|
|
25
|
+
| Every case already returns the same shape (LSP, see `solid-triggers.md`) | Safe to extract now — the interface is exactly that shared shape | Extracting before the shapes agree — the interface degrades to `any` or a union of incompatibles |
|
|
26
|
+
| Only one case exists and no second is concretely planned | Do not extract. A single `if` is not a smell | A `StrategyRegistry` with one entry — OCP paid for a case that never happened |
|
|
27
|
+
| The active case is fixed for the process lifetime (an env-driven backend chosen once at boot) | Plain dependency injection of the one active implementation | A registry of N strategies when exactly 1 is ever selected at runtime |
|
|
28
|
+
|
|
29
|
+
## Why this works
|
|
30
|
+
|
|
31
|
+
A `switch` on a variant duplicates its list of cases every time the branch is copy-pasted into a
|
|
32
|
+
new function: N call sites × M cases means up to N×M places that drift when case M+1 arrives.
|
|
33
|
+
Strategy collapses that to N call sites each holding one lookup, plus M single-purpose files —
|
|
34
|
+
adding case M+1 then touches exactly 1 new file and 1 registry line, never the N call sites.
|
|
35
|
+
|
|
36
|
+
## Anti-patterns
|
|
37
|
+
|
|
38
|
+
- ❌ A `StrategyRegistry` holding one entry "for when we add the second provider." Inline the one
|
|
39
|
+
implementation. Extract on the second real case, not the imagined one.
|
|
40
|
+
- ❌ Interfaces that leak the framework in the port (`RegistryAdapter.publish(ctx: TRPCContext)`).
|
|
41
|
+
The port must be as narrow as ISP allows — see `solid-triggers.md` § ISP.
|
|
42
|
+
- ❌ A registry keyed by a raw `string` instead of the closed literal union of kinds. A typo in the
|
|
43
|
+
key then fails at runtime instead of at compile time.
|
|
44
|
+
- ❌ Keeping the old `switch` alongside the new registry "just in case." Delete it in the same
|
|
45
|
+
change — two selection mechanisms for the same kind is worse than the one you started with.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: pattern
|
|
3
|
+
description: Chooses between an inherited algorithm skeleton with overridable steps and a plain function that takes the varying step as a parameter.
|
|
4
|
+
load: cold
|
|
5
|
+
smell: 'two or more functions or classes repeat the same ordered sequence of steps, differing only in 1-2 of those steps'
|
|
6
|
+
when_to_use: the skeleton has 3+ fixed steps and only 1-2 vary across callers
|
|
7
|
+
when_not_to_use: the varying step is the only step, or fewer than 3 callers share the skeleton
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Pattern — Template Method vs. composition
|
|
11
|
+
|
|
12
|
+
> Suggestion only. This pattern does not become project convention by existing here — it
|
|
13
|
+
> materializes into `code-style/`, `ach.md`, or an ADR only when the operator accepts it for
|
|
14
|
+
> this codebase.
|
|
15
|
+
|
|
16
|
+
Shares the Rule-of-Three threshold from `rubrics/when-to-create-lib.md`, applied to a *sequence*
|
|
17
|
+
of steps instead of a single helper — and it decides between two ways to remove the duplication,
|
|
18
|
+
not just whether to remove it.
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
| Situation | Verdict | Anti-pattern |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| 3+ callers share an ordered skeleton (validate → transform → persist → notify), 1-2 steps vary, and the language has first-class functions | Composition: one function takes the varying step(s) as parameters/callbacks | Copy-pasting the whole skeleton per caller so the 1 varying line can differ |
|
|
25
|
+
| Same skeleton, but the varying steps need to read or mutate protected state shared across steps (a running total, an accumulator built up across the sequence) | Template Method: a base class fixes the sequence, subclasses override only the varying steps | Threading that shared state through 4 separate callback parameters to fake what inheritance gives for free |
|
|
26
|
+
| Only 1-2 callers share the skeleton today | Do not extract either way — inline duplication for 2 callers costs less than an abstraction (Rule of Three, `when-to-create-lib.md`) | A base class with exactly one subclass, built ahead of the 2nd real caller |
|
|
27
|
+
| The "skeleton" is actually just the 1 step that varies, wrapped in ceremony | There is no skeleton to extract — this is a Strategy situation instead, see `strategy.md` | Template Method with a base class whose every method is abstract — nothing is actually shared |
|
|
28
|
+
|
|
29
|
+
## Why this works
|
|
30
|
+
|
|
31
|
+
A skeleton with S total steps where V of them vary means V×N points of difference across N
|
|
32
|
+
callers when duplicated in full. Extracting the skeleton — either way — reduces that to N call
|
|
33
|
+
sites providing only the V varying steps, plus 1 shared definition of the S−V fixed ones.
|
|
34
|
+
Composition and Template Method both hit that number; the choice between them is only about
|
|
35
|
+
where the shared state between steps needs to live — a closure (composition) or `this`
|
|
36
|
+
(inheritance).
|
|
37
|
+
|
|
38
|
+
## Anti-patterns
|
|
39
|
+
|
|
40
|
+
- ❌ Reaching for inheritance by default. Composition is the smaller design (KISS) whenever no
|
|
41
|
+
step needs shared mutable state across the sequence — prefer it, and use Template Method only
|
|
42
|
+
when composition would require threading that state through every callback.
|
|
43
|
+
- ❌ A Template Method base class with a step marked `abstract` that every subclass overrides
|
|
44
|
+
identically. That step isn't varying — fold it back into the fixed skeleton.
|
|
45
|
+
- ❌ Composition where the "varying step" callback secretly depends on 3+ pieces of the caller's
|
|
46
|
+
outer scope. At that point the callback IS the logic and the shared skeleton is the smaller
|
|
47
|
+
part — question whether extracting the skeleton was the right cut at all.
|
|
48
|
+
- ❌ Extracting the skeleton before the 3rd caller exists. Two callers sharing steps can be
|
|
49
|
+
coincidence, not a real pattern — the same Rule-of-Three reasoning `when-to-create-lib.md` uses
|
|
50
|
+
for helpers applies here.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
questions:
|
|
2
|
+
- id: status
|
|
3
|
+
prompt: What is the status of this decision?
|
|
4
|
+
header: Status
|
|
5
|
+
recommended: Accepted
|
|
6
|
+
options:
|
|
7
|
+
- label: Proposed
|
|
8
|
+
description: Written down, not yet in force. Pass it as --status proposed.
|
|
9
|
+
- label: Accepted
|
|
10
|
+
description: In force today. Pass it as --status accepted.
|
|
11
|
+
- label: Superseded by ADR-NNNN
|
|
12
|
+
description: A later decision replaced it; write the new ADR with --supersedes N.
|
|
13
|
+
- label: Deprecated
|
|
14
|
+
description: No longer in force and nothing replaced it. Pass it as --status deprecated.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
questions:
|
|
2
|
+
- id: remediation
|
|
3
|
+
prompt: Do you want concrete edits for the top findings?
|
|
4
|
+
header: Remediation
|
|
5
|
+
recommended: top-5
|
|
6
|
+
options:
|
|
7
|
+
- label: top-5
|
|
8
|
+
description: Apply the edits for the top 5 findings in severity order, then report what changed and where.
|
|
9
|
+
- label: top-10
|
|
10
|
+
description: Same as top-5, for the top 10 findings.
|
|
11
|
+
- label: report-only
|
|
12
|
+
description: The report is enough. Nothing is edited and the findings are addressed manually.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
questions:
|
|
2
|
+
- id: mapping
|
|
3
|
+
prompt: Does the component-type to stack mapping drafted for the architecture doc make sense?
|
|
4
|
+
header: Mapping
|
|
5
|
+
recommended: All match
|
|
6
|
+
options:
|
|
7
|
+
- label: All match
|
|
8
|
+
description: Materializes the mapping as drafted.
|
|
9
|
+
- label: Adjust
|
|
10
|
+
description: One or two entries change; the operator points them out.
|
|
11
|
+
- label: Some do not apply
|
|
12
|
+
description: The operator lists the component types the project does not have.
|
|
13
|
+
- label: Rewrite
|
|
14
|
+
description: The operator dictates the mapping again.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
questions:
|
|
2
|
+
- id: rules
|
|
3
|
+
prompt: Does any inherited hard rule not fit this project? Inalienable rules are never offered.
|
|
4
|
+
header: Rules
|
|
5
|
+
recommended: Keep all
|
|
6
|
+
options:
|
|
7
|
+
- label: Keep all
|
|
8
|
+
description: Every opt-out-able rule stays in force.
|
|
9
|
+
- label: Opt out of some
|
|
10
|
+
description: The operator names each rule and why; each becomes N/A with that reason.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
questions:
|
|
2
|
+
- id: stack
|
|
3
|
+
prompt: Is the stack that afm init reported, layer by layer with its evidence, right?
|
|
4
|
+
header: Stack
|
|
5
|
+
recommended: Confirm
|
|
6
|
+
options:
|
|
7
|
+
- label: Confirm
|
|
8
|
+
description: Records every reported layer as decided.
|
|
9
|
+
- label: Adjust
|
|
10
|
+
description: Some layers are wrong or missing; the operator names them and the answer is recorded as given.
|
|
11
|
+
- label: Leave as TBD
|
|
12
|
+
description: Records [TBD] for the layers; a recommendation works better once the operator also knows what they do not want.
|
|
13
|
+
- id: modules
|
|
14
|
+
prompt: Apply every opt-in module detected for the stack? A module is applied whole, so the default is to opt out only what does not fit.
|
|
15
|
+
header: Modules
|
|
16
|
+
recommended: All
|
|
17
|
+
options:
|
|
18
|
+
- label: All
|
|
19
|
+
description: Merges each detected module's architecture and rule patches.
|
|
20
|
+
- label: Some
|
|
21
|
+
description: Applies all but the modules the operator names; those simply stay out.
|
|
22
|
+
- label: None
|
|
23
|
+
description: No module is applied.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
questions:
|
|
2
|
+
- id: underspecified
|
|
3
|
+
prompt: Most categories are Missing and many markers are open. How should clarify proceed?
|
|
4
|
+
header: Thin spec
|
|
5
|
+
recommended: respecify
|
|
6
|
+
options:
|
|
7
|
+
- label: respecify
|
|
8
|
+
description: Re-run specify with new input. A spec this thin needs rewriting, not a long question loop.
|
|
9
|
+
- label: continue
|
|
10
|
+
description: Keep clarifying anyway, within the limit of 5 questions for this session.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
questions:
|
|
2
|
+
- id: code-style
|
|
3
|
+
prompt: The listed code-style files are house conventions one project observed, not facts of the stack. Apply any? An unmarked item is written nowhere.
|
|
4
|
+
header: Code style
|
|
5
|
+
recommended: None
|
|
6
|
+
options:
|
|
7
|
+
- label: None
|
|
8
|
+
description: Nothing applies. The default, because a silent opt-in is the defect this question corrects.
|
|
9
|
+
- label: Some
|
|
10
|
+
description: The operator names the files; each is copied verbatim as the project's rule.
|
|
11
|
+
- label: All
|
|
12
|
+
description: Every listed file is copied verbatim as the project's rule.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
questions:
|
|
2
|
+
- id: restated
|
|
3
|
+
prompt: Is the restatement above correct?
|
|
4
|
+
header: Confirmation
|
|
5
|
+
recommended: Yes, exact
|
|
6
|
+
options:
|
|
7
|
+
- label: Yes, exact
|
|
8
|
+
description: Materializes it as restated.
|
|
9
|
+
- label: Almost
|
|
10
|
+
description: A small adjustment; the operator describes the fix.
|
|
11
|
+
- label: No, rewrite
|
|
12
|
+
description: The operator dictates it again.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
questions:
|
|
2
|
+
- id: outcome
|
|
3
|
+
prompt: The plan is drafted and verified. What should the delivery do now?
|
|
4
|
+
header: Outcome
|
|
5
|
+
recommended: run-to-completion
|
|
6
|
+
options:
|
|
7
|
+
- label: run-to-completion
|
|
8
|
+
description: Approve the plan and execute every task, stopping only at a halt or the push boundary.
|
|
9
|
+
- label: pause-per-phase
|
|
10
|
+
description: Approve the plan, execute it, and stop after each phase to ask whether to continue.
|
|
11
|
+
- label: materialize-only
|
|
12
|
+
description: Keep the drafted spec, plan and tasks on disk and execute nothing.
|
|
13
|
+
- label: adjust-or-cancel
|
|
14
|
+
description: Record no approval. Say what to change in the drafts, or stop here.
|
|
15
|
+
- id: phase-continue
|
|
16
|
+
prompt: The phase is done. Continue to the next phase?
|
|
17
|
+
header: Next phase
|
|
18
|
+
recommended: continue
|
|
19
|
+
options:
|
|
20
|
+
- label: continue
|
|
21
|
+
description: Run the next phase.
|
|
22
|
+
- label: stop
|
|
23
|
+
description: Stop here; re-running deliver resumes at the first open task.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# One question per (b) item of the evolve package. Run it once per item:
|
|
2
|
+
# afm ask evolve --scope <item-slug> --recommend <label>
|
|
3
|
+
# The item's evidence, its recommendation and "what changes if this is wrong" sit in the package the
|
|
4
|
+
# agent shows before asking; the answer applies to that one item only.
|
|
5
|
+
questions:
|
|
6
|
+
- id: apply
|
|
7
|
+
prompt: Apply this proposed change to the docs?
|
|
8
|
+
header: Apply
|
|
9
|
+
options:
|
|
10
|
+
- label: Apply
|
|
11
|
+
description: Apply the change after the gate, exactly as itemized in the package.
|
|
12
|
+
- label: Skip
|
|
13
|
+
description: Reject it; the report records the rejection as attempt memory, so it is not proposed again without new evidence.
|
|
14
|
+
- label: Stage
|
|
15
|
+
description: Defer it to the next cycle; the report records it as staged.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
questions:
|
|
2
|
+
- id: apply
|
|
3
|
+
prompt: Delete the listed files and write the template marker?
|
|
4
|
+
header: Apply
|
|
5
|
+
options:
|
|
6
|
+
- label: Apply
|
|
7
|
+
description: Runs the same command with --yes. The deletion is not reversible outside git.
|
|
8
|
+
- label: Adjust
|
|
9
|
+
description: Go back to the keep question and review the plan again.
|
|
10
|
+
- label: Cancel
|
|
11
|
+
description: Nothing is touched.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
questions:
|
|
2
|
+
- id: keep
|
|
3
|
+
prompt: Which of the artifacts a template normally drops should STAY? Leave empty to keep none.
|
|
4
|
+
header: Keep
|
|
5
|
+
multiSelect: true
|
|
6
|
+
options:
|
|
7
|
+
- label: prd
|
|
8
|
+
description: prd.md is product-specific; a template usually drops it.
|
|
9
|
+
- label: ust
|
|
10
|
+
description: ust.md holds the product's stories; a template usually drops it.
|
|
11
|
+
- label: features
|
|
12
|
+
description: docs/features/ is product work; its tasks are first induced into a reusable shape.
|
|
13
|
+
- label: afm-version
|
|
14
|
+
description: A template is not an instance, so the version pin is dropped unless kept.
|
|
15
|
+
- id: research
|
|
16
|
+
prompt: What happens to docs/research/, which may hold reusable technical research?
|
|
17
|
+
header: Research
|
|
18
|
+
recommended: Keep
|
|
19
|
+
options:
|
|
20
|
+
- label: Keep
|
|
21
|
+
description: The research stays in the template.
|
|
22
|
+
- label: Delete
|
|
23
|
+
description: The research goes with the product content.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
questions:
|
|
2
|
+
- id: dod
|
|
3
|
+
prompt: Which checks must pass to merge? Pre-check the ones the scan reported as gating merge.
|
|
4
|
+
header: Merge DoD
|
|
5
|
+
multiSelect: true
|
|
6
|
+
options:
|
|
7
|
+
- label: Test runner
|
|
8
|
+
description: The project's tests.
|
|
9
|
+
- label: Type check
|
|
10
|
+
description: The type checker with no emit.
|
|
11
|
+
- label: Lint
|
|
12
|
+
description: The linter or formatter check.
|
|
13
|
+
- label: Build
|
|
14
|
+
description: A production build.
|
|
15
|
+
- id: pre-push
|
|
16
|
+
prompt: Which checks run before a push? Pre-check the ones the scan reported in a pre-push hook.
|
|
17
|
+
header: Pre-push
|
|
18
|
+
multiSelect: true
|
|
19
|
+
options:
|
|
20
|
+
- label: Test runner
|
|
21
|
+
description: The project's tests.
|
|
22
|
+
- label: Type check
|
|
23
|
+
description: The type checker with no emit.
|
|
24
|
+
- label: Lint
|
|
25
|
+
description: The linter or formatter check.
|
|
26
|
+
- label: Build
|
|
27
|
+
description: A production build.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# One question per merge of gotchas into an abstract rule:
|
|
2
|
+
# afm ask generalize --scope <rule-slug>
|
|
3
|
+
questions:
|
|
4
|
+
- id: merge
|
|
5
|
+
prompt: Merge the batch of gotchas into the proposed rule and archive the members with tombstones?
|
|
6
|
+
header: Merge
|
|
7
|
+
options:
|
|
8
|
+
- label: Merge as a rule
|
|
9
|
+
description: Write a hard rule in afm.md section 3 with its 0/1 trigger, then archive the merged gotchas with tombstones.
|
|
10
|
+
- label: Merge as a principle
|
|
11
|
+
description: Write the abstraction in afm.md section 1.3 (guidance only, no executable trigger), then archive the merged gotchas with tombstones.
|
|
12
|
+
- label: Keep separate
|
|
13
|
+
description: The abstraction loses too much; keep the gotchas as they are and report "not generalizable without loss".
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
questions:
|
|
2
|
+
- id: basis
|
|
3
|
+
prompt: Does this behavior qualify for registration?
|
|
4
|
+
header: Qualify
|
|
5
|
+
options:
|
|
6
|
+
- label: bitten-twice
|
|
7
|
+
description: Confirmed to have bitten a developer at least twice.
|
|
8
|
+
- label: documented-sdk
|
|
9
|
+
description: Documented behavior of a known external SDK or runtime that surprises its users.
|
|
10
|
+
- label: neither
|
|
11
|
+
description: No second incidence and no external documentation; nothing is registered.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
questions:
|
|
2
|
+
- id: branch
|
|
3
|
+
prompt: This project comes from an architectural template (docs/.template). How should the interview run?
|
|
4
|
+
header: Interview
|
|
5
|
+
recommended: Product only
|
|
6
|
+
options:
|
|
7
|
+
- label: Product only
|
|
8
|
+
description: Runs only product, flows, a short validation step and gotchas. Stack, data model, mapping and rules are inherited.
|
|
9
|
+
- label: Full interview
|
|
10
|
+
description: Ignores the marker for this session and runs all seven steps. The marker stays on disk.
|