plain-forge 1.0.13 → 1.0.15
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/forge/rules/definitions.md +17 -0
- package/forge/rules/func-specs.md +1 -2
- package/forge/rules/impl-reqs.md +2 -0
- package/forge/rules/linked-resources.md +9 -10
- package/forge/rules/test-reqs.md +3 -0
- package/forge/skills/add-resource/SKILL.md +5 -6
- package/forge/skills/analyze-if-func-spec-too-complex/SKILL.md +4 -6
- package/forge/skills/break-down-func-spec/SKILL.md +4 -4
- package/forge/skills/load-plain-reference/SKILL.md +10 -10
- package/forge/skills/run-codeplain/SKILL.md +19 -36
- package/package.json +1 -1
|
@@ -63,6 +63,23 @@ Bad — circular:
|
|
|
63
63
|
- Nest attributes and constraints as sub-bullets
|
|
64
64
|
- Do not use programming language constructs (generics, annotations, framework types) in definitions
|
|
65
65
|
|
|
66
|
+
## Concept granularity and technical components
|
|
67
|
+
- Definitions are not restricted to high-level domain objects. When an implementation warrants abstract, technical, or infrastructural components to clarify responsibilities, it is desired and encouraged to define them.
|
|
68
|
+
- Group related technical concepts using the `of` keyword or by stating their relationship explicitly.
|
|
69
|
+
|
|
70
|
+
Example of defining technical components alongside their behavior:
|
|
71
|
+
|
|
72
|
+
```plain
|
|
73
|
+
- :CsvToJsonConverter: bidirectionally converts csv and json strings.
|
|
74
|
+
- :CsvToJson: of :CsvToJsonConverter: converts a list of csv strings (e.g., "value1,value2,value3") to a list of json strings (e.g., "{\"key1\":\"value1\"}").
|
|
75
|
+
- :JsonToCsv: of :CsvToJsonConverter: converts a list of json strings (e.g., "{\"key1\":\"value1\"}") to a list of csv strings (e.g., "value1,value2").
|
|
76
|
+
|
|
77
|
+
- :StorageService: is an abstraction for a remote blob storage backend.
|
|
78
|
+
- :CsvFileWriter: writes CSV rows to local files, automatically rotates to new files when size limits are reached, and flushes completed files to :StorageService:.
|
|
79
|
+
- :CsvFileReader: reads CSV rows in a batched manner.
|
|
80
|
+
- :CsvJoiner: joins csvs and uses :CsvFileWriter: to create the merged CSV.
|
|
81
|
+
```
|
|
82
|
+
|
|
66
83
|
## Format
|
|
67
84
|
|
|
68
85
|
```plain
|
|
@@ -74,6 +74,5 @@ When writing or editing a `***functional specs***` section in a `.plain` file, a
|
|
|
74
74
|
- All :Participant: members of the :Conversation: can see the new :Message:.
|
|
75
75
|
|
|
76
76
|
***acceptance tests***
|
|
77
|
-
- Sending a :Message: to a :Conversation: with three participants should
|
|
78
|
-
make the message visible to all three.
|
|
77
|
+
- Sending a :Message: to a :Conversation: with three participants should make the message visible to all three.
|
|
79
78
|
```
|
package/forge/rules/impl-reqs.md
CHANGED
|
@@ -39,6 +39,7 @@ When writing or editing an `***implementation reqs***` section in a `.plain` fil
|
|
|
39
39
|
- Unit-test guidance (`:UnitTests:` framework, structure, mocking) goes **here**, not in `***test reqs***`
|
|
40
40
|
- `***test reqs***` is exclusively for `:ConformanceTests:` — framework, execution command, mocking policy, environment setup
|
|
41
41
|
- Putting unit-test guidance in `***test reqs***` is one of the most common authoring mistakes; the rendered code will silently miss those requirements because the unit-test generator only reads `***implementation reqs***`
|
|
42
|
+
- Unit testing run scripts should be linked here as a linked resource
|
|
42
43
|
|
|
43
44
|
## Encapsulation warning
|
|
44
45
|
- `requires` modules only receive functional specs from their dependencies — not implementation reqs
|
|
@@ -60,4 +61,5 @@ When writing or editing an `***implementation reqs***` section in a `.plain` fil
|
|
|
60
61
|
- :Implementation: should be in Python 3.12.
|
|
61
62
|
- :Implementation: should use pip for dependency management.
|
|
62
63
|
- When writing CSV files, :Implementation: should use streaming writes to avoid holding large datasets in memory.
|
|
64
|
+
- :UnitTests: are executed via the run script [test_scripts/run_unittests_python.sh](test_scripts/run_unittests_python.sh).
|
|
63
65
|
```
|
|
@@ -14,8 +14,8 @@ A linked resource **must not** be any of the following:
|
|
|
14
14
|
1. **A folder / directory.** `[integrations](src/integrations/)`, `[host project](../host_project/)` are invalid — the renderer cannot ingest a directory. Pick the single most representative file inside (a `README.md`, an exemplar source file, a manifest) and link **that**.
|
|
15
15
|
2. **A URL / external location.** `[Stripe docs](https://stripe.com/docs/api)`, any `http://` / `https://` / `ftp://` / `git://` / `s3://` / `gs://` target. Linked resources are local-file only. If a URL's content is essential, fetch it once, save the response to a text file under `resources/`, and link the saved file.
|
|
16
16
|
3. **A binary file.** PNG, JPG, GIF, PDF, DOCX, XLSX, ZIP, MP3, MP4, compiled binaries (`.exe`, `.so`, `.class`, `.wasm`), and anything else that isn't human-readable text in its raw form. Binary content cannot be meaningfully consumed by the renderer — transcribe it into a text-based form first (a UI screenshot becomes a Markdown description, a PDF spec becomes a Markdown extract or the underlying JSON Schema / OpenAPI, an architecture diagram becomes a Mermaid block).
|
|
17
|
+
4. **Another `.plain` file.** `[Auth Module](auth.plain)` is invalid. To reference another module, use the `require` or `import` frontmatter directives. Do not link it as a markdown resource; the `plain-dry-run` will flag this as a syntax error.
|
|
17
18
|
|
|
18
|
-
If the markdown-link target ends with `/`, contains `://`, resolves to a directory, or has a binary extension, **stop** — it cannot be a linked resource. Convert it first.
|
|
19
19
|
|
|
20
20
|
## URLs and folder paths must not appear *anywhere* in `.plain` content
|
|
21
21
|
- The constraint is not only about markdown links — URLs and folder paths must not appear **anywhere** in `.plain` content (concept body prose, functional-spec text, implementation reqs, test reqs)
|
|
@@ -31,15 +31,15 @@ If the markdown-link target ends with `/`, contains `://`, resolves to a directo
|
|
|
31
31
|
```plain
|
|
32
32
|
***definitions***
|
|
33
33
|
|
|
34
|
-
- :TaskCreateRequest: is the JSON payload for creating a task
|
|
35
|
-
[resources/task_create_request.schema.json](resources/task_create_request.schema.json).
|
|
36
|
-
- :TasksAPI: is the public HTTP surface for tasks
|
|
37
|
-
[resources/tasks_openapi.yaml](resources/tasks_openapi.yaml).
|
|
34
|
+
- :TaskCreateRequest: is the JSON payload for creating a task.
|
|
35
|
+
- It is defined by [resources/task_create_request.schema.json](resources/task_create_request.schema.json).
|
|
36
|
+
- :TasksAPI: is the public HTTP surface for tasks.
|
|
37
|
+
- It is defined by [resources/tasks_openapi.yaml](resources/tasks_openapi.yaml).
|
|
38
38
|
|
|
39
39
|
***functional specs***
|
|
40
40
|
|
|
41
|
-
- :User: should be able to add :Task: by POSTing :TaskCreateRequest: to the
|
|
42
|
-
|
|
41
|
+
- :User: should be able to add :Task: by POSTing :TaskCreateRequest: to the `POST /tasks` endpoint of :TasksAPI:.
|
|
42
|
+
- The endpoint responds per :TasksAPI:.
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
## Each linked resource is referenced from exactly one place
|
|
@@ -50,8 +50,8 @@ If the markdown-link target ends with `/`, contains `://`, resolves to a directo
|
|
|
50
50
|
```plain
|
|
51
51
|
***definitions***
|
|
52
52
|
|
|
53
|
-
- :TaskModalSpec: is the user-interface contract for the task modal
|
|
54
|
-
fully described in [task_modal_specification.yaml](task_modal_specification.yaml).
|
|
53
|
+
- :TaskModalSpec: is the user-interface contract for the task modal.
|
|
54
|
+
- It is fully described in [task_modal_specification.yaml](task_modal_specification.yaml).
|
|
55
55
|
|
|
56
56
|
***functional specs***
|
|
57
57
|
|
|
@@ -62,5 +62,4 @@ If the markdown-link target ends with `/`, contains `://`, resolves to a directo
|
|
|
62
62
|
|
|
63
63
|
## File location and path resolution
|
|
64
64
|
- Paths are resolved relative to the `.plain` file's directory
|
|
65
|
-
- Only files in the same folder (and subfolders) can be linked
|
|
66
65
|
- The conventional location is `resources/` under the `.plain` file's directory
|
package/forge/rules/test-reqs.md
CHANGED
|
@@ -18,6 +18,7 @@ When writing or editing a `***test reqs***` section in a `.plain` file, always f
|
|
|
18
18
|
- `:ConformanceTests:` live outside the generated codebase (typically in a separate project under `conformance_tests/<module>/`), so requirements that shape them belong in test reqs by definition
|
|
19
19
|
- The conformance-test generator reads **only** `***test reqs***` — anything about `:ConformanceTests:` placed elsewhere (e.g. `***implementation reqs***`) is silently ignored
|
|
20
20
|
- Author each `:ConformanceTests:` requirement via `add-test-requirement` and phrase it in terms of `:ConformanceTests:` so the partition stays visible at a glance
|
|
21
|
+
- Conformance testing run scripts should be linked here as a linked resource
|
|
21
22
|
|
|
22
23
|
## What belongs here
|
|
23
24
|
- Test framework: which framework to use (e.g., pytest, Unittest, xUnit)
|
|
@@ -50,4 +51,6 @@ When writing or editing a `***test reqs***` section in a `.plain` file, always f
|
|
|
50
51
|
- :ConformanceTests: will be run using "pytest" command.
|
|
51
52
|
- :ConformanceTests: must be implemented and executed - do not skip tests.
|
|
52
53
|
- :ConformanceTests: should mock all external HTTP calls.
|
|
54
|
+
- :ConformanceTests: are preapred via the preapre script [test_scripts/prepare_environment_python.sh](test_scripts/prepare_environment_python.sh).
|
|
55
|
+
- :ConformanceTests: are executed via the run script [test_scripts/run_conformance_tests_python.sh](test_scripts/run_conformance_tests_python.sh).
|
|
53
56
|
```
|
|
@@ -26,17 +26,16 @@ Use standard markdown link syntax inside any spec section:
|
|
|
26
26
|
|
|
27
27
|
```plain
|
|
28
28
|
***definitions***
|
|
29
|
-
- :AuthData: is the authentication data structure.
|
|
30
|
-
in the [auth schema](resources/auth_schema.json).
|
|
29
|
+
- :AuthData: is the authentication data structure.
|
|
30
|
+
- Its format is defined in the [auth schema](resources/auth_schema.json).
|
|
31
31
|
|
|
32
32
|
***implementation reqs***
|
|
33
|
-
- When transforming :BackupData:, use the JOLT transform
|
|
34
|
-
[backup_transform.jolt](resources/backup_transform.jolt).
|
|
33
|
+
- When transforming :BackupData:, use the JOLT transform.
|
|
34
|
+
- The transform is defined in [backup_transform.jolt](resources/backup_transform.jolt).
|
|
35
35
|
|
|
36
36
|
***functional specs***
|
|
37
37
|
|
|
38
|
-
- The system should expose an API conforming to the
|
|
39
|
-
[API specification](resources/api_spec.yaml).
|
|
38
|
+
- The system should expose an API conforming to the [API specification](resources/api_spec.yaml).
|
|
40
39
|
```
|
|
41
40
|
|
|
42
41
|
## Path Rules
|
|
@@ -69,10 +69,9 @@ Too complex:
|
|
|
69
69
|
|
|
70
70
|
Acceptable (separate the modes):
|
|
71
71
|
- The system should process standard :Order: by validating and storing it.
|
|
72
|
-
- The system should process express :Order: by queuing it for immediate dispatch
|
|
73
|
-
|
|
74
|
-
-
|
|
75
|
-
items each and processing them individually.
|
|
72
|
+
- The system should process express :Order: by queuing it for immediate dispatch without validation.
|
|
73
|
+
- The system should process bulk :Order: by splitting it into sub-orders of 100 items each.
|
|
74
|
+
- Each sub-order is processed individually.
|
|
76
75
|
```
|
|
77
76
|
|
|
78
77
|
### 4. Cross-Cutting Concerns
|
|
@@ -88,8 +87,7 @@ Too complex:
|
|
|
88
87
|
Acceptable (separate concerns):
|
|
89
88
|
- The system should fetch :Resource: items from the external API.
|
|
90
89
|
- The system should paginate when fetching :Resource: items from the external API.
|
|
91
|
-
- The system should retry fetching :Resource: on transient errors using
|
|
92
|
-
exponential backoff.
|
|
90
|
+
- The system should retry fetching :Resource: on transient errors using exponential backoff.
|
|
93
91
|
```
|
|
94
92
|
|
|
95
93
|
### 5. UI Complexity
|
|
@@ -111,10 +111,10 @@ If the spec describes different modes or branches, give each its own spec.
|
|
|
111
111
|
**After:**
|
|
112
112
|
```plain
|
|
113
113
|
- The system should generate a standard :MealPlan: using round-robin :Recipe: assignment.
|
|
114
|
-
- The system should generate a restrictive :MealPlan
|
|
115
|
-
:Ingredient: items
|
|
116
|
-
-
|
|
117
|
-
|
|
114
|
+
- The system should generate a restrictive :MealPlan:.
|
|
115
|
+
- Excluded :Ingredient: items are filtered out first.
|
|
116
|
+
- Round-robin :Recipe: assignment is then applied.
|
|
117
|
+
- The system should allow :User: to manually assign :Recipe: items to :Slot: items for a custom :MealPlan:.
|
|
118
118
|
```
|
|
119
119
|
|
|
120
120
|
### Strategy 5: Build UI Incrementally
|
|
@@ -184,8 +184,8 @@ The frontmatter is enclosed between `---` markers and supports:
|
|
|
184
184
|
Specifications can reference external files using markdown link syntax. The linked resource is passed along with the spec to the renderer. File paths are resolved relative to the `.plain` file location. Only files in the same folder (and subfolders) are supported.
|
|
185
185
|
|
|
186
186
|
```plain
|
|
187
|
-
- :User: should be able to add :Task:.
|
|
188
|
-
|
|
187
|
+
- :User: should be able to add :Task:.
|
|
188
|
+
- The user-interface details are in [task_modal_specification.yaml](task_modal_specification.yaml).
|
|
189
189
|
```
|
|
190
190
|
|
|
191
191
|
#### Hard constraint: a linked resource is always a single, text-based file on disk
|
|
@@ -220,15 +220,15 @@ The accompanying spec line should describe the *role* of the artifact ("the requ
|
|
|
220
220
|
```plain
|
|
221
221
|
***definitions***
|
|
222
222
|
|
|
223
|
-
- :TaskCreateRequest: is the JSON payload for creating a task
|
|
224
|
-
[resources/task_create_request.schema.json](resources/task_create_request.schema.json).
|
|
225
|
-
- :TasksAPI: is the public HTTP surface for tasks
|
|
226
|
-
[resources/tasks_openapi.yaml](resources/tasks_openapi.yaml).
|
|
223
|
+
- :TaskCreateRequest: is the JSON payload for creating a task.
|
|
224
|
+
- It is defined by [resources/task_create_request.schema.json](resources/task_create_request.schema.json).
|
|
225
|
+
- :TasksAPI: is the public HTTP surface for tasks.
|
|
226
|
+
- It is defined by [resources/tasks_openapi.yaml](resources/tasks_openapi.yaml).
|
|
227
227
|
|
|
228
228
|
***functional specs***
|
|
229
229
|
|
|
230
|
-
- :User: should be able to add :Task: by POSTing :TaskCreateRequest: to the
|
|
231
|
-
|
|
230
|
+
- :User: should be able to add :Task: by POSTing :TaskCreateRequest: to the `POST /tasks` endpoint of :TasksAPI:.
|
|
231
|
+
- The endpoint responds per :TasksAPI:.
|
|
232
232
|
```
|
|
233
233
|
|
|
234
234
|
**Each linked resource must be referenced from exactly one place** in the project — a single functional spec, implementation requirement, or `***definitions***` entry. Linking the same file from two functional specs (or from a functional spec *and* a requirement, etc.) creates two independent sources of truth: any later edit to one site silently diverges from the other, and the renderer has no way to know which one is canonical.
|
|
@@ -243,8 +243,8 @@ For example, instead of linking `task_modal_specification.yaml` from two differe
|
|
|
243
243
|
```plain
|
|
244
244
|
***definitions***
|
|
245
245
|
|
|
246
|
-
- :TaskModalSpec: is the user-interface contract for the task modal
|
|
247
|
-
fully described in [task_modal_specification.yaml](task_modal_specification.yaml).
|
|
246
|
+
- :TaskModalSpec: is the user-interface contract for the task modal.
|
|
247
|
+
- It is fully described in [task_modal_specification.yaml](task_modal_specification.yaml).
|
|
248
248
|
|
|
249
249
|
***functional specs***
|
|
250
250
|
|
|
@@ -81,13 +81,9 @@ Before launching anything:
|
|
|
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*.
|
|
83
83
|
|
|
84
|
-
## Launch
|
|
84
|
+
## Launch always in `--headless` mode
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
### Mode A — `--headless`, agent-launched (default; preferred for supervised runs)
|
|
89
|
-
|
|
90
|
-
The agent launches the renderer in the background and supervises via the log file + filesystem. The terminal tool **cannot** drive an interactive TUI, so TUI mode is incompatible with agent-launched rendering. Use `--headless`:
|
|
86
|
+
The agent must always launch the renderer in the background and supervise it via the log file and filesystem. The terminal tool **cannot** drive an interactive TUI, so TUI mode is incompatible with agent-launched rendering. Always use `--headless`:
|
|
91
87
|
|
|
92
88
|
```bash
|
|
93
89
|
nohup codeplain <module>.plain --headless <other-flags> > /dev/null 2>&1 &
|
|
@@ -96,12 +92,6 @@ echo $! # capture the PID
|
|
|
96
92
|
|
|
97
93
|
Record the PID. Confirm `codeplain.log` starts growing within a few seconds; if it doesn't, the launch failed — check the user's shell / API key and re-try.
|
|
98
94
|
|
|
99
|
-
### Mode B — user runs the TUI in another terminal; agent attaches
|
|
100
|
-
|
|
101
|
-
The user has, or wants, the TUI running in a separate terminal of their own. The agent does not launch anything — it only monitors. Confirm the PID with the user (`pgrep -fl codeplain` is the easy way) and confirm the log path. Everything else in the workflow is identical.
|
|
102
|
-
|
|
103
|
-
Never try to "screenshot" or "read" the TUI directly — you can't see it. Treat the TUI as opaque; rely on log + filesystem signals.
|
|
104
|
-
|
|
105
95
|
## Log monitoring contract
|
|
106
96
|
|
|
107
97
|
The monitor loop in Phase 1 leans almost entirely on `codeplain.log`. Before describing the loop, here is exactly how to read this file efficiently and what to look for. Treat this section as the reference the loop calls into.
|
|
@@ -189,11 +179,11 @@ Use these as cheap, idempotent ways to interrogate the log. Each is safe to run
|
|
|
189
179
|
|
|
190
180
|
## Reading test-script output
|
|
191
181
|
|
|
192
|
-
The renderer drives three external shell scripts during a run — `unittests-script`, `prepare-environment-script`, and `conformance-tests-script` (whichever are declared in the project's `config.yaml`). Each script wraps a real test framework (vitest, jest, pytest, tsc, etc.) and writes verbose output.
|
|
182
|
+
The renderer drives three external shell scripts during a run — `unittests-script`, `prepare-environment-script`, and `conformance-tests-script` (whichever are declared in the project's `config.yaml`). Each script wraps a real test framework (vitest, jest, pytest, tsc, etc.) and writes verbose output. It reads the output those scripts produce while the renderer is iterating. Three places to look, in priority order:
|
|
193
183
|
|
|
194
184
|
### 1. Inline in `codeplain.log` (the primary source)
|
|
195
185
|
|
|
196
|
-
With verbose logging on (the default — `--verbose` is `
|
|
186
|
+
With verbose logging on (the default — `--verbose` is `disabled`), codeplain captures each script's stdout/stderr and writes it into `codeplain.log` between its own wrapper lines:
|
|
197
187
|
|
|
198
188
|
```
|
|
199
189
|
INFO:codeplain:Running unit tests script .../unit_testing_typescript.sh. (attempt: 1)
|
|
@@ -233,10 +223,6 @@ This is the renderer telling you, in its own words, what it tried and what is st
|
|
|
233
223
|
|
|
234
224
|
Refresh these files on each pass while a retry loop is active — the renderer rewrites them between attempts.
|
|
235
225
|
|
|
236
|
-
### 3. The TUI (last resort, agent can't see it)
|
|
237
|
-
|
|
238
|
-
If the user is running in Mode B (TUI visible to them, not to you), the script output is also painted on the TUI live. The agent cannot read it directly. When you need it and it isn't in `codeplain.log`, **ask the user to paste the latest test-output panel of the TUI**, or to relaunch in `--headless` so the log captures everything.
|
|
239
|
-
|
|
240
226
|
## Spec-deviation classification
|
|
241
227
|
|
|
242
228
|
This is the most important active judgment the skill makes. Once a functionality enters a retry loop (unit-test or conformance), the renderer iterates — changing source code, and sometimes changing its own conformance tests — trying to satisfy the test-script output. **Not every iteration is honest.** Each iteration must be classified before deciding whether to let the renderer continue, stop and fix the spec, or stop and fix the test script.
|
|
@@ -247,7 +233,7 @@ The inputs to the classifier are:
|
|
|
247
233
|
2. The **test-script output** for the most recent attempt, from `codeplain.log` per the section above.
|
|
248
234
|
3. The renderer's own **`.memory/conformance_test_memory/<id>.json`** for this functionality (when present).
|
|
249
235
|
4. The newest **conformance test file** the renderer just edited under `conformance_tests/<module>/<fname>/`.
|
|
250
|
-
5. The newest **implementation file(s)** the renderer just edited under `plain_modules/<module
|
|
236
|
+
5. The newest **implementation file(s)** the renderer just edited under `plain_modules/<module>/`.
|
|
251
237
|
|
|
252
238
|
With these in hand, place the current iteration into one of four buckets:
|
|
253
239
|
|
|
@@ -267,11 +253,11 @@ Action: let the renderer keep going, up to the threshold (5 conformance attempts
|
|
|
267
253
|
Signals — any one of these is enough:
|
|
268
254
|
|
|
269
255
|
- The **same test** fails every attempt with the **same assertion**, and the assertion checks something the functional spec **does not explicitly say** (e.g. exact exit code, exact error wording, specific status field).
|
|
270
|
-
- `current_issue_summary` in memory describes a question the spec does not answer (e.g. "unclear whether `--help` should exit 0 or 2").
|
|
256
|
+
- `current_issue_summary` in memory describes a question the spec does not answer (e.g. "unclear whether `--help` should exit 0 or 2").
|
|
271
257
|
- The renderer's `fix_attempt_summary` keeps oscillating between two opposite interpretations of the same requirement (regex variant A this attempt, variant B next attempt, A again the attempt after).
|
|
272
258
|
- The conformance test file is being rewritten between attempts in a way that **changes which behavior is being asserted**, not just how it is asserted.
|
|
273
259
|
|
|
274
|
-
Action: stop the renderer (SIGINT). Hand off to `debug-specs
|
|
260
|
+
Action: stop the renderer (SIGINT). Hand off to `debug-specs`. The spec must be tightened so there is only one valid behavior to converge on. Then resume with `--render-from <N>` for the offending functionality.
|
|
275
261
|
|
|
276
262
|
### Bucket 3 — Renderer is drifting away from the spec (stop immediately)
|
|
277
263
|
|
|
@@ -282,10 +268,12 @@ The dangerous case. Signals:
|
|
|
282
268
|
- The renderer's `key_learnings` reads like rationalization rather than diagnosis (e.g. "adjusted assertion to match observed behavior", "removed strict check that was causing failures").
|
|
283
269
|
- Failure count is going **up** between attempts.
|
|
284
270
|
|
|
285
|
-
Action: stop the renderer **immediately**, don't wait for the threshold.
|
|
271
|
+
Action: stop the renderer **immediately**, don't wait for the threshold. The fix must be applied to the `.plain` file (the spec was probably not specific enough and the renderer chose the path of least resistance):
|
|
272
|
+
- If it happened during the **conformance testing phase**, the `***test reqs***` need to be tightened.
|
|
273
|
+
- If it happened during the rendering of a **functional requirement**, the functional specs, definitions, or `***impl reqs***` need to change.
|
|
274
|
+
- If it happened during **acceptance testing**, the acceptance test definitions need to be tightened.
|
|
286
275
|
|
|
287
|
-
|
|
288
|
-
2. **Generated-code side** — do nothing; the broken code under `plain_modules/` will be overwritten on resume. **Never** hand-edit it.
|
|
276
|
+
Do nothing on the generated-code side; the broken code under `plain_modules/` will be overwritten on resume. **Never** hand-edit it.
|
|
289
277
|
|
|
290
278
|
Then resume with `--render-from <N>` (or `--force-render` if the drift contaminated earlier functionalities). Re-running `plain-healthcheck` first is mandatory.
|
|
291
279
|
|
|
@@ -298,7 +286,10 @@ Signals:
|
|
|
298
286
|
- The script is failing **before** running any framework command at all (`die: prepared environment missing`, missing argument, etc.).
|
|
299
287
|
- The failure mode is identical across functionalities, not specific to the spec being rendered.
|
|
300
288
|
|
|
301
|
-
Action:
|
|
289
|
+
Action: This is **not** a spec problem and the spec should stay as is. Stop the renderer and investigate why the script fails:
|
|
290
|
+
- If it's a bug in the script (e.g., pathing issue, syntax error, missing environment variable load), attempt to fix the script directly, or hand off to the matching `implement-*-testing-script` skill.
|
|
291
|
+
- If it's a missing host dependency (e.g., Python or Node is not installed, or a required global package is missing), inform the user and ask them to install it.
|
|
292
|
+
- **Before resuming the renderer**, test the script by running it manually exactly as the renderer would. If the same infrastructure/script issue persists, the fix didn't work. If the script now runs (even if it reports legitimate test failures), the fix was successful.
|
|
302
293
|
|
|
303
294
|
### Classifier discipline
|
|
304
295
|
|
|
@@ -371,7 +362,7 @@ Do **not** treat hitting the threshold as the diagnosis. From `ATTEMPT_COUNTER >
|
|
|
371
362
|
- **Bucket 1** — keep going until the threshold; report the per-attempt failure count.
|
|
372
363
|
- **Bucket 2** — stop now (regardless of how close to the threshold you are); hand off to `debug-specs` / `add-implementation-requirement` / inline spec edit. The spec is under-specified.
|
|
373
364
|
- **Bucket 3** — stop **immediately**, do not wait for the threshold; the renderer is drifting. Tighten the spec or acceptance test before resuming.
|
|
374
|
-
- **Bucket 4** — the test script is the problem; route to Pathology
|
|
365
|
+
- **Bucket 4** — the test script is the problem; route to Pathology E instead.
|
|
375
366
|
|
|
376
367
|
### Pathology B — `Functional spec too complex!`
|
|
377
368
|
|
|
@@ -385,19 +376,11 @@ The renderer can't resolve a reference. Stop is automatic. Hand off to `add-conc
|
|
|
385
376
|
|
|
386
377
|
Renderer surfaces a conflict, or you can see two specs in the same module that contradict each other in the generated code. Hand off to `resolve-spec-conflict`.
|
|
387
378
|
|
|
388
|
-
### Pathology E —
|
|
389
|
-
|
|
390
|
-
No new bytes appended to `codeplain.log` for **>2 minutes** *and* the process is still alive. Detect it via `stat -f %m codeplain.log` (mtime) and `wc -c` (size unchanged across passes). Usually the API is slow; occasionally the renderer is wedged. Action:
|
|
391
|
-
|
|
392
|
-
1. Confirm the process is still alive (`ps -p <pid>`).
|
|
393
|
-
2. Confirm the API is reachable (`curl -sSI https://api.codeplain.ai` or whatever `--api` points at).
|
|
394
|
-
3. Wait one more cadence cycle. If the log is still frozen, ask the user whether to stop.
|
|
395
|
-
|
|
396
|
-
### Pathology F — Test scripts themselves are broken
|
|
379
|
+
### Pathology E — Test scripts themselves are broken
|
|
397
380
|
|
|
398
381
|
Symptom: log shows the unit-test or conformance-test **script** itself failing (non-zero exit, syntax error, missing dependency) on every attempt, rather than the renderer's code failing the tests. The fix is **not** a spec change — it is a `test_scripts/` change. Stop and hand off to the matching `implement-*-testing-script` skill, or have the user repair the script directly.
|
|
399
382
|
|
|
400
|
-
### Pathology
|
|
383
|
+
### Pathology F — Unit-test retry loop
|
|
401
384
|
|
|
402
385
|
Less common than the conformance loop, but the same shape: `Running unit tests script ... (attempt: <N>)` with `<N>` climbing for the same functionality. Threshold: **3 attempts**. From `ATTEMPT_COUNTER >= 2` onwards, run the same [Spec-deviation classification](#spec-deviation-classification) classifier and act on the bucket it returns. The most common root causes for unit-test loops are an implementation req that doesn't match the unit-test scaffolding (Bucket 2), or test reqs / framework usage that the renderer is satisfying by weakening assertions (Bucket 3). Hand-off is typically `add-implementation-requirement` or `debug-specs`.
|
|
403
386
|
|