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.
Files changed (61) hide show
  1. package/README.md +14 -11
  2. package/bin/cli.mjs +5 -4
  3. package/forge/rules/plain-forge.md +10 -0
  4. package/forge/skills/add-concept/SKILL.md +1 -1
  5. package/forge/skills/add-feature/SKILL.md +8 -7
  6. package/forge/skills/add-feature/references/checklist.md +2 -2
  7. package/forge/skills/add-functional-spec/SKILL.md +14 -10
  8. package/forge/skills/add-functional-specs/SKILL.md +14 -10
  9. package/forge/skills/add-implementation-requirement/SKILL.md +1 -1
  10. package/forge/skills/add-resource/SKILL.md +3 -2
  11. package/forge/skills/add-template/SKILL.md +1 -1
  12. package/forge/skills/add-test-requirement/SKILL.md +4 -4
  13. package/forge/skills/add-test-scenarios/SKILL.md +98 -0
  14. package/forge/skills/analyze-2-func-specs/SKILL.md +1 -1
  15. package/forge/skills/analyze-func-specs/SKILL.md +2 -2
  16. package/forge/skills/analyze-if-func-spec-too-complex/SKILL.md +44 -24
  17. package/forge/skills/break-down-func-spec/SKILL.md +57 -33
  18. package/forge/skills/check-plain-env/SKILL.md +2 -2
  19. package/forge/skills/consolidate-concepts/SKILL.md +8 -8
  20. package/forge/skills/create-import-module/SKILL.md +1 -1
  21. package/forge/skills/create-requires-module/SKILL.md +6 -3
  22. package/forge/skills/debug-specs/SKILL.md +14 -8
  23. package/forge/skills/forge-plain/SKILL.md +3 -3
  24. package/forge/skills/forge-plain/references/checklist.md +3 -3
  25. package/forge/skills/forge-plain/references/phase-1-product.md +2 -2
  26. package/forge/skills/forge-plain/references/phase-2-tech.md +1 -1
  27. package/forge/skills/forge-plain/references/phase-3-testing.md +5 -5
  28. package/forge/skills/init-config-file/SKILL.md +2 -2
  29. package/forge/skills/init-plain-project/SKILL.md +6 -6
  30. package/forge/skills/load-plain-reference/SKILL.md +25 -25
  31. package/forge/skills/load-plain-reference/references/project-model.md +2 -1
  32. package/forge/skills/load-plain-reference/references/rendering-and-testing.md +7 -5
  33. package/forge/{rules → skills/load-plain-reference/rules}/bullet-continuation.md +11 -11
  34. package/forge/{rules → skills/load-plain-reference/rules}/concise-specs-examples.md +100 -69
  35. package/forge/{rules → skills/load-plain-reference/rules}/concise-specs-integration-examples.md +39 -24
  36. package/forge/{rules → skills/load-plain-reference/rules}/concise-specs.md +3 -2
  37. package/forge/{rules → skills/load-plain-reference/rules}/func-specs.md +37 -28
  38. package/forge/{rules → skills/load-plain-reference/rules}/impl-reqs.md +1 -1
  39. package/forge/{rules → skills/load-plain-reference/rules}/integration-embedded-testing.md +1 -1
  40. package/forge/{rules → skills/load-plain-reference/rules}/linked-resources.md +7 -4
  41. package/forge/{rules → skills/load-plain-reference/rules}/module-structure.md +16 -9
  42. package/forge/{rules → skills/load-plain-reference/rules}/requires-modules.md +1 -0
  43. package/forge/skills/load-plain-reference/rules/semantic-ids.md +47 -0
  44. package/forge/skills/load-plain-reference/rules/test-plain-files.md +67 -0
  45. package/forge/{rules → skills/load-plain-reference/rules}/test-reqs.md +6 -6
  46. package/forge/skills/plain-healthcheck/SKILL.md +31 -13
  47. package/forge/skills/refactor-module/SKILL.md +16 -16
  48. package/forge/skills/resolve-section-ownership/SKILL.md +3 -3
  49. package/forge/skills/resolve-spec-conflict/SKILL.md +14 -8
  50. package/package.json +1 -1
  51. package/forge/skills/add-acceptance-test/SKILL.md +0 -101
  52. /package/forge/{rules → skills/load-plain-reference/rules}/definitions.md +0 -0
  53. /package/forge/{rules → skills/load-plain-reference/rules}/examples/integration-embedded-testing/prepare_environment_java.sh +0 -0
  54. /package/forge/{rules → skills/load-plain-reference/rules}/examples/integration-embedded-testing/run_conformance_tests_java.sh +0 -0
  55. /package/forge/{rules → skills/load-plain-reference/rules}/examples/integration-embedded-testing/run_unittests_java.sh +0 -0
  56. /package/forge/{rules → skills/load-plain-reference/rules}/exported-concepts.md +0 -0
  57. /package/forge/{rules → skills/load-plain-reference/rules}/import-modules.md +0 -0
  58. /package/forge/{rules → skills/load-plain-reference/rules}/integration-embedded.md +0 -0
  59. /package/forge/{rules → skills/load-plain-reference/rules}/integration-standalone.md +0 -0
  60. /package/forge/{rules → skills/load-plain-reference/rules}/integrations.md +0 -0
  61. /package/forge/{rules → skills/load-plain-reference/rules}/required-concepts.md +0 -0
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-acceptance-test`, `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.
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
@@ -87,23 +87,26 @@ Each install writes three subfolders under the chosen directory:
87
87
 
