plain-forge 1.0.23 → 1.0.24-next.019bba8
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 +14 -11
- package/bin/cli.mjs +5 -4
- package/forge/rules/plain-forge.md +10 -0
- package/forge/skills/add-concept/SKILL.md +1 -1
- package/forge/skills/add-feature/SKILL.md +8 -7
- package/forge/skills/add-feature/references/checklist.md +2 -2
- package/forge/skills/add-functional-spec/SKILL.md +14 -10
- package/forge/skills/add-functional-specs/SKILL.md +14 -10
- package/forge/skills/add-implementation-requirement/SKILL.md +1 -1
- package/forge/skills/add-resource/SKILL.md +3 -2
- package/forge/skills/add-template/SKILL.md +1 -1
- package/forge/skills/add-test-requirement/SKILL.md +4 -4
- package/forge/skills/add-test-scenarios/SKILL.md +98 -0
- package/forge/skills/analyze-2-func-specs/SKILL.md +1 -1
- package/forge/skills/analyze-func-specs/SKILL.md +2 -2
- package/forge/skills/analyze-if-func-spec-too-complex/SKILL.md +44 -24
- package/forge/skills/break-down-func-spec/SKILL.md +57 -33
- package/forge/skills/check-plain-env/SKILL.md +2 -2
- package/forge/skills/consolidate-concepts/SKILL.md +8 -8
- package/forge/skills/create-import-module/SKILL.md +1 -1
- package/forge/skills/create-requires-module/SKILL.md +6 -3
- package/forge/skills/debug-specs/SKILL.md +14 -8
- package/forge/skills/forge-plain/SKILL.md +3 -3
- 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 +6 -6
- package/forge/skills/load-plain-reference/SKILL.md +25 -25
- 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/{rules → skills/load-plain-reference/rules}/bullet-continuation.md +11 -11
- package/forge/{rules → skills/load-plain-reference/rules}/concise-specs-examples.md +100 -69
- package/forge/{rules → skills/load-plain-reference/rules}/concise-specs-integration-examples.md +39 -24
- package/forge/{rules → skills/load-plain-reference/rules}/concise-specs.md +3 -2
- package/forge/{rules → skills/load-plain-reference/rules}/func-specs.md +37 -28
- package/forge/{rules → skills/load-plain-reference/rules}/impl-reqs.md +1 -1
- package/forge/{rules → skills/load-plain-reference/rules}/integration-embedded-testing.md +1 -1
- package/forge/{rules → skills/load-plain-reference/rules}/linked-resources.md +7 -4
- package/forge/{rules → skills/load-plain-reference/rules}/module-structure.md +16 -9
- package/forge/{rules → 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/{rules → skills/load-plain-reference/rules}/test-reqs.md +6 -6
- package/forge/skills/plain-healthcheck/SKILL.md +31 -13
- package/forge/skills/refactor-module/SKILL.md +16 -16
- package/forge/skills/resolve-section-ownership/SKILL.md +3 -3
- package/forge/skills/resolve-spec-conflict/SKILL.md +14 -8
- package/package.json +1 -1
- package/forge/skills/add-acceptance-test/SKILL.md +0 -101
- /package/forge/{rules → skills/load-plain-reference/rules}/definitions.md +0 -0
- /package/forge/{rules → skills/load-plain-reference/rules}/examples/integration-embedded-testing/prepare_environment_java.sh +0 -0
- /package/forge/{rules → skills/load-plain-reference/rules}/examples/integration-embedded-testing/run_conformance_tests_java.sh +0 -0
- /package/forge/{rules → skills/load-plain-reference/rules}/examples/integration-embedded-testing/run_unittests_java.sh +0 -0
- /package/forge/{rules → skills/load-plain-reference/rules}/exported-concepts.md +0 -0
- /package/forge/{rules → skills/load-plain-reference/rules}/import-modules.md +0 -0
- /package/forge/{rules → skills/load-plain-reference/rules}/integration-embedded.md +0 -0
- /package/forge/{rules → skills/load-plain-reference/rules}/integration-standalone.md +0 -0
- /package/forge/{rules → skills/load-plain-reference/rules}/integrations.md +0 -0
- /package/forge/{rules → skills/load-plain-reference/rules}/required-concepts.md +0 -0
|
@@ -38,8 +38,9 @@ A linked resource **must not** be any of the following:
|
|
|
38
38
|
|
|
39
39
|
***functional specs***
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
# add-task
|
|
42
|
+
A :User: can add a :Task: by POSTing :TaskCreateRequest: to the `POST /tasks` endpoint of :TasksAPI:.
|
|
43
|
+
- The endpoint responds per :TasksAPI:.
|
|
43
44
|
```
|
|
44
45
|
|
|
45
46
|
## Each linked resource is referenced from exactly one place
|
|
@@ -55,9 +56,11 @@ A linked resource **must not** be any of the following:
|
|
|
55
56
|
|
|
56
57
|
***functional specs***
|
|
57
58
|
|
|
58
|
-
|
|
59
|
+
# add-task
|
|
60
|
+
A :User: can add a :Task: using :TaskModalSpec:.
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
# edit-task
|
|
63
|
+
A :User: can edit a :Task: using :TaskModalSpec:.
|
|
61
64
|
```
|
|
62
65
|
|
|
63
66
|
## File location and path resolution
|
|
@@ -9,7 +9,8 @@ When creating a new `.plain` file or reviewing the structure of a whole file, al
|
|
|
9
9
|
## File skeleton
|
|
10
10
|
- A `.plain` file is one **module**: optional YAML frontmatter between `---` markers, followed by sections marked with `***section name***` headers
|
|
11
11
|
- The frontmatter, when present, must be the first thing in the file
|
|
12
|
-
- Every content line inside
|
|
12
|
+
- Every content line inside `***definitions***`, `***implementation reqs***`, and `***test reqs***` is a `- ` list item — see `bullet-continuation.md`
|
|
13
|
+
- Every functionality in `***functional specs***` is a `# <func-id>` heading followed by its body — see `func-specs.md` and `semantic-ids.md`
|
|
13
14
|
- Every line must be as short and plain as its content allows — see `concise-specs.md`
|
|
14
15
|
|
|
15
16
|
## Frontmatter fields
|
|
@@ -23,18 +24,19 @@ When creating a new `.plain` file or reviewing the structure of a whole file, al
|
|
|
23
24
|
| `required_concepts` | Declare concepts an import module expects the importing module to define | `required-concepts.md` |
|
|
24
25
|
|
|
25
26
|
## Sections
|
|
26
|
-
-
|
|
27
|
+
- A spec plain file has exactly four top-level section markers: `***definitions***`, `***implementation reqs***`, `***test reqs***`, and `***functional specs***`
|
|
27
28
|
- Each section appears **at most once** per file; all are optional (which ones are allowed depends on the module kind below)
|
|
28
|
-
- `***acceptance tests***`
|
|
29
|
+
- `***conformance tests***` and `***acceptance tests***` never appear in a spec plain file, not even nested under a functional spec; they are the two sections of a test plain file (see `test-plain-files.md`)
|
|
29
30
|
- Write sections in canonical order: `***definitions***` → `***implementation reqs***` → `***test reqs***` → `***functional specs***`
|
|
30
31
|
- Definitions come first because every concept must be defined before it is referenced
|
|
31
|
-
- Functional specs come last because they are rendered incrementally
|
|
32
|
+
- Functional specs come last because they are rendered incrementally
|
|
32
33
|
|
|
33
34
|
## Module kinds
|
|
34
35
|
- A **root module** lives at the repository root and carries behavior: it contains `***functional specs***`
|
|
35
36
|
- To be renderable, a root module needs at least one functional spec plus the implementation reqs to build it — its own or from an `import`ed module (implementation reqs are not inherited through `requires`). A frontmatter-only file is a valid scaffold, but it cannot be rendered until a functional spec is added
|
|
36
37
|
- A **requires module** is a root module that is used by another root module via `requires` directive (see `requires-modules.md`)
|
|
37
38
|
- An **import module** provides shared content that other modules pull in via `import`: it contains only `***definitions***`, `***implementation reqs***`, and/or `***test reqs***` — never `***functional specs***`, never `requires` (see `import-modules.md`)
|
|
39
|
+
- A **test plain file** holds the scenarios of one functionality of a root module; its frontmatter `module:` and `func_id:` bind it to that functionality, by convention it lives under `tests/<module>/`, and it has no section of a spec plain file (see `test-plain-files.md`)
|
|
38
40
|
|
|
39
41
|
## Section ownership (where a fact lives)
|
|
40
42
|
- The renderer reads each kind of fact **only from its owning section** — a fact placed in the wrong section is silently ignored, not flagged
|
|
@@ -47,7 +49,7 @@ When creating a new `.plain` file or reviewing the structure of a whole file, al
|
|
|
47
49
|
| HOW the software is built — tech stack, architecture, coding standards — and **everything about `:UnitTests:`** | `***implementation reqs***` | `impl-reqs.md` |
|
|
48
50
|
| **Everything about `:ConformanceTests:`** — framework, run command, mocking and network policy | `***test reqs***` | `test-reqs.md` |
|
|
49
51
|
| WHAT the software does — observable, language-agnostic behavior | `***functional specs***` | `func-specs.md` |
|
|
50
|
-
|
|
|
52
|
+
| Test scenarios of one functionality, conformance and acceptance | the test plain file (by convention `tests/<module>/<func-id>.plain`) | `test-plain-files.md` |
|
|
51
53
|
|
|
52
54
|
## Comments
|
|
53
55
|
- Lines beginning with `>` are ignored when rendering
|
|
@@ -67,9 +69,12 @@ When creating a new `.plain` file or reviewing the structure of a whole file, al
|
|
|
67
69
|
|
|
68
70
|
***functional specs***
|
|
69
71
|
|
|
70
|
-
-
|
|
72
|
+
# create-widget
|
|
73
|
+
A :Widget: can be created with up to {{ max_tags }} tags.
|
|
71
74
|
{% if max_tags > 1 %}
|
|
72
|
-
|
|
75
|
+
|
|
76
|
+
# list-widget-tags
|
|
77
|
+
A :Widget: can have its tags listed.
|
|
73
78
|
{% endif %}
|
|
74
79
|
```
|
|
75
80
|
|
|
@@ -99,7 +104,9 @@ import:
|
|
|
99
104
|
|
|
100
105
|
***functional specs***
|
|
101
106
|
|
|
102
|
-
-
|
|
107
|
+
# add-task
|
|
108
|
+
A :Task: can be added to the :TaskList:.
|
|
103
109
|
|
|
104
|
-
-
|
|
110
|
+
# show-task-list
|
|
111
|
+
The :TaskList: is displayed.
|
|
105
112
|
```
|
|
@@ -13,6 +13,7 @@ When creating or editing a `.plain` file that uses `requires`, or one that is re
|
|
|
13
13
|
- The `***functional specs***` of the required module **and of all its ancestors** become visible as **previous functional specs** — this visibility **is transitive** down the whole chain
|
|
14
14
|
- Of a required module's definitions, only the concepts listed in its `exported_concepts` are visible; the module's other definitions stay internal. Each exported concept arrives with its full definition text
|
|
15
15
|
- Export visibility **is not transitive**: an ancestor's exports are visible only if that ancestor is itself listed in `requires`
|
|
16
|
+
- The test plain files of a required module stay with that module; the current module never lists scenarios for a required module's functionality (see `test-plain-files.md`)
|
|
16
17
|
|
|
17
18
|
## Chain topology
|
|
18
19
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Syntax, uniqueness, and use of semantic func-ids and scenario-ids in .plain files
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Rules for semantic IDs
|
|
6
|
+
|
|
7
|
+
Every functionality in `***functional specs***` and every scenario in a test plain file carries a semantic ID. The ID is the stable name that test plain files, render commands, render state, change detection, logs, and generated tests use for that functionality or scenario. Always follow these rules when writing or reading one.
|
|
8
|
+
|
|
9
|
+
## Two kinds of ID
|
|
10
|
+
|
|
11
|
+
| ID | Written as | Identifies | Unique within |
|
|
12
|
+
|---|---|---|---|
|
|
13
|
+
| func-id | `# <func-id>` heading in `***functional specs***` of a spec plain file | one functionality | its module |
|
|
14
|
+
| scenario-id | `# <scenario-id>` heading in `***conformance tests***` or `***acceptance tests***` of a test plain file | one scenario | its functionality, across every test plain file bound to that functionality |
|
|
15
|
+
|
|
16
|
+
## Syntax
|
|
17
|
+
- Lowercase letters, digits, and hyphens only: `add-task`, `export-csv-2`, `ctrl-d-exit`
|
|
18
|
+
- The heading is `# ` (hash, one space) followed by the ID and nothing else
|
|
19
|
+
|
|
20
|
+
## Uniqueness
|
|
21
|
+
- A func-id is unique in its module; two modules may use the same func-id
|
|
22
|
+
- A scenario-id is unique for its functionality after every test plain file bound to that functionality is merged; two functionalities may use the same scenario-id
|
|
23
|
+
- Before adding an ID, search the module (or the functionality's test plain files) for the same heading; a duplicate is a syntax error that `plain-parser check` reports
|
|
24
|
+
|
|
25
|
+
## Stability
|
|
26
|
+
- An ID is an identity, not a label: a functionality keeps its func-id for as long as it exists, even when its text changes
|
|
27
|
+
- To the renderer, renaming a func-id is deleting one functionality and adding another; rename only when the user asks, then rename `func_id:` in every test plain file bound to it and move the file to the new conventional path
|
|
28
|
+
- Never renumber or reorder IDs; the order of the headings in the file is the render order, the ID carries no order
|
|
29
|
+
|
|
30
|
+
## How coding agents use IDs
|
|
31
|
+
- Name a functionality by its func-id (`<module>:<func-id>` when the module is not obvious) in questions to the user, in review snippets, in commit messages, and in render commands; never by position ("the third spec")
|
|
32
|
+
- Pick the func-id before writing the functional spec text, check that it is unique in the module, then write the heading and the body (see `func-specs.md`)
|
|
33
|
+
- A new functionality is finished only when its test plain file exists (by convention at `tests/<module>/<func-id>.plain`) with at least one conformance scenario (see `test-plain-files.md`)
|
|
34
|
+
- A generated conformance or acceptance test carries the scenario-id of the scenario it implements; when a test fails, the scenario-id in its name leads back to the scenario text
|
|
35
|
+
- Everything about one functionality is found through its func-id: the `# <func-id>` heading in the spec plain file, the test plain files whose frontmatter names it, and the generated tests labelled with its scenario-ids
|
|
36
|
+
|
|
37
|
+
## Format
|
|
38
|
+
|
|
39
|
+
```plain
|
|
40
|
+
***functional specs***
|
|
41
|
+
|
|
42
|
+
# add-task
|
|
43
|
+
A :User: can add a :Task:. Only valid :Task: items are added.
|
|
44
|
+
|
|
45
|
+
# delete-task
|
|
46
|
+
A :User: can delete a :Task:.
|
|
47
|
+
```
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Syntax and authoring rules for test plain files, which hold the conformance and acceptance scenarios of one functionality
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Rules for test plain files
|
|
6
|
+
|
|
7
|
+
A test plain file holds the test scenarios of one functionality. Conformance scenarios test the core functionality, its expected use; acceptance scenarios catch the edge cases, the use that is not expected. The renderer generates conformance and acceptance tests from these scenarios and from nothing else: it never invents a scenario. Scenarios are written at authoring time and are reviewed like any other spec line. Always follow these rules when creating or editing one.
|
|
8
|
+
|
|
9
|
+
## File skeleton
|
|
10
|
+
- A test plain file is a `.plain` file with YAML frontmatter and two sections, in this order: `***conformance tests***`, then `***acceptance tests***`
|
|
11
|
+
- Both sections are required; `***acceptance tests***` may be empty
|
|
12
|
+
- The frontmatter has exactly two keys, both required:
|
|
13
|
+
- `module:` the name of the module that holds the functionality (the spec plain file's name without `.plain`)
|
|
14
|
+
- `func_id:` the func-id of the functionality (see `semantic-ids.md`)
|
|
15
|
+
- The pair `(module, func_id)` must name a functionality that exists; a pair with no match is an error
|
|
16
|
+
- A test plain file must not have `***definitions***`, `***implementation reqs***`, `***test reqs***`, or `***functional specs***`
|
|
17
|
+
- Comment lines starting with `>` are allowed, as in a spec plain file
|
|
18
|
+
|
|
19
|
+
## Location
|
|
20
|
+
- By convention a test plain file lives at `tests/<module>/<func_id>.plain`, with `tests/` next to the spec plain file
|
|
21
|
+
- The location and the file name are convention only: the renderer discovers test plain files by reading the frontmatter of every `.plain` file under its test folders
|
|
22
|
+
- plain-forge always writes to the conventional path, one file per functionality
|
|
23
|
+
- More than one test plain file may bind to the same functionality; their scenarios are merged, and scenario-ids must be unique across the merged set. Hand-written files may use this; plain-forge keeps one file per functionality
|
|
24
|
+
|
|
25
|
+
## Scenarios
|
|
26
|
+
- A scenario is a `# <scenario-id>` heading (see `semantic-ids.md`) followed by free text that says what is done and what result is expected
|
|
27
|
+
- A scenario body line may be prose, a `- ` bullet, or any other text, as long as it does not start with `# ` (that starts a new scenario) or with `***`
|
|
28
|
+
- A scenario may reference every concept visible to its module: its own definitions, its `import` modules, and the `exported_concepts` of its `requires` modules. It defines no concepts
|
|
29
|
+
- Scenarios are language-agnostic: they describe behavior through the observable interface (CLI, HTTP, files, UI) and never name a function, class, or file of the implementation
|
|
30
|
+
- A scenario tests the functionality as a black box; the generated test never imports the implementation's internals
|
|
31
|
+
- A scenario is a direct consequence of the functional spec: it does not contradict, narrow, or extend the behavior the spec states
|
|
32
|
+
- Each scenario states one concrete, checkable outcome; "works correctly" is not an outcome
|
|
33
|
+
- Scenario text follows `concise-specs.md`: no narration, no rationale, no step a reader would assume
|
|
34
|
+
|
|
35
|
+
## Wording
|
|
36
|
+
- plain-forge writes every scenario in plain English; hand-written scenarios may use any shape
|
|
37
|
+
- Values that matter to the check are concrete (`named "Buy milk"`, `exits with status 0`), never descriptive (`a valid name`)
|
|
38
|
+
|
|
39
|
+
## Conformance scenarios
|
|
40
|
+
- `***conformance tests***` holds the scenarios of the expected use of the functionality: its main path, with valid parameters, the expected caller, and the data present.
|
|
41
|
+
- These scenarios gate the functionality: it is done only when every conformance scenario passes
|
|
42
|
+
- When conformance tests are enabled for the module (its `config.yaml` has a `conformance-tests-script`), every functionality has at least one conformance scenario; an empty section is an error
|
|
43
|
+
- Cover the main path first, then each variant of expected use the functional spec states (another valid input shape, an optional parameter); stop when every expected behavior has one scenario
|
|
44
|
+
- Do not write the same scenario twice in different words; one scenario per distinct outcome
|
|
45
|
+
|
|
46
|
+
## Acceptance scenarios
|
|
47
|
+
- `***acceptance tests***` holds the scenarios of use that is not expected
|
|
48
|
+
- Acceptance scenarios are written only on the developer's explicit instruction, through a coding agent or by hand; the section may be empty
|
|
49
|
+
- An acceptance scenario is rendered after the conformance tests of its functionality pass
|
|
50
|
+
- A scenario 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 before writing it
|
|
51
|
+
- The kind of use decides the section, not the number of functionalities the scenario touches (see *Scenarios across functionalities*)
|
|
52
|
+
|
|
53
|
+
## Scenarios across functionalities
|
|
54
|
+
- A scenario may use functionalities rendered before the one it is bound to, for its setup or as steps of a longer path
|
|
55
|
+
- Such a scenario is bound to the last functionality it exercises, because the earlier ones must exist when it runs
|
|
56
|
+
- It goes under `***conformance tests***` when every step is expected use, and under `***acceptance tests***` when any step is not; plain-forge writes one only when the user asks for it
|
|
57
|
+
|
|
58
|
+
## Keeping test plain files in step with functional specs
|
|
59
|
+
- Every change to a functional spec is followed by a review of its test plain file: scenarios that no longer follow from the spec are removed or rewritten, and new behavior gets a scenario
|
|
60
|
+
- When a functionality is split, each new functionality gets its own test plain file; each scenario moves to the functionality it tests
|
|
61
|
+
- When a functionality is deleted, its test plain file is deleted
|
|
62
|
+
- When a functionality moves to another module, its test plain file moves to that module's folder and its `module:` key is updated
|
|
63
|
+
- When a func-id is renamed, `func_id:` is renamed in every test plain file bound to it and the file moves to the new conventional path
|
|
64
|
+
|
|
65
|
+
## Relation to `***test reqs***`
|
|
66
|
+
- `***test reqs***` of the module say how `:ConformanceTests:` and `:AcceptanceTests:` are built and run (framework, command, network policy); the scenarios say what they check
|
|
67
|
+
- A fact about the framework or the run command never goes into a scenario, and a scenario never goes into `***test reqs***`
|
|
@@ -9,7 +9,7 @@ When writing or editing a `***test reqs***` section in a `.plain` file, always f
|
|
|
9
9
|
## Conformance tests only
|
|
10
10
|
- Test reqs specify how **conformance tests** should be written and run
|
|
11
11
|
- Unit test guidance goes in `***implementation reqs***`, not here
|
|
12
|
-
-
|
|
12
|
+
- Test scenarios, conformance and acceptance, live in test plain files, not here — see `test-plain-files.md`
|
|
13
13
|
- Behavioral requirements go in `***functional specs***`, not here
|
|
14
14
|
|
|
15
15
|
## `:ConformanceTests:` lives here (hard rule)
|
|
@@ -28,11 +28,11 @@ When writing or editing a `***test reqs***` section in a `.plain` file, always f
|
|
|
28
28
|
|
|
29
29
|
## Test type reference
|
|
30
30
|
|
|
31
|
-
| Test type | Where to specify | Generated | Purpose |
|
|
32
|
-
|
|
33
|
-
| Unit tests | `***implementation reqs***` |
|
|
34
|
-
| Conformance tests | `***test reqs***` |
|
|
35
|
-
| Acceptance tests | `***acceptance tests***`
|
|
31
|
+
| Test type | Where to specify | Generated from | Purpose |
|
|
32
|
+
|-----------|-----------------|----------------|---------|
|
|
33
|
+
| Unit tests | `***implementation reqs***` | the implementation, by the renderer | Test individual functionalities in isolation |
|
|
34
|
+
| Conformance tests | how: `***test reqs***`; what: `***conformance tests***` of the functionality's test plain file | the conformance scenarios, one test per scenario-id | Verify the expected use of one functionality, its main path |
|
|
35
|
+
| Acceptance tests | how: `***test reqs***`; what: `***acceptance tests***` of the functionality's test plain file | the acceptance scenarios, one test per scenario-id | Verify one functionality under use that is not expected: invalid parameters, wrong or missing authentication, missing data |
|
|
36
36
|
|
|
37
37
|
## No duplication
|
|
38
38
|
- Do not duplicate guidance already present in the file or its imports
|
|
@@ -3,8 +3,8 @@ name: plain-healthcheck
|
|
|
3
3
|
description: >-
|
|
4
4
|
Verification gate for a ***plain project. Verifies that every `config.yaml`
|
|
5
5
|
exists and points at scripts that actually live in `test_scripts/`, parses
|
|
6
|
-
every top module with `plain-parser check`, and checks every module for
|
|
7
|
-
the parser can't judge (section ownership, bullets, linked resources). Run this whenever anything in the project is finalized —
|
|
6
|
+
every top module with `plain-parser check`, and checks every module and test plain file for
|
|
7
|
+
what the parser can't judge (section ownership, bullets, scenarios, linked resources). Run this whenever anything in the project is finalized —
|
|
8
8
|
including (but not limited to) the end of `forge-plain`, the end of
|
|
9
9
|
`add-feature`, after `debug-specs`, after any single-skill edit that
|
|
10
10
|
finalizes a concept, functional spec, requirement, template, or config —
|
|
@@ -13,7 +13,7 @@ description: >-
|
|
|
13
13
|
|
|
14
14
|
# Plain Healthcheck
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
**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. Step 3b checks every module against those rules, and they are needed to fix what `plain-parser` reports in Step 3a.
|
|
17
17
|
|
|
18
18
|
## When to run
|
|
19
19
|
|
|
@@ -22,7 +22,7 @@ Run this skill **whenever anything in the ***plain project is finalized** and th
|
|
|
22
22
|
- **End of `forge-plain`** (Phase 4) — before handing off the render target.
|
|
23
23
|
- **End of `add-feature`** (Phase 3 final review) — before declaring the feature done.
|
|
24
24
|
- **End of `debug-specs`** — after applying a fix, before telling the user to re-render.
|
|
25
|
-
- **After finalizing any single edit** that changes the renderable surface — e.g. after `add-concept`, `add-functional-spec`, `add-functional-specs`, `add-implementation-requirement`, `add-test-requirement`, `add-
|
|
25
|
+
- **After finalizing any single edit** that changes the renderable surface — e.g. after `add-concept`, `add-functional-spec`, `add-functional-specs`, `add-implementation-requirement`, `add-test-requirement`, `add-test-scenarios`, `add-template`, `add-resource`, `resolve-spec-conflict`, `break-down-func-spec`, `consolidate-concepts`, `refactor-module`, `create-import-module`, `create-requires-module`, or any of the `implement-*-testing-script` skills.
|
|
26
26
|
- **After hand-editing** a `.plain` file, a `config.yaml`, or anything under `test_scripts/`.
|
|
27
27
|
- **On demand** — whenever the user asks whether the project is in a renderable state.
|
|
28
28
|
|
|
@@ -40,9 +40,10 @@ The skill is a **detect → fix → re-run** loop. It does not stop at the first
|
|
|
40
40
|
2. Identify **top modules** — every module that is not `requires`-ed by any other module. A single-stack project has one top module; a multi-part project (e.g. backend + frontend) has one top module per part.
|
|
41
41
|
3. List every `config.yaml` in the repo (root and per-part directories such as `backend/`, `frontend/`).
|
|
42
42
|
4. List every script under `test_scripts/`.
|
|
43
|
-
5.
|
|
43
|
+
5. List every test plain file: each `.plain` file in the project whose frontmatter has `module:` and `func_id:` (by convention under `tests/`). Record the pair it binds to.
|
|
44
|
+
6. Pair each top module with the `config.yaml` that governs it. The pairing rule is: the config file in the same directory as the top module wins; failing that, the repo-root `config.yaml`. A multi-part project must have one config per part — record any top module that has no governing config as a failure.
|
|
44
45
|
|
|
45
|
-
Print a one-line inventory summary so the rest of the run is easy to follow, e.g. `Top modules: backend/api.plain (config: backend/config.yaml), frontend/web.plain (config: frontend/config.yaml). Scripts in test_scripts/: 4.`
|
|
46
|
+
Print a one-line inventory summary so the rest of the run is easy to follow, e.g. `Top modules: backend/api.plain (config: backend/config.yaml), frontend/web.plain (config: frontend/config.yaml). Scripts in test_scripts/: 4. Test plain files: 12.`
|
|
46
47
|
|
|
47
48
|
### Step 2 — Validate every `config.yaml`
|
|
48
49
|
|
|
@@ -77,24 +78,39 @@ Step 3 has two halves: a mechanical parse by `plain-parser`, then the checks tha
|
|
|
77
78
|
[`plain-parser`](https://pypi.org/project/plain-parser/) is the ***plain parser. It parses a module together with its whole `import` / `requires` chain, so running it on every top module covers every module in the project.
|
|
78
79
|
|
|
79
80
|
1. **Check it is installed.** Run `plain-parser --help`. If the command is not found, look for it where `plain-forge install` puts it before giving up: `~/.local/bin/plain-parser` (`%USERPROFILE%\.local\bin\plain-parser.exe` on Windows), or the directory printed by `uv tool dir --bin`. If it is there, run it by that full path for the rest of this step and tell the user to add the directory to `PATH`. If it is nowhere, stop and report `FAIL` with the install command (`pipx install plain-parser` or `uv tool install plain-parser`; it needs Python 3.11 or newer). Do **not** fall back to checking these rules by reading the files — without the parser there is no syntax gate.
|
|
80
|
-
2. **
|
|
81
|
+
2. **Check that it parses the current syntax.** Write this probe module as `probe.plain` into a fresh temporary directory and run `plain-parser check probe.plain` there:
|
|
82
|
+
|
|
83
|
+
```plain
|
|
84
|
+
***implementation reqs***
|
|
85
|
+
|
|
86
|
+
- :Implementation: is written in Python 3.12.
|
|
87
|
+
|
|
88
|
+
***functional specs***
|
|
89
|
+
|
|
90
|
+
# probe
|
|
91
|
+
:Implementation: starts.
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
If it prints `OK`, continue. If it reports an error, the installed plain-parser predates the current syntax (`# func-id` headings, test plain files). Then record one failure against the project — `plain-parser <version> does not parse the current ***plain syntax; install the release that does and run plain-healthcheck again` — skip steps 3 and 4 of 3a, still run 3b, and report `FAIL`. Never rewrite the specs into an older syntax to satisfy the old parser.
|
|
95
|
+
3. **Run it from the top module's own directory**, once per top module:
|
|
81
96
|
|
|
82
97
|
```bash
|
|
83
98
|
cd <top-module-dir> && plain-parser check <top>.plain
|
|
84
99
|
```
|
|
85
100
|
|
|
86
101
|
Add `--config-name <name>` when the governing config is not named `config.yaml`. `plain-parser` reads `template-dir` from the config next to the `.plain` file or in the working directory, and exits `2` when it finds one in both — running from the module's own directory avoids that in multi-part projects.
|
|
87
|
-
|
|
102
|
+
4. **Read the result.** Exit `0` prints `<file>: OK`. Exit `1` prints `Error: …` on stderr — record that message verbatim as a failure against the top module. Exit `2` is a usage or config error (ambiguous or malformed config) — record it against the config.
|
|
88
103
|
|
|
89
|
-
`plain-parser` checks, among other things: frontmatter, that every `import` / `requires` entry exists and the graph has no cycles, that `requires` modules have one fixed order, that imported modules have no functional specs, section headings (allowed, not duplicated, `***definitions***` first, `***
|
|
104
|
+
`plain-parser` checks, among other things: frontmatter, that every `import` / `requires` entry exists and the graph has no cycles, that `requires` modules have one fixed order, that imported modules have no functional specs, section headings (allowed, not duplicated, `***definitions***` first), `# func-id` headings in `***functional specs***` with unique func-ids, test plain files (frontmatter `module:` and `func_id:` naming an existing functionality, both sections present, unique scenario-ids), concepts (defined, exported and required correctly), that a module with functional specs has implementation reqs, and that every linked resource and template resolves to an existing, relative, non-`.plain` file. It does not always report every error in one run, so after fixing what it reported, run it again until it prints `OK`.
|
|
90
105
|
|
|
91
106
|
#### 3b. Check what the parser can't judge
|
|
92
107
|
|
|
93
108
|
Check every `.plain` module against the rules loaded by `load-plain-reference`:
|
|
94
109
|
|
|
95
110
|
1. **Section ownership.** No fact sits in a section that doesn't own it — `:UnitTests:` facts only in `***implementation reqs***`, `:ConformanceTests:` facts only in `***test reqs***`, technology only in `***implementation reqs***`.
|
|
96
|
-
2. **Bullets.** Every line in
|
|
111
|
+
2. **Bullets and headings.** Every line in `***definitions***`, `***implementation reqs***`, and `***test reqs***` is a valid `- ` list item or a correctly indented sub-bullet — no bare continuation lines. Every functionality in `***functional specs***` is a `# <func-id>` heading followed by its body.
|
|
97
112
|
3. **Linked resources.** Every linked resource is a single **text** file (not a binary), and no URL or folder path appears in the surrounding spec text unless it is a runtime value the generated software itself uses.
|
|
113
|
+
4. **Test plain files.** Every test plain file binds to an existing functionality (`module:` names a module, `func_id:` one of its `# func-id` headings) and has both sections in order. Scenario-ids are unique per functionality across every file bound to it. When the module's `config.yaml` has a `conformance-tests-script`, every functionality has at least one conformance scenario; a functionality with none is a failure that names `add-test-scenarios`. A scenario under `***conformance tests***` that describes use that is not expected (invalid parameters, wrong or missing authentication, missing data), or one under `***acceptance tests***` that describes the expected use, is a failure that names `add-test-scenarios`.
|
|
98
114
|
|
|
99
115
|
Functional-spec complexity is checked when a spec is authored (`add-functional-spec(s)` → `analyze-if-func-spec-too-complex`). Re-run `analyze-if-func-spec-too-complex` here only for a spec that was hand-edited since it was authored.
|
|
100
116
|
|
|
@@ -105,7 +121,7 @@ Treat 3a and 3b together as a hard gate: the healthcheck **only passes** when `p
|
|
|
105
121
|
Iterate until it passes:
|
|
106
122
|
|
|
107
123
|
1. Identify the offending `.plain` file, the line, and the kind of issue: missing or duplicated concept, cyclic definition, broken `import`/`requires`, misplaced fact, bare continuation line, missing resource or template, etc.
|
|
108
|
-
2. Fix only the `.plain` files (or the relevant `config.yaml` / template) using the appropriate edit skill — `add-concept`, `add-functional-spec`, `add-functional-specs`, `add-implementation-requirement`, `resolve-section-ownership`, `resolve-spec-conflict`, `break-down-func-spec`, `consolidate-concepts`, or an inline edit. **Never** modify generated code under `plain_modules/<module>/code/` or `plain_modules/<module>/tests/`.
|
|
124
|
+
2. Fix only the `.plain` files (or the relevant `config.yaml` / template) using the appropriate edit skill — `add-concept`, `add-functional-spec`, `add-functional-specs`, `add-implementation-requirement`, `add-test-scenarios`, `resolve-section-ownership`, `resolve-spec-conflict`, `break-down-func-spec`, `consolidate-concepts`, or an inline edit. **Never** modify generated code under `plain_modules/<module>/code/` or `plain_modules/<module>/tests/`.
|
|
109
125
|
3. If you are uncertain about ***plain syntax for the failing construct, re-load `load-plain-reference` before fixing.
|
|
110
126
|
4. Re-run the failed checks — for a `plain-parser` failure, re-run `plain-parser check`. Repeat until they pass.
|
|
111
127
|
|
|
@@ -115,7 +131,7 @@ If the failure is something the healthcheck cannot reasonably fix on its own (e.
|
|
|
115
131
|
|
|
116
132
|
Emit one of:
|
|
117
133
|
|
|
118
|
-
- **`PASS`** — followed by a short summary of what was checked: `N config.yaml(s) validated`, `M module(s) checked (plain-parser OK for every top module)`, `K scripts referenced`. The caller (`forge-plain`, `add-feature`, `debug-specs`) can then continue to its hand-off step.
|
|
134
|
+
- **`PASS`** — followed by a short summary of what was checked: `N config.yaml(s) validated`, `M module(s) checked (plain-parser OK for every top module)`, `T test plain file(s) bound`, `K scripts referenced`. The caller (`forge-plain`, `add-feature`, `debug-specs`) can then continue to its hand-off step.
|
|
119
135
|
- **`FAIL`** — followed by a numbered list of every unresolved problem. Each entry must include: the file (config / `.plain` / script) it applies to, the concrete issue, and what the user needs to decide if the healthcheck couldn't resolve it.
|
|
120
136
|
|
|
121
137
|
The verdict goes on the first line so callers can pattern-match without parsing the whole report.
|
|
@@ -136,6 +152,8 @@ The verdict goes on the first line so callers can pattern-match without parsing
|
|
|
136
152
|
- [ ] No `config.yaml` mixes stacks (e.g. Python + JS scripts in the same file)
|
|
137
153
|
- [ ] No `config.yaml` declares `prepare-environment-script` without also declaring `conformance-tests-script`
|
|
138
154
|
- [ ] Every `test_scripts/*` file is referenced by some `config.yaml` (or surfaced as a warning)
|
|
155
|
+
- [ ] The parser probe passed, or the report says 3a is suspended and names the plain-parser release that is needed
|
|
139
156
|
- [ ] `plain-parser check` printed `OK` for every top module, run from that module's directory
|
|
140
|
-
- [ ] Every module passes every check in Step 3b (section ownership, bullets, linked resources)
|
|
157
|
+
- [ ] Every module passes every check in Step 3b (section ownership, bullets and headings, linked resources, test plain files)
|
|
158
|
+
- [ ] Every test plain file binds to an existing functionality, and every functionality has at least one conformance scenario when conformance tests are enabled
|
|
141
159
|
- [ ] Verdict (`PASS` / `FAIL`) is on the first line, with a numbered list of remaining problems if it failed
|
|
@@ -9,7 +9,7 @@ description: >-
|
|
|
9
9
|
|
|
10
10
|
# Refactor Module
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**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.
|
|
13
13
|
|
|
14
14
|
## When to Use
|
|
15
15
|
|
|
@@ -29,7 +29,7 @@ The `.plain` file to refactor, plus guidance from the user on the desired groupi
|
|
|
29
29
|
## Phase 1 — Analyze the Current Module
|
|
30
30
|
|
|
31
31
|
1. **Read the entire `.plain` file** — frontmatter, definitions, implementation reqs, test reqs, and all functional specs. Also read any `import` and `requires` chains to understand the full context.
|
|
32
|
-
2. **Inventory the functional specs.**
|
|
32
|
+
2. **Inventory the functional specs.** List each functionality by its func-id and note which `:Concepts:` it references. Build a dependency map: which specs depend on earlier specs (by referencing behavior or state they introduced)?
|
|
33
33
|
3. **Inventory the definitions.** For each concept, note which functional specs reference it. Identify concepts that are used across multiple logical groups vs. concepts used only within one group.
|
|
34
34
|
4. **Identify logical groups.** Look for natural seams — clusters of functional specs that share concepts, represent a cohesive domain, or describe a single feature area. Common groupings:
|
|
35
35
|
- Data model setup and CRUD operations
|
|
@@ -50,7 +50,7 @@ The modules form a `requires` chain that preserves the original chronological or
|
|
|
50
50
|
```
|
|
51
51
|
original-module
|
|
52
52
|
↓ splits into
|
|
53
|
-
module-group-a (no requires — this is the
|
|
53
|
+
module-group-a (no requires — this is the chain root)
|
|
54
54
|
module-group-b (requires: module-group-a)
|
|
55
55
|
module-group-c (requires: module-group-b)
|
|
56
56
|
```
|
|
@@ -86,7 +86,7 @@ If many concepts are shared across all modules, consider creating a new import m
|
|
|
86
86
|
|
|
87
87
|
Summarize for the user:
|
|
88
88
|
- Number of resulting modules and their names
|
|
89
|
-
- Which functional specs go in each module (listed by
|
|
89
|
+
- Which functional specs go in each module (listed by func-id)
|
|
90
90
|
- The `requires` chain order
|
|
91
91
|
- Any new import module being created
|
|
92
92
|
- Which concepts are exported from each module
|
|
@@ -96,20 +96,20 @@ Get explicit user confirmation before proceeding.
|
|
|
96
96
|
|
|
97
97
|
## Phase 3 — Execute the Split
|
|
98
98
|
|
|
99
|
-
Create the new modules in order, from the
|
|
99
|
+
Create the new modules in order, from the root of the chain upward.
|
|
100
100
|
|
|
101
101
|
### 3a. Create or update the import template (if needed)
|
|
102
102
|
|
|
103
103
|
If shared definitions or reqs are being moved to a new import template, create it first using the `create-import-module` skill.
|
|
104
104
|
|
|
105
|
-
### 3b. Create the
|
|
105
|
+
### 3b. Create the chain root
|
|
106
106
|
|
|
107
107
|
Create the first module in the chain:
|
|
108
108
|
1. Set the YAML frontmatter — inherit the original module's `import` references. Add `exported_concepts` for any concepts that downstream modules need.
|
|
109
109
|
2. Add the `***definitions***` section with concepts used by this module's specs and concepts that need to be exported.
|
|
110
110
|
3. Add `***implementation reqs***` and `***test reqs***` specific to this module (if not fully covered by the import template).
|
|
111
111
|
4. Add the `***functional specs***` assigned to this module, preserving their original order and exact wording.
|
|
112
|
-
5.
|
|
112
|
+
5. Set the `module:` key of the moved functionalities' test plain files to the new module name and move the files to the new module's conventional location; func-ids and scenario text stay unchanged.
|
|
113
113
|
|
|
114
114
|
### 3c. Create subsequent modules
|
|
115
115
|
|
|
@@ -119,7 +119,7 @@ For each subsequent module in the chain:
|
|
|
119
119
|
3. Add `***definitions***` for concepts local to this module. Do **not** redefine concepts already available via `requires` (exported) or `import`.
|
|
120
120
|
4. Add `***implementation reqs***` and `***test reqs***` specific to this module.
|
|
121
121
|
5. Add the `***functional specs***` assigned to this module, preserving their original order and exact wording.
|
|
122
|
-
6.
|
|
122
|
+
6. Move the test plain files of the moved functionalities the same way.
|
|
123
123
|
|
|
124
124
|
### 3d. Handle the original module file
|
|
125
125
|
|
|
@@ -135,12 +135,12 @@ This is the most critical verification. Walk through every functional spec from
|
|
|
135
135
|
|
|
136
136
|
Checklist:
|
|
137
137
|
- [ ] Total spec count across all new modules equals the original spec count
|
|
138
|
-
- [ ] Each spec's text is identical to the original (no rewording)
|
|
139
|
-
- [ ] Each
|
|
138
|
+
- [ ] Each spec's text is identical to the original (no rewording) and keeps its func-id
|
|
139
|
+
- [ ] Each functionality's test plain file moved with it, with `module:` updated and scenarios intact
|
|
140
140
|
|
|
141
141
|
### 4b. Chronological ordering check
|
|
142
142
|
|
|
143
|
-
Verify that the chronological order of all functional specs — when read across the requires chain from
|
|
143
|
+
Verify that the chronological order of all functional specs — when read across the requires chain from root to leaf — matches the original ordering exactly. A spec must not appear before a spec it depends on.
|
|
144
144
|
|
|
145
145
|
### 4c. Concept availability check
|
|
146
146
|
|
|
@@ -169,7 +169,7 @@ Read each new `.plain` file in full and present the final structure to the user
|
|
|
169
169
|
Creating many tiny modules with 1–2 specs each adds overhead without clarity. Aim for modules with 3–10 functional specs each, grouped around a cohesive theme.
|
|
170
170
|
|
|
171
171
|
### Breaking chronological order
|
|
172
|
-
Specs that set up foundational behavior (entry point, database init, core CRUD) must stay in the
|
|
172
|
+
Specs that set up foundational behavior (entry point, database init, core CRUD) must stay in the chain root even if they touch concepts from multiple domains. Only split when specs are cleanly separable.
|
|
173
173
|
|
|
174
174
|
### Forgetting exported_concepts
|
|
175
175
|
If a concept defined in module A is referenced by a spec in module B (which requires A), the concept must be in A's `exported_concepts`. Missing exports cause rendering failures.
|
|
@@ -177,21 +177,21 @@ If a concept defined in module A is referenced by a spec in module B (which requ
|
|
|
177
177
|
### Modifying spec text during the split
|
|
178
178
|
This is a refactoring, not a rewrite. Spec text must be copied verbatim. If a spec needs rewording to work in its new module context, that is a sign the split boundary is wrong — adjust the grouping instead.
|
|
179
179
|
|
|
180
|
-
### Losing
|
|
181
|
-
|
|
180
|
+
### Losing test plain files
|
|
181
|
+
A test plain file binds to its functionality by `module:` and `func_id:`. When a functionality moves to a new module, its `module:` key changes and the file moves to the new module's conventional location; otherwise the renderer reports a pair that matches no functionality.
|
|
182
182
|
|
|
183
183
|
## Validation Checklist
|
|
184
184
|
|
|
185
185
|
- [ ] User confirmed the split plan before execution
|
|
186
186
|
- [ ] All original functional specs are present in exactly one new module — none lost
|
|
187
187
|
- [ ] Spec text is identical to the original — no rewording
|
|
188
|
-
- [ ]
|
|
188
|
+
- [ ] Test plain files moved with their functionalities and rebound to the new module
|
|
189
189
|
- [ ] Chronological order preserved across the requires chain
|
|
190
190
|
- [ ] Every referenced `:Concept:` is available in each module (local, import, or exported)
|
|
191
191
|
- [ ] `exported_concepts` are correctly set on each module
|
|
192
192
|
- [ ] No concept name collisions
|
|
193
193
|
- [ ] Each module has at least one functional spec and one implementation req
|
|
194
|
-
- [ ] `requires` chain is correctly ordered (
|
|
194
|
+
- [ ] `requires` chain is correctly ordered (root → leaf)
|
|
195
195
|
- [ ] Original module removed or updated
|
|
196
196
|
- [ ] Downstream modules (if any) updated to require the chain tip, plus any earlier chain modules whose exported concepts they reference
|
|
197
197
|
- [ ] User approved the final result
|
|
@@ -6,7 +6,7 @@ description: >-
|
|
|
6
6
|
|
|
7
7
|
# Resolve Section Ownership
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
**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.
|
|
10
10
|
|
|
11
11
|
This is the ownership counterpart to `break-down-func-spec`. That skill splits one functional spec into several because it is **too large**; this one moves facts between sections because they are in the **wrong place**. The two are unrelated: a correctly placed spec can be too large, and a one-line bullet can be misplaced.
|
|
12
12
|
|
|
@@ -36,7 +36,7 @@ The bullet, section, or `.plain` file to resolve.
|
|
|
36
36
|
4. **Route each fact** by the *Section ownership* table in `module-structure.md`. Where a fact resists the table, apply the question it encodes: **would a caller of the finished software observe this?** Yes → `***functional specs***`. No, it is how the result is reached → `***implementation reqs***`. It says what a term means → `***definitions***`. It shapes `:ConformanceTests:` → `***test reqs***`.
|
|
37
37
|
5. **Split a fact that carries both a mechanism and its consequence.** The consequence is observable and becomes the functional spec; the mechanism becomes the implementation req. *"Sends the same idempotency key on every retry, so a retried write creates at most one record"* is two facts, not one.
|
|
38
38
|
6. **Give each moved fact a subject that exists in the built system.** A fact leaving a functional spec often loses its subject: name the component that owns the behavior, and add it to `***definitions***` if it is not defined yet. `:Implementation:` is the whole codebase — use it only for a fact that holds everywhere.
|
|
39
|
-
7. **Author each fact into its owning section** with the right edit skill — `add-concept`, `add-implementation-requirement`, `add-test-requirement`, `add-
|
|
39
|
+
7. **Author each fact into its owning section** with the right edit skill — `add-concept`, `add-implementation-requirement`, `add-test-requirement`, `add-test-scenarios`. **Never hand-author `***functional specs***`**: a fact moving *into* that section goes through `add-functional-spec`, which runs the complexity and conflict analyzers for you.
|
|
40
40
|
8. **Remove each fact from where it no longer belongs.** If a bullet is left stating nothing observable, delete the bullet; do not leave a stub. Deleting the last bullet of a section deletes the section.
|
|
41
41
|
9. **Verify nothing was lost and nothing was duplicated.** Walk every fact from the original text and confirm it appears in exactly one section. A fact that now reads as obvious in its new home is still a cut decision — make it deliberately, per `concise-specs.md`.
|
|
42
42
|
10. **Run `plain-healthcheck`.** Moving facts changes the renderable surface; do not finish on a `FAIL`.
|
|
@@ -48,7 +48,7 @@ The bullet, section, or `.plain` file to resolve.
|
|
|
48
48
|
- **`add-functional-spec` reports a conflict** → resolve it with `resolve-spec-conflict` **before** removing the fact from its old section, so no version of it is lost in between.
|
|
49
49
|
- **A fact appears to belong to two sections** → it is two facts; split it per step 5. If it still resists, it is a mechanism whose consequence has not been written down — write the consequence, and the split follows.
|
|
50
50
|
- **The owning section does not exist in the file** → create it in canonical order. An import module carries no `***functional specs***` at all (see `import-modules.md`), so an observable fact found there belongs on the root module that imports it.
|
|
51
|
-
- **The move empties a functional spec** → delete the spec rather than leaving a placeholder, and
|
|
51
|
+
- **The move empties a functional spec** → delete the spec rather than leaving a placeholder, and move or delete its test plain file with `add-test-scenarios`.
|
|
52
52
|
|
|
53
53
|
## Worked examples
|
|
54
54
|
|
|
@@ -9,7 +9,7 @@ description: >-
|
|
|
9
9
|
|
|
10
10
|
# Resolve Spec Conflict
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**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.
|
|
13
13
|
|
|
14
14
|
## When This Applies
|
|
15
15
|
|
|
@@ -31,7 +31,7 @@ There are three possible outcomes — determine which one applies **before** mak
|
|
|
31
31
|
| Outcome | Symptom | Fix |
|
|
32
32
|
|---------|---------|-----|
|
|
33
33
|
| **Implementation is incorrect** | Generated code doesn't match the spec's intent. The specs themselves are fine. | Clarify the ambiguous spec so the renderer interprets it correctly. Re-render. |
|
|
34
|
-
| **Conformance tests are incorrect** | The tests don't accurately verify the spec. The implementation is actually correct. | Adjust `***test reqs
|
|
34
|
+
| **Conformance tests are incorrect** | The tests don't accurately verify the spec. The implementation is actually correct. | Adjust `***test reqs***`, or the scenarios in the test plain file via `add-test-scenarios`, to guide better test generation. Re-render. |
|
|
35
35
|
| **Requirements truly conflict** | The two specs are inherently contradictory — no implementation can satisfy both. | One or both specs must be revised. See Step 3. |
|
|
36
36
|
|
|
37
37
|
**How to diagnose:**
|
|
@@ -49,25 +49,29 @@ Before (ambiguous):
|
|
|
49
49
|
```plain
|
|
50
50
|
***functional specs***
|
|
51
51
|
|
|
52
|
-
-
|
|
52
|
+
# list-resources
|
|
53
|
+
All :Resource: items are returned.
|
|
53
54
|
|
|
54
|
-
-
|
|
55
|
+
# list-active-resources
|
|
56
|
+
Only active :Resource: items are returned.
|
|
55
57
|
```
|
|
56
58
|
|
|
57
59
|
After (disambiguated):
|
|
58
60
|
```plain
|
|
59
61
|
***functional specs***
|
|
60
62
|
|
|
61
|
-
-
|
|
63
|
+
# list-resources
|
|
64
|
+
All :Resource: items are returned when no filter is specified.
|
|
62
65
|
|
|
63
|
-
-
|
|
66
|
+
# list-active-resources
|
|
67
|
+
When the "active" filter is specified, only active :Resource: items are returned.
|
|
64
68
|
```
|
|
65
69
|
|
|
66
70
|
**Strategy B: Revise the newer spec.** If the new spec introduced the conflict, rewrite it to be compatible with the established behavior from earlier specs.
|
|
67
71
|
|
|
68
72
|
**Strategy C: Revise the older spec.** If the older spec was under-specified and the new requirement reveals a better design, update the older spec. This is more disruptive — all conformance tests for that spec and everything after it may need re-rendering.
|
|
69
73
|
|
|
70
|
-
**Strategy D: Merge into one spec.** If the two specs describe overlapping behavior, combine them into a single, clear spec. Remove the redundant one. Be mindful of the 200 LOC limit.
|
|
74
|
+
**Strategy D: Merge into one spec.** If the two specs describe overlapping behavior, combine them into a single, clear spec. Remove the redundant one and its test plain file, moving any still valid scenario into the kept functionality's file. Be mindful of the 200 LOC limit.
|
|
71
75
|
|
|
72
76
|
### Step 4: Validate the Resolution
|
|
73
77
|
|
|
@@ -75,7 +79,8 @@ After editing:
|
|
|
75
79
|
1. Re-read the full `***functional specs***` section to confirm no new conflicts were introduced.
|
|
76
80
|
2. Check that any revised spec still respects the 200 LOC limit.
|
|
77
81
|
3. Check that chronological ordering still makes sense (earlier specs should not depend on later ones).
|
|
78
|
-
4. If resolving via test adjustments, verify the `***test reqs***` or
|
|
82
|
+
4. If resolving via test adjustments, verify the `***test reqs***` or test plain file changes are appropriate.
|
|
83
|
+
5. For every revised functionality, invoke `add-test-scenarios` to bring its test plain file in step with the new text.
|
|
79
84
|
|
|
80
85
|
## Prevention (for use during add-functional-spec / add-functional-specs)
|
|
81
86
|
|
|
@@ -95,3 +100,4 @@ Before adding a new spec, run through this quick conflict check:
|
|
|
95
100
|
- [ ] No new conflicts introduced by the fix
|
|
96
101
|
- [ ] Chronological ordering preserved
|
|
97
102
|
- [ ] All referenced `:Concepts:` are still defined
|
|
103
|
+
- [ ] Test plain files of the revised functionalities brought in step via `add-test-scenarios`
|