@tenkara/afm-linux-arm64 0.0.0-stage → 4.0.0-alpha.10
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 +4320 -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/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/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/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-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/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-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,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: template
|
|
3
|
+
description: 'Template rendered during materialization: Template — guardrail runner.'
|
|
4
|
+
load: cold
|
|
5
|
+
renders_to: 'docs/tools/gate/rules/*.sh'
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Template — guardrail runner
|
|
9
|
+
|
|
10
|
+
<!-- guidance -->
|
|
11
|
+
> Skeleton of the script that a guardrail of **`hard-rule` origin** runs. The consumer repo materializes it as `docs/tools/gate/rules/<NN>-<slug>.sh` (or the path the project already uses for gates).
|
|
12
|
+
> **Two forms.** `afm rule new` writes a TypeScript skeleton (`<NN>-<slug>.ts`) by default and a bash one (`<NN>-<slug>.sh`) with `--runner sh`. Use TypeScript when the check is "files in a scope, a regex per line": no shell, no execute bit, and it runs on Windows. Use bash (or any executable) for a diff, a count against the ratchet, or another tool. Both obey the contract below.
|
|
13
|
+
> **The runner is the only part you write.** Since 3.7.0-rc.1 the aggregator, its two libraries, the ratchet and the hook body arrive materialized in `docs/tools/gate/`. Before that they were described here and shipped nowhere, so a runner written from this template died at its own `source` line.
|
|
14
|
+
<!-- /guidance -->
|
|
15
|
+
|
|
16
|
+
## Contract
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
argv[1] : "staged" | "worktree"
|
|
20
|
+
env RATCHET : path to the budget baseline (TSV: rule region count note)
|
|
21
|
+
env AFM_GATE_LIB : directory holding scope.sh and ratchet.sh, exported by the aggregator
|
|
22
|
+
|
|
23
|
+
stdout : one line per finding — "<NN>\t<path>[:<line>]\t<short message>"
|
|
24
|
+
exit 0 : compliant
|
|
25
|
+
exit 1 : violation found
|
|
26
|
+
exit 2 : COULD NOT decide (missing dependency, mode not applicable)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
<!-- guidance -->
|
|
30
|
+
**Exit 2 is mandatory. It is not decoration.** "Could not verify" must never become "failed". The first machine without the tool would turn the gate into a permanent block. A gate like that gets disabled, together with every other gate in the same aggregator.
|
|
31
|
+
<!-- /guidance -->
|
|
32
|
+
|
|
33
|
+
## The two classes — choose before you write
|
|
34
|
+
|
|
35
|
+
| Class | Scope | Budget | Example |
|
|
36
|
+
| --- | --- | --- | --- |
|
|
37
|
+
| **Diff** | the index (what becomes the commit) | always 0 | plaintext secret, version bump, test that must run |
|
|
38
|
+
| **Count** | the whole repo, **even in `--staged`** | ratchet, decreases only | path convention, identifier language, single source |
|
|
39
|
+
|
|
40
|
+
<!-- guidance -->
|
|
41
|
+
Counting a count rule over the index is a **silent false negative**. With a budget of 7, a commit that adds 1 new violation counts 1 ≤ 7 and passes clean. The ratchet means "did not grow" only if it measures the same total it recorded.
|
|
42
|
+
<!-- /guidance -->
|
|
43
|
+
|
|
44
|
+
## Skeleton: TypeScript (the default)
|
|
45
|
+
|
|
46
|
+
`afm gate` runs the file in a child process (`afm gate ts-runner`) under the same timeout and exit contract. The default export is a function of the rule builder: it imports nothing.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
export default ({ rule }) =>
|
|
50
|
+
rule("{{NN}}")
|
|
51
|
+
.in("{{glob}}") // repeat .in to add globs
|
|
52
|
+
.except("{{glob}}") // paths left out
|
|
53
|
+
.skipping(/{{comment}}/) // a line that matches is ignored
|
|
54
|
+
.forbid(/{{pattern}}/, "{{message}}"); // or .require(/{{pattern}}/, "{{message}}")
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The builder reports each match at its line and exits 0, 1 or 2 for you. Check it with `afm gate --dry-run --only {{NN}}`. Full API: `docs/tools/gate/rules/README.md`. The skeleton `afm rule new` writes throws until you replace it, so an unfinished rule exits 2 and never passes.
|
|
58
|
+
|
|
59
|
+
## Skeleton: bash
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
#!/usr/bin/env bash
|
|
63
|
+
# Hard rule {{NN}} — {{short statement}}.
|
|
64
|
+
# Why a gate, not a paragraph: {{the mistake is cheap to make, expensive to review, and
|
|
65
|
+
# the review that would catch it does not scale — it costs context every time the code is touched}}.
|
|
66
|
+
set -u
|
|
67
|
+
MODE="${1:-staged}"
|
|
68
|
+
REPO="$(git rev-parse --show-toplevel)"
|
|
69
|
+
# Resolve the library through the variable, never through a fixed path. The runner does not
|
|
70
|
+
# know where the gate lives, which is what lets the same runner work in a project that keeps
|
|
71
|
+
# it under `docs/tools/gate/` and in one that keeps it somewhere else.
|
|
72
|
+
. "${AFM_GATE_LIB:?}/scope.sh"
|
|
73
|
+
|
|
74
|
+
# Dependency guard — exit 2, never 1.
|
|
75
|
+
# command -v {{tool}} >/dev/null 2>&1 || exit 2
|
|
76
|
+
|
|
77
|
+
RC=0
|
|
78
|
+
while IFS= read -r f; do
|
|
79
|
+
[ -f "$REPO/$f" ] || continue
|
|
80
|
+
while IFS=: read -r n _; do
|
|
81
|
+
printf '{{NN}}\t%s:%s\t{{message}}\n' "$f" "$n"
|
|
82
|
+
RC=1
|
|
83
|
+
done < <(grep -n '{{pattern}}' "$REPO/$f")
|
|
84
|
+
done < <(scope_all '{{pathspec}}') # scope_files "$MODE" ... for a DIFF rule
|
|
85
|
+
|
|
86
|
+
exit $RC
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Before you call it done
|
|
90
|
+
|
|
91
|
+
- [ ] Did the assertion **fail on the old code**? Before you accept it, run it against the code as it was before the fix (`git show HEAD:<file>`, or the parent commit). It MUST fail there. A regression test that passes on the old code proves nothing.
|
|
92
|
+
- [ ] Does the command **distinguish** the violating case from the clean case? Test both. A gate that returns green without checking buys trust it cannot back up.
|
|
93
|
+
- [ ] Is there a diff that **passes the trigger but violates the intent** of the rule? If yes, the rule is reward-hackable. Rewrite it, or demote it to a principle (`core/afm.md § 1.3`).
|
|
94
|
+
- [ ] Does the runner fail **legitimate work** in any real case in the repo? Test this before you turn the gate on. Failing correct work is the shortest path to `--no-verify` becoming a habit.
|
|
95
|
+
- [ ] Did you run `guardrails.sh --baseline` before turning the rule on? It records what HEAD already breaks as declared debt. **A gate that starts red is disabled the next day**, and it takes every other rule in the same aggregator with it.
|
|
96
|
+
- [ ] Is the constant (threshold, prefix, directory list) **the operator's own**? Measure the repo and propose it together with the measurement (`ops/rule.md` 3.6). A "best practice" value set by the agent is the first thing to get turned off.
|
|
97
|
+
- [ ] Was the ratchet's `count` **measured on HEAD** before you turned the gate on? A gate that starts red gets turned off the next day.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: template
|
|
3
|
+
description: 'Template rendered during materialization: Guardrail: {{title — what this gate blocks}}.'
|
|
4
|
+
load: cold
|
|
5
|
+
renders_to: 'docs/guardrails/*.md'
|
|
6
|
+
frontmatter_for_output: |
|
|
7
|
+
type: guardrail
|
|
8
|
+
description: '<one sentence: what this gate blocks>'
|
|
9
|
+
load: warm
|
|
10
|
+
id: '<stable kebab-case slug>'
|
|
11
|
+
origin: recurring-failure | hard-rule
|
|
12
|
+
surface: pre-commit | ci | linter | type-check | script-local # the chosen surface
|
|
13
|
+
trigger: '<the 0/1 command>'
|
|
14
|
+
cost: low | medium | high
|
|
15
|
+
signal: '<the concrete error people kept fixing by hand: import from billing into ui, a new case in the union broke nothing>'
|
|
16
|
+
installed_on: 'YYYY-MM-DD' # omit the key while the guardrail is still a proposal
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Guardrail: {{title — what this gate blocks}}
|
|
20
|
+
|
|
21
|
+
<!-- guidance -->
|
|
22
|
+
> This is a **mechanical** gate. A 0/1 check runs it on its own. It needs no judgment and no one to remember it.
|
|
23
|
+
> Family `docs/guardrails/` (v3.5.0+). One responsibility per file.
|
|
24
|
+
<!-- /guidance -->
|
|
25
|
+
|
|
26
|
+
**Two origins, one artifact** (the object is the same: a 0/1 check plus the burden of proof to refute it):
|
|
27
|
+
|
|
28
|
+
| `origin:` | Where it comes from | Who proposes it |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| `recurring-failure` | `sig=` recurred in the failure records (`afm failures promotable`) | `remediate.md` (CRITIC loop, `failure-classification.md` rubric — precedence destination) |
|
|
31
|
+
| `hard-rule` | a hard rule already written in `afm.md § 3`, with a 0/1 trigger no one ran | `rule.md § Install the gate` |
|
|
32
|
+
|
|
33
|
+
## Origin
|
|
34
|
+
|
|
35
|
+
{{The failure record (sig=`<hash>`, recurred N times), "explicit user correction on <date>", OR, for `hard-rule`, the rule number and proof its trigger never ran. If the surface is a new tool, state its cost.}}
|
|
36
|
+
|
|
37
|
+
## The trigger
|
|
38
|
+
|
|
39
|
+
`{{comando}}` returns {{0 or nonzero}} when {{the condition}}.
|
|
40
|
+
|
|
41
|
+
<!-- guidance -->
|
|
42
|
+
This is the guardrail's whole contract. If the command cannot tell the violated case from the clean case, **the guardrail does not exist**. Measure it before you trust it. A gate that returns green without checking is worse than no gate. It buys trust it cannot back up.
|
|
43
|
+
<!-- /guidance -->
|
|
44
|
+
|
|
45
|
+
## Why mechanical, not documented
|
|
46
|
+
|
|
47
|
+
{{Why a procedure or a learning was not enough here. Usually: the error is cheap to make, costly to review, and the review that would catch it does not scale. It spends context every time the code is touched.}}
|
|
48
|
+
|
|
49
|
+
## Accepted cost
|
|
50
|
+
|
|
51
|
+
{{What this gate charges: build time, a known false positive, ceremony on a legitimate change. An undeclared cost breeds resentment. The next agent then disables the gate without recording why.}}
|
|
52
|
+
|
|
53
|
+
## What would refute this
|
|
54
|
+
|
|
55
|
+
{{Mandatory. The conditions under which this guardrail stops making sense, and who carries the burden of proof to remove it.}}
|
|
56
|
+
|
|
57
|
+
- {{condition 1 — e.g., "the project has only one package, so there is no boundary to cross without a graph"}}
|
|
58
|
+
- {{condition 2 — e.g., "measured it, and the command misses the violation you actually have"}}
|
|
59
|
+
- {{condition 3 — e.g., "the structure is still forming, so freezing it now rejects legitimate work"}}
|
|
60
|
+
|
|
61
|
+
<!-- guidance -->
|
|
62
|
+
> **Burden of proof.** Changing or removing this guardrail requires **refuting one of the conditions above with evidence**, not claiming that it got in the way. Friction is the gate's intended effect. Friction alone does not prove the gate is wrong. Same discipline as "a violated rule is not a wrong rule" (`ops/reflect.md § 2`).
|
|
63
|
+
<!-- /guidance -->
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: template
|
|
3
|
+
description: 'Template rendered during materialization: Learning: {{title — the lesson in one line}}.'
|
|
4
|
+
load: cold
|
|
5
|
+
renders_to: 'docs/learnings/*.md'
|
|
6
|
+
frontmatter_for_output: |
|
|
7
|
+
type: learning
|
|
8
|
+
description: '<one sentence: the lesson, and the area it applies to>'
|
|
9
|
+
load: warm
|
|
10
|
+
fires_on: file-shape
|
|
11
|
+
trigger_path: 'the glob whose files this lesson applies to'
|
|
12
|
+
fires_when: 'if you edit <area or path>, read this file first'
|
|
13
|
+
origin: 'the failure record (sig=<hash>) or the explicit user correction that recognized the failure'
|
|
14
|
+
recognized_by: 'the external signal: a red test, tsc, a command returning non-zero, or a user correction'
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Learning: {{title — the lesson in one line}}
|
|
18
|
+
|
|
19
|
+
<!-- guidance -->
|
|
20
|
+
> This is an instructive file for **other Claude sessions** (and developers). It holds one **conceptual** lesson from a real failure.
|
|
21
|
+
> This file belongs to the `docs/learnings/` family (v3.1.0+). It comes from the CRITIC loop (`remediate.md`) when the failure is conceptual or contextual. The value sits in the *cause*, not in a mechanical sequence of steps — that case belongs in a `procedure` instead. The hook `afm-pre-edit.sh` injects this file into future sessions by path match (see `trigger_path` and `fires_when` in the frontmatter). Keep one lesson per file.
|
|
22
|
+
<!-- /guidance -->
|
|
23
|
+
|
|
24
|
+
## What failed
|
|
25
|
+
|
|
26
|
+
{{The concrete symptom, anchored in the external signal — the command that returned ≠0, or the user's correction. Do not write "I thought I failed". CRITIC requires recognition by tool, not self-judgment.}}
|
|
27
|
+
|
|
28
|
+
## The lesson
|
|
29
|
+
|
|
30
|
+
{{The conceptual root cause and what to do differently. This is reusable knowledge — the "why", not only the "what". If another Claude session, without this session's context, needs this fact to avoid repeating the failure, it belongs here (#1).}}
|
|
31
|
+
|
|
32
|
+
## How to apply
|
|
33
|
+
|
|
34
|
+
{{What the next agent must do when it touches the trigger area. Keep this concrete and actionable.}}
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
<!-- guidance -->
|
|
39
|
+
> This file **does not become a hard rule** (it has no executable 0/1 trigger — a rule with a trigger belongs in `afm.md § 3`). It is **not a gotcha** either (a gotcha is an SDK or runtime surprise, a learning is a lesson from one's own failure). This file is injectable conceptual instruction. If the lesson later gains a mechanical trigger, promote it to a rule (`afm rule`). If 2 or more learnings converge on the same point, consider `afm generalize`.
|
|
40
|
+
<!-- /guidance -->
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: template
|
|
3
|
+
description: 'Template rendered during materialization: Procedure: {{title — what this runbook does}}.'
|
|
4
|
+
load: cold
|
|
5
|
+
renders_to: 'docs/procedures/*.md'
|
|
6
|
+
frontmatter_for_output: |
|
|
7
|
+
type: procedure
|
|
8
|
+
description: '<one sentence: what this runbook does>'
|
|
9
|
+
load: cold
|
|
10
|
+
fires_on: event | cadence
|
|
11
|
+
fires_when: 'the condition that starts this runbook, in one line: before cutting a release, when the build fails with X'
|
|
12
|
+
owner: 'who maintains this (optional, omit the key when nobody does)'
|
|
13
|
+
last_run: 'YYYY-MM-DD: update on each run (optional)'
|
|
14
|
+
origin: 'the failure record (sig=<hash>, recurred N times) or: operational sequence observed N times'
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Procedure: {{title — what this runbook does}}
|
|
18
|
+
|
|
19
|
+
<!-- guidance -->
|
|
20
|
+
> Repeatable runbook. A **mechanical** sequence of steps, each with a 0/1 check.
|
|
21
|
+
> Family `docs/procedures/`, since v3.1.0. It starts from a mechanical failure that
|
|
22
|
+
> recurred (CRITIC loop, `remediate.md`) OR from an operational sequence repeated
|
|
23
|
+
> 2+ times (release, deploy, migration). One responsibility per file, 300 lines max.
|
|
24
|
+
<!-- /guidance -->
|
|
25
|
+
|
|
26
|
+
## Preconditions
|
|
27
|
+
|
|
28
|
+
{{What must be true before you start. Reference `afm.md § 6.1` (pre-push) and current rules. Do not duplicate them — point to them.}}
|
|
29
|
+
|
|
30
|
+
## Steps
|
|
31
|
+
|
|
32
|
+
1. {{action}} — `{{command}}`
|
|
33
|
+
*Check:* `{{0/1 command}}` returns {{expected result}}.
|
|
34
|
+
2. {{action}} — `{{command}}`
|
|
35
|
+
*Check:* `{{0/1 command}}` returns {{expected result}}.
|
|
36
|
+
|
|
37
|
+
<!-- guidance -->
|
|
38
|
+
> Each step has a **command** and a **0/1 check**. A step with no executable check is not a procedure. It is prose, so it becomes a `learning` instead.
|
|
39
|
+
<!-- /guidance -->
|
|
40
|
+
|
|
41
|
+
## Rollback
|
|
42
|
+
|
|
43
|
+
{{How to undo safely if a step fails. Flag any irreversible external effect BEFORE the DB commit (saga ordering, `afm.md § 1.3`).}}
|
|
44
|
+
|
|
45
|
+
## Known gotchas
|
|
46
|
+
|
|
47
|
+
{{Links to the surprises in `docs/gotchas.md` that bite during this runbook. Do not copy them here — link to them.}}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: protocol
|
|
3
|
+
description: 'Template rendered during materialization: P1 — Autonomous Delivery.'
|
|
4
|
+
load: cold
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# P1 — Autonomous Delivery
|
|
8
|
+
|
|
9
|
+
> POC and MVP work. Speed and no interaction matter more than depth.
|
|
10
|
+
> **Granted per session, never by the repo** (`core/protocol.md` § 6).
|
|
11
|
+
|
|
12
|
+
| Field | Value |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| `plan` | `auto` |
|
|
15
|
+
| `exec` | `auto` |
|
|
16
|
+
| `RETRY_CAP` | 2 |
|
|
17
|
+
| `ROUND_CAP` | **0** |
|
|
18
|
+
| `MAX_DISCOVERY_ROUNDS` | 2 |
|
|
19
|
+
| `HALT_PER_PHASE` | off |
|
|
20
|
+
| `SUPPRESS_SUBGATES` | on |
|
|
21
|
+
| `UNKNOWN_POLICY` | `[ASSUMIDO: X — porque Y]` |
|
|
22
|
+
| `delegation` | full |
|
|
23
|
+
| `MAX_PARALLEL_SUBAGENTS` | 4 |
|
|
24
|
+
|
|
25
|
+
**What "autonomous" does NOT mean here:** a hard rule with an executable trigger still stays 0/1. Safety posture stays non-negotiable (`afm.md § 1.3`). P1 relaxes **depth**: coverage, edge-case exhaustiveness, and name refinement.
|
|
26
|
+
|
|
27
|
+
**How "no questions" works mechanically:** `ROUND_CAP = 0`. With no round available, every irreducible unknown falls to `UNKNOWN_POLICY`. It becomes an assumption **recorded in the artifact** — documented, never guessed in silence (principle #4).
|
|
28
|
+
|
|
29
|
+
**Cadence:** run `reflect` after each deliverable. Run `evolve` every 3-4 deliverables.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: protocol
|
|
3
|
+
description: 'Template rendered during materialization: P2 — Assisted Delivery.'
|
|
4
|
+
load: cold
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# P2 — Assisted Delivery
|
|
8
|
+
|
|
9
|
+
> pair programming. The human is the senior dev. The agent escalates early instead of continuing on a wrong path.
|
|
10
|
+
|
|
11
|
+
| Field | Value |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| `plan` | `assisted` |
|
|
14
|
+
| `exec` | `assisted` |
|
|
15
|
+
| `RETRY_CAP` | **1** |
|
|
16
|
+
| `ROUND_CAP` | 4 |
|
|
17
|
+
| `MAX_DISCOVERY_ROUNDS` | 3 |
|
|
18
|
+
| `HALT_PER_PHASE` | **on** |
|
|
19
|
+
| `SUPPRESS_SUBGATES` | **off** |
|
|
20
|
+
| `UNKNOWN_POLICY` | ask |
|
|
21
|
+
| `delegation` | none |
|
|
22
|
+
| `MAX_PARALLEL_SUBAGENTS` | **2** |
|
|
23
|
+
|
|
24
|
+
**P2 is compositional, not introspective.** It does not mean "ask when unsure". Self-reported confidence is not a mechanical trigger (principle #3). CRITIC shows that self-critique without an external tool degrades quality. P2 sets exactly three existing knobs: suppression off, `RETRY_CAP=1` (the first red escalates), and per-phase halt.
|
|
25
|
+
|
|
26
|
+
**Floor.** Below the feature-folder heuristic (`afm.md § 2.1`), the posture degrades to "report before you commit". Asking at every step of a trivial change adds noise. Noise makes people turn the protocol off, and that is worse than not having it.
|
|
27
|
+
|
|
28
|
+
**Cadence:** run `reflect` after each deliverable. Run `evolve` every 3 to 4 deliverables.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: protocol
|
|
3
|
+
description: 'Template rendered during materialization: P3 — Planned Autonomous Delivery.'
|
|
4
|
+
load: cold
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# P3 — Planned Autonomous Delivery
|
|
8
|
+
|
|
9
|
+
> the middle ground — P2 quality with P1 interaction. You plan together. The agent executes alone.
|
|
10
|
+
|
|
11
|
+
| Field | Phase 1 (planning) | Phase 2 (execution) |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| posture | `assisted` | `auto` |
|
|
14
|
+
| `RETRY_CAP` | 2 | 2 |
|
|
15
|
+
| `ROUND_CAP` | 2 | **0** |
|
|
16
|
+
| `HALT_PER_PHASE` | — | off |
|
|
17
|
+
| `SUPPRESS_SUBGATES` | off | on |
|
|
18
|
+
| `delegation` | read-only | full |
|
|
19
|
+
| `MAX_PARALLEL_SUBAGENTS` | **6** | 4 |
|
|
20
|
+
|
|
21
|
+
**Transition gate — the only gate. The criterion is mechanical.** `plan.md` and `tasks.md` have no **open** `[NEEDS CLARIFICATION:]` marker. `grep` returns 0 or 1. This is not a judgment call about plan quality.
|
|
22
|
+
|
|
23
|
+
The command is:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
sed 's/`[^`]*`//g' plan.md tasks.md | grep -c '\[NEEDS CLARIFICATION:'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The `sed` step is load-bearing. Without it, the gate is **vacuously red**. A plan that *mentions* the marker inside backticks — describing the gate itself, or citing an example — fails itself. This happened in delivery 001 of this repo, where the only "hit" was the line that documented the gate. A gate that fails because it talks about itself is as useless as a gate that passes without looking. Both teach the operator to ignore it.
|
|
30
|
+
|
|
31
|
+
**Why phase 2 can be autonomous:** every unknown was already decided in phase 1, and every critical point was already resolved. Execution is predictable and known. `ROUND_CAP = 0` in phase 2 makes this concrete. If something **outside the plan** appears, there is no question budget left. That case falls to the `deliver` stop table (rule 11, bright line, failure beyond `RETRY_CAP`), which escalates on external signal, not on confidence.
|
|
32
|
+
|
|
33
|
+
**Cadence (large initiative):** run `reflect` every 3-4 tasks. When you close the deliverable, run a general `reflect`, then `evolve`.
|
|
34
|
+
|
|
35
|
+
## The native Plan Mode is the mechanism, not the analogy
|
|
36
|
+
|
|
37
|
+
P3 **is** the shape of Claude Code's plan mode: assisted planning. Approval offers *"Yes, and use auto mode"* — a gate that transitions to autonomous execution. From v3.5.0 onward, this is not a comparison. It is the executed path.
|
|
38
|
+
|
|
39
|
+
| Moment | Mechanism |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| Enter phase 1 | `EnterPlanMode` |
|
|
42
|
+
| Transition gate | the `grep` 0/1 check above, over `plan.md`/`tasks.md` |
|
|
43
|
+
| Exit to phase 2 | `afm approve <feature>` on the consolidated plan — the recorded approval (sha256 of the plan) **is** the gate |
|
|
44
|
+
|
|
45
|
+
**Declared degradation.** If the harness has no native plan approval, P3 **does not stop**. It falls back to the path already described in `ops/deliver.md` Phase 1 (chat summary + one recommendation-first `afm ask deliver`). The transition criterion is the same `grep` check in both paths. The native mode changes the **approval surface**, never the criterion. A gate whose criterion depended on the mode being on would be posture, not mechanism.
|
|
46
|
+
|
|
47
|
+
**What the native mode buys you.** Phase 1 becomes read-only by construction of the harness, not by a promise from the model. `delegation: read-only` in phase 1 stops being cooperative prose and becomes a floor imposed from outside — exactly the "hard vs. soft" distinction in `core/protocol.md § 6`.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: template
|
|
3
|
+
description: 'Template rendered during materialization: Research — {{topic or area}}.'
|
|
4
|
+
load: cold
|
|
5
|
+
renders_to: 'docs/research/*.md'
|
|
6
|
+
frontmatter_for_output: |
|
|
7
|
+
type: research
|
|
8
|
+
description: '<one sentence: the question this research answers>'
|
|
9
|
+
load: cold
|
|
10
|
+
fires_on: op-call # a human never fires research directly — an op reads it to decide
|
|
11
|
+
fires_when: '<the question it answers, in one line — the sentence the body already states>'
|
|
12
|
+
date: 'YYYY-MM-DD'
|
|
13
|
+
context: 'free context: before bootstrap, during refactor, decide auth library'
|
|
14
|
+
status: draft | reviewed | applied
|
|
15
|
+
consumed_by: ADR-NNNN # ONLY once an ADR or feature used it: omit the key while `status: draft`
|
|
16
|
+
# and add it in the same edit that moves status to `applied`
|
|
17
|
+
# — a consumed dossier is not re-read.
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# Research — {{topic or area}}
|
|
21
|
+
|
|
22
|
+
<!-- guidance -->
|
|
23
|
+
{{Repeat the block below for each investigated topic.}}
|
|
24
|
+
<!-- /guidance -->
|
|
25
|
+
|
|
26
|
+
## {{topic 1 — concrete question}}
|
|
27
|
+
|
|
28
|
+
**Decision (proposed):** {{X}}
|
|
29
|
+
|
|
30
|
+
**Rationale:**
|
|
31
|
+
- {{bullet 1 with concrete evidence}}
|
|
32
|
+
- {{bullet 2}}
|
|
33
|
+
- {{bullet 3}}
|
|
34
|
+
|
|
35
|
+
**Alternatives considered:**
|
|
36
|
+
- **{{alt A}}** — rejected because {{concrete reason}}.
|
|
37
|
+
- **{{alt B}}** — rejected because {{reason}}.
|
|
38
|
+
|
|
39
|
+
**Sources:**
|
|
40
|
+
- {{real URL or reference}}
|
|
41
|
+
- {{real URL or reference}}
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
<!-- guidance -->
|
|
46
|
+
*Global research (not tied to a feature) feeds future PRD/ACH decisions or cross-project ADRs. To incorporate it:*
|
|
47
|
+
*1. Cite this research in any project doc that decides based on it (e.g. `prd.md` § 4 RFs, `ach.md` § 1 stack, a specific ADR).*
|
|
48
|
+
*2. If it becomes a load-bearing decision, turn it into an ADR via `afm adr`.*
|
|
49
|
+
*3. After you incorporate it, change this file's frontmatter `status` from `draft` to `applied`.*
|
|
50
|
+
<!-- /guidance -->
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: template
|
|
3
|
+
description: 'Template rendered during materialization: Session {{YYYY-MM-DD-HHMM}} — {{name}}.'
|
|
4
|
+
load: cold
|
|
5
|
+
renders_to: 'the session record in the state store'
|
|
6
|
+
frontmatter_for_output: |
|
|
7
|
+
type: session
|
|
8
|
+
description: 'Session {{YYYY-MM-DD-HHMM}} — {{name}}.'
|
|
9
|
+
load: cold
|
|
10
|
+
tier: dual
|
|
11
|
+
state: open
|
|
12
|
+
name: '{{human label — mechanical default = dominant subtree in files_touched; reflect refines it}}'
|
|
13
|
+
date: '{{YYYY-MM-DD}}'
|
|
14
|
+
claude_session_id: '{{FULL session id — pointer to the harness transcript}}'
|
|
15
|
+
cwd: '{{absolute path of the consumer project}}'
|
|
16
|
+
created_at: '{{ISO-8601 UTC}}'
|
|
17
|
+
reflection: '{{link to docs/evolution/<date>-NNN.md — what reflect found AND fixed in the local docs}}'
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# Session {{YYYY-MM-DD-HHMM}} — {{name}}
|
|
21
|
+
|
|
22
|
+
<!-- guidance -->
|
|
23
|
+
> **Two tiers in the same file** (v4/F9). The **handoff** block (`state`, `open_questions`, `next_steps`) is episodic and single-use. `state: open|consumed` governs **only this block**. The `reconcile` op consumes it. The rest is **durable telemetry**. It survives, it is versioned, and a plugin-repo agent reads it to improve AFM from real usage. It stays **outside** the `diagnose` A1–A7 axes. It is not a normative doc.
|
|
24
|
+
>
|
|
25
|
+
> **Two writers.** The `afm-session-end.sh` hook (`Stop`, 0-LLM) writes the skeleton and the mechanical fields for a session with work (non-empty `git diff`). `afm reflect` (§ 5.1) fills in the fields that need judgment: `name`, the two timeline sections, `afm_findings`, and `reflection:`. **A session without a `reflect` run keeps only the skeleton.** This is acceptable, not a defect.
|
|
26
|
+
>
|
|
27
|
+
> **File name ≠ `name:`.** The file is `<date>-<sid6>.md` (stable identity, dedup key, target of links already emitted). `name:` is a label and can be rewritten.
|
|
28
|
+
>
|
|
29
|
+
> ⚠️ **Hard rule 13 covers this directory.** The narrative cites commands. A command with a key inside becomes a versioned secret. Write the narrative with the secret removed.
|
|
30
|
+
<!-- /guidance -->
|
|
31
|
+
|
|
32
|
+
## files_touched
|
|
33
|
+
|
|
34
|
+
- {{`git diff --name-only HEAD`}}
|
|
35
|
+
|
|
36
|
+
## summary (events in this session)
|
|
37
|
+
|
|
38
|
+
- {{titles of the `s=<sid>` events for this session in the event ledger (the state store)}}
|
|
39
|
+
|
|
40
|
+
## what was asked
|
|
41
|
+
|
|
42
|
+
- {{reflect — what the agent UNDERSTOOD from the user's request, including where the reading changed midway. Interpretation, not transcription.}}
|
|
43
|
+
|
|
44
|
+
## how it was executed
|
|
45
|
+
|
|
46
|
+
- {{reflect — how AFM was used: ops run, rules that fired, where the harness helped and where it got in the way. No other artifact holds this data.}}
|
|
47
|
+
|
|
48
|
+
## afm_findings
|
|
49
|
+
|
|
50
|
+
- {{reflect/promote — what generalizes to the PLUGIN, in the format of `ops/promote.md` step 4 (title · `target:` · `evidence:` · `origin:` · why). An explicit empty result is valid.}}
|
|
51
|
+
|
|
52
|
+
## open_questions
|
|
53
|
+
|
|
54
|
+
- {{what stayed open — session state, not the same as a spec `[NEEDS CLARIFICATION:]`}}
|
|
55
|
+
|
|
56
|
+
## next_steps
|
|
57
|
+
|
|
58
|
+
- {{concrete next step / `T0NN` — points to tasks, does not change spec/plan/tasks}}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: template
|
|
3
|
+
description: 'Template rendered during materialization: .'
|
|
4
|
+
load: cold
|
|
5
|
+
renders_to: 'docs/ust.md'
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
### US-NNN — {{objective title, "[Persona] [verb] [outcome]"}}
|
|
9
|
+
|
|
10
|
+
- **Persona:** {{who, from PRD §3}}.
|
|
11
|
+
- **Pain:** {{1 sentence on the current workaround}}.
|
|
12
|
+
- **Story:** As {{persona}}, I want {{action}} to get {{measurable outcome}}.
|
|
13
|
+
|
|
14
|
+
**Acceptance criteria:**
|
|
15
|
+
|
|
16
|
+
```gherkin
|
|
17
|
+
Scenario: {{happy path scenario name}}
|
|
18
|
+
Given {{precondition}}
|
|
19
|
+
And {{extra precondition, if any}}
|
|
20
|
+
When {{user action}}
|
|
21
|
+
Then {{expected observable result}}
|
|
22
|
+
And {{verifiable side effect}}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```gherkin
|
|
26
|
+
Scenario: {{most likely error scenario}}
|
|
27
|
+
Given {{precondition}}
|
|
28
|
+
When {{user action in an invalid state}}
|
|
29
|
+
Then {{expected error, typed classification}}
|
|
30
|
+
And {{no DB side effect}}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Metadata:**
|
|
34
|
+
- **Priority:** P0 | P1 | P2
|
|
35
|
+
- **Status:** draft | ready | in_progress | done | cancelled
|
|
36
|
+
- **RF:** RF-NN
|
|
37
|
+
- **RNF:** RNF-NN (if applicable)
|
|
38
|
+
- **Success metric:** {{how to measure that the job was done}}
|
|
39
|
+
- **Dependencies:** US-NNN, US-NNN (if any)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hard rule 13 — a token or a secret never leaks, the docs/sessions/ narrative included.
|
|
3
|
+
# It is a gate because it is the cheapest error to make (the agent quotes the command it ran,
|
|
4
|
+
# and the command carried the key) and the most expensive to undo: a committed secret is a
|
|
5
|
+
# rotated secret.
|
|
6
|
+
set -u
|
|
7
|
+
MODE="${1:-staged}"
|
|
8
|
+
REPO="${AFM_GATE_REPO:-$PWD}"
|
|
9
|
+
. "${AFM_GATE_LIB:?}/scope.sh"
|
|
10
|
+
RC=0
|
|
11
|
+
|
|
12
|
+
# A secret in the ADDED lines. The awk tracks the current `+++ b/<file>` because "diff:7"
|
|
13
|
+
# locates no leak at all — and locating it fast is the point: a committed secret is a rotated
|
|
14
|
+
# secret, and the rotation starts by knowing which file to open.
|
|
15
|
+
scan() {
|
|
16
|
+
scope_diff "$MODE" | awk -v pat="$1" -v msg="$2" '
|
|
17
|
+
/^\+\+\+ b\// { f = substr($0, 7); next }
|
|
18
|
+
/^\+/ && $0 ~ pat { printf "13\t%s\t%s\n", (f == "" ? "(index)" : f), msg }
|
|
19
|
+
'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
OUT="$(scan "(token|secret|api[_-]?key|password|bearer)[[:space:]]*[:=][[:space:]]*[\"'"'"'][^\"'"'"']+" "key/value pair with a plaintext secret")
|
|
23
|
+
$(scan "(sk-[A-Za-z0-9]{16,}|ghp_[A-Za-z0-9]{20,}|AIza[A-Za-z0-9_-]{30,}|xox[baprs]-[A-Za-z0-9-]{10,}|eyJ[A-Za-z0-9_-]{20,}[.])" "token in a recognizable format (sk-/ghp_/AIza/xox/JWT)")"
|
|
24
|
+
if printf '%s' "$OUT" | grep -q .; then
|
|
25
|
+
printf '%s\n' "$OUT" | grep -v '^$'
|
|
26
|
+
RC=1
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
# A versioned .env. `.env.example` is legitimate and stays out.
|
|
30
|
+
while IFS= read -r f; do
|
|
31
|
+
case "$f" in *.env.example|*.env.sample) continue ;; esac
|
|
32
|
+
printf '13\t%s\ta .env file must not be versioned\n' "$f"
|
|
33
|
+
RC=1
|
|
34
|
+
done < <(scope_files "$MODE" | grep -E '(^|/)\.env')
|
|
35
|
+
|
|
36
|
+
exit $RC
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hard rule 21 (INALIENABLE) — code and tests are written in English.
|
|
3
|
+
# The trigger covers an identifier and a test name with a non-ASCII character. It does NOT
|
|
4
|
+
# cover unaccented Portuguese (an identifier without a diacritic passes) and it does not cover
|
|
5
|
+
# a comment — English prose uses em dashes and curly quotes, so non-ASCII inside a comment is
|
|
6
|
+
# noise, not signal. Since 3.9.0-rc.1 the comment is covered from the other side, by density,
|
|
7
|
+
# in `tools/afm-lang.sh`.
|
|
8
|
+
set -u
|
|
9
|
+
MODE="${1:-staged}"; : "$MODE" # COUNTING rule: the scope is the whole repo (see the gate lib scope.sh)
|
|
10
|
+
REPO="${AFM_GATE_REPO:-$PWD}"
|
|
11
|
+
. "${AFM_GATE_LIB:?}/scope.sh"
|
|
12
|
+
|
|
13
|
+
# `grep -P` is GNU. Without it the runner does NOT decide — and an abstention never becomes a
|
|
14
|
+
# failure, or the first machine without GNU grep turns the gate into a permanent block.
|
|
15
|
+
echo x | grep -qP 'x' 2>/dev/null || exit 2
|
|
16
|
+
|
|
17
|
+
RC=0
|
|
18
|
+
PAT='\b(?:function|class|const|let|var|def|interface|type|enum|describe|it|test)\b\s*\(?\s*["\x27]?[A-Za-z_$][\w$ ]*[^\x00-\x7F]'
|
|
19
|
+
while IFS= read -r f; do
|
|
20
|
+
[ -f "$REPO/$f" ] || continue
|
|
21
|
+
while IFS=: read -r n _; do
|
|
22
|
+
printf '21\t%s:%s\tidentifier or test name with a non-ASCII character\n' "$f" "$n"
|
|
23
|
+
RC=1
|
|
24
|
+
done < <(grep -nP "$PAT" "$REPO/$f" 2>/dev/null)
|
|
25
|
+
done < <(scope_all 'plugins/*/mcp/src/*')
|
|
26
|
+
|
|
27
|
+
exit $RC
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hard rule 35 — a rule with a 0/1 trigger has a versioned runner and sits in the gate.
|
|
3
|
+
# It is the rule that stops the gate from rotting: without it, someone adds a rule with a
|
|
4
|
+
# verification written in prose and the document goes back to promising what nobody runs.
|
|
5
|
+
set -u
|
|
6
|
+
: "${1:-staged}" # the rule is about the STRUCTURE of the gate, not about the diff
|
|
7
|
+
# The aggregator ships BESIDE this runner, in the plugin and in a materialized `docs/tools/gate/`
|
|
8
|
+
# alike, so `$0` resolves it in both. Until 3.20.0 this line read `$REPO/test/guardrails.sh` —
|
|
9
|
+
# one repository's path, hardcoded in a file meant to travel.
|
|
10
|
+
GATE="$(cd "$(dirname "$0")/.." && pwd)/guardrails.sh"
|
|
11
|
+
[ -x "$GATE" ] || { printf 'PLUGIN-35\tdocs/afm.md\tthe aggregator is not beside this runner at %s\n' "$GATE"; exit 2; }
|
|
12
|
+
|
|
13
|
+
OUT="$("$GATE" --repo "${AFM_GATE_REPO:-$PWD}" --audit 2>&1)"; RC=$?
|
|
14
|
+
[ "$RC" = 0 ] && exit 0
|
|
15
|
+
|
|
16
|
+
printf '%s\n' "$OUT" | grep -E '^ FAIL' | sed 's/^ FAIL — //' | while IFS= read -r l; do
|
|
17
|
+
printf 'PLUGIN-35\tdocs/afm.md\t%s\n' "$l"
|
|
18
|
+
done
|
|
19
|
+
exit 1
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hard rule 36 — a doc under docs/ carries no absolute path.
|
|
3
|
+
# A runbook holding a home directory of one user runs only on the machine of whoever wrote it,
|
|
4
|
+
# and the agent that reads it in a different clone either obeys the wrong path or hallucinates
|
|
5
|
+
# the correction. A relative path is what makes the markdown executable in any checkout.
|
|
6
|
+
#
|
|
7
|
+
# TWO exclusions, both structural and not "convenience":
|
|
8
|
+
#
|
|
9
|
+
# 1. `docs/sessions/` — the `cwd: <path>` line is LOAD-BEARING: afm-session-start.sh matches
|
|
10
|
+
# the pending handoff with `grep -lF "cwd: $PWD"`. Without the absolute path the
|
|
11
|
+
# cross-session handoff stops finding the right session. The directory also grows one entry
|
|
12
|
+
# per session, so a ratchet (which only decreases) would be broken by design.
|
|
13
|
+
#
|
|
14
|
+
# 2. The pattern requires a segment AFTER the user name. Without that, a doc that *describes*
|
|
15
|
+
# the trigger — this one — would accuse itself, and a rule that fails its own documentation
|
|
16
|
+
# is the first one to be turned off.
|
|
17
|
+
set -u
|
|
18
|
+
MODE="${1:-staged}"; : "$MODE" # COUNTING rule: the scope is the whole repo (see the gate lib scope.sh)
|
|
19
|
+
REPO="${AFM_GATE_REPO:-$PWD}"
|
|
20
|
+
. "${AFM_GATE_LIB:?}/scope.sh"
|
|
21
|
+
RC=0
|
|
22
|
+
|
|
23
|
+
while IFS= read -r f; do
|
|
24
|
+
[ -f "$REPO/$f" ] || continue
|
|
25
|
+
while IFS=: read -r n _; do
|
|
26
|
+
printf '36\t%s:%s\tabsolute path in a doc (use a path relative to the repo root)\n' "$f" "$n"
|
|
27
|
+
RC=1
|
|
28
|
+
done < <(grep -nE '(^|[^A-Za-z0-9_])(/home/[A-Za-z0-9._-]+/|/Users/[A-Za-z0-9._-]+/|[A-Z]:\\\\[A-Za-z0-9._-]+)' "$REPO/$f")
|
|
29
|
+
# Three exclusions, and all three are the same reason: a MACHINE-WRITTEN, append-only record
|
|
30
|
+
# whose content is evidence. `docs/sessions/` was excluded from the start. The other two were
|
|
31
|
+
# missed, and `.afm-log-failures/` proved it on 2026-09-03: the CRITIC hook recorded a failing
|
|
32
|
+
# command verbatim — which is the point of the record — and this rule then failed the tree over
|
|
33
|
+
# the absolute path inside that command. Rewriting the record to satisfy the rule would destroy
|
|
34
|
+
# the evidence the record exists to hold, and rules 17/18 forbid rewriting either substrate.
|
|
35
|
+
done < <(scope_all 'docs/*.md' 'docs/**/*.md' \
|
|
36
|
+
| grep -vE '^docs/(sessions|\.afm-log|\.afm-log-failures)/')
|
|
37
|
+
|
|
38
|
+
exit $RC
|