88
88
  ```
89
89
  <agent-dir>/
90
- skills/ # every plain-forge skill
91
- rules/ # spec-writing rules (see "How the rules get applied" below)
90
+ skills/ # every plain-forge skill; the spec-writing rules ship in skills/load-plain-reference/rules/
91
+ rules/ # plain-forge.md, a short pointer to load-plain-reference (see "How the rules get applied" below)
92
92
  docs/ # shared reference docs
93
93
  ```
94
94
 
95
95
  #### How the rules get applied per agent
96
96
 
97
- The `skills/` are discovered natively by every supported agent. The `load-plain-reference` skill
98
- loads only the rules relevant to the current task and skips rules already present in context. Some
99
- agents additionally support native rules wiring:
97
+ The `skills/` are discovered natively by every supported agent. The spec-writing rules ship inside the
98
+ `load-plain-reference` skill, which loads only the rules relevant to the current task and skips rules
99
+ already present in context — so a session pays for the rules its task needs, not for the whole rule
100
+ set. The installed `rules/` dir holds only `plain-forge.md`, a short pointer telling the agent to
101
+ invoke `load-plain-reference` when it works on `.plain` files. Each agent picks that pointer up as
102
+ follows:
100
103
 
101
104
  | Agent | How rules are applied |
102
105
  |-------|-----------------------|
103
- | **Claude Code** | Native — Claude Code auto-loads `.claude/rules/*.md` at launch. Each rule carries `paths: "**/*.plain"` frontmatter so Claude scopes it to `.plain` files. No extra wiring. |
106
+ | **Claude Code** | Native — Claude Code auto-loads `.claude/rules/*.md`. The pointer carries `paths: "**/*.plain"` frontmatter, so it loads only once Claude reads or edits a `.plain` file. No extra wiring. |
104
107
  | **OpenCode** | OpenCode doesn't auto-load a `rules/` dir; it reads globs from the `instructions` array in `opencode.json`. plain-forge **merges** a rules glob there — `.opencode/rules/*.md` (project, written to `./opencode.json`) or the absolute `~/.config/opencode/rules/*.md` (global, written to `~/.config/opencode/opencode.json`; absolute because OpenCode doesn't expand `~`). |
105
108
  | **ForgeCode** | plain-forge also appends a fenced managed pointer block to `AGENTS.md`: repo-root `./AGENTS.md` for project installs or `~/forge/AGENTS.md` globally. |
106
- | **Codex / GitHub Copilot / Universal** | No extra instruction file is generated. Their discovered `load-plain-reference` skill loads applicable files from `.agents/rules/` when needed. |
109
+ | **Codex / GitHub Copilot / Universal** | No extra instruction file is generated. Their discovered `load-plain-reference` skill loads applicable files from `.agents/skills/load-plain-reference/rules/` when needed. |
107
110
 
108
111
  When plain-forge touches `opencode.json` or ForgeCode's `AGENTS.md`, it merges into existing content
109
112
  and leaves unrelated configuration intact. `uninstall` removes only plain-forge's glob or block.
@@ -254,7 +257,7 @@ git add vendor/pyro
254
257
  git commit -m "Bump pyro to vX.Y.Z"
