@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,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
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hard rule 37 — the prose of an artifact is English.
|
|
3
|
+
#
|
|
4
|
+
# It complements rule 21, which covers only an IDENTIFIER and a TEST NAME carrying a
|
|
5
|
+
# non-ASCII character. Rule 21 is blind to prose: a `.md` written entirely in Portuguese
|
|
6
|
+
# passes it clean, and that is exactly how this repo reached 2026-08 with 175 Portuguese
|
|
7
|
+
# doc files while the gate reported green.
|
|
8
|
+
#
|
|
9
|
+
# The measurement itself lives in `framework-template/tools/afm-lang.sh` and NOT here.
|
|
10
|
+
# Rule 34: one canonical source. The same threshold has to decide at `PreToolUse`, where
|
|
11
|
+
# the text is still a proposal, and at commit, where it is already a fact — two copies of
|
|
12
|
+
# a measured threshold drift apart in silence, and the commit gate would then contradict
|
|
13
|
+
# the hook that had just approved the write.
|
|
14
|
+
set -u
|
|
15
|
+
MODE="${1:-staged}"; : "$MODE" # COUNTING rule: the scope is the whole repo
|
|
16
|
+
REPO="${AFM_GATE_REPO:-$PWD}"
|
|
17
|
+
. "${AFM_GATE_LIB:?}/scope.sh"
|
|
18
|
+
. "${AFM_GATE_LIB:?}/ratchet.sh"
|
|
19
|
+
|
|
20
|
+
# Resolved through $0, not $REPO (see README "Resolve a sibling tool through $0"): the tool
|
|
21
|
+
# ships beside this directory both in the plugin (framework-template/tools/, two levels up from
|
|
22
|
+
# tools/gate/core-rules/) and in a materialized consumer (docs/tools/, same two levels up from
|
|
23
|
+
# docs/tools/gate/core-rules/). $REPO/plugins/afm/framework-template/tools/afm-lang.sh only
|
|
24
|
+
# exists when this very repository is being dogfooded through ./test/ — in a project bootstrapped
|
|
25
|
+
# by afm init it never exists, so this used to report "missing" against a tool that was right
|
|
26
|
+
# there at docs/tools/afm-lang.sh.
|
|
27
|
+
LANG_TOOL="$(dirname "$0")/../../afm-lang.sh"
|
|
28
|
+
if [ ! -x "$LANG_TOOL" ]; then
|
|
29
|
+
printf 'PLUGIN-37\t%s\tthe language tool is missing or not executable — rule 37 cannot be decided\n' \
|
|
30
|
+
"$LANG_TOOL"
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
RC=0
|
|
35
|
+
while IFS= read -r f; do
|
|
36
|
+
[ -f "$REPO/$f" ] || continue
|
|
37
|
+
# Exemptions live in the ratchet, never in this file. A `case` arm naming a path is an
|
|
38
|
+
# exclusion that only one repository can have, invisible to any reviewer who does not read
|
|
39
|
+
# the runner. See `ratchet_exempt` in `lib/ratchet.sh`.
|
|
40
|
+
ratchet_exempt PLUGIN-37 "$f" && continue
|
|
41
|
+
# An archived CHANGELOG is a frozen historical record everywhere, not a per-project choice,
|
|
42
|
+
# so it stays in code: it is a SHAPE, not a path.
|
|
43
|
+
case "$f" in */CHANGELOG-archive.md) continue ;; esac
|
|
44
|
+
D="$("$LANG_TOOL" --density "$REPO/$f" 2>/dev/null)" || continue
|
|
45
|
+
# Exit 1 is the accusation; exit 2 is "too short to be a ratio" and has to read as a pass.
|
|
46
|
+
# Collapsing the two reported 83 extra files on the first run of this delegation — every
|
|
47
|
+
# short eval fixture — because `if ! cmd` cannot tell an accusation from an abstention.
|
|
48
|
+
"$LANG_TOOL" --verdict --path "$f" "$REPO/$f" >/dev/null 2>&1; V=$?
|
|
49
|
+
if [ "$V" -eq 1 ]; then
|
|
50
|
+
printf '37\t%s\tPortuguese prose (density %s, %s hits in %s words)\n' \
|
|
51
|
+
"$f" "$(printf '%s' "$D" | cut -f3)" "$(printf '%s' "$D" | cut -f2)" "$(printf '%s' "$D" | cut -f1)"
|
|
52
|
+
RC=1
|
|
53
|
+
fi
|
|
54
|
+
done < <(scope_all '*.md')
|
|
55
|
+
|
|
56
|
+
exit $RC
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hard rule 38 — a Portuguese literal inside a script or inside a quoted marker.
|
|
3
|
+
#
|
|
4
|
+
# Why it exists: "the data was translated and the parser was not" was the MOST FREQUENT failure
|
|
5
|
+
# of the english-first migration, and NONE of the occurrences was caught by a gate. Three of
|
|
6
|
+
# them killed a mechanism in silence:
|
|
7
|
+
#
|
|
8
|
+
# - afm-health.sh matched the Portuguese "superseded by ADR-" heading while the ADRs said
|
|
9
|
+
# something else, so vital sign A4 (broken ADR chain) found zero, always.
|
|
10
|
+
# - ops/restructure.md read the Portuguese bite and last-bite fields while the template wrote
|
|
11
|
+
# `Bites:`/`last:`, so the dead-gotcha prune never found anything.
|
|
12
|
+
# - guardrails/README.md documented the Portuguese key names while the files used `signal:`
|
|
13
|
+
# and `trigger:`, so a new guardrail would be born invisible.
|
|
14
|
+
#
|
|
15
|
+
# The symptom never varies: the literal stays Portuguese and the target has already changed.
|
|
16
|
+
# Because the repo is english-first (rule 37), the HEURISTIC is cheap and precise — an accented
|
|
17
|
+
# word inside a `.sh`, or inside backticks in a plugin `.md`, is a candidate. It does not prove
|
|
18
|
+
# the drift; it points at where the drift lives. The human triages.
|
|
19
|
+
#
|
|
20
|
+
# It complements rule 37, which looks only at prose DENSITY in `.md` and is therefore blind both
|
|
21
|
+
# to `.sh` and to an isolated literal inside an English doc.
|
|
22
|
+
#
|
|
23
|
+
# Since 2026-08-27 `test/` is NO LONGER exempt. It used to be, by an explicit decision that the
|
|
24
|
+
# gates of this repo speak to the maintainer and are not distributed surface. Translating them
|
|
25
|
+
# found three dead mechanisms this exemption had been hiding for months — rule 34's check (a),
|
|
26
|
+
# the plugin-effect boundary in refs-lint, and the protocol assert in update-rehearsal — each one
|
|
27
|
+
# a parser left on a spelling nothing produces any more. The exemption was protecting exactly the
|
|
28
|
+
# files that most needed this rule.
|
|
29
|
+
set -u
|
|
30
|
+
MODE="${1:-staged}"; : "$MODE" # COUNTING rule: the scope is the whole repo
|
|
31
|
+
REPO="${AFM_GATE_REPO:-$PWD}"
|
|
32
|
+
. "${AFM_GATE_LIB:?}/scope.sh"
|
|
33
|
+
. "${AFM_GATE_LIB:?}/ratchet.sh"
|
|
34
|
+
|
|
35
|
+
# LC_ALL=C: the [À-ÿ] range is INVALID outside a UTF-8 locale and makes grep abort.
|
|
36
|
+
# The prototype of this runner swallowed that error with 2>/dev/null and reported "0 findings"
|
|
37
|
+
# over a corpus with 6 known cases — a gate that swallows its own error is indistinguishable
|
|
38
|
+
# from one that passed, which is exactly the bug hunted here.
|
|
39
|
+
# Hence: an explicit alternation, no range, and the grep NEVER goes to /dev/null.
|
|
40
|
+
export LC_ALL=C
|
|
41
|
+
PT='ã|ç|õ|á|é|í|ó|ú|â|ê|ô|à|Ã|Ç|Õ|Á|É|Í|Ó|Ú|Â|Ê|Ô|À|ambos|planejada|gatilho|Gatilho'
|
|
42
|
+
|
|
43
|
+
RC=0
|
|
44
|
+
report() { printf '38\t%s\t%s\n' "$1" "$2"; RC=1; }
|
|
45
|
+
|
|
46
|
+
# --- 1. shell: any accented word (a comment included: it is instruction) ------
|
|
47
|
+
while IFS= read -r f; do
|
|
48
|
+
[ -f "$REPO/$f" ] || continue
|
|
49
|
+
# Exemptions live in the ratchet, never in this file. A `case` arm naming a path is an
|
|
50
|
+
# exclusion that only one repository can have, invisible to any reviewer who does not read
|
|
51
|
+
# the runner. See `ratchet_exempt` in `lib/ratchet.sh`.
|
|
52
|
+
ratchet_exempt PLUGIN-38 "$f" && continue
|
|
53
|
+
n=$(grep -cE "$PT" "$REPO/$f") || n=0
|
|
54
|
+
[ "$n" -gt 0 ] && report "$f" "${n} line(s) with a Portuguese literal in a script"
|
|
55
|
+
done < <(scope_all '*.sh')
|
|
56
|
+
|
|
57
|
+
# --- 2. plugin markdown: a backticked literal (marker candidate) -------------
|
|
58
|
+
while IFS= read -r f; do
|
|
59
|
+
[ -f "$REPO/$f" ] || continue
|
|
60
|
+
# Exemptions live in the ratchet, never in this file. A `case` arm naming a path is an
|
|
61
|
+
# exclusion that only one repository can have, invisible to any reviewer who does not read
|
|
62
|
+
# the runner. See `ratchet_exempt` in `lib/ratchet.sh`.
|
|
63
|
+
ratchet_exempt PLUGIN-38 "$f" && continue
|
|
64
|
+
# These three are SHAPES that hold in any AFM instance, not paths one project happens to
|
|
65
|
+
# have, so they stay in code: a changelog is a historical record; `core/afm.md` quotes a
|
|
66
|
+
# Portuguese identifier as the example of what rule 21 forbids, and the example has to be
|
|
67
|
+
# wrong to be an example; `ops/deliver.md` lists the override phrases, which are USER SPEECH.
|
|
68
|
+
case "$f" in
|
|
69
|
+
*CHANGELOG.md|*CHANGELOG-archive.md) continue ;;
|
|
70
|
+
*/core/afm.md|*/ops/deliver.md|*/ops/update.md) continue ;;
|
|
71
|
+
esac
|
|
72
|
+
# REAL backtick pairing: splitting on the backtick leaves the EVEN fields inside the code
|
|
73
|
+
# span. A naive grep for a backtick, anything, a Portuguese word, anything, a backtick also
|
|
74
|
+
# matches the SPACE BETWEEN two spans — that is how the first version reported a French loan
|
|
75
|
+
# phrase as a Portuguese marker.
|
|
76
|
+
n=$(awk -v pat="$PT" '
|
|
77
|
+
{ k=split($0, S, "`"); for (i=2; i<=k; i+=2) if (S[i] ~ pat) c++ }
|
|
78
|
+
END { print c+0 }' "$REPO/$f")
|
|
79
|
+
[ "$n" -gt 0 ] && report "$f" "${n} backticked Portuguese literal(s)"
|
|
80
|
+
done < <(scope_all 'plugins/*/**/*.md' 'plugins/*/*.md')
|
|
81
|
+
|
|
82
|
+
exit $RC
|