plain-forge 1.0.19 → 1.0.20
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 +2 -2
- package/forge/rules/impl-reqs.md +1 -1
- package/forge/rules/integration-embedded-testing.md +3 -3
- package/forge/rules/integration-embedded.md +4 -1
- package/forge/rules/requires-modules.md +1 -1
- package/forge/rules/test-reqs.md +1 -1
- package/forge/skills/create-requires-module/SKILL.md +1 -1
- package/forge/skills/debug-specs/SKILL.md +5 -5
- package/forge/skills/forge-plain/SKILL.md +1 -1
- package/forge/skills/implement-conformance-testing-script/SKILL.md +2 -2
- package/forge/skills/implement-prepare-environment-script/SKILL.md +2 -2
- package/forge/skills/implement-unit-testing-script/SKILL.md +1 -1
- package/forge/skills/init-config-file/SKILL.md +2 -3
- package/forge/skills/load-codeplain-reference/SKILL.md +4 -4
- package/forge/skills/load-plain-reference/references/project-model.md +3 -2
- package/forge/skills/load-plain-reference/references/rendering-and-testing.md +5 -5
- package/forge/skills/plain-healthcheck/SKILL.md +1 -1
- package/forge/skills/run-codeplain/SKILL.md +14 -14
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
# plain-forge
|
|
6
6
|
|
|
7
|
-
A toolkit for working with [
|
|
7
|
+
A toolkit for working with [∗∗∗plain](https://plainlang.org) projects from inside your AI coding agent of choice — Claude Code, Codex, ForgeCode, OpenCode, and any other agent that reads from a standard skills directory. plain-forge ships skills, rules, and docs that turn a conversation into complete `.plain` spec files, then keeps maintaining them across the lifetime of the project. The specs are rendered into production-ready code by the [codeplain](https://codeplain.ai) renderer.
|
|
8
8
|
|
|
9
9
|
## What plain-forge does
|
|
10
10
|
|
|
@@ -195,7 +195,7 @@ Hit a bug in the rendered app, a failing test, or behavior that doesn't match wh
|
|
|
195
195
|
2. plain-forge applies the fix in the `.plain` file(s) only and summarizes what changed.
|
|
196
196
|
3. Re-render to regenerate the code (see [Rendering specs](#rendering-specs)).
|
|
197
197
|
|
|
198
|
-
> **Important:** Never edit generated
|
|
198
|
+
> **Important:** Never edit generated output under `plain_modules/` directly — neither the code in `plain_modules/<module>/code/` nor the conformance tests in `plain_modules/<module>/tests/`. Your changes will be overwritten on the next render. Always fix the spec and re-render.
|
|
199
199
|
|
|
200
200
|
|
|
201
201
|
## Repository Structure
|
package/forge/rules/impl-reqs.md
CHANGED
|
@@ -13,7 +13,7 @@ When writing or editing an `***implementation reqs***` section in a `.plain` fil
|
|
|
13
13
|
|
|
14
14
|
## `:UnitTests:` lives here (hard rule)
|
|
15
15
|
- **Everything** about `:UnitTests:` goes in `***implementation reqs***` — paths, approach, packages, framework, conventions, fixtures, mocking policy, file layout, naming, lint / static-analysis gates
|
|
16
|
-
- `:UnitTests:` are part of the generated codebase (they sit inside `plain_modules/<module
|
|
16
|
+
- `:UnitTests:` are part of the generated codebase (they sit inside `plain_modules/<module>/code/` alongside the implementation), so requirements that shape them are implementation reqs by definition
|
|
17
17
|
- The unit-test generator reads **only** `***implementation reqs***` — anything about `:UnitTests:` placed elsewhere (e.g. `***test reqs***`) is silently ignored
|
|
18
18
|
- Author each `:UnitTests:` requirement via `add-implementation-requirement` and phrase it in terms of `:UnitTests:` so the partition stays visible at a glance
|
|
19
19
|
|
|
@@ -75,7 +75,7 @@ mvn test -Dtest='<:UnitTests: package>.**.*Test' checkstyle:check
|
|
|
75
75
|
|
|
76
76
|
These reqs feed `run_conformance_tests_<lang>`. At minimum, declare:
|
|
77
77
|
|
|
78
|
-
1. **`:ConformanceTests:` source location** —
|
|
78
|
+
1. **`:ConformanceTests:` source location** — the generated suite lives under `plain_modules/<module>/tests/`, one folder per functional spec; the renderer passes the resolved path of the folder under test as `$2`
|
|
79
79
|
2. **`:ConformanceTests:` framework and execution command** — `mvn test --no-transfer-progress`, `pytest`, `npm test`, `go test ./...`, etc., with any flags / profiles the project requires
|
|
80
80
|
3. **Fully qualified `:ConformanceTests:` package** (or path / pattern) used to scope discovery, if the runner needs one
|
|
81
81
|
4. **`:ConformanceTests:` network and secrets policy** — by default the suite runs against the **live provider** (see [`integrations.md`](integrations.md) → *`:ConformanceTests:` always run against the live integration*). Declare the env-var names the script reads (e.g. `<PROVIDER>_API_KEY`), whether the script loads a `.env` file before running, and any specific endpoints that are mocked because they can't be exercised live safely (429, forced 5xx)
|
|
@@ -85,7 +85,7 @@ These reqs feed `run_conformance_tests_<lang>`. At minimum, declare:
|
|
|
85
85
|
Author the conformance facts as one or more entries, phrased in terms of `:ConformanceTests:`:
|
|
86
86
|
|
|
87
87
|
```plain
|
|
88
|
-
- :ConformanceTests: of :Implementation: live in `
|
|
88
|
+
- :ConformanceTests: of :Implementation: live in `plain_modules/foo/tests/` and are implemented with JUnit 5 + Maven.
|
|
89
89
|
- The fully qualified package used for :ConformanceTests: discovery is `com.example.integrations.foo.conformance`.
|
|
90
90
|
- :ConformanceTests: are run via `mvn test --no-transfer-progress`; the host's Surefire plugin must be installed.
|
|
91
91
|
- :ConformanceTests: run against the live :ProviderName: sandbox — no mocking of provider calls.
|
|
@@ -139,7 +139,7 @@ All three scripts are invoked by the `codeplain` renderer with positional argume
|
|
|
139
139
|
|
|
140
140
|
## 1. `prepare_environment_<lang>` — copy into the host, then compile
|
|
141
141
|
|
|
142
|
-
Receives one positional argument: the renderer's build output folder (e.g. `plain_modules/<module
|
|
142
|
+
Receives one positional argument: the renderer's build output folder (e.g. `plain_modules/<module>/code/`).
|
|
143
143
|
|
|
144
144
|
Purpose: stage the generated code **into the host codebase at the module's package path**, then run the host's install / build so that downstream test projects (specifically the conformance suite) can depend on it from the local dependency cache.
|
|
145
145
|
|
|
@@ -30,6 +30,9 @@ The embedded integration's `.plain` specs (and the rest of the ***plain project
|
|
|
30
30
|
│ ├── resources/
|
|
31
31
|
│ ├── test_scripts/
|
|
32
32
|
│ ├── plain_modules/ # generated; gitignored
|
|
33
|
+
│ │ └── <module>/
|
|
34
|
+
│ │ ├── code/ # implementation + unit tests
|
|
35
|
+
│ │ └── tests/ # conformance tests, per functional spec
|
|
33
36
|
│ └── config.yaml
|
|
34
37
|
└── src/ # host source tree (Java, Python, etc.)
|
|
35
38
|
```
|
|
@@ -117,7 +120,7 @@ The renderer reads the directives from the spec and the shapes from the linked s
|
|
|
117
120
|
|
|
118
121
|
## Test-script wiring — copy into the host, run tests there
|
|
119
122
|
|
|
120
|
-
Embedded integrations are tested **inside the host codebase itself**. The prepare and unit-test scripts copy the renderer's output (`$1`, i.e. `plain_modules/<module
|
|
123
|
+
Embedded integrations are tested **inside the host codebase itself**. The prepare and unit-test scripts copy the renderer's output (`$1`, i.e. `plain_modules/<module>/code/`) into the host's source tree at the module's package path, then compile / test the host project in place. Only the conformance script uses a scratch folder in the system temp directory (`/tmp/<lang>_conformance/`), because the conformance suite is a separate project that consumes the host build as a dependency.
|
|
121
124
|
|
|
122
125
|
This matters because the integration's generated code references host symbols by their full import path (e.g. `from host_project.integrations.base import IntegrationContract`). Those imports only resolve cleanly when the test process is rooted in the host's package layout — anything else creates path edge cases that bite later in conformance failures.
|
|
123
126
|
|
|
@@ -8,7 +8,7 @@ When creating or editing a `.plain` file that uses `requires`, always follow the
|
|
|
8
8
|
|
|
9
9
|
## What requires does
|
|
10
10
|
- `requires` establishes a **build ordering** — the required module is built before the current one
|
|
11
|
-
- The required module's generated code (`plain_modules/<required_module
|
|
11
|
+
- The required module's generated code (`plain_modules/<required_module>/code`) is copied as the starting point
|
|
12
12
|
- The required module's `***functional specs***` become visible as **previous functional specs** — this property **is transitive**
|
|
13
13
|
- Only `exported_concepts` from the required module are available — not its full definitions — and this property **is not transitive**
|
|
14
14
|
|
package/forge/rules/test-reqs.md
CHANGED
|
@@ -14,7 +14,7 @@ When writing or editing a `***test reqs***` section in a `.plain` file, always f
|
|
|
14
14
|
|
|
15
15
|
## `:ConformanceTests:` lives here (hard rule)
|
|
16
16
|
- **Everything** about `:ConformanceTests:` goes in `***test reqs***` — paths, approach, packages, framework, execution command, mocking / network policy, fixtures, pass criteria, environment prerequisites
|
|
17
|
-
- `:ConformanceTests:` live outside the generated codebase
|
|
17
|
+
- `:ConformanceTests:` live outside the generated codebase, in their own tree under `plain_modules/<module>/tests/` (one folder per functional spec), so requirements that shape them belong in test reqs by definition
|
|
18
18
|
- The conformance-test generator reads **only** `***test reqs***` — anything about `:ConformanceTests:` placed elsewhere (e.g. `***implementation reqs***`) is silently ignored
|
|
19
19
|
- Author each `:ConformanceTests:` requirement via `add-test-requirement` and phrase it in terms of `:ConformanceTests:` so the partition stays visible at a glance
|
|
20
20
|
- Conformance testing run scripts should be linked here as a linked resource
|
|
@@ -16,7 +16,7 @@ Always use the skill `load-plain-reference` to retrieve the ***plain syntax rule
|
|
|
16
16
|
`requires` establishes a build ordering between modules. The required module is built **before** the current one. This does not necessarily mean the current module extends or depends on the required module's code — it may be completely independent. The `requires` relationship simply ensures the build order is correct.
|
|
17
17
|
|
|
18
18
|
When this module is rendered:
|
|
19
|
-
- The required module's generated code (`plain_modules/<required_module
|
|
19
|
+
- The required module's generated code (`plain_modules/<required_module>/code`) is copied as the starting point.
|
|
20
20
|
- The required module's `***functional specs***` become visible as **previous functional specs**.
|
|
21
21
|
- Only `exported_concepts` from the required module are available (not its full definitions).
|
|
22
22
|
|
|
@@ -20,11 +20,11 @@ Always use the skill `load-plain-reference` to retrieve the ***plain syntax rule
|
|
|
20
20
|
|
|
21
21
|
## Guiding Principle
|
|
22
22
|
|
|
23
|
-
Generated code in `plain_modules/` and `
|
|
23
|
+
Generated code in `plain_modules/<module>/code/` and `plain_modules/<module>/tests/` is **read-only** — it exists solely as evidence for diagnosis. All fixes are applied exclusively to the `.plain` spec files. The workflow is: observe → read generated code → trace to spec → fix the spec.
|
|
24
24
|
|
|
25
25
|
## Input
|
|
26
26
|
|
|
27
|
-
1. **The module name** — identifies the `plain_modules/<module_name>/` directory and the corresponding `.plain` file(s).
|
|
27
|
+
1. **The module name** — identifies the `plain_modules/<module_name>/` directory (`code/` and `tests/`) and the corresponding `.plain` file(s).
|
|
28
28
|
2. **The user's observation** — what is wrong? This can be a bug description, a screenshot, a test failure, an error message, or a general "this doesn't work right."
|
|
29
29
|
3. **Optional: a specific functional spec** — if the user suspects a particular spec, start there. Otherwise, investigate broadly.
|
|
30
30
|
|
|
@@ -38,7 +38,7 @@ Generated code in `plain_modules/` and `conformance_tests/` is **read-only** —
|
|
|
38
38
|
|
|
39
39
|
## Phase 2 — Investigate the Generated Code
|
|
40
40
|
|
|
41
|
-
Read files in `plain_modules/<module_name
|
|
41
|
+
Read files in `plain_modules/<module_name>/code/` to understand what the renderer produced. **Do not modify any generated files.**
|
|
42
42
|
|
|
43
43
|
### 2a. Narrow the search
|
|
44
44
|
|
|
@@ -60,7 +60,7 @@ For each relevant file:
|
|
|
60
60
|
### 2c. Check conformance tests and unit tests (if relevant)
|
|
61
61
|
|
|
62
62
|
If the bug manifests as a test failure:
|
|
63
|
-
1. Read the failing test in `
|
|
63
|
+
1. Read the failing test — conformance tests in `plain_modules/<module_name>/tests/<functionality>/`, unit tests inside `plain_modules/<module_name>/code/`.
|
|
64
64
|
2. Understand what the test expects vs. what the implementation does.
|
|
65
65
|
3. Determine whether the test expectation is correct (matches the spec) or incorrect (doesn't match the spec).
|
|
66
66
|
|
|
@@ -164,7 +164,7 @@ revise the new spec
|
|
|
164
164
|
## Common Pitfalls
|
|
165
165
|
|
|
166
166
|
### Fixing the code instead of the spec
|
|
167
|
-
Never modify files in `plain_modules/` or `
|
|
167
|
+
Never modify files in `plain_modules/<module>/code/` or `plain_modules/<module>/tests/`. Even if the fix is obvious in the code, the change must be made in the `.plain` file so it persists across re-renders.
|
|
168
168
|
|
|
169
169
|
### Treating symptoms instead of root causes
|
|
170
170
|
If the user says "the button is in the wrong place," don't just add positioning detail. Investigate why the renderer placed it there — the root cause might be a missing layout spec, an ambiguous screen description, or a conflict with another spec.
|
|
@@ -124,4 +124,4 @@ Once the initial specs exist, the user will return with new features. Use the `a
|
|
|
124
124
|
- Applicable language rules and operational references: `load-plain-reference`.
|
|
125
125
|
- Spec-editing skills live in `.claude/skills/`.
|
|
126
126
|
- Templates go in `template/`, but import paths omit the `template/` prefix. Resources go in `resources/`.
|
|
127
|
-
- Generated code lands in `plain_modules/` (read-only, never edit). Test scripts live in `test_scripts/`.
|
|
127
|
+
- Generated code lands in `plain_modules/<module>/code/` and generated conformance tests in `plain_modules/<module>/tests/` (both read-only, never edit). Test scripts live in `test_scripts/`.
|
|
@@ -43,7 +43,7 @@ Everything else — toolchain check, build staging, dependency isolation, exit c
|
|
|
43
43
|
|
|
44
44
|
### Why this split exists
|
|
45
45
|
|
|
46
|
-
The conformance runner is invoked **once per functional spec** by the renderer. Each functional spec in a module has its own `
|
|
46
|
+
The conformance runner is invoked **once per functional spec** by the renderer. Each functional spec in a module has its own `plain_modules/<module>/tests/<spec>/` folder, and after the renderer finishes generating code for a new spec, it runs the conformance tests of **every previous spec** in the same module to detect regressions. For a module with N functional specs, this script is called **on the order of N times per render** — not once per render.
|
|
47
47
|
|
|
48
48
|
That per-spec invocation pattern is what makes the install step expensive. A naive runner that does `pip install` / `npm ci` / `mvn install -DskipTests` / `cargo build` on every invocation pays the install cost N times per render. For anything beyond a toy project, that cost dominates wall-clock time.
|
|
49
49
|
|
|
@@ -123,7 +123,7 @@ A conformance script has **two** read-only inputs: the source build folder (`$1`
|
|
|
123
123
|
|
|
124
124
|
Why each input is read-only:
|
|
125
125
|
|
|
126
|
-
- **`$1` (build folder)** is shared with the renderer (`plain_modules
|
|
126
|
+
- **`$1` (build folder)** is shared with the renderer (`plain_modules/<module>/code` by default) and downstream tooling. Writing into it corrupts the renderer's view of "what was generated" and breaks subsequent renders. The whole point of staging into the system temp directory is so the source folder stays a clean, reproducible artifact of the render.
|
|
127
127
|
- **`$2` (conformance tests folder)** is the user's authored test source — typically checked into version control. Writing into it pollutes the working tree, churns git status, and (with frameworks that auto-discover) can make subsequent runs pick up generated files as if they were tests.
|
|
128
128
|
|
|
129
129
|
If you find yourself about to issue any command whose `cwd` is `$1` or `$2`, or whose target path starts with `$1/` or `$2/`, **stop**. Either move the operation into `<temp>/<lang>_<basename>`, or you're doing something the script must not do.
|
|
@@ -27,7 +27,7 @@ When this script exists for a project, the corresponding conformance script's ow
|
|
|
27
27
|
|
|
28
28
|
### Why this script exists at all (the structural reason)
|
|
29
29
|
|
|
30
|
-
The conformance test runner is invoked **once per functional spec** by the renderer — not once per render. Each functional spec in a module has its own `
|
|
30
|
+
The conformance test runner is invoked **once per functional spec** by the renderer — not once per render. Each functional spec in a module has its own `plain_modules/<module>/tests/<spec>/` folder, and after the renderer finishes generating code for a new spec, it runs the conformance tests of **every previous spec** in the same module to detect regressions. For a module with N functional specs, the conformance script is invoked roughly N times on every render.
|
|
31
31
|
|
|
32
32
|
Without a prepare script, every one of those N invocations does the full dependency install (Python venv + `pip install`, full Maven dependency tree, `npm ci`, `cargo build`, ...) from scratch. That cost — paid N times per render — dominates the wall-clock time of rendering a non-trivial project.
|
|
33
33
|
|
|
@@ -103,7 +103,7 @@ The source build folder passed in as `$1` is **input only**. Prepare reads from
|
|
|
103
103
|
- pre-build into it (every compile output — `target/`, `build/`, `dist/`, native binaries, generated sources — lives inside `<temp>/<lang>_<basename>`),
|
|
104
104
|
- create logs, caches, or temp files inside it.
|
|
105
105
|
|
|
106
|
-
The build folder is shared with the renderer (`plain_modules
|
|
106
|
+
The build folder is shared with the renderer (`plain_modules/<module>/code` by default) and with the conformance script, which staging-checks the working folder via `if [ ! -d "/tmp/<lang>_$(basename "$1")" ]` and expects `$1` itself to look the same as it did right after rendering. Writing into `$1` corrupts the renderer's view of "what was generated", churns git status if the project commits `$1`, and (if the conformance script ever does an `rm -rf $1` during its own setup) silently destroys work prepare did.
|
|
107
107
|
|
|
108
108
|
The whole point of staging into `<temp>/<lang>_<basename>` is so the source build folder stays a clean, reproducible artifact of the render and no build debris lands inside the user's project. Every dependency, every compiled class, every binary, every cache must land inside the working folder — because that is exactly what the conformance script's activate-only variant attaches to.
|
|
109
109
|
|
|
@@ -47,7 +47,7 @@ The source build folder passed in as `$1` is **input only**. The script must nev
|
|
|
47
47
|
- run the test command from inside it (every test command runs from inside `<temp>/<lang>_<basename>` after the `cd` in step 5),
|
|
48
48
|
- create logs, caches, build outputs, or temp files inside it.
|
|
49
49
|
|
|
50
|
-
The build folder is shared with the renderer (`plain_modules
|
|
50
|
+
The build folder is shared with the renderer (`plain_modules/<module>/code` by default) and downstream tooling. Writing into it corrupts the renderer's view of "what was generated" and breaks subsequent renders. Every write must go into `<temp>/<lang>_<basename>` — the whole point of staging into the system temp directory is so the source build folder stays a clean, reproducible artifact of the render and no build debris is left inside the user's project.
|
|
51
51
|
|
|
52
52
|
If you find yourself about to issue any command whose `cwd` is the source folder, or whose target path starts with `$1/`, **stop**. Either move the operation into `<temp>/<lang>_<basename>`, or you're doing something the script must not do.
|
|
53
53
|
|
|
@@ -59,8 +59,7 @@ These keys reflect choices made in Phase 3 of `forge-plain` and are the bread an
|
|
|
59
59
|
| `test-script-timeout` | int (seconds) | `120` | Include only when the user explicitly raised/lowered the default. |
|
|
60
60
|
| `template-dir` | path (string) | — | Include whenever the project has an `import` module or a custom template directory (e.g. `template/`). Required for projects with shared templates. |
|
|
61
61
|
| `logging-config-path` | path (string) | `logging_config.yaml` | Points at a **separate** YAML file consumed by Python's `logging.config.dictConfig`. This is the only knob that lets the user actually change log **levels** for the renderer and its dependencies. See [Logging configuration](#logging-configuration) below. Include the key explicitly whenever the project ships a non-default logging config; leave it out only when the user is happy with the renderer's defaults (`INFO` root, `WARNING` for `git`, `ERROR` for `transitions`). |
|
|
62
|
-
| `
|
|
63
|
-
| `build-folder` | string | `plain_modules` | Include only when the user picked a non-default folder name. Must differ from `build-dest`. |
|
|
62
|
+
| `build-folder` | string | `plain_modules` | Include only when the user picked a non-default folder name. Must differ from `build-dest`. The renderer writes `<build-folder>/<module>/code` (implementation + unit tests) and `<build-folder>/<module>/tests` (conformance tests, one folder per functional spec). |
|
|
64
63
|
| `build-dest` | string | `dist` | **Always include with the value `dist`.** This skill pins the copy destination explicitly so every project's `config.yaml` has the same, predictable target folder for the post-render copy. Even though `dist` matches the renderer's default, we still write it out so the choice is visible in the file and protected against future default changes. Must differ from `build-folder`. |
|
|
65
64
|
| `base-folder` | string | — | Include when the user wants build output rooted somewhere other than the project root. |
|
|
66
65
|
|
|
@@ -72,7 +71,7 @@ These are useful but the defaults are almost always fine. Only include them when
|
|
|
72
71
|
|---|---|---|---|
|
|
73
72
|
| `copy-build` | bool | `true` | The renderer copies the rendered code to `build-dest` after a successful render. Set to `false` only when the user doesn't want this. |
|
|
74
73
|
| `copy-conformance-tests` | bool | `false` | Requires `conformance-tests-script` to also be set. |
|
|
75
|
-
| `conformance-tests-dest` | string | `dist_conformance_tests` | Target folder for the
|
|
74
|
+
| `conformance-tests-dest` | string | `dist_conformance_tests` | Target folder for the post-render copy of `plain_modules/<module>/tests`. Must differ from `build-folder`. |
|
|
76
75
|
| `log-to-file` | bool | `true` | Disable only when the user explicitly does not want a log file. Controls whether logs are mirrored to disk — it does **not** set the log level (that's `logging-config-path`'s job). |
|
|
77
76
|
| `log-file-name` | string | `codeplain.log` | If `log-to-file` is `false`, this key must be left out. A relative value set here resolves against the config file's directory; when the key is left out entirely, the default resolves against the `.plain` file's directory. |
|
|
78
77
|
| `render-machine-graph` | bool | `false` | Include only when the user wants the state-machine graph rendered. |
|
|
@@ -13,7 +13,7 @@ description: >-
|
|
|
13
13
|
|
|
14
14
|
# CODEPLAIN_CLI_REFERENCE.md
|
|
15
15
|
|
|
16
|
-
`codeplain` is the CLI that renders `***plain` specification files into production-ready code. It reads a `.plain` module (and everything it `import`s / `requires`), calls the codeplain API, and writes generated code under `plain_modules/` and conformance tests under `
|
|
16
|
+
`codeplain` is the CLI that renders `***plain` specification files into production-ready code. It reads a `.plain` module (and everything it `import`s / `requires`), calls the codeplain API, and writes generated code under `plain_modules/<module>/code/` and conformance tests under `plain_modules/<module>/tests/`. The `.plain` specs are the source of truth; the generated code is a read-only artifact.
|
|
17
17
|
|
|
18
18
|
This reference covers the CLI surface only. For the `***plain` language itself use `load-plain-reference`; to supervise a live render use `run-codeplain`; to assemble or validate `config.yaml` use `init-config-file` / `plain-healthcheck`.
|
|
19
19
|
|
|
@@ -75,7 +75,7 @@ A path's meaning depends on **where it was written**:
|
|
|
75
75
|
### Folders
|
|
76
76
|
|
|
77
77
|
- **`--base-folder BASE_FOLDER`** — base folder for the build files.
|
|
78
|
-
- **`--build-folder BUILD_FOLDER`** — folder for build files (generated code lands under here, per module: `plain_modules/<module
|
|
78
|
+
- **`--build-folder BUILD_FOLDER`** — folder for build files (generated code lands under here, per module: `plain_modules/<module>/code/` and `plain_modules/<module>/tests/`).
|
|
79
79
|
- **`--template-dir TEMPLATE_DIR`** — path to a custom template directory. Templates are searched in this order: 1) the directory containing the `.plain` file, 2) this custom template directory, 3) the built-in `standard_template_library` directory. In `config.yaml` the equivalent key is `template_dir` — set it whenever the project has import modules or templates.
|
|
80
80
|
|
|
81
81
|
### Test-script wiring
|
|
@@ -126,8 +126,8 @@ A path's meaning depends on **where it was written**:
|
|
|
126
126
|
|
|
127
127
|
Generated artifacts (gitignored, read-only — never edit):
|
|
128
128
|
|
|
129
|
-
- `plain_modules/<module
|
|
130
|
-
- `
|
|
129
|
+
- `plain_modules/<module>/code/` — the generated project for each `.plain` spec (implementation + unit tests).
|
|
130
|
+
- `plain_modules/<module>/tests/<functionality>/` — generated conformance tests, one subfolder per functionality.
|
|
131
131
|
- `codeplain.log` — the per-run log (overwritten each run).
|
|
132
132
|
|
|
133
133
|
When a run ends, `codeplain` writes a result banner (to the log, and to the terminal outside headless mode):
|
|
@@ -15,8 +15,9 @@ those specifications.
|
|
|
15
15
|
*.plain # Root specification modules
|
|
16
16
|
template/*.plain # Reusable import modules
|
|
17
17
|
resources/ # Linked text artifacts such as schemas and fixtures
|
|
18
|
-
plain_modules/ # Generated
|
|
19
|
-
|
|
18
|
+
plain_modules/ # Generated output, one directory per module
|
|
19
|
+
<module>/code/ # implementation and unit tests
|
|
20
|
+
<module>/tests/ # conformance tests, one folder per functional spec
|
|
20
21
|
test_scripts/ # Unit, environment-preparation, and conformance runners
|
|
21
22
|
config.yaml # codeplain CLI configuration
|
|
22
23
|
```
|
|
@@ -18,7 +18,7 @@ and debugging skills rather than editing generated output.
|
|
|
18
18
|
|
|
19
19
|
## Generated artifacts are read-only
|
|
20
20
|
|
|
21
|
-
Everything under `plain_modules/`
|
|
21
|
+
Everything under `plain_modules/` is generated — both `<module>/code/` and `<module>/tests/`. It may be read, executed,
|
|
22
22
|
and debugged, but never edited directly. Apply fixes as follows:
|
|
23
23
|
|
|
24
24
|
- Behavior or implementation/unit-test guidance: edit definitions, functional specs, or
|
|
@@ -37,7 +37,7 @@ Test scripts are renderer entry points as well as developer utilities:
|
|
|
37
37
|
- `prepare_environment_<lang>` optionally prepares a reusable system-temporary environment for
|
|
38
38
|
conformance testing once per render.
|
|
39
39
|
- `run_conformance_tests_<lang>` receives the generated build folder and one functionality's
|
|
40
|
-
conformance-test folder. It may run repeatedly during a render.
|
|
40
|
+
conformance-test folder (`plain_modules/<module_name>/tests/<functionality>`). It may run repeatedly during a render.
|
|
41
41
|
|
|
42
42
|
Invoke the corresponding `implement-*-script` skill when creating or changing a test script. Those
|
|
43
43
|
skills own exact staging, cleanup, dependency-installation, shell, and exit-code contracts.
|
|
@@ -47,10 +47,10 @@ skills own exact staging, cleanup, dependency-installation, shell, and exit-code
|
|
|
47
47
|
Run project scripts from the repository root, using the filenames configured for that project:
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
|
-
./test_scripts/run_unittests.sh plain_modules/<module_name
|
|
51
|
-
./test_scripts/prepare_environment.sh plain_modules/<module_name
|
|
50
|
+
./test_scripts/run_unittests.sh plain_modules/<module_name>/code
|
|
51
|
+
./test_scripts/prepare_environment.sh plain_modules/<module_name>/code
|
|
52
52
|
./test_scripts/run_conformance_tests.sh \
|
|
53
|
-
plain_modules/<module_name
|
|
53
|
+
plain_modules/<module_name>/code plain_modules/<module_name>/tests/<functionality>
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
The renderer resolves script arguments to absolute paths. Test scripts must treat input directories
|
|
@@ -90,7 +90,7 @@ Treat the dry-run as a hard gate: the healthcheck **only passes** when every top
|
|
|
90
90
|
Iterate until it passes:
|
|
91
91
|
|
|
92
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 `
|
|
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/<module>/code/` or `plain_modules/<module>/tests/`.
|
|
94
94
|
3. If you are uncertain about ***plain syntax for the failing construct, re-load `load-plain-reference` before fixing.
|
|
95
95
|
4. Re-run the same `codeplain <top_module>.plain --dry-run …` command with the same flags. Repeat until it exits successfully.
|
|
96
96
|
|
|
@@ -21,7 +21,7 @@ A **supervisor** around a live `codeplain` render. The renderer itself is the co
|
|
|
21
21
|
1. Launches `codeplain <module>.plain` (or attaches to an in-flight run).
|
|
22
22
|
2. Watches three signal sources in a tight loop, in priority order:
|
|
23
23
|
- **`codeplain.log`** — the primary signal. Everything the renderer is doing, deciding, retrying, or failing at gets written here. This is the file you stare at.
|
|
24
|
-
- the generated **code outputs** under `plain_modules/<module>/` and `
|
|
24
|
+
- the generated **code outputs** under `plain_modules/<module>/` and `plain_modules/<module>/tests/` — a secondary signal, used to corroborate or contradict what the log says.
|
|
25
25
|
- the **process / TUI** itself (alive? exited? exit code?) — a tertiary signal, used only to know whether to keep monitoring.
|
|
26
26
|
3. Surfaces what is happening to the user in plain English, in near-real-time.
|
|
27
27
|
4. On pathology, stops the renderer (with user approval), hands off to the right edit skill, and resumes from the last completed functionality.
|
|
@@ -76,7 +76,7 @@ Before launching anything:
|
|
|
76
76
|
- **What "pass" means**, exit-code-wise. Some scripts combine multiple checks (e.g. `unit_testing_typescript.sh` here runs `tsc --noEmit` *and* `vitest`, and its final exit code is the worst of the two — so a type error alone fails the unit-test gate).
|
|
77
77
|
- **What "fail" means**, including any failures that the script deliberately downgrades to warnings (e.g. `prepare_environment_typescript.sh` here treats a failed `npm run build` as a non-fatal warning). Failures the script swallows are failures the renderer will **never see**, so a spec defect that depends on them will silently slip through.
|
|
78
78
|
- **Where the scripts materialize their working environment** (current-convention scripts stage into the system temp directory, e.g. `/tmp/typescript_<build_folder_basename>/`; older scripts used project-local folders like `.tmp/typescript_<build_folder>/`, `build/`, `target/`). This is where the renderer's iteration actually runs; if you need to look at what is breaking, this is the directory — not `plain_modules/<module>/` directly.
|
|
79
|
-
- **How conformance tests are discovered and staged** (glob, naming convention, alias setup, etc.). Some scripts stage tests into the source tree (this repo flattens `
|
|
79
|
+
- **How conformance tests are discovered and staged** (glob, naming convention, alias setup, etc.). Some scripts stage tests into the source tree (this repo flattens `plain_modules/<module>/tests/<fname>/` into `src/<module>/`); some run them in place; some require a specific file extension. This tells you exactly which conformance test file is in play for a given functionality.
|
|
80
80
|
- **Toolchain prerequisites** the script asserts (Node version, Python version, specific binaries). If any are missing on the user's machine, stop now and tell them — the renderer will burn credits on phantom failures otherwise.
|
|
81
81
|
|
|
82
82
|
Keep this synthesis short (5–10 bullets, project-specific). It is the single most important reference for the classifier in [Spec-deviation classification](#spec-deviation-classification). The healthcheck only checks that the scripts *exist* and are *referenced correctly*; this step is the only place that reads what they actually *do*.
|
|
@@ -132,7 +132,7 @@ All patterns below are taken from the actual codeplain runtime. Treat them as th
|
|
|
132
132
|
| `Implementing conformance tests...` / `Implementing test requirements:` | Conformance phase starting for the current functionality. | Routine. |
|
|
133
133
|
| `Running testing environment preparation script .* for build folder` | `prepare-environment-script` is running. | Routine. |
|
|
134
134
|
| `\[#79FC96\]All Testing Environment Preparation scripts have passed successfully.\[/#79FC96\]` | Env prep green. | Routine. |
|
|
135
|
-
| `Running conformance tests script .* for
|
|
135
|
+
| `Running conformance tests script .* for plain_modules/<m>/tests/<fname> \(functionality <N> in module <m>\)` | Conformance tests starting for functionality `<N>`. | Note `<fname>` — that is the on-disk folder where the latest conformance test lives. |
|
|
136
136
|
| `Running conformance tests attempt <N>.` | Conformance retry loop. **Watch `<N>` carefully.** | Increment `ATTEMPT_COUNTER = <N>`. At `>=5`, trigger Pathology A. |
|
|
137
137
|
| `Fixing conformance test for functionality <N> in module <m>.` | Renderer is patching its own conformance test between attempts. | On its own, routine. Combined with climbing `<N>`, smoking gun for Pathology A. |
|
|
138
138
|
| `Functional spec too complex!` | Single spec implies >200 LOC. Renderer aborts. | Pathology B. |
|
|
@@ -199,7 +199,7 @@ What to extract from the framework output — stay framework-agnostic, look for
|
|
|
199
199
|
- **Individual test names that failed**: lines beginning with `×`, `FAIL`, `✗`, `× should ...`, `FAIL src/.../foo.test.ts > <name>`. The *same* test failing across attempts is the smoking gun for an under-specified spec.
|
|
200
200
|
- **Assertion bodies**: `expected X, got Y`. The values reveal exactly what the test expects vs what the implementation produced — the cleanest input to the classifier below.
|
|
201
201
|
- **Compile / type errors** (when the script wraps a type-checker): `error TS<NNNN>`, `cannot find module`, `is not assignable to`. A unit-test gate that keeps re-failing on the same type error means the implementation req or the type-level spec is wrong, not the code.
|
|
202
|
-
- **Stack traces**: which file under the prepared working folder threw, and at which line. Map the file back to `plain_modules/<module>/
|
|
202
|
+
- **Stack traces**: which file under the prepared working folder threw, and at which line. Map the file back to `plain_modules/<module>/code/...` to find the code the spec is supposed to be governing.
|
|
203
203
|
- **"No test files found" / "No tests collected"**: the script ran but discovered nothing. Almost always a path/glob mismatch in the staged working folder, not a spec problem. Treat as Pathology F.
|
|
204
204
|
|
|
205
205
|
Always set the logs to be verbose in `config.yaml`.
|
|
@@ -232,8 +232,8 @@ The inputs to the classifier are:
|
|
|
232
232
|
1. The **spec** that governs the failing functionality — the functional spec and its acceptance test(s) in the `.plain` file.
|
|
233
233
|
2. The **test-script output** for the most recent attempt, from `codeplain.log` per the section above.
|
|
234
234
|
3. The renderer's own **`.memory/conformance_test_memory/<id>.json`** for this functionality (when present).
|
|
235
|
-
4. The newest **conformance test file** the renderer just edited under `
|
|
236
|
-
5. The newest **implementation file(s)** the renderer just edited under `plain_modules/<module
|
|
235
|
+
4. The newest **conformance test file** the renderer just edited under `plain_modules/<module>/tests/<fname>/`.
|
|
236
|
+
5. The newest **implementation file(s)** the renderer just edited under `plain_modules/<module>/code/`.
|
|
237
237
|
|
|
238
238
|
With these in hand, place the current iteration into one of four buckets:
|
|
239
239
|
|
|
@@ -320,15 +320,15 @@ If the process is gone but you haven't yet seen a `✓` or `✗` banner in the l
|
|
|
320
320
|
|
|
321
321
|
This is a secondary signal — it confirms what the log already said. Don't go on a fishing trip here.
|
|
322
322
|
|
|
323
|
-
For the current module, the renderer drops generated code into `plain_modules/<module>/` and conformance tests into `
|
|
323
|
+
For the current module, the renderer drops generated code into `plain_modules/<module>/` and conformance tests into `plain_modules/<module>/tests/<functionality_name>/`. Each pass, inspect what is new:
|
|
324
324
|
|
|
325
|
-
- New files under `plain_modules/<module>/
|
|
326
|
-
- New folders under `
|
|
325
|
+
- New files under `plain_modules/<module>/code/` confirm the functionality is being implemented.
|
|
326
|
+
- New folders under `plain_modules/<module>/tests/` confirm the functionality has reached the conformance phase.
|
|
327
327
|
- Files that were rewritten between passes are the renderer's "fix" attempts — diffing them across iterations is what reveals whether the renderer is converging or thrashing.
|
|
328
328
|
|
|
329
329
|
Read **only the newest** file(s) (the ones that changed since last pass), and read them to understand *what the renderer chose to do*, not just *that* it did something. This is the first line of defense against "the spec is ambiguous and the renderer guessed wrong" — you can often spot the wrong guess in the generated code long before tests fail.
|
|
330
330
|
|
|
331
|
-
Generated code under `plain_modules/` and `
|
|
331
|
+
Generated code under `plain_modules/<module>/code/` and `plain_modules/<module>/tests/` is **read-only**. Never edit it. Edits go in the `.plain` files.
|
|
332
332
|
|
|
333
333
|
### 1d. Cadence
|
|
334
334
|
|
|
@@ -384,7 +384,7 @@ Symptom: log shows the unit-test or conformance-test **script** itself failing (
|
|
|
384
384
|
|
|
385
385
|
```
|
|
386
386
|
ImportError: Start directory is not importable
|
|
387
|
-
/Users/x/project//Users/x/project/
|
|
387
|
+
/Users/x/project//Users/x/project/plain_modules/module/tests/spec
|
|
388
388
|
```
|
|
389
389
|
|
|
390
390
|
The render then gets stuck "fixing" tests that can never pass. The fix is never a spec edit: stop the render and regenerate the affected scripts via the matching `implement-*-testing-script` skill (current convention: system-temp working folder from `basename "$1"`, `$2` resolved to absolute before any `cd`).
|
|
@@ -434,7 +434,7 @@ If the fix required regenerating a module's earlier output (e.g. a definition ch
|
|
|
434
434
|
When the renderer exits successfully:
|
|
435
435
|
|
|
436
436
|
1. Read the success banner from the log: render id, generated code folder, functionalities count, used credits, render time. Report it to the user verbatim — these are the numbers they actually care about.
|
|
437
|
-
2. List the top-level files/folders that appeared (or changed) under `plain_modules/<module>/` and `
|
|
437
|
+
2. List the top-level files/folders that appeared (or changed) under `plain_modules/<module>/` and `plain_modules/<module>/tests/` so the user knows where to look.
|
|
438
438
|
3. Remind the user of the **side-channel commands** they may want to run themselves, based on the config:
|
|
439
439
|
- `./test_scripts/<unittests-script>` for unit tests,
|
|
440
440
|
- `./test_scripts/<prepare-environment-script>` to set up the test env,
|
|
@@ -446,7 +446,7 @@ When the renderer exits with a failure that wasn't intercepted by Phase 2 (e.g.
|
|
|
446
446
|
|
|
447
447
|
## Anti-patterns
|
|
448
448
|
|
|
449
|
-
- **Editing generated code to "fix" a render.** Never. Generated files under `plain_modules/` and `
|
|
449
|
+
- **Editing generated code to "fix" a render.** Never. Generated files under `plain_modules/<module>/code/` and `plain_modules/<module>/tests/` exist as evidence only; they are overwritten every render. All fixes go in `.plain` files.
|
|
450
450
|
- **Reading the test scripts' source code to understand what's failing.** Don't. The scripts run real frameworks (vitest, pytest, etc.) and the *output* of those frameworks — captured in `codeplain.log` and in `.memory/conformance_test_memory/*.json` — is what tells you what is failing and why. Reading the script source tells you nothing the log doesn't already say.
|
|
451
451
|
- **Treating every conformance loop as under-specification.** Run the classifier. The renderer sometimes drifts (Bucket 3) by silently weakening its own tests; that is the opposite problem and the fix is different.
|
|
452
452
|
- **Re-reading the whole log on every pass.** It grows. Track the byte offset and read only what was appended since the last pass. Full reads are reserved for "I just saw an error and need backstory."
|
|
@@ -480,4 +480,4 @@ When the renderer exits with a failure that wasn't intercepted by Phase 2 (e.g.
|
|
|
480
480
|
- [ ] Spec fixes were delegated to the right edit skill, not done inside this skill
|
|
481
481
|
- [ ] Resumes use `--render-from <N+1>` (or `--render-range`) — `--force-render` only with user approval
|
|
482
482
|
- [ ] On success, final render id / credits / time were reported and side-channel test commands were surfaced
|
|
483
|
-
- [ ] No generated code under `plain_modules/` or `
|
|
483
|
+
- [ ] No generated code under `plain_modules/<module>/code/` or `plain_modules/<module>/tests/` was modified
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plain-forge",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.20",
|
|
4
4
|
"description": "Conversational spec-writing tool for ***plain specification language",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "tsx bin/forge-build.ts",
|
|
35
35
|
"clean": "tsx bin/forge-build.ts --clean",
|
|
36
|
-
"test": "node --test
|
|
36
|
+
"test": "node --test test/*.test.mjs"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/node": "^22.10.0",
|