255
258
  ```
256
259
 
257
- On `install`, the CLI reads `forge/skills` and `forge/rules` and writes them into the chosen agent directory (`.claude/`, `.agents/` for Codex/Copilot/universal, `.forge/`, or `.opencode/` — see the per-agent table above for global-scope paths), recording every file it wrote in `<agent-dir>/.plain-forge/manifest.json` so `update` can later refresh and prune precisely. For agents that need it, it also wires the rules into `opencode.json` or ForgeCode's `AGENTS.md` (see [How the rules get applied per agent](#how-the-rules-get-applied-per-agent)).
260
+ On `install`, the CLI reads `forge/skills` and `forge/rules` and writes them into the chosen agent directory (`.claude/`, `.agents/` for Codex/Copilot/universal, `.forge/`, or `.opencode/` — see the per-agent table above for global-scope paths), recording every file it wrote in `<agent-dir>/.plain-forge/manifest.json` so `update` can later refresh and prune precisely. For agents that need it, it also wires the rules pointer into `opencode.json` or ForgeCode's `AGENTS.md` (see [How the rules get applied per agent](#how-the-rules-get-applied-per-agent)).
258
261
 
259
262
  ## Available Skills
260
263
 
@@ -276,7 +279,7 @@ On `install`, the CLI reads `forge/skills` and `forge/rules` and writes them int
276
279
  | `add-implementation-requirement` | Add a non-functional requirement to `***implementation reqs***` |
277
280
  | `add-test-requirement` | Add a testing requirement to `***test reqs***` |
278
281
  | `add-concept` | Define a new concept in `***definitions***` |
279
- | `add-acceptance-test` | Add verification criteria under a functional spec |
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 |
280
283
  | `add-resource` | Link an external file (schema, API spec) to a spec |
281
284
  | `add-template` | Create or include a reusable Liquid template |
282
285
 
@@ -294,7 +297,7 @@ On `install`, the CLI reads `forge/skills` and `forge/rules` and writes them int
294
297
  | Skill | Description |
295
298
  |-------|-------------|
296
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. |
297
- | `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. |
298
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. |
299
302
  | `analyze-if-func-spec-too-complex` | Check if a spec exceeds the 200-line complexity limit |
300
303
  | `analyze-func-specs` | Check a batch of specs (2+) against each other in one call and return every conflicting pair |
