plain-forge 1.0.1
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/LICENSE +21 -0
- package/README.md +247 -0
- package/bin/cli.mjs +143 -0
- package/forge/docs/.gitkeep +0 -0
- package/forge/rules/definitions.md +57 -0
- package/forge/rules/exported-concepts.md +39 -0
- package/forge/rules/func-specs.md +72 -0
- package/forge/rules/impl-reqs.md +50 -0
- package/forge/rules/import-modules.md +51 -0
- package/forge/rules/required-concepts.md +45 -0
- package/forge/rules/requires-modules.md +59 -0
- package/forge/rules/test-reqs.md +47 -0
- package/forge/skills/add-acceptance-test/SKILL.md +98 -0
- package/forge/skills/add-concept/SKILL.md +67 -0
- package/forge/skills/add-feature/SKILL.md +136 -0
- package/forge/skills/add-functional-spec/SKILL.md +81 -0
- package/forge/skills/add-functional-specs/SKILL.md +115 -0
- package/forge/skills/add-implementation-requirement/SKILL.md +73 -0
- package/forge/skills/add-resource/SKILL.md +108 -0
- package/forge/skills/add-template/SKILL.md +65 -0
- package/forge/skills/add-test-requirement/SKILL.md +68 -0
- package/forge/skills/analyze-2-func-specs/SKILL.md +102 -0
- package/forge/skills/analyze-func-specs/SKILL.md +124 -0
- package/forge/skills/analyze-if-func-spec-too-complex/SKILL.md +152 -0
- package/forge/skills/break-down-func-spec/SKILL.md +156 -0
- package/forge/skills/check-plain-env/SKILL.md +288 -0
- package/forge/skills/consolidate-concepts/SKILL.md +193 -0
- package/forge/skills/create-import-module/SKILL.md +98 -0
- package/forge/skills/create-requires-module/SKILL.md +104 -0
- package/forge/skills/debug-specs/SKILL.md +189 -0
- package/forge/skills/forge-integration/SKILL.md +443 -0
- package/forge/skills/forge-plain/SKILL.md +333 -0
- package/forge/skills/implement-conformance-testing-script/SKILL.md +247 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_cypress.ps1 +324 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_golang.ps1 +100 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +102 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.ps1 +92 -0
- package/forge/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +100 -0
- package/forge/skills/implement-prepare-environment-script/SKILL.md +242 -0
- package/forge/skills/implement-prepare-environment-script/assets/prepare_environment_java.sh +42 -0
- package/forge/skills/implement-prepare-environment-script/assets/prepare_environment_python.sh +81 -0
- package/forge/skills/implement-unit-testing-script/SKILL.md +133 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_flutter.ps1 +82 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_golang.ps1 +68 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_java.sh +45 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_python.ps1 +76 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_python.sh +90 -0
- package/forge/skills/implement-unit-testing-script/assets/run_unittests_react.ps1 +83 -0
- package/forge/skills/init-config-file/SKILL.md +261 -0
- package/forge/skills/init-plain-project/SKILL.md +124 -0
- package/forge/skills/load-plain-reference/SKILL.md +646 -0
- package/forge/skills/plain-healthcheck/SKILL.md +132 -0
- package/forge/skills/refactor-module/SKILL.md +197 -0
- package/forge/skills/resolve-spec-conflict/SKILL.md +88 -0
- package/forge/skills/run-codeplain/SKILL.md +540 -0
- package/package.json +42 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plain-healthcheck
|
|
3
|
+
description: >-
|
|
4
|
+
Verification gate for a ***plain project. Verifies that every `config.yaml`
|
|
5
|
+
exists, points at scripts that actually live in `test_scripts/`, and that
|
|
6
|
+
`codeplain <top_module>.plain --dry-run` passes for every top module in
|
|
7
|
+
the project. Run this whenever anything in the project is finalized —
|
|
8
|
+
including (but not limited to) the end of `forge-plain`, the end of
|
|
9
|
+
`add-feature`, after `debug-specs`, after any single-skill edit that
|
|
10
|
+
finalizes a concept, functional spec, requirement, template, or config —
|
|
11
|
+
and any time the user asks "is the project ready to render?".
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Plain Healthcheck
|
|
15
|
+
|
|
16
|
+
Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
|
|
17
|
+
|
|
18
|
+
## When to run
|
|
19
|
+
|
|
20
|
+
Run this skill **whenever anything in the ***plain project is finalized** and the project is about to be left in a state the user (or another skill) might render from. That includes, but is not limited to:
|
|
21
|
+
|
|
22
|
+
- **End of `forge-plain`** (Phase 4) — before presenting the render command.
|
|
23
|
+
- **End of `add-feature`** (Phase 3 final review) — before declaring the feature done.
|
|
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-acceptance-test`, `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
|
+
- **After hand-editing** a `.plain` file, a `config.yaml`, or anything under `test_scripts/`.
|
|
27
|
+
- **On demand** — whenever the user asks whether the project is in a renderable state.
|
|
28
|
+
|
|
29
|
+
The healthcheck is **not** a forge-plain-only step. Treat it as the default closing move for any workflow that finalizes something in the project.
|
|
30
|
+
|
|
31
|
+
Do **not** skip this skill because "the dry-run passed earlier" — `config.yaml`s, scripts, and specs can all drift between runs. The healthcheck is cheap; rendering against stale specs is expensive.
|
|
32
|
+
|
|
33
|
+
## Workflow
|
|
34
|
+
|
|
35
|
+
The skill is a **detect → fix → re-run** loop. It does not stop at the first failure; it surfaces everything wrong, fixes what it can, and only returns when either everything passes or a gap genuinely requires user input.
|
|
36
|
+
|
|
37
|
+
### Step 1 — Inventory the project
|
|
38
|
+
|
|
39
|
+
1. List every `.plain` file in the repo root (and any subdirectories that contain `.plain` files). Build the module graph from each file's YAML frontmatter (`requires`, `import`).
|
|
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
|
+
3. List every `config.yaml` in the repo (root and per-part directories such as `backend/`, `frontend/`).
|
|
42
|
+
4. List every script under `test_scripts/`.
|
|
43
|
+
5. 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
|
+
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
|
+
|
|
47
|
+
### Step 2 — Validate every `config.yaml`
|
|
48
|
+
|
|
49
|
+
For each `config.yaml` in the inventory, check **all** of the following. Collect every failure — do **not** stop at the first.
|
|
50
|
+
|
|
51
|
+
1. **File parses.** It is valid YAML.
|
|
52
|
+
2. **At minimum `unittests-script` is present.** Every project gets a unit-test runner.
|
|
53
|
+
3. **For every script field that is present** (`unittests-script`, `conformance-tests-script`, `prepare-environment-script`):
|
|
54
|
+
- The path is a string ending in `.sh` (macOS/Linux) or `.ps1` (Windows). The extension must match the rest of the project — do not mix `.sh` and `.ps1` in a single config.
|
|
55
|
+
- The referenced file actually exists on disk under `test_scripts/`.
|
|
56
|
+
- On Unix, the script has the executable bit set (`-x`). If not, that is a fixable failure.
|
|
57
|
+
4. **No mixed stacks per config.** Every script referenced from a single `config.yaml` must target the same language/stack. For example, `backend/config.yaml` should not reference `run_unittests_js.sh`. If a config crosses stacks, that is a failure — the project should have been split into multiple configs per the rule in `PLAIN_REFERENCE.md`.
|
|
58
|
+
5. **No dangling fields.** Any `*-script` field whose target file does not exist is a failure.
|
|
59
|
+
6. **`prepare-environment-script` implies `conformance-tests-script`.** A `prepare-environment-script` only makes sense in service of conformance tests — the environment is what those tests run against. If a `config.yaml` declares `prepare-environment-script` but does **not** declare `conformance-tests-script`, that is a failure. Surface it to the user and offer to either (a) invoke `implement-conformance-testing-script` to add the missing script, or (b) remove the `prepare-environment-script` field if it was added in error. Do not auto-pick.
|
|
60
|
+
7. **No orphan scripts.** Every script under `test_scripts/` should be referenced by *some* `config.yaml`. If a script is never referenced, surface it as a **warning** (not a hard failure — the user may be in the middle of authoring).
|
|
61
|
+
|
|
62
|
+
For each failure, record the offending config path, the offending field, and the concrete problem (`file missing`, `not executable`, `mixed stack`, etc.).
|
|
63
|
+
|
|
64
|
+
#### Auto-fixes you may apply
|
|
65
|
+
|
|
66
|
+
- **Missing executable bit** on a script that otherwise looks fine → `chmod +x <path>`.
|
|
67
|
+
- **Stale path that points at a renamed script that clearly exists under a different name in `test_scripts/`** → only if there is exactly one obvious candidate (same language tag, same script kind). When in doubt, leave it for the user.
|
|
68
|
+
|
|
69
|
+
Anything else (missing script, mixed stacks, missing `config.yaml`) must be surfaced to the user — do not silently regenerate scripts here. Re-invoking `implement-unit-testing-script`, `implement-conformance-testing-script`, or `implement-prepare-environment-script` from inside the healthcheck is allowed **only** if the user explicitly approves it after being shown the gap.
|
|
70
|
+
|
|
71
|
+
### Step 3 — Dry-run every top module
|
|
72
|
+
|
|
73
|
+
For each `(top_module, config.yaml)` pair from Step 1, run a dry-run from the project root via the `terminal` tool:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
codeplain <top_module>.plain --dry-run
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Match the dry-run to how the user will actually render.** Pass the flags the user would pass for the real render so what you validate is what they will run:
|
|
80
|
+
|
|
81
|
+
- **`--config-name <name>`** — required whenever the governing config file is not the default `config.yaml`, or when the project has multiple `config.yaml`s and the dry-run is being launched from somewhere that isn't the part's directory. `--config-name` takes a *file name*, not a path; if needed, `cd` into the part's directory before running so the right `config.yaml` is found.
|
|
82
|
+
- **`--template-dir <path>`** — only when templates live outside `template/` **and** `template_dir` is not already set in the relevant config.
|
|
83
|
+
- **`--full-plain`** — useful when an `import`/`requires` chain is suspect.
|
|
84
|
+
- **`--verbose` / `-v`** — strongly recommended on a failed dry-run; the extra log output usually pinpoints the offending `.plain` file and spec.
|
|
85
|
+
|
|
86
|
+
Treat the dry-run as a hard gate: the healthcheck **only passes** when every top module's dry-run exits successfully.
|
|
87
|
+
|
|
88
|
+
#### When a dry-run fails
|
|
89
|
+
|
|
90
|
+
Iterate until it passes:
|
|
91
|
+
|
|
92
|
+
1. Read the error output. If the first run was not verbose, immediately re-run with `--verbose`. Identify the offending `.plain` file, the line (if reported), and the kind of issue: missing concept, syntax error, cyclic definition, complexity violation (`Functional spec too complex!`), conflicting reqs, missing template, broken `import`/`requires`, missing config field, etc.
|
|
93
|
+
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-spec-conflict`, `break-down-func-spec`, `consolidate-concepts`, or an inline edit. **Never** modify generated code under `plain_modules/` or `conformance_tests/`.
|
|
94
|
+
3. If you are uncertain about ***plain syntax for the failing construct, re-load `load-plain-reference` before fixing.
|
|
95
|
+
4. Re-run the same `codeplain <top_module>.plain --dry-run …` command with the same flags. Repeat until it exits successfully.
|
|
96
|
+
|
|
97
|
+
If the failure is something the healthcheck cannot reasonably fix on its own (e.g. the user has to choose between two contradictory specs and neither side was pre-approved, or a missing concept whose semantics aren't clear), **stop and surface it to the user** with the offending snippet and a concrete question. Do not invent behavior.
|
|
98
|
+
|
|
99
|
+
#### Environment failures
|
|
100
|
+
|
|
101
|
+
If `codeplain` is not on PATH, or `CODEPLAIN_API_KEY` is not set:
|
|
102
|
+
|
|
103
|
+
- Do **not** pretend the dry-run passed.
|
|
104
|
+
- Tell the user exactly what's missing and how to fix it (install the CLI, export the env var) and stop the healthcheck with a clearly-marked environment failure. This is the only kind of failure that may legitimately remain unresolved at the end of the skill.
|
|
105
|
+
|
|
106
|
+
### Step 4 — Report
|
|
107
|
+
|
|
108
|
+
Emit one of:
|
|
109
|
+
|
|
110
|
+
- **`PASS`** — followed by a short summary of what was checked: `N config.yaml(s) validated`, `M top module(s) dry-run`, `K scripts referenced`. The caller (`forge-plain`, `add-feature`, `debug-specs`) can then continue to its hand-off step.
|
|
111
|
+
- **`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.
|
|
112
|
+
|
|
113
|
+
The verdict goes on the first line so callers can pattern-match without parsing the whole report.
|
|
114
|
+
|
|
115
|
+
## What this skill does NOT do
|
|
116
|
+
|
|
117
|
+
- It does **not** author new specs from scratch — use `forge-plain` / `add-feature` for that.
|
|
118
|
+
- It does **not** run the real render — only `--dry-run`.
|
|
119
|
+
- It does **not** execute the testing scripts (`run_unittests`, `run_conformance_tests`, `prepare_environment`). It only verifies that the scripts are wired up correctly via `config.yaml`. The user runs the scripts themselves.
|
|
120
|
+
- It does **not** silently regenerate config files or scripts. The most it does is `chmod +x` and (with user approval) re-invoke the relevant `implement-*-testing-script` skill.
|
|
121
|
+
|
|
122
|
+
## Validation Checklist
|
|
123
|
+
|
|
124
|
+
- [ ] Every `.plain` module was inventoried and every top module was identified
|
|
125
|
+
- [ ] Every top module is governed by exactly one `config.yaml`
|
|
126
|
+
- [ ] Every `config.yaml` parses as YAML and has at least `unittests-script`
|
|
127
|
+
- [ ] Every `*-script` field points at a file that exists under `test_scripts/`
|
|
128
|
+
- [ ] No `config.yaml` mixes stacks (e.g. Python + JS scripts in the same file)
|
|
129
|
+
- [ ] No `config.yaml` declares `prepare-environment-script` without also declaring `conformance-tests-script`
|
|
130
|
+
- [ ] Every `test_scripts/*` file is referenced by some `config.yaml` (or surfaced as a warning)
|
|
131
|
+
- [ ] `codeplain <top>.plain --dry-run` exits successfully for **every** top module, with the right `--config-name` for multi-part projects
|
|
132
|
+
- [ ] Verdict (`PASS` / `FAIL`) is on the first line, with a numbered list of remaining problems if it failed
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: refactor-module
|
|
3
|
+
description: >-
|
|
4
|
+
Split a large ***plain module into smaller modules grouped by logical domain.
|
|
5
|
+
The resulting modules are connected via a requires chain so that functionality
|
|
6
|
+
is 100% preserved. Use when a module has grown too large and its functional
|
|
7
|
+
specs span multiple distinct concerns that would be clearer as separate modules.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Refactor Module
|
|
11
|
+
|
|
12
|
+
Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
- A module has many functional specs spanning multiple distinct domains or feature areas.
|
|
17
|
+
- The module is hard to reason about because unrelated concerns are interleaved.
|
|
18
|
+
- New features are difficult to add because the module's scope is too broad.
|
|
19
|
+
- The user explicitly asks to split or reorganize a module.
|
|
20
|
+
|
|
21
|
+
## Guiding Principle
|
|
22
|
+
|
|
23
|
+
The refactoring is purely structural. The **combined behavior** of the resulting modules must be **identical** to the original module. No functional spec is added, removed, or weakened. The split is semantic — grouping related specs together — not behavioral.
|
|
24
|
+
|
|
25
|
+
## Input
|
|
26
|
+
|
|
27
|
+
The `.plain` file to refactor, plus guidance from the user on the desired grouping (or ask the user to confirm your proposed grouping).
|
|
28
|
+
|
|
29
|
+
## Phase 1 — Analyze the Current Module
|
|
30
|
+
|
|
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.** Number each spec and note which `:Concepts:` it references. Build a dependency map: which specs depend on earlier specs (by referencing behavior or state they introduced)?
|
|
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
|
+
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
|
+
- Data model setup and CRUD operations
|
|
36
|
+
- Business logic and processing rules
|
|
37
|
+
- UI screens and navigation
|
|
38
|
+
- Integrations and external interfaces
|
|
39
|
+
- Statistics, reporting, and analytics
|
|
40
|
+
5. **Verify group independence.** Each group's specs should form a contiguous or near-contiguous block in chronological order. If a group's specs are scattered and interleaved with other groups, the split boundary may need adjustment.
|
|
41
|
+
|
|
42
|
+
## Phase 2 — Plan the Split
|
|
43
|
+
|
|
44
|
+
Present the proposed split to the user and get explicit confirmation before making any changes.
|
|
45
|
+
|
|
46
|
+
### 2a. Define the module chain
|
|
47
|
+
|
|
48
|
+
The modules form a `requires` chain that preserves the original chronological ordering of functional specs. The first module in the chain contains the earliest specs; each subsequent module `requires` the previous one and adds the next logical group.
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
original-module
|
|
52
|
+
↓ splits into
|
|
53
|
+
module-group-a (no requires — this is the new base)
|
|
54
|
+
module-group-b (requires: module-group-a)
|
|
55
|
+
module-group-c (requires: module-group-b)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If the original module already had `requires` or `import` dependencies, the first new module inherits them.
|
|
59
|
+
|
|
60
|
+
### 2b. Assign functional specs to modules
|
|
61
|
+
|
|
62
|
+
Place each functional spec in exactly one module. The placement must respect chronological ordering:
|
|
63
|
+
- Within each module, the specs appear in the same relative order as in the original.
|
|
64
|
+
- Across the chain, the ordering is preserved: all specs in module A come before all specs in module B, which come before all specs in module C.
|
|
65
|
+
- A spec **cannot** move to an earlier module than a spec it depends on.
|
|
66
|
+
|
|
67
|
+
### 2c. Assign definitions to modules
|
|
68
|
+
|
|
69
|
+
For each concept, determine where it belongs:
|
|
70
|
+
|
|
71
|
+
| Concept usage | Placement |
|
|
72
|
+
|---------------|-----------|
|
|
73
|
+
| Used only within one module's specs | Define in that module |
|
|
74
|
+
| Used across multiple modules in the chain | Define in the first module that uses it, and add to that module's `exported_concepts` |
|
|
75
|
+
| Already defined in an import template | Leave in the import — no change needed |
|
|
76
|
+
|
|
77
|
+
If many concepts are shared across all modules, consider creating a new import module (template) to hold them. This avoids long `exported_concepts` lists and keeps definitions centralized. Use the `create-import-module` skill for this.
|
|
78
|
+
|
|
79
|
+
### 2d. Assign implementation reqs and test reqs
|
|
80
|
+
|
|
81
|
+
- Reqs that apply to all modules should live in a shared import template. If one already exists, keep them there.
|
|
82
|
+
- Reqs specific to a single module's domain move to that module.
|
|
83
|
+
- When in doubt, keep reqs in the shared template — duplication across modules is worse than a slightly broad template.
|
|
84
|
+
|
|
85
|
+
### 2e. Present the plan
|
|
86
|
+
|
|
87
|
+
Summarize for the user:
|
|
88
|
+
- Number of resulting modules and their names
|
|
89
|
+
- Which functional specs go in each module (listed by number or short description)
|
|
90
|
+
- The `requires` chain order
|
|
91
|
+
- Any new import module being created
|
|
92
|
+
- Which concepts are exported from each module
|
|
93
|
+
- Confirmation that all original specs are accounted for (none lost)
|
|
94
|
+
|
|
95
|
+
Get explicit user confirmation before proceeding.
|
|
96
|
+
|
|
97
|
+
## Phase 3 — Execute the Split
|
|
98
|
+
|
|
99
|
+
Create the new modules in order, from the base of the chain upward.
|
|
100
|
+
|
|
101
|
+
### 3a. Create or update the import template (if needed)
|
|
102
|
+
|
|
103
|
+
If shared definitions or reqs are being moved to a new import template, create it first using the `create-import-module` skill.
|
|
104
|
+
|
|
105
|
+
### 3b. Create the base module
|
|
106
|
+
|
|
107
|
+
Create the first module in the chain:
|
|
108
|
+
1. Set the YAML frontmatter — inherit the original module's `import` references. Add `exported_concepts` for any concepts that downstream modules need.
|
|
109
|
+
2. Add the `***definitions***` section with concepts used by this module's specs and concepts that need to be exported.
|
|
110
|
+
3. Add `***implementation reqs***` and `***test reqs***` specific to this module (if not fully covered by the import template).
|
|
111
|
+
4. Add the `***functional specs***` assigned to this module, preserving their original order and exact wording.
|
|
112
|
+
5. Carry over any `***acceptance tests***` nested under the moved functional specs.
|
|
113
|
+
|
|
114
|
+
### 3c. Create subsequent modules
|
|
115
|
+
|
|
116
|
+
For each subsequent module in the chain:
|
|
117
|
+
1. Set `requires` to point to the previous module in the chain. Set `import` if it uses shared templates.
|
|
118
|
+
2. Add `exported_concepts` for any concepts that later modules in the chain need.
|
|
119
|
+
3. Add `***definitions***` for concepts local to this module. Do **not** redefine concepts already available via `requires` (exported) or `import`.
|
|
120
|
+
4. Add `***implementation reqs***` and `***test reqs***` specific to this module.
|
|
121
|
+
5. Add the `***functional specs***` assigned to this module, preserving their original order and exact wording.
|
|
122
|
+
6. Carry over any `***acceptance tests***`.
|
|
123
|
+
|
|
124
|
+
### 3d. Handle the original module file
|
|
125
|
+
|
|
126
|
+
After all new modules are created:
|
|
127
|
+
- If the original module is being fully replaced (all specs moved out), delete it or rename it to avoid confusion.
|
|
128
|
+
- If the original module was required by other modules, update those modules to `require` the last module in the new chain instead (since it transitively includes all prior modules' specs and generated code).
|
|
129
|
+
|
|
130
|
+
## Phase 4 — Verify
|
|
131
|
+
|
|
132
|
+
### 4a. Completeness check
|
|
133
|
+
|
|
134
|
+
This is the most critical verification. Walk through every functional spec from the original module and confirm it appears in exactly one of the new modules. Nothing may be lost, weakened, modified, or left implicit.
|
|
135
|
+
|
|
136
|
+
Checklist:
|
|
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 spec's acceptance tests (if any) are carried over intact
|
|
140
|
+
|
|
141
|
+
### 4b. Chronological ordering check
|
|
142
|
+
|
|
143
|
+
Verify that the chronological order of all functional specs — when read across the requires chain from base to leaf — matches the original ordering exactly. A spec must not appear before a spec it depends on.
|
|
144
|
+
|
|
145
|
+
### 4c. Concept availability check
|
|
146
|
+
|
|
147
|
+
For each module, verify:
|
|
148
|
+
- [ ] Every `:Concept:` referenced in its specs is either defined locally, available via `import`, or available via `exported_concepts` from the `requires` chain
|
|
149
|
+
- [ ] `exported_concepts` includes every concept that downstream modules need
|
|
150
|
+
- [ ] No concept name collisions between modules
|
|
151
|
+
|
|
152
|
+
### 4d. Structural validation per module
|
|
153
|
+
|
|
154
|
+
For each new module:
|
|
155
|
+
- [ ] Has at least one functional spec and one implementation req
|
|
156
|
+
- [ ] YAML frontmatter is correctly formatted
|
|
157
|
+
- [ ] `requires` and `import` paths are correct
|
|
158
|
+
- [ ] Module file is at the repository root (not in `template/`)
|
|
159
|
+
- [ ] Specs are language-agnostic
|
|
160
|
+
- [ ] All external interfaces remain explicit
|
|
161
|
+
|
|
162
|
+
### 4e. Read all new modules
|
|
163
|
+
|
|
164
|
+
Read each new `.plain` file in full and present the final structure to the user for approval. If the user requests changes, apply them and re-verify.
|
|
165
|
+
|
|
166
|
+
## Common Pitfalls
|
|
167
|
+
|
|
168
|
+
### Splitting too aggressively
|
|
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
|
+
|
|
171
|
+
### Breaking chronological order
|
|
172
|
+
Specs that set up foundational behavior (entry point, database init, core CRUD) must stay in the base module even if they touch concepts from multiple domains. Only split when specs are cleanly separable.
|
|
173
|
+
|
|
174
|
+
### Forgetting exported_concepts
|
|
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.
|
|
176
|
+
|
|
177
|
+
### Modifying spec text during the split
|
|
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
|
+
|
|
180
|
+
### Losing acceptance tests
|
|
181
|
+
Acceptance tests are nested under their parent functional spec. When moving a spec to a new module, its acceptance tests must move with it.
|
|
182
|
+
|
|
183
|
+
## Validation Checklist
|
|
184
|
+
|
|
185
|
+
- [ ] User confirmed the split plan before execution
|
|
186
|
+
- [ ] All original functional specs are present in exactly one new module — none lost
|
|
187
|
+
- [ ] Spec text is identical to the original — no rewording
|
|
188
|
+
- [ ] Acceptance tests moved with their parent specs
|
|
189
|
+
- [ ] Chronological order preserved across the requires chain
|
|
190
|
+
- [ ] Every referenced `:Concept:` is available in each module (local, import, or exported)
|
|
191
|
+
- [ ] `exported_concepts` are correctly set on each module
|
|
192
|
+
- [ ] No concept name collisions
|
|
193
|
+
- [ ] Each module has at least one functional spec and one implementation req
|
|
194
|
+
- [ ] `requires` chain is correctly ordered (base → leaf)
|
|
195
|
+
- [ ] Original module removed or updated
|
|
196
|
+
- [ ] Downstream modules (if any) updated to require the correct module
|
|
197
|
+
- [ ] User approved the final result
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: resolve-spec-conflict
|
|
3
|
+
description: >-
|
|
4
|
+
Resolve a conflict between two functional specs in a ***plain spec file. Use
|
|
5
|
+
when conformance tests for a previously passing spec start failing after a new
|
|
6
|
+
spec is rendered, or when a potential conflict is detected while adding a new
|
|
7
|
+
functional spec (via `add-functional-spec` or `add-functional-specs`).
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Resolve Spec Conflict
|
|
11
|
+
|
|
12
|
+
Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
|
|
13
|
+
|
|
14
|
+
## When This Applies
|
|
15
|
+
|
|
16
|
+
A conflict exists (or is suspected) when:
|
|
17
|
+
- Conformance tests for a **previously passing** functional spec begin to fail after a new spec is rendered.
|
|
18
|
+
- A new spec being added (via the `add-functional-spec` or `add-functional-specs` skill) appears to contradict an existing spec.
|
|
19
|
+
- Two specs make incompatible assertions about the same behavior, data, or state.
|
|
20
|
+
|
|
21
|
+
## Workflow
|
|
22
|
+
|
|
23
|
+
### Step 1: Identify the Conflicting Pair
|
|
24
|
+
|
|
25
|
+
Read the `.plain` file and pinpoint the two specs in tension. If the conflict was detected via a conformance test failure, also read the failing test and the generated implementation in `plain_modules/` to understand what behavior changed.
|
|
26
|
+
|
|
27
|
+
### Step 2: Diagnose the Root Cause
|
|
28
|
+
|
|
29
|
+
There are three possible outcomes — determine which one applies **before** making changes:
|
|
30
|
+
|
|
31
|
+
| Outcome | Symptom | Fix |
|
|
32
|
+
|---------|---------|-----|
|
|
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***` or `***acceptance tests***` to guide better test generation. Re-render. |
|
|
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
|
+
|
|
37
|
+
**How to diagnose:**
|
|
38
|
+
1. Read both functional specs carefully. Can a single implementation satisfy both simultaneously?
|
|
39
|
+
2. If yes → the specs are compatible; the issue is ambiguity (outcome 1) or bad tests (outcome 2).
|
|
40
|
+
3. If no → the requirements truly conflict (outcome 3).
|
|
41
|
+
|
|
42
|
+
### Step 3: Resolve the Conflict
|
|
43
|
+
|
|
44
|
+
When the requirements truly conflict, choose a resolution strategy:
|
|
45
|
+
|
|
46
|
+
**Strategy A: Add detail to disambiguate.** Often the specs aren't contradictory — they're just ambiguous enough that the renderer picks a conflicting interpretation. Adding explicit context to one or both specs eliminates the ambiguity.
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
Before (ambiguous):
|
|
50
|
+
- The system should return all :Resource: items.
|
|
51
|
+
- The system should return only active :Resource: items.
|
|
52
|
+
|
|
53
|
+
After (disambiguated):
|
|
54
|
+
- The system should return all :Resource: items when no filter is specified.
|
|
55
|
+
- When the "active" filter is specified, the system should return only active :Resource: items.
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**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.
|
|
59
|
+
|
|
60
|
+
**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.
|
|
61
|
+
|
|
62
|
+
**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.
|
|
63
|
+
|
|
64
|
+
### Step 4: Validate the Resolution
|
|
65
|
+
|
|
66
|
+
After editing:
|
|
67
|
+
1. Re-read the full `***functional specs***` section to confirm no new conflicts were introduced.
|
|
68
|
+
2. Check that any revised spec still respects the 200 LOC limit.
|
|
69
|
+
3. Check that chronological ordering still makes sense (earlier specs should not depend on later ones).
|
|
70
|
+
4. If resolving via test adjustments, verify the `***test reqs***` or `***acceptance tests***` changes are appropriate.
|
|
71
|
+
|
|
72
|
+
## Prevention (for use during add-functional-spec / add-functional-specs)
|
|
73
|
+
|
|
74
|
+
Before adding a new spec, run through this quick conflict check:
|
|
75
|
+
|
|
76
|
+
1. List every existing functional spec that touches the same `:Concepts:` as the new spec.
|
|
77
|
+
2. For each, ask: "Can a single implementation satisfy both this existing spec and the new one?"
|
|
78
|
+
3. If any answer is "not obviously yes" — add explicit detail to the new spec to eliminate the ambiguity **before** inserting it.
|
|
79
|
+
|
|
80
|
+
## Validation Checklist
|
|
81
|
+
|
|
82
|
+
- [ ] Root cause diagnosed (implementation / tests / true conflict)
|
|
83
|
+
- [ ] Resolution strategy chosen and applied
|
|
84
|
+
- [ ] Revised specs are language-agnostic
|
|
85
|
+
- [ ] Revised specs each imply ≤ 200 LOC
|
|
86
|
+
- [ ] No new conflicts introduced by the fix
|
|
87
|
+
- [ ] Chronological ordering preserved
|
|
88
|
+
- [ ] All referenced `:Concepts:` are still defined
|