plain-forge 1.0.24-next.2f8299c → 1.0.24-next.7618d65
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/README.md +3 -3
- package/forge/skills/add-feature/SKILL.md +7 -6
- package/forge/skills/add-feature/references/checklist.md +2 -2
- package/forge/skills/add-functional-spec/SKILL.md +13 -9
- package/forge/skills/add-functional-specs/SKILL.md +13 -9
- package/forge/skills/add-resource/SKILL.md +2 -1
- package/forge/skills/add-test-requirement/SKILL.md +3 -3
- package/forge/skills/add-test-scenarios/SKILL.md +98 -0
- package/forge/skills/analyze-func-specs/SKILL.md +1 -1
- package/forge/skills/analyze-if-func-spec-too-complex/SKILL.md +43 -23
- package/forge/skills/break-down-func-spec/SKILL.md +56 -32
- package/forge/skills/check-plain-env/SKILL.md +1 -1
- package/forge/skills/consolidate-concepts/SKILL.md +7 -7
- package/forge/skills/create-requires-module/SKILL.md +5 -2
- package/forge/skills/debug-specs/SKILL.md +13 -7
- package/forge/skills/forge-plain/SKILL.md +2 -2
- package/forge/skills/forge-plain/references/checklist.md +3 -3
- package/forge/skills/forge-plain/references/phase-1-product.md +2 -2
- package/forge/skills/forge-plain/references/phase-2-tech.md +1 -1
- package/forge/skills/forge-plain/references/phase-3-testing.md +5 -5
- package/forge/skills/init-config-file/SKILL.md +2 -2
- package/forge/skills/init-plain-project/SKILL.md +5 -5
- package/forge/skills/load-plain-reference/SKILL.md +5 -3
- package/forge/skills/load-plain-reference/references/project-model.md +2 -1
- package/forge/skills/load-plain-reference/references/rendering-and-testing.md +7 -5
- package/forge/skills/load-plain-reference/rules/bullet-continuation.md +11 -11
- package/forge/skills/load-plain-reference/rules/concise-specs-examples.md +100 -69
- package/forge/skills/load-plain-reference/rules/concise-specs-integration-examples.md +39 -24
- package/forge/skills/load-plain-reference/rules/concise-specs.md +3 -2
- package/forge/skills/load-plain-reference/rules/func-specs.md +37 -28
- package/forge/skills/load-plain-reference/rules/impl-reqs.md +1 -1
- package/forge/skills/load-plain-reference/rules/linked-resources.md +7 -4
- package/forge/skills/load-plain-reference/rules/module-structure.md +16 -9
- package/forge/skills/load-plain-reference/rules/requires-modules.md +1 -0
- package/forge/skills/load-plain-reference/rules/semantic-ids.md +47 -0
- package/forge/skills/load-plain-reference/rules/test-plain-files.md +67 -0
- package/forge/skills/load-plain-reference/rules/test-reqs.md +6 -6
- package/forge/skills/plain-healthcheck/SKILL.md +30 -12
- package/forge/skills/refactor-module/SKILL.md +15 -15
- package/forge/skills/resolve-section-ownership/SKILL.md +2 -2
- package/forge/skills/resolve-spec-conflict/SKILL.md +13 -7
- package/package.json +1 -1
- package/forge/skills/add-acceptance-test/SKILL.md +0 -101
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ Pick whichever entry point matches how much upfront design you want:
|
|
|
20
20
|
### 2. Grow an existing project
|
|
21
21
|
|
|
22
22
|
- **`add-feature`** — takes a feature request in plain English and runs the same one-question-at-a-time loop that `forge-plain` uses, scoped to a single feature against an existing `.plain` file.
|
|
23
|
-
- **Per-section authoring skills** — `add-functional-spec`, `add-functional-specs`, `add-implementation-requirement`, `add-test-requirement`, `add-concept`, `add-
|
|
23
|
+
- **Per-section authoring skills** — `add-functional-spec`, `add-functional-specs`, `add-implementation-requirement`, `add-test-requirement`, `add-concept`, `add-test-scenarios`, `add-resource`, `add-template`. Each enforces the relevant ***plain syntax rules (concept uniqueness, complexity limits, bullet syntax, linked-resource constraints, …) so hand-authoring doesn't drift from the language. `add-test-scenarios` writes the test plain file of a functionality — by convention `tests/<module>/<func-id>.plain` — with the conformance and acceptance scenarios the renderer implements, and nothing else.
|
|
24
24
|
- **Module-management skills** — `create-import-module`, `create-requires-module`, `refactor-module`, `consolidate-concepts` for restructuring as the project grows.
|
|
25
25
|
|
|
26
26
|
### 3. Validate and maintain
|
|
@@ -279,7 +279,7 @@ On `install`, the CLI reads `forge/skills` and `forge/rules` and writes them int
|
|
|
279
279
|
| `add-implementation-requirement` | Add a non-functional requirement to `***implementation reqs***` |
|
|
280
280
|
| `add-test-requirement` | Add a testing requirement to `***test reqs***` |
|
|
281
281
|
| `add-concept` | Define a new concept in `***definitions***` |
|
|
282
|
-
| `add-
|
|
282
|
+
| `add-test-scenarios` | Write or update the test plain file of a functionality (by convention `tests/<module>/<func-id>.plain`): conformance scenarios for its expected use and, when asked, acceptance scenarios for its unexpected use, in plain English |
|
|
283
283
|
| `add-resource` | Link an external file (schema, API spec) to a spec |
|
|
284
284
|
| `add-template` | Create or include a reusable Liquid template |
|
|
285
285
|
|
|
@@ -297,7 +297,7 @@ On `install`, the CLI reads `forge/skills` and `forge/rules` and writes them int
|
|
|
297
297
|
| Skill | Description |
|
|
298
298
|
|-------|-------------|
|
|
299
299
|
| `init-config-file` | Build / finalize the project's `config.yaml` file(s) from the decisions made in Phase 3. Knows the full set of valid keys, refuses to write secrets or per-invocation options, and produces one config per part of the project. Run at the end of `forge-plain` (just before `plain-healthcheck`) and any time the testing surface changes. |
|
|
300
|
-
| `plain-healthcheck` | Verification gate: validates every `config.yaml`, confirms each `*-script` field points at a real file in `test_scripts/`, runs `plain-parser check` on every top module, and checks every module against the rules. Run whenever anything in the project is finalized — at the end of `forge-plain`, at the end of `add-feature`, after `debug-specs`, and after any single-skill edit that touches the renderable surface. |
|
|
300
|
+
| `plain-healthcheck` | Verification gate: validates every `config.yaml`, confirms each `*-script` field points at a real file in `test_scripts/`, runs `plain-parser check` on every top module, and checks every module and test plain file against the rules. Run whenever anything in the project is finalized — at the end of `forge-plain`, at the end of `add-feature`, after `debug-specs`, and after any single-skill edit that touches the renderable surface. |
|
|
301
301
|
| `check-plain-env` | Read the project's `.plain` files, `test_scripts/`, `config.yaml`(s), and `resources/`, then probe the host for every requirement **the package manager can't install**: language toolchains (`python` + `pip`, `node` + `npm`, JDK + `mvn`, Go, Rust, .NET, etc.), external services (Postgres, Redis, Docker, ...), system binaries that language packages wrap (`ffmpeg`, `tesseract`, `pdftoppm`, browser binaries, ...), hardware / drivers / accelerators (NVIDIA driver → CUDA toolkit → cuDNN → framework-sees-GPU chain), credential env vars, and `plain-parser`. Does **not** probe individual language packages — `pip install -r requirements.txt` (and equivalents) handle those when the test scripts run. Emits a `PASS` / `WARN` / `FAIL` report with OS-specific install commands for any gaps. Read-only — never installs anything. Run on first-time setup, before rendering on a new machine, after adding a new tech to a project, or any time `command not found` shows up in test output. |
|
|
302
302
|
| `analyze-if-func-spec-too-complex` | Check if a spec exceeds the 200-line complexity limit |
|
|
303
303
|
| `analyze-func-specs` | Check a batch of specs (2+) against each other in one call and return every conflicting pair |
|
|
@@ -4,7 +4,7 @@ description: >-
|
|
|
4
4
|
End-to-end feature addition on an existing ***plain project: runs a short feature-intent
|
|
5
5
|
interview, then takes the confirmed request and, one question at a time, incrementally writes
|
|
6
6
|
***plain specs (concepts, implementation reqs, functional specs, test reqs,
|
|
7
|
-
|
|
7
|
+
test scenarios) to disk — asking, authoring, and reviewing per
|
|
8
8
|
functionality — then closes with a plain-healthcheck gate. Use when the user
|
|
9
9
|
wants to add a feature to an existing project. Not for bootstrapping a new
|
|
10
10
|
project from scratch (use forge-plain) or for editing generated code (the
|
|
@@ -49,7 +49,7 @@ Carry the confirmed brief into every later phase. Before advancing, check the Ph
|
|
|
49
49
|
Keep this short. The goal is to know enough to ask the **very first** writable question — not to design the whole feature on paper.
|
|
50
50
|
|
|
51
51
|
1. **Read the confirmed feature-intent brief.** Identify which existing `.plain` file(s) the feature most likely belongs to.
|
|
52
|
-
2. **Read the target `.plain` file(s)**, following their `import` and `requires` chains, so the existing definitions, implementation reqs, functional specs, test reqs, and
|
|
52
|
+
2. **Read the target `.plain` file(s)**, following their `import` and `requires` chains, and the module's test plain files, so the existing definitions, implementation reqs, functional specs, test reqs, and scenarios are in context. This is what lets Phase 2 recognize impact when it surfaces.
|
|
53
53
|
3. **Pick the target module with one question — only if it is genuinely ambiguous** which file to modify. Otherwise skip it and start authoring immediately.
|
|
54
54
|
|
|
55
55
|
End Phase 1 the moment the target file and a single concrete starter question are clear. Do **not** ask framing, scope, or multi-part design questions here.
|
|
@@ -77,15 +77,16 @@ Route each answer to the right edit skill — never hand-author a `***plain` sec
|
|
|
77
77
|
|
|
78
78
|
- **New concept** → `add-concept` (into `***definitions***`; define before any reference).
|
|
79
79
|
- **New functional spec** → `add-functional-spec`. It runs `analyze-if-func-spec-too-complex` and `analyze-func-specs` for you — let it. **Never hand-author functional specs.** If it reports the spec is too complex, ask the user a follow-up question to split it (the next loop iteration) — do not break it down alone.
|
|
80
|
+
- **Changed functional spec** → edit its statement line or `- ` bullets in place, then invoke `add-test-scenarios` so its test plain file follows the new text.
|
|
80
81
|
- **New implementation req** → `add-implementation-requirement`. When the answer states HOW the functionality is built — a retry or error-handling policy, a data format, a library, an architectural pattern — and it is not already in the file or its imports.
|
|
81
|
-
- **New
|
|
82
|
+
- **New test scenario** → `add-test-scenarios`, on the functionality's test plain file. Only when the *Conformance gate* is satisfied and the answer describes a concrete verification.
|
|
82
83
|
- **New test req** → `add-test-requirement`. Only when conformance testing is configured and the answer changes how conformance tests are run.
|
|
83
84
|
|
|
84
85
|
If the answer contradicts or refines an earlier snippet, fix that snippet in place now (per *Fix contradictions in place* above).
|
|
85
86
|
|
|
86
87
|
### 2c. Handle conflicts just-in-time
|
|
87
88
|
|
|
88
|
-
If `add-functional-spec` (via its analyzers) reports a conflict, or the snippet just written would **break** (contradict, invalidate) or **augment** (change the meaning of, add behavior to) an existing concept / functional spec / implementation req / test req /
|
|
89
|
+
If `add-functional-spec` (via its analyzers) reports a conflict, or the snippet just written would **break** (contradict, invalidate) or **augment** (change the meaning of, add behavior to) an existing concept / functional spec / implementation req / test req / test scenario, the **next question** must be about that conflict. Show the exact existing snippet in the question and offer:
|
|
89
90
|
|
|
90
91
|
- **(a) keep** the existing spec — back out or narrow what was just written,
|
|
91
92
|
- **(b) augment** the existing spec — embed the proposed new wording in the question,
|
|
@@ -99,7 +100,7 @@ Ask the user whether the feature is fully covered. Yes → Phase 3. No → retur
|
|
|
99
100
|
|
|
100
101
|
### Conformance gate
|
|
101
102
|
|
|
102
|
-
Author `***test reqs***` and
|
|
103
|
+
Author `***test reqs***` and test plain files **only** when the project has a `config.yaml` with a valid `conformance-tests-script` entry pointing at an existing script in `test_scripts/`. Check the `config.yaml` that covers this module (multi-part projects may have several) and confirm the referenced script exists. If conformance testing is not configured, skip those two authoring paths entirely — concepts, functional specs, and implementation reqs are still authored normally.
|
|
103
104
|
|
|
104
105
|
## Phase 3 — Final review
|
|
105
106
|
|
|
@@ -111,7 +112,7 @@ Most checks already happened in the loop; this is a slim consistency pass whose
|
|
|
111
112
|
- Chronological ordering is correct end-to-end — no spec depends on something that comes after it.
|
|
112
113
|
- Functional specs are language-agnostic.
|
|
113
114
|
- Every external interface is explicit (endpoint paths, methods, CLI args, formats).
|
|
114
|
-
-
|
|
115
|
+
- Every new or changed functionality has a test plain file whose scenarios follow from its spec, with at least one conformance scenario when conformance tests are enabled.
|
|
115
116
|
3. Present the final diff for the modified file(s) and get the user's approval.
|
|
116
117
|
4. If the user requests changes, drop **straight back into the one-question loop** — one question, one write, one fix at a time. Do not restart the loop from scratch.
|
|
117
118
|
5. **Run `plain-healthcheck`** — the last check this skill runs. It validates every `config.yaml`, runs `plain-parser check` on every top module, and checks every module against the rules, so a feature is never finished while the project would fail to render. If it returns `FAIL`, work through its numbered list (fixing only `.plain` files / `config.yaml` / scripts — never generated code) by dropping back into the loop, then re-run. Repeat until `PASS`. Only then tell the user the feature is ready to render as `<module>.plain`.
|
|
@@ -27,12 +27,12 @@ Use this to verify the workflow was followed — never as a substitute for it. R
|
|
|
27
27
|
- [ ] New concepts defined before they are referenced, with no circular references.
|
|
28
28
|
- [ ] Any answer that contradicted an earlier snippet was fixed in place before the next question — no stale intent left on disk.
|
|
29
29
|
- [ ] Every conflict / break / augment surfaced by the analyzers was put to the user as the *next* question (keep / augment / replace) and resolved before continuing.
|
|
30
|
-
- [ ] `***test reqs***` /
|
|
30
|
+
- [ ] `***test reqs***` / test plain files authored only when the Conformance gate holds (a `config.yaml` with a valid `conformance-tests-script` pointing at an existing script).
|
|
31
31
|
- [ ] Asked the user whether the feature is fully covered before leaving the loop.
|
|
32
32
|
|
|
33
33
|
## Phase 3 — Final review
|
|
34
34
|
|
|
35
35
|
- [ ] Read the modified `.plain` file(s) in full.
|
|
36
|
-
- [ ] Verified: concepts defined before use, no cycles, chronological ordering correct end-to-end, functional specs language-agnostic, every external interface explicit (endpoints, methods, CLI args, formats),
|
|
36
|
+
- [ ] Verified: concepts defined before use, no cycles, chronological ordering correct end-to-end, functional specs language-agnostic, every external interface explicit (endpoints, methods, CLI args, formats), every new or changed functionality's test plain file in step with its spec.
|
|
37
37
|
- [ ] Presented the final diff and got the user's approval (change requests dropped back into the one-question loop, not a restart).
|
|
38
38
|
- [ ] Ran `plain-healthcheck`; worked its numbered list to `PASS` (fixing only `.plain`/`config.yaml`/scripts — never generated code) before declaring the feature ready and reminding the user to re-render `<module>.plain`.
|
|
@@ -19,11 +19,12 @@ description: >-
|
|
|
19
19
|
|
|
20
20
|
1. **Identify the target `.plain` file.** If ambiguous, ask the user.
|
|
21
21
|
2. **Read the entire file** to understand existing definitions, implementation reqs, and all current functional specs (including those in `requires` modules).
|
|
22
|
-
3. **
|
|
22
|
+
3. **Pick the func-id and draft the functional spec.** Choose a func-id per `semantic-ids.md` and confirm no `# <func-id>` heading with that id exists in the module. Draft the body, a statement line and any detail under it, following the rules below, then run the review pass in `concise-specs.md` over the draft — trim it to the shortest wording that keeps every fact before any other check.
|
|
23
23
|
4. **Analyze complexity** — use the `analyze-if-func-spec-too-complex` skill to verify the drafted spec implies ≤ 200 LOC. If too complex, use the `break-down-func-spec` skill to split it, then repeat from step 3 for each resulting spec.
|
|
24
24
|
5. **Check for conflicts** with every existing functional spec — this is critical. Run `analyze-func-specs` **once** with the new spec plus all existing specs (in the file and in any `requires` chain) as a single batch. The batched analyzer returns every conflicting pair in one call — do **not** invoke a pair-by-pair analyzer. For each conflicting pair it reports, run `resolve-spec-conflict` on that pair; re-run `analyze-func-specs` over the touched set after each resolution until the verdict is `COMPATIBLE`.
|
|
25
|
-
6. **Append the spec** to the end of the `***functional specs***` section (specs are chronological; new ones go last).
|
|
25
|
+
6. **Append the spec** to the end of the `***functional specs***` section as a `# <func-id>` heading followed by its body, one blank line after the previous functionality (specs are chronological; new ones go last).
|
|
26
26
|
7. **Read the file again** to confirm correct placement and syntax.
|
|
27
|
+
8. **Write the test plain file.** When conformance tests are enabled for the module, invoke `add-test-scenarios` for the new functionality (see *Test Scenarios* below).
|
|
27
28
|
|
|
28
29
|
## Rules
|
|
29
30
|
|
|
@@ -48,15 +49,16 @@ The new spec must not contradict any existing functional spec. Conflicting specs
|
|
|
48
49
|
|
|
49
50
|
### Disambiguation
|
|
50
51
|
|
|
51
|
-
Each functional spec must be unambiguous — the renderer should have only one reasonable interpretation. If
|
|
52
|
+
Each functional spec must be unambiguous — the renderer should have only one reasonable interpretation. If the statement line is not enough to fully disambiguate the behavior, add `- ` bullets or sentences under it. The detail clarifies the statement; it does not introduce separate functionality. Even with the detail, the spec must still imply ≤ 200 LOC.
|
|
52
53
|
|
|
53
54
|
```plain
|
|
54
55
|
***functional specs***
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
# send-message
|
|
58
|
+
A :User: can send a :Message: to a :Conversation:.
|
|
59
|
+
- A :Message: must have non-empty content.
|
|
60
|
+
- The :Message: is appended to the end of the :Conversation:.
|
|
61
|
+
- All :Participant: members of the :Conversation: can see the new :Message:.
|
|
60
62
|
```
|
|
61
63
|
|
|
62
64
|
|
|
@@ -68,9 +70,9 @@ Specs must be detailed enough that a developer can use the built software withou
|
|
|
68
70
|
|
|
69
71
|
Functionality must be self-contained in the spec text. `requires` modules only import functional specs, so do not rely on implementation reqs to convey behavior — they won't be visible in downstream modules.
|
|
70
72
|
|
|
71
|
-
##
|
|
73
|
+
## Test Scenarios
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
After inserting the spec, invoke `add-test-scenarios` for it. It writes the functionality's test plain file (by convention `tests/<module>/<func-id>.plain`) with at least one conformance scenario when conformance tests are enabled for the module.
|
|
74
76
|
|
|
75
77
|
## Validation Checklist
|
|
76
78
|
|
|
@@ -83,3 +85,5 @@ If the functional spec needs verification, use the `add-acceptance-test` skill t
|
|
|
83
85
|
- [ ] Trimmed per `concise-specs.md`: nothing obvious, no rationale, no uncheckable adjectives or hedges, plain words throughout
|
|
84
86
|
- [ ] No redundancy with existing specs
|
|
85
87
|
- [ ] Placed in correct chronological position (usually at the end)
|
|
88
|
+
- [ ] The func-id follows `semantic-ids.md` and is unique in the module
|
|
89
|
+
- [ ] `add-test-scenarios` was invoked for the new functionality when conformance tests are enabled
|
|
@@ -28,7 +28,7 @@ This skill is `add-functional-spec` applied **one spec at a time, in order**, wi
|
|
|
28
28
|
|
|
29
29
|
1. **Identify the target `.plain` file.** If ambiguous, ask the user.
|
|
30
30
|
2. **Read the entire file** to understand existing definitions, implementation reqs, and all current functional specs (including those reachable via `import` / `requires`).
|
|
31
|
-
3. **Draft all the specs you intend to add**, in the chronological order they should appear. Keep the drafts in a working list — nothing is inserted yet. Run the review pass in `concise-specs.md` over every draft before continuing; trim each to the shortest wording that keeps every fact.
|
|
31
|
+
3. **Draft all the specs you intend to add**, in the chronological order they should appear, each with its own func-id per `semantic-ids.md`, unique in the module and within the batch. Keep the drafts in a working list — nothing is inserted yet. Run the review pass in `concise-specs.md` over every draft before continuing; trim each to the shortest wording that keeps every fact.
|
|
32
32
|
4. **For each drafted spec, in order:**
|
|
33
33
|
1. **Analyze complexity.** Run `analyze-if-func-spec-too-complex` on the spec. If the verdict is `TOO COMPLEX`, run `break-down-func-spec`, replace the entry in the working list with the resulting smaller specs (preserving order), and restart this step on the first of the replacements.
|
|
34
34
|
2. **Check for conflicts.** Run `analyze-func-specs` **once** with this single input set:
|
|
@@ -37,8 +37,9 @@ This skill is `add-functional-spec` applied **one spec at a time, in order**, wi
|
|
|
37
37
|
- every spec from this batch that has already been inserted.
|
|
38
38
|
|
|
39
39
|
The batched analyzer returns every conflicting pair in one call — do **not** loop over pairs invoking a per-pair analyzer. For each conflicting pair it reports, run `resolve-spec-conflict`. Apply the resolution — which may revise the new spec, an existing spec, or both — then re-run `analyze-func-specs` once over the touched set until the verdict is `COMPATIBLE`.
|
|
40
|
-
3. **Append the spec** to the `***functional specs***` section. Specs are chronological; the new entry goes at the end (unless an earlier existing spec must come *after* it — in that rare case, insert at the correct position).
|
|
40
|
+
3. **Append the spec** to the `***functional specs***` section as a `# <func-id>` heading followed by its body. Specs are chronological; the new entry goes at the end (unless an earlier existing spec must come *after* it — in that rare case, insert at the correct position).
|
|
41
41
|
5. **Read the file again** to confirm correct placement, ordering, and syntax for the full batch.
|
|
42
|
+
6. **Write the test plain files.** When conformance tests are enabled for the module, invoke `add-test-scenarios` once per inserted functionality, in order.
|
|
42
43
|
|
|
43
44
|
Order matters: each new spec is inserted only after its complexity and conflict checks pass, so subsequent specs in the batch are always checked against an already-validated file.
|
|
44
45
|
|
|
@@ -71,15 +72,16 @@ That coverage is achieved by running `analyze-func-specs` **once per spec being
|
|
|
71
72
|
|
|
72
73
|
### Disambiguation (per spec)
|
|
73
74
|
|
|
74
|
-
Each functional spec must be unambiguous — the renderer should have only one reasonable interpretation. If
|
|
75
|
+
Each functional spec must be unambiguous — the renderer should have only one reasonable interpretation. If the statement line is not enough to fully disambiguate the behavior, add `- ` bullets or sentences under it. The detail clarifies the statement; it does not introduce separate functionality. Even with the detail, the spec must still imply ≤ 200 LOC.
|
|
75
76
|
|
|
76
77
|
```plain
|
|
77
78
|
***functional specs***
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
# send-message
|
|
81
|
+
A :User: can send a :Message: to a :Conversation:.
|
|
82
|
+
- A :Message: must have non-empty content.
|
|
83
|
+
- The :Message: is appended to the end of the :Conversation:.
|
|
84
|
+
- All :Participant: members of the :Conversation: can see the new :Message:.
|
|
83
85
|
```
|
|
84
86
|
|
|
85
87
|
|
|
@@ -91,9 +93,9 @@ Specs must be detailed enough that a developer can use the built software withou
|
|
|
91
93
|
|
|
92
94
|
Functionality must be self-contained in the spec text. `requires` modules only import functional specs, so do not rely on implementation reqs to convey behavior — they won't be visible in downstream modules.
|
|
93
95
|
|
|
94
|
-
##
|
|
96
|
+
## Test Scenarios
|
|
95
97
|
|
|
96
|
-
|
|
98
|
+
After the batch has been inserted, invoke `add-test-scenarios` once per inserted functionality, in order. It writes each functionality's test plain file (by convention `tests/<module>/<func-id>.plain`) with at least one conformance scenario when conformance tests are enabled for the module. Do this per spec, not as part of the bulk pass.
|
|
97
99
|
|
|
98
100
|
## Anti-Patterns
|
|
99
101
|
|
|
@@ -117,3 +119,5 @@ If any of the newly added functional specs need verification, use the `add-accep
|
|
|
117
119
|
- [ ] Every spec trimmed per `concise-specs.md`: nothing obvious, no rationale, no uncheckable adjectives or hedges, plain words throughout
|
|
118
120
|
- [ ] No redundancy with existing specs or within the batch
|
|
119
121
|
- [ ] Specs placed in correct chronological positions
|
|
122
|
+
- [ ] Every func-id follows `semantic-ids.md` and is unique in the module and within the batch
|
|
123
|
+
- [ ] `add-test-scenarios` was invoked for every inserted functionality when conformance tests are enabled
|
|
@@ -35,7 +35,8 @@ Use standard markdown link syntax inside any spec section:
|
|
|
35
35
|
|
|
36
36
|
***functional specs***
|
|
37
37
|
|
|
38
|
-
-
|
|
38
|
+
# expose-api
|
|
39
|
+
An API conforming to the [API specification](resources/api_spec.yaml) is exposed.
|
|
39
40
|
```
|
|
40
41
|
|
|
41
42
|
## Path Rules
|
|
@@ -33,7 +33,7 @@ Test reqs specify how **conformance tests** should be written and run. Common co
|
|
|
33
33
|
## What Does NOT Belong Here
|
|
34
34
|
|
|
35
35
|
- **Unit test guidance** — that goes in `***implementation reqs***`
|
|
36
|
-
- **
|
|
36
|
+
- **Test scenarios** — conformance and acceptance scenarios live in test plain files, written with `add-test-scenarios` (see `test-plain-files.md`)
|
|
37
37
|
- **Behavioral requirements** — those go in `***functional specs***`
|
|
38
38
|
- **Technology choices for the implementation** — those go in `***implementation reqs***`
|
|
39
39
|
|
|
@@ -42,8 +42,8 @@ Test reqs specify how **conformance tests** should be written and run. Common co
|
|
|
42
42
|
| Test Type | Where to Specify | Purpose |
|
|
43
43
|
|-----------|-----------------|---------|
|
|
44
44
|
| Unit tests | `***implementation reqs***` | Test individual functionalities in isolation |
|
|
45
|
-
| Conformance tests | `***test reqs***` | Verify
|
|
46
|
-
| Acceptance tests | `***acceptance tests***`
|
|
45
|
+
| Conformance tests | how: `***test reqs***`; what: `***conformance tests***` of the test plain file | Verify the expected use of one functionality, its main path |
|
|
46
|
+
| Acceptance tests | how: `***test reqs***`; what: `***acceptance tests***` of the test plain file | Verify one functionality under use that is not expected: invalid parameters, wrong or missing authentication, missing data |
|
|
47
47
|
|
|
48
48
|
## Format
|
|
49
49
|
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: add-test-scenarios
|
|
3
|
+
description: >-
|
|
4
|
+
Write or update the test plain file of one functionality
|
|
5
|
+
(by convention tests/<module>/<func-id>.plain): conformance scenarios for its expected use
|
|
6
|
+
and, when the user asks for them, acceptance scenarios for its unexpected use, in plain English. Use after
|
|
7
|
+
a functional spec is added or changed, when a functionality has no
|
|
8
|
+
conformance scenario, or when the user asks for a test scenario.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Add Test Scenarios
|
|
12
|
+
|
|
13
|
+
**Load the rules first.** Before you read, edit, or write any `.plain` file, invoke the `load-plain-reference` skill and read the rule files it routes you to. Skip this only if `load-plain-reference` already ran in this conversation.
|
|
14
|
+
|
|
15
|
+
## What this skill writes
|
|
16
|
+
|
|
17
|
+
One test plain file per functionality, by convention at `tests/<module>/<func-id>.plain`, with the frontmatter keys `module:` and `func_id:` and the two sections `***conformance tests***` and `***acceptance tests***`. Every scenario is a `# <scenario-id>` heading, one plain-English statement line, and `- ` bullets when the line is not enough. Conformance scenarios are written with the spec; acceptance scenarios only when the user asks for them. The renderer generates one test per scenario and nothing else, so the scenarios in this file are the only tests the functionality gets.
|
|
18
|
+
|
|
19
|
+
## When to Use
|
|
20
|
+
|
|
21
|
+
- `add-functional-spec` or `add-functional-specs` inserted a functionality — those skills invoke this one for each new functionality.
|
|
22
|
+
- A functional spec changed (edit, split, conflict resolution, move) and its scenarios must be brought back in step.
|
|
23
|
+
- A functionality has no test plain file, or an empty `***conformance tests***` section, while conformance tests are enabled.
|
|
24
|
+
- The user asks for a conformance or acceptance scenario.
|
|
25
|
+
|
|
26
|
+
## Conformance gate
|
|
27
|
+
|
|
28
|
+
Conformance tests are enabled for a module when the `config.yaml` that governs it has a `conformance-tests-script` entry pointing at an existing script. When they are enabled, every functionality must end up with at least one conformance scenario. When they are not enabled, write a test plain file only if the user asks for one, and say that conformance tests are off for the module.
|
|
29
|
+
|
|
30
|
+
## Workflow
|
|
31
|
+
|
|
32
|
+
1. **Identify the functionality.** Take the module name and func-id from the caller or the user. If the user points at a spec by its text, find its `# <func-id>` heading.
|
|
33
|
+
2. **Read the context.** Read the functional spec (heading and body), the `***definitions***` the module sees (its own, its `import` modules, and the `exported_concepts` of its `requires` modules), the `***test reqs***`, and the functional specs that come before this one, because a scenario may rely on behavior they established.
|
|
34
|
+
3. **Locate or create the test plain file.** Find every `.plain` file whose frontmatter binds to the pair `(module, func_id)`; by convention it is `tests/<module>/<func-id>.plain`, but only the frontmatter decides. Read every file found, so scenario-ids stay unique across the merged set. If none exists, create the file at the conventional path with the frontmatter and both sections.
|
|
35
|
+
4. **List and sort the outcomes the spec states.** Walk the statement line and every clarification bullet. Write down the main path and each boundary, validation, and error case the spec names. Conformance scenarios cover the expected use (the main path and its valid variants). Use that is not expected (invalid parameters, wrong or missing authentication, missing data, an unavailable dependency) becomes an acceptance scenario only when the user asks for it; never draft one on your own. Do not add an outcome the spec does not state: a scenario may not extend the spec. If a needed outcome is missing from the spec, ask the user one question and route the answer into the functional spec through `add-functional-spec` (or an inline edit of the clarification bullets) before writing the scenario.
|
|
36
|
+
5. **Draft one conformance scenario per expected-use outcome, and the acceptance scenarios the user asked for.** Give each a scenario-id per `semantic-ids.md` (short slug, unique for this functionality). Write the body in plain English:
|
|
37
|
+
- One statement line: a sentence that names the action and the expected result, with concrete values.
|
|
38
|
+
- When that line is not enough, `- ` bullets, in order: the state before the action, the one action under test, and each observable result, one fact per bullet.
|
|
39
|
+
- `given:` / `when:` / `then:` lists are allowed when the user asks for them; otherwise plain English, and one shape per project.
|
|
40
|
+
Test the functionality through the interface the spec names, as a black box. A scenario may use earlier functionalities for its setup; a scenario that spans several functionalities is bound to the last one it exercises and is written only when the user asks for it.
|
|
41
|
+
6. **Check what the test can cause.** An acceptance scenario the user asked for that needs a dependency to fail (a backend that does not respond, a database that is unavailable) is written only when `***test reqs***` let the test cause that failure, for example with a local mock of that dependency. Otherwise ask the user one question: add such a test req, or leave the scenario out.
|
|
42
|
+
7. **Run the review pass** from `concise-specs.md` over every scenario: no narration, no rationale, no step a reader would assume, concrete values, plain words.
|
|
43
|
+
8. **Write the file and read it again.** Confirm the frontmatter keys, the section order, at least one conformance scenario when conformance tests are enabled, and that no body line starts with `# ` or `***`.
|
|
44
|
+
9. **Review with the user** when running inside `forge-plain` or `add-feature`: show the scenarios as the snippet for that loop iteration and apply the response before moving on.
|
|
45
|
+
|
|
46
|
+
## Updating existing scenarios
|
|
47
|
+
|
|
48
|
+
- **The spec changed.** Compare every scenario with the new spec text. Remove or rewrite a scenario that no longer follows from the spec; add a scenario for every new outcome. Keep the scenario-id of a scenario whose meaning is unchanged, because the generated test carries it.
|
|
49
|
+
- **The functionality was split.** Each new functionality gets its own test plain file; move each scenario to the functionality it tests and write new scenarios for outcomes that have none.
|
|
50
|
+
- **The func-id was renamed.** Rename `func_id:` in every test plain file bound to it and move the file to the new conventional path.
|
|
51
|
+
- **The functionality was deleted.** Delete its test plain file; confirm with the user first when it holds hand-written scenarios.
|
|
52
|
+
- **The functionality moved to another module.** Update `module:` and move the file to the new conventional path.
|
|
53
|
+
|
|
54
|
+
## Rules
|
|
55
|
+
|
|
56
|
+
- A scenario is a direct consequence of the functional spec: it does not contradict, narrow, or extend it.
|
|
57
|
+
- The kind of use decides the section, not the number of functionalities a scenario touches: expected use under `***conformance tests***`, everything else under `***acceptance tests***`.
|
|
58
|
+
- Acceptance scenarios are written only on the user's explicit instruction; conformance scenarios come with the spec.
|
|
59
|
+
- Scenarios are language-agnostic and black box: no function, class, or file of the implementation is named.
|
|
60
|
+
- Values that matter to the check are concrete (`named "Buy milk"`, `returns 404`); descriptive values (`a valid name`) are not checkable.
|
|
61
|
+
- One scenario per distinct outcome; the same outcome is never written twice in different words.
|
|
62
|
+
- Framework, run command, and network policy belong in `***test reqs***`, never in a scenario.
|
|
63
|
+
- No `***acceptance tests***` section is ever written into a spec plain file.
|
|
64
|
+
|
|
65
|
+
## Format
|
|
66
|
+
|
|
67
|
+
```plain
|
|
68
|
+
---
|
|
69
|
+
module: task-manager
|
|
70
|
+
func_id: add-task
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
***conformance tests***
|
|
74
|
+
|
|
75
|
+
# add-valid-task
|
|
76
|
+
Adding a :Task: named "Buy milk" to an empty :TaskList: shows one :Task: named "Buy milk".
|
|
77
|
+
|
|
78
|
+
***acceptance tests***
|
|
79
|
+
|
|
80
|
+
# reject-short-name
|
|
81
|
+
Adding a :Task: named "Go" to an empty :TaskList: is rejected.
|
|
82
|
+
- :App: shows the error "Name must be at least 3 characters".
|
|
83
|
+
- :TaskList: stays empty.
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Validation Checklist
|
|
87
|
+
|
|
88
|
+
- [ ] The file's `module:` and `func_id:` name an existing functionality
|
|
89
|
+
- [ ] `***conformance tests***` comes first, `***acceptance tests***` second; both sections exist
|
|
90
|
+
- [ ] At least one conformance scenario when conformance tests are enabled for the module
|
|
91
|
+
- [ ] Every expected-use outcome the functional spec states has one conformance scenario; no scenario states an outcome the spec does not
|
|
92
|
+
- [ ] No unexpected-use scenario under `***conformance tests***`, no expected-use scenario under `***acceptance tests***`
|
|
93
|
+
- [ ] Acceptance scenarios only where the user asked for them
|
|
94
|
+
- [ ] Every scenario is a `# <scenario-id>` heading, a plain-English statement line, bullets when needed, and concrete values
|
|
95
|
+
- [ ] Scenario-ids follow `semantic-ids.md` and are unique across every test plain file bound to this functionality
|
|
96
|
+
- [ ] Scenarios are black box and language-agnostic
|
|
97
|
+
- [ ] Trimmed per `concise-specs.md`
|
|
98
|
+
- [ ] No `***acceptance tests***` section was written into the spec plain file
|
|
@@ -19,7 +19,7 @@ A **set of two or more functional specs** to check against each other. Callers t
|
|
|
19
19
|
- A new spec (or batch of new specs) **plus** the existing specs from the same file and any `requires` modules.
|
|
20
20
|
- An explicit list of spec snippets the user wants compared.
|
|
21
21
|
|
|
22
|
-
Each spec must be identifiable.
|
|
22
|
+
Each spec must be identifiable. Use its func-id (`<module>:<func-id>` when the batch spans modules). A draft that has no func-id yet gets a **stable identifier** in order of appearance: `S1`, `S2`, `S3`, …. Use those identifiers in the output. If the caller provided its own labels or quoted snippets, use those instead and keep them verbatim.
|
|
23
23
|
|
|
24
24
|
The skill also needs the `***definitions***` section (and any imported definitions) so referenced `:Concepts:` can be resolved.
|
|
25
25
|
|
|
@@ -50,20 +50,25 @@ Too complex:
|
|
|
50
50
|
```plain
|
|
51
51
|
***functional specs***
|
|
52
52
|
|
|
53
|
-
-
|
|
53
|
+
# manage-tasks
|
|
54
|
+
A :User: can create, edit, delete, and archive :Task: items, with validation on all fields and confirmation dialogs for destructive actions.
|
|
54
55
|
```
|
|
55
56
|
|
|
56
57
|
Acceptable (one behavior each):
|
|
57
58
|
```plain
|
|
58
59
|
***functional specs***
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
# create-task
|
|
62
|
+
A :User: can create :Task:. Only valid :Task: items can be added.
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
# edit-task
|
|
65
|
+
A :User: can edit :Task:.
|
|
63
66
|
|
|
64
|
-
|
|
67
|
+
# delete-task
|
|
68
|
+
A :User: can delete :Task:.
|
|
65
69
|
|
|
66
|
-
|
|
70
|
+
# archive-task
|
|
71
|
+
A :User: can archive :Task:.
|
|
67
72
|
|
|
68
73
|
```
|
|
69
74
|
|
|
@@ -84,19 +89,23 @@ Too complex:
|
|
|
84
89
|
```plain
|
|
85
90
|
***functional specs***
|
|
86
91
|
|
|
87
|
-
|
|
92
|
+
# process-order
|
|
93
|
+
:Order: processing depends on :OrderType:. Standard orders are validated and stored. Express orders skip validation and are queued for immediate dispatch. Bulk orders are split into sub-orders of 100 items each, validated individually, and processed in parallel with progress tracking.
|
|
88
94
|
```
|
|
89
95
|
|
|
90
96
|
Acceptable (separate the modes):
|
|
91
97
|
```plain
|
|
92
98
|
***functional specs***
|
|
93
99
|
|
|
94
|
-
-
|
|
100
|
+
# process-standard-order
|
|
101
|
+
A standard :Order: is validated and stored.
|
|
95
102
|
|
|
96
|
-
-
|
|
103
|
+
# process-express-order
|
|
104
|
+
An express :Order: is queued for immediate dispatch without validation.
|
|
97
105
|
|
|
98
|
-
|
|
99
|
-
|
|
106
|
+
# split-bulk-order
|
|
107
|
+
A bulk :Order: is split into sub-orders of 100 items each.
|
|
108
|
+
- Each sub-order is processed individually.
|
|
100
109
|
```
|
|
101
110
|
|
|
102
111
|
### 4. Cross-Cutting Concerns
|
|
@@ -107,17 +116,21 @@ Too complex:
|
|
|
107
116
|
```plain
|
|
108
117
|
***functional specs***
|
|
109
118
|
|
|
110
|
-
-
|
|
119
|
+
# fetch-resources
|
|
120
|
+
:Resource: items are fetched from the external API with pagination support, retry on transient errors with exponential backoff, caching for 5 minutes, and logging of all API calls.
|
|
111
121
|
```
|
|
112
122
|
|
|
113
123
|
Acceptable (separate concerns):
|
|
114
124
|
```plain
|
|
115
125
|
***functional specs***
|
|
116
|
-
-
|
|
126
|
+
# fetch-resources
|
|
127
|
+
:Resource: items are fetched from the external API.
|
|
117
128
|
|
|
118
|
-
-
|
|
129
|
+
# fetch-resources-paged
|
|
130
|
+
:Resource: items are fetched from the external API in pages.
|
|
119
131
|
|
|
120
|
-
-
|
|
132
|
+
# retry-resource-fetch
|
|
133
|
+
Fetching :Resource: items is retried on transient errors using exponential backoff.
|
|
121
134
|
```
|
|
122
135
|
|
|
123
136
|
### 5. UI Complexity
|
|
@@ -128,18 +141,22 @@ Too complex:
|
|
|
128
141
|
```plain
|
|
129
142
|
***functional specs***
|
|
130
143
|
|
|
131
|
-
|
|
144
|
+
# dashboard
|
|
145
|
+
The dashboard shows :User: profile, recent :Task: items in a sortable table, a notification bell with unread count, and a sidebar with navigation links that highlights the active page.
|
|
132
146
|
```
|
|
133
147
|
|
|
134
148
|
Acceptable (build incrementally):
|
|
135
149
|
```plain
|
|
136
150
|
***functional specs***
|
|
137
151
|
|
|
138
|
-
|
|
152
|
+
# dashboard-page
|
|
153
|
+
A dashboard page is shown for :User:.
|
|
139
154
|
|
|
140
|
-
|
|
155
|
+
# dashboard-recent-tasks
|
|
156
|
+
Recent :Task: items are shown in a sortable table on the dashboard.
|
|
141
157
|
|
|
142
|
-
|
|
158
|
+
# dashboard-notifications
|
|
159
|
+
A notification indicator with the unread count is shown on the dashboard.
|
|
143
160
|
```
|
|
144
161
|
|
|
145
162
|
### 6. Data Transformation Complexity
|
|
@@ -157,18 +174,21 @@ Too complex (builds the component and uses it in one spec):
|
|
|
157
174
|
```plain
|
|
158
175
|
***functional specs***
|
|
159
176
|
|
|
160
|
-
|
|
177
|
+
# export-report-pdf
|
|
178
|
+
A :Report: is exported to PDF, laying out multi-page tables with repeating headers and page numbers, and charts rendered from :Report: data.
|
|
161
179
|
```
|
|
162
180
|
|
|
163
181
|
Acceptable (component in its own spec, then referenced):
|
|
164
182
|
```plain
|
|
165
183
|
***functional specs***
|
|
166
184
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
185
|
+
# pdf-renderer-tables
|
|
186
|
+
:PdfRenderer: lays out multi-page tables from structured content.
|
|
187
|
+
- Table headers repeat at the top of each page.
|
|
188
|
+
- Each page shows its page number.
|
|
170
189
|
|
|
171
|
-
-
|
|
190
|
+
# export-report-pdf
|
|
191
|
+
A :Report: is exported to PDF using :PdfRenderer:, embedding charts rendered from :Report: data.
|
|
172
192
|
```
|
|
173
193
|
|
|
174
194
|
When this indicator fires, the fix is `break-down-func-spec` Strategy 6 — extract the component into its own earlier spec and reference it.
|