package/bin/cli.mjs CHANGED
@@ -369,8 +369,8 @@ function opencodeConfigPath(scope) {
369
369
  // The instructions glob to add. Project scope uses a cwd-relative glob (opencode
370
370
  // resolves relative instruction paths against the launch cwd). Global scope must
371
371
  // be absolute: opencode does not expand ~ and would resolve a relative path
372
- // against the project cwd, not the config dir. Only top-level rules/*.md are
373
- // wired in — the examples/ subtree holds reference scripts, not instructions.
372
+ // against the project cwd, not the config dir. rules/ holds only the pointer to
373
+ // load-plain-reference; the authoring rules ship inside that skill and load on demand.
374
374
  function opencodeRulesGlob(scope) {
375
375
  if (scope === "global") {
376
376
  return toPosix(
@@ -531,8 +531,9 @@ function agentsMdBlock(glob) {
531
531
  "## ***plain authoring rules (plain-forge)",
532
532
  "",
533
533
  "When creating or editing `.plain` specification files, first read and follow",
534
- `every rule file matching \`${glob}\`. Each file covers one section or topic of`,
535
- "the ***plain language; they are installed and maintained by plain-forge.",
534
+ `every rule file matching \`${glob}\`. They route to the \`load-plain-reference\``,
535
+ "skill, which loads the ***plain authoring rules for the task; they are installed",
536
+ "and maintained by plain-forge.",
536
537
  AGENTS_MD_END,
537
538
  ].join("\n");
538
539
  }
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Routes .plain work to the load-plain-reference skill, which loads the ***plain authoring rules
3
+ paths:
4
+ - "**/*.plain"
5
+ ---
6
+
7
+ # ***plain authoring rules
8
+
9
+ - Before you read, edit, or write any `.plain` file, invoke the `load-plain-reference` skill and read the rule files it routes you to.
10
+ - It loads only the ***plain authoring rules that apply to the task; they ship inside that skill under `rules/`.
@@ -8,7 +8,7 @@ description: >-
8
8
 
9
9
  # Add Concept
10
10
 
11
- Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
11
+ **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.
12
12
 
13
13
  ## Workflow
14
14
 
@@ -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
- acceptance tests) to disk — asking, authoring, and reviewing per
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
@@ -13,7 +13,7 @@ description: >-
13
13
 
14
14
  # Add Feature
15
15
 
16
- Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
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.
17
17
 
18
18
  `add-feature` is the continuous-loop counterpart of `forge-plain`. Where `forge-plain` bootstraps an entire project from scratch, `add-feature` adds a single feature to an **existing** set of `.plain` specs. It begins with a short intent phase, then runs the authoring loop scoped to one feature.
19
19
 
@@ -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 acceptance tests are in context. This is what lets Phase 2 recognize impact when it surfaces.
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 acceptance test** → `add-acceptance-test`, under the relevant functional spec. Only when the *Conformance gate* is satisfied and the answer describes a concrete verification.
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 / acceptance test, the **next question** must be about that conflict. Show the exact existing snippet in the question and offer:
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 `***acceptance tests***` **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
+ 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
- - Acceptance tests (if any) are consistent with their parent specs.
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***` / `***acceptance tests***` authored only when the Conformance gate holds (a `config.yaml` with a valid `conformance-tests-script` pointing at an existing script).
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), acceptance tests consistent with their parent specs.
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`.
@@ -13,17 +13,18 @@ description: >-
13
13
 
14
14
  # Add Functional Spec
15
15
 
16
- Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
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.
17
17
 
18
18
  ## Workflow
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. **Draft the functional spec** 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.
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 a single line is not enough to fully disambiguate the behavior, use **nested sub-bullets** to add detail. Nested lines clarify the parent spec; they do not introduce separate functionality. Even with nested detail, the spec must still imply ≤ 200 LOC.
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
- - A :User: can send a :Message: to a :Conversation:.
57
- - A :Message: must have non-empty content.
58
- - The :Message: is appended to the end of the :Conversation:.
59
- - All :Participant: members of the :Conversation: can see the new :Message:.
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
- ## Acceptance Tests
73
+ ## Test Scenarios
72
74
 
73
- If the functional spec needs verification, use the `add-acceptance-test` skill to add acceptance tests after inserting the spec.
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
@@ -12,7 +12,7 @@ description: >-
12
12
 
13
13
  # Add Functional Specs
14
14
 
15
- Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
15
+ **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.
16
16
 
17
17
  ## When to Use
18
18
 
@@ -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 a single line is not enough to fully disambiguate the behavior, use **nested sub-bullets** to add detail. Nested lines clarify the parent spec; they do not introduce separate functionality. Even with nested detail, the spec must still imply ≤ 200 LOC.
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
- - A :User: can send a :Message: to a :Conversation:.
80
- - A :Message: must have non-empty content.
81
- - The :Message: is appended to the end of the :Conversation:.
82
- - All :Participant: members of the :Conversation: can see the new :Message:.
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
- ## Acceptance Tests
96
+ ## Test Scenarios
95
97
 
96
- If any of the newly added functional specs need verification, use the `add-acceptance-test` skill to add acceptance tests after the batch has been inserted. Do this per spec, not as part of the bulk pass.
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
@@ -10,7 +10,7 @@ description: >-
10
10
 
11
11
  # Add Implementation Requirement
12
12
 
13
- Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
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
14
 
15
15
  ## Workflow
16
16
 
@@ -9,7 +9,7 @@ description: >-
9
9
 
10
10
  # Add Resource
11
11
 
12
- Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
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
  Linked resources are external files referenced from within a `.plain` spec using markdown link syntax. The file contents are passed to the renderer alongside the spec, providing additional context for code generation.
15
15
 
@@ -35,7 +35,8 @@ Use standard markdown link syntax inside any spec section:
35
35
 
36
36
  ***functional specs***
37
37
 
38
- - An API conforming to the [API specification](resources/api_spec.yaml) is exposed.
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
@@ -8,7 +8,7 @@ description: >-
8
8
 
9
9
  # Add Template
10
10
 
11
- Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
11
+ **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.
12
12
 
13
13
  Templates use Liquid syntax (`{% include %}`) to reuse the same spec content across multiple `.plain` files. Each inclusion can pass different parameters, producing tailored output from a single source. This is distinct from `import` and `requires` — templates are about textual reuse with parameterization, not module dependencies.
14
14
 
@@ -9,7 +9,7 @@ description: >-
9
9
 
10
10
  # Add Test Requirement
11
11
 
12
- Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
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
  ## Workflow
15
15
 
@@ -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
- - **Acceptance tests** — those are nested under individual functional specs in `***functional specs***`
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 implementation conforms to the full spec |
46
- | Acceptance tests | `***acceptance tests***` under a functional spec | Verify a specific functional spec |
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
@@ -9,7 +9,7 @@ description: >-
9
9
 
10
10
  # Analyze Two Functional Specs
11
11
 
12
- Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
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
  ## Input
15
15
 
@@ -9,7 +9,7 @@ description: >-
9
9
 
10
10
  # Analyze Functional Specs
11
11
 
12
- Always use the skill `load-plain-reference` to retrieve the ***plain syntax rules — but only if you haven't done so yet.
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
  ## Input
15
15
 
@@ -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. If the caller didn't label them, assign **stable identifiers** in order of appearance: `S1`, `S2`, `S3`, …. Use those identifiers in the output. If the caller provided their own IDs or quoted snippets, use those instead and keep them verbatim.
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