@turri-dev/cli 0.1.16-next.b861614 → 0.1.16-next.ce2cd46
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/.pi/themes/turri-dark.json +1 -1
- package/dist/extension.js +2 -1
- package/dist/init-config.d.ts +1 -1
- package/dist/init-config.js +1 -1
- package/dist/loop-tools.js +1 -1
- package/dist/regenerate/cases.js +2 -2
- package/dist/regenerate/change-view.js +5 -3
- package/dist/regenerate/conform.js +0 -2
- package/dist/regenerate/delivery.d.ts +1 -5
- package/dist/regenerate/delivery.js +2 -9
- package/dist/regenerate/loop.js +1 -2
- package/dist/regenerate/regenerate.js +27 -9
- package/dist/regenerate/release.d.ts +3 -7
- package/dist/regenerate/release.js +59 -15
- package/dist/regenerate/testing.d.ts +7 -0
- package/dist/regenerate/testing.js +14 -0
- package/dist/regenerate-cli.js +1 -1
- package/dist/release-agent.d.ts +1 -1
- package/dist/release-agent.js +3 -3
- package/dist/release-tools.js +2 -1
- package/dist/skill-progress.d.ts +1 -1
- package/docs/authoring-plain.md +2 -2
- package/docs/config.md +1 -1
- package/docs/deploy.md +4 -6
- package/docs/hosting.md +1 -1
- package/docs/regenerating.md +3 -3
- package/docs/using.md +2 -2
- package/genome/rules/func-specs.md +30 -0
- package/genome/rules/impl-reqs.md +1 -1
- package/genome/rules/integration-embedded-testing.md +1 -1
- package/genome/rules/integration-embedded.md +1 -1
- package/genome/rules/integration-standalone.md +1 -1
- package/genome/rules/linked-resources.md +4 -0
- package/genome/rules/project-model.md +1 -1
- package/genome/rules/test-reqs.md +1 -1
- package/genome/rules/turri-regeneration.md +1 -1
- package/genome/skills/analyze-if-func-spec-too-complex/SKILL.md +5 -5
- package/genome/skills/break-down-func-spec/SKILL.md +1 -1
- package/genome/skills/brood/references/product.md +2 -2
- package/genome/skills/bud/SKILL.md +4 -4
- package/genome/skills/debug-specs/SKILL.md +6 -6
- package/genome/skills/mature/SKILL.md +1 -1
- package/genome/skills/resolve-section-ownership/SKILL.md +4 -4
- package/genome/skills/resolve-spec-conflict/SKILL.md +3 -3
- package/genome/skills/spawn/SKILL.md +2 -2
- package/package.json +1 -1
- package/genome/skills/add-acceptance-test/SKILL.md +0 -100
- package/genome/skills/add-concept/SKILL.md +0 -71
- package/genome/skills/add-functional-spec/SKILL.md +0 -93
- package/genome/skills/add-functional-specs/SKILL.md +0 -128
- package/genome/skills/add-implementation-requirement/SKILL.md +0 -85
- package/genome/skills/add-resource/SKILL.md +0 -105
- package/genome/skills/add-template/SKILL.md +0 -64
- package/genome/skills/add-test-requirement/SKILL.md +0 -73
package/docs/regenerating.md
CHANGED
|
@@ -148,7 +148,7 @@ Every time a review sends tests back, the agent that fixes them also leaves the
|
|
|
148
148
|
|
|
149
149
|
### Then
|
|
150
150
|
|
|
151
|
-
Once the unit tests pass and are reviewed, the job lands: the code record becomes the \*\*\*plain description the job ends on, and a commit is made to the module's history. The conformance tests are not run here: they are the conformance track's, and its job for what this one built runs next, before anything is built on it (see [conformance tests in the work loop](#conformance-tests-in-the-work-loop)). A job that does not pass is undone instead - see [below](#what-the-code-is-built-from).
|
|
151
|
+
Once the unit tests pass and are reviewed, the job lands: the code record becomes the \*\*\*plain description the job ends on, and a commit is made to the module's history. The conformance tests are not run here: they are the conformance track's, and its job for what this one built runs next, before anything is built on it (see [conformance tests in the work loop](#conformance-tests-in-the-work-loop)). A job that does not pass is undone instead - see [below](#what-the-code-is-built-from). Trying what it built is [deploy](deploy.md)'s, not the job's: on the command line, a run that landed ends with `turri release <spec>`.
|
|
152
152
|
|
|
153
153
|
## A whole module
|
|
154
154
|
|
|
@@ -276,14 +276,14 @@ Every job is a \*\*\*plain diff: the agent that regenerates it is given the \*\*
|
|
|
276
276
|
|
|
277
277
|
**Every part of \*\*\*plain is given with its module.** A codebase is built from its whole requires chain's \*\*\*plain, and each module numbers its functional specs from 1, so every agent is shown each section grouped under the module each item belongs to - `<module name="base">`, then `<module name="app" role="current">` - as `<already implemented>` groups the functional specs (`moduleSection`, `functionalitiesByModule` in `prompt.ts`). A module's own items, and what it imports, are the current module's. `<spec change>` names a functional spec as "functionality 2 of module `app`", and a definition or req of a module below with its module; each case line does too ("fs 2 of module `app`"). The primer every agent reads first says that modules are how [\*\*\*plain](https://plainlang.org/docs/) is written, not how the code is laid out: the agent works only in the current module's codebase, which holds the code of every module it requires, and organises the code as the implementation reqs say.
|
|
278
278
|
|
|
279
|
-
It is told, too, what to do with each functional spec the job touches, by its case (`src/regenerate/cases.ts`): a fresh project is set up first, with its unit tests where the unit testing script runs them; a new functional spec is built and unit tested; a changed one - its text, or a concept it uses - is changed in place, its code and tests to match, never built again from scratch; one regenerated again is
|
|
279
|
+
It is told, too, what to do with each functional spec the job touches, by its case (`src/regenerate/cases.ts`): a fresh project is set up first, with its unit tests where the unit testing script runs them; a new functional spec is built and unit tested; a changed one - its text, or a concept it uses - is changed in place, its code and tests to match, never built again from scratch; one regenerated again is built anew, not patched - its implementation taken out and built again, even where the old code already does what \*\*\*plain says, what it replaces taken out; one taken out has its code and the tests only it had removed. A job holding several cases has a line for each. A job that touches no functional spec - implementation reqs, or definitions none uses - is mechanical: the code adapts, no new test is written, and an existing one may change only mechanically, never what it asserts. The unit test review holds each part to its case, and a mechanical job only to its reqs and to no test removed or weakened. A conformance job's agent and its reviewer are told the same, for the tests:
|
|
280
280
|
|
|
281
281
|
| case | when | code | conformance |
|
|
282
282
|
| --- | --- | --- | --- |
|
|
283
283
|
| fresh | the module requires none and nothing is built | set up the project and its unit tests where the unit testing script runs them, then build | set up `tests/` so the conformance testing script, which brings the tests together with `code/`, runs them, then write |
|
|
284
284
|
| add | a functional spec is new | build it and write its unit tests | write its tests |
|
|
285
285
|
| patch | its text changed, or a concept it uses did | change the existing code and tests to match - never build it again from scratch | rewrite its existing tests to match |
|
|
286
|
-
| again | `regenerate` named it: it is built, and marked in the code record to be regenerated again |
|
|
286
|
+
| again | `regenerate` named it: it is built, and marked in the code record to be regenerated again | take its implementation out and build it anew, doing what \*\*\*plain says now - the old code already doing it is no reason to keep it; no second implementation beside the old, nothing of it left unused; its unit tests written anew. A coding agent that writes nothing is sent back twice to build it anew, and then the pulse does not land | its tests were written against the code it replaced: run against the new code, what they check that \*\*\*plain says stays checked, and what they check that \*\*\*plain leaves open - a path, a field, a message the old code chose - is rewritten to what the new code does, or taken out |
|
|
287
287
|
| delete | a functional spec is gone | take out its code and the tests only it had | take out its tests |
|
|
288
288
|
| mechanical | no functional spec is touched - only reqs, or definitions none uses | adapt the code; write no new test; an existing one may change only mechanically - an import, a fixture, its setup - never what it asserts | the same, for test reqs, definitions or implementation reqs alone |
|
|
289
289
|
|
package/docs/using.md
CHANGED
|
@@ -21,7 +21,7 @@ Three skills you start yourself, by their commands or by picking them when turri
|
|
|
21
21
|
|
|
22
22
|
Peeking is safe while a question is open - a skill's or the chat's: `ctrl+h` opens the side panel over the question, which waits under it as it was - the panel says `your question is waiting`, and `ctrl+h` or `esc` takes you back to answer it. (The question has the keys, so turri catches `ctrl+h` itself while one is open.) The dialog holds the question alone - no hint and no invitation; the `ctrl+h` under the job panel breathes until it is first pressed.
|
|
23
23
|
|
|
24
|
-
While a skill runs, a line above the input shows its phases, every one by name - those done ticked, the one it is in marked, the rest to come - and where it is: the skill's name at the left edge, `phase 2 of 4` at the right, and its phases centred between them, `✓ intent ━━━━ ⠋ stack ──── ○ testing ──── ○ product`. Under it, dimmed, the phase it is in and what it does: `stack - the language, frameworks, storage and architecture`. The phases are the skill's own steps, read from its `SKILL.md`. A skill of one phase, or none, has nothing to be partway through: its line is the spinner and its name alone, `⠹
|
|
24
|
+
While a skill runs, a line above the input shows its phases, every one by name - those done ticked, the one it is in marked, the rest to come - and where it is: the skill's name at the left edge, `phase 2 of 4` at the right, and its phases centred between them, `✓ intent ━━━━ ⠋ stack ──── ○ testing ──── ○ product`. Under it, dimmed, the phase it is in and what it does: `stack - the language, frameworks, storage and architecture`. The phases are the skill's own steps, read from its `SKILL.md`. A skill of one phase, or none, has nothing to be partway through: its line is the spinner and its name alone, `⠹ analyze-func-specs`.
|
|
25
25
|
|
|
26
26
|
`genome/skills/` holds the rest: adding a feature, a concept, a requirement, a resource; splitting a functional spec that is too big; resolving conflicts; checking the environment - see [authoring \*\*\*plain](authoring-plain.md#the-skills). A skill run that is interrupted can be resumed where it stopped. A project can have skills of its own, in `.turri/skills/` or `.agents/skills/` - see [skills and gates](skills-and-gates.md#a-projects-own-skills).
|
|
27
27
|
|
|
@@ -29,7 +29,7 @@ While a skill runs, a line above the input shows its phases, every one by name -
|
|
|
29
29
|
|
|
30
30
|
| tool | |
|
|
31
31
|
| --- | --- |
|
|
32
|
-
| `regenerate` | regenerate a module and its chain from \*\*\*plain as it is now - after any change to it, by any means: what is left to regenerate is planned into pulses of one to three functional specs, each with the definitions and reqs it uses, and a pulse regenerating what \*\*\*plain no longer wants is stopped. With functionalities named, those are regenerated though their \*\*\*plain did not change -
|
|
32
|
+
| `regenerate` | regenerate a module and its chain from \*\*\*plain as it is now - after any change to it, by any means: what is left to regenerate is planned into pulses of one to three functional specs, each with the definitions and reqs it uses, and a pulse regenerating what \*\*\*plain no longer wants is stopped. With functionalities named, those are regenerated though their \*\*\*plain did not change - their code taken out and built anew, planned into pulses as any change is; with `from_scratch`, the whole module, its code deleted first - `"chain"` for every module of its requires chain too, built again from the bottom - only when you ask, or agree |
|
|
33
33
|
| `drift` | what is left to regenerate: how far the code and its conformance tests have drifted from \*\*\*plain, starting nothing |
|
|
34
34
|
| `glimpse` | the pulse a module's codebases would start next, and the whole prompt its coding agent would get - starting nothing |
|
|
35
35
|
| `steer` | say how the work is planned - which functional specs go together, what first - for the project or one module, for the session; the next plan follows it, beside what AGENTS.md says under a heading naming the queue |
|
|
@@ -73,6 +73,22 @@ GOOD — statements of fact with concrete subjects:
|
|
|
73
73
|
- Before adding, review all existing specs and verify compatibility
|
|
74
74
|
- If ambiguity exists, add explicit detail to eliminate any conflicting interpretation
|
|
75
75
|
|
|
76
|
+
## Adding a functional spec
|
|
77
|
+
Every new functional spec - one or a batch - is checked before it is written into the file:
|
|
78
|
+
1. Draft it, then trim it per `concise-specs.md` to the shortest wording that keeps every fact
|
|
79
|
+
2. Check its size with `analyze-if-func-spec-too-complex`; when it is too complex, split it with `break-down-func-spec` and check each part from step 1
|
|
80
|
+
3. Check it for conflicts with **one** `analyze-func-specs` call over the new spec and every existing functional spec in the file and its `requires` chain - never pair by pair. Resolve each conflicting pair it reports with `resolve-spec-conflict`, then run it again over what changed until it is compatible
|
|
81
|
+
4. Only then write it in, where it belongs (see Placement)
|
|
82
|
+
|
|
83
|
+
A batch is checked one spec at a time, in order: each spec's conflict check includes the specs of the batch already written in. Never write the whole batch in first and check it afterwards - a bad spec already in the file skews every later check. A few specs are no reason to skip a check.
|
|
84
|
+
|
|
85
|
+
## Placement
|
|
86
|
+
Put a new spec where it fits the module as it reads, not at the end by default:
|
|
87
|
+
- **Below every spec it builds on** - each one whose behaviour it references or extends, and the first to use each concept it relies on
|
|
88
|
+
- **Above every spec that builds on it** - one that already assumes what it adds
|
|
89
|
+
- **Within those bounds, beside the specs of its feature** - usually straight after the last one it extends
|
|
90
|
+
- **At the end** only when it starts something new or fits nowhere better
|
|
91
|
+
|
|
76
92
|
## Language agnosticism
|
|
77
93
|
- Write in terms of behavior, concepts, and domain logic
|
|
78
94
|
- Avoid language-specific terminology: generics syntax, framework annotations, language-specific collection types, decorator syntax, base-class keywords, framings like "POJO" or "dataclass"
|
|
@@ -112,6 +128,20 @@ GOOD — statements of fact with concrete subjects:
|
|
|
112
128
|
- Acceptance tests must describe concrete, verifiable outcomes — not vague qualities
|
|
113
129
|
- Acceptance tests must not contradict, narrow, or extend beyond the parent spec
|
|
114
130
|
|
|
131
|
+
```plain
|
|
132
|
+
Functional spec:
|
|
133
|
+
- :Resource: items are returned sorted by creation date in descending order.
|
|
134
|
+
|
|
135
|
+
Good - follows from the spec:
|
|
136
|
+
- After three :Resource: items are created one after another, listing them returns the last one created first.
|
|
137
|
+
|
|
138
|
+
Bad - contradicts it (the spec says descending):
|
|
139
|
+
- The first :Resource: listed is the oldest.
|
|
140
|
+
|
|
141
|
+
Bad - extends it (the spec says nothing about a limit):
|
|
142
|
+
- At most 50 :Resource: items are listed.
|
|
143
|
+
```
|
|
144
|
+
|
|
115
145
|
## Format
|
|
116
146
|
|
|
117
147
|
```plain
|
|
@@ -15,7 +15,7 @@ When writing or editing an `***implementation reqs***` section in a `.plain` fil
|
|
|
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
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
|
+
- Phrase each `:UnitTests:` requirement in terms of `:UnitTests:` so the partition stays visible at a glance
|
|
19
19
|
|
|
20
20
|
## What belongs here
|
|
21
21
|
- Technology choices: language, framework, runtime version
|
|
@@ -31,7 +31,7 @@ The two scripts are generated from facts in the integration's spec. For an embed
|
|
|
31
31
|
- **Everything about `:UnitTests:`** — paths, approach, packages, framework, conventions, fixtures, mocking policy — lives in `***implementation reqs***`. Unit tests are part of the generated codebase, so requirements that shape them are implementation reqs (see [`impl-reqs.md`](impl-reqs.md))
|
|
32
32
|
- **Everything about `:ConformanceTests:`** — paths, approach, packages, framework, execution command, pass criteria, mocking policy — lives in `***test reqs***`. Conformance tests are external to the generated codebase, so requirements that shape them are test reqs (see [`test-reqs.md`](test-reqs.md))
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
The first group follows `impl-reqs.md`, the second `test-reqs.md`. The two groups are parallel — each predefined concept owns a complete authoring story in its own section.
|
|
35
35
|
|
|
36
36
|
### In `***implementation reqs***` — everything about `:UnitTests:`
|
|
37
37
|
|
|
@@ -70,7 +70,7 @@ The integration's `.plain` module lives **inside the host codebase** (per the "a
|
|
|
70
70
|
|
|
71
71
|
- Every host file the integration touches (base classes, configuration modules, registries, exception classes, lifecycle hooks) is referenced from the relevant spec using `***linked resource***` syntax with the **path as it exists in the host codebase** — e.g. `[base.py](host_project/integrations/base.py)` if the `.plain` module sits next to `host_project/`
|
|
72
72
|
- **Do NOT copy host files into `resources/host/`.** A copy creates a second source of truth that drifts the moment the host file is edited; the rendered code will then disagree with whatever the host actually ships
|
|
73
|
-
- **Do NOT
|
|
73
|
+
- **Do NOT copy host files into `resources/`** when that would duplicate them — link the existing host path directly
|
|
74
74
|
- **Never inline a host file's contents** into a spec
|
|
75
75
|
- **Never describe a host symbol's shape from memory** — the renderer reads the linked file's bytes at its host path and that is the source of truth
|
|
76
76
|
- This still obeys the broader [`linked-resources.md`](linked-resources.md) rules: a directory is not a valid link, a URL is not a valid link, a binary is not a valid link. Only the *location* changes — host files live where the host put them, not under `resources/`
|
|
@@ -101,7 +101,7 @@ Capture as a contract-version concept; pin the version in every published schema
|
|
|
101
101
|
|
|
102
102
|
## Testing — live conformance, secrets from env, webhooks
|
|
103
103
|
|
|
104
|
-
`:ConformanceTests:` for a standalone integration **run against the live provider** (see [`integrations.md`](integrations.md) → *`:ConformanceTests:` always run against the live integration*). The testing strategy is captured as `***test reqs***` entries
|
|
104
|
+
`:ConformanceTests:` for a standalone integration **run against the live provider** (see [`integrations.md`](integrations.md) → *`:ConformanceTests:` always run against the live integration*). The testing strategy is captured as `***test reqs***` entries (`test-reqs.md`):
|
|
105
105
|
|
|
106
106
|
- **Conformance is live by default.** No VCR cassettes, no prerecorded responses for the calls under test, no mock servers. A green conformance run that never touched the provider proves nothing. Recorded responses may back unit tests — never conformance
|
|
107
107
|
- **Secrets come from environment variables.** Pin every credential as an env-var name (e.g. `<PROVIDER>_API_KEY`, `<PROVIDER>_CLIENT_ID` + `<PROVIDER>_CLIENT_SECRET`) in `***test reqs***` and in the auth concept. Use the names the provider's docs use so users don't have to translate
|
|
@@ -63,6 +63,10 @@ A linked resource **must not** be any of the following:
|
|
|
63
63
|
- A :User: can edit a :Task: using :TaskModalSpec:.
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
## When to link
|
|
67
|
+
- Link content too long or too structured to state inline, or used from more than one place (through a concept, as above); state a short fact in the text instead
|
|
68
|
+
- Never link generated code - it lives in `plain_modules/`, not `resources/`
|
|
69
|
+
|
|
66
70
|
## File location and path resolution
|
|
67
71
|
- Paths are resolved relative to the directory where `turri` is run (the current working directory)
|
|
68
72
|
- Relative paths may traverse into parent directories — `[resource](../../resources/resource.md)` is valid — as long as they resolve to a real text file on disk
|
|
@@ -54,7 +54,7 @@ Besides frontmatter `import`, a template can be included with parameters:
|
|
|
54
54
|
{% include "python-console-app-template.plain", main_executable_file_name: "my_app.py" %}
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
Parameters are key-value pairs; the template reads them as `{{ variable_name }}`.
|
|
57
|
+
Parameters are key-value pairs; the template reads them as `{{ variable_name }}`. Templates live in `template/`. One is worth writing only for text more than one `.plain` file repeats, differing only in values the parameters carry; text used once stays inline.
|
|
58
58
|
|
|
59
59
|
## When an earlier test fails after a render
|
|
60
60
|
|
|
@@ -16,7 +16,7 @@ When writing or editing a `***test reqs***` section in a `.plain` file, always f
|
|
|
16
16
|
- **Everything** about `:ConformanceTests:` goes in `***test reqs***` — paths, approach, packages, framework, execution command, mocking / network policy, fixtures, pass criteria, environment prerequisites
|
|
17
17
|
- `:ConformanceTests:` live outside the generated codebase, in one folder, `plain_modules/<module>/tests/` - the module's whole conformance suite, 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
|
+
- Phrase each `:ConformanceTests:` requirement in terms of `:ConformanceTests:` so the partition stays visible at a glance
|
|
20
20
|
- Do not link the conformance testing script here (or anywhere in the specs; a link to it is ignored). turri finds it in the project root - `conformance-tests-script:` in `config.turri.yaml`, else the one `run_conformance_tests*.sh` in the root, else the one in `test_scripts/` - and shows it to the agents that write the conformance tests itself. Describe the framework and execution command here in words
|
|
21
21
|
|
|
22
22
|
## What belongs here
|
|
@@ -26,7 +26,7 @@ The other rules say what a spec means. This one says what turri does with a chan
|
|
|
26
26
|
- A definition changed patches every functional spec that uses its concept, directly or through other definitions. So does a change to a linked resource: the spec or definition linking it is changed though its text is not. A widely used definition is the costly edit - not a spec's position
|
|
27
27
|
- Implementation reqs alone, or definitions no functional spec uses, are a mechanical change: the code adapts, and no test is written or changes what it asserts
|
|
28
28
|
- Test reqs and acceptance tests reach the conformance tests only, never the code
|
|
29
|
-
- A functional spec regenerated again by name has its conformance tests written again once its new code lands: what they check that the spec leaves open - a path, a field, a message the old code chose - goes by the new code
|
|
29
|
+
- A functional spec regenerated again by name has its code taken out and built anew - never left as it was, even where it already does what the spec says; a pulse that changes nothing does not land. Its conformance tests are written again once its new code lands: what they check that the spec leaves open - a path, a field, a message the old code chose - goes by the new code
|
|
30
30
|
- Definitions moved to a common module and reqs reordered are recorded, not rendered
|
|
31
31
|
- A functional spec written on its happy path and hardened later - its validation, edge cases and errors added to it - is patched in place each time: growing a spec a step at a time costs no more than writing it whole up front
|
|
32
32
|
- A module's first pulse, when it builds one functional spec - the project set up and the smallest thing that runs - lands on its unit tests with no review
|
|
@@ -3,9 +3,9 @@ name: analyze-if-func-spec-too-complex
|
|
|
3
3
|
description: >-
|
|
4
4
|
Analyze a functional spec to determine if it is too complex for the renderer.
|
|
5
5
|
A spec is too complex if it would produce more than 200 lines of code changes.
|
|
6
|
-
Use after drafting a new functional spec (
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
Use after drafting a new functional spec (per `func-specs.md`, *Adding a
|
|
7
|
+
functional spec*) to verify it fits within the complexity limit before
|
|
8
|
+
inserting it.
|
|
9
9
|
allowed-tools: [read, ls, grep, find]
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -198,9 +198,9 @@ TOO COMPLEX
|
|
|
198
198
|
|
|
199
199
|
The internal analysis (checklist, LOC estimation, reasoning) informs the verdict but must not appear in the output. The caller decides what to do with the result.
|
|
200
200
|
|
|
201
|
-
##
|
|
201
|
+
## Where it is called
|
|
202
202
|
|
|
203
|
-
This skill is
|
|
203
|
+
This skill is step 2 of adding a functional spec (`func-specs.md`, *Adding a functional spec*) - for each spec of a batch, in order - after drafting a spec but **before** inserting it into the file. The caller acts on the one-word verdict:
|
|
204
204
|
|
|
205
205
|
- **ACCEPTABLE** — proceed to insert the spec.
|
|
206
206
|
- **TOO COMPLEX** — invoke `break-down-func-spec` to produce smaller specs, then insert each one individually (running conflict checks on each).
|
|
@@ -160,7 +160,7 @@ If the spec describes a full screen, split into layout + individual interactive
|
|
|
160
160
|
|
|
161
161
|
Sometimes a spec is too complex not because it bundles many behaviors, but because it implies building one substantial technical component inline — an engine, parser, scheduler, layout algorithm, state machine, or sync mechanism. Splitting the behavior sideways does not help when the weight sits in that single component. Instead, pull the component out: define a concept for it, build it in its own dedicated spec placed **earlier** in the chain, then rewrite the original to use the component **by reference**. Because specs render incrementally top-to-bottom, the original now implies far less code — it wires up a component that already exists rather than implementing it from scratch.
|
|
162
162
|
|
|
163
|
-
Define the component concept in `***definitions***` (
|
|
163
|
+
Define the component concept in `***definitions***` (per `definitions.md`) before the first spec that references it.
|
|
164
164
|
|
|
165
165
|
**Before:**
|
|
166
166
|
```plain
|
|
@@ -17,9 +17,9 @@ Every iteration is exactly this, at every questioning level:
|
|
|
17
17
|
|
|
18
18
|
1. **Ask one question** with `ask_user`, about the product: a feature, its trigger and outcome, one of its edge cases or rules, the next step of a flow - as broad as the level says. Never bundle two, and never ask about a spec section ("what concepts are there?", "what reqs apply?") - ask about what the product does, and let the answer decide which sections change.
|
|
19
19
|
2. **Turn the answer into a spec change** - one for each feature it covers - everything it calls for, across sections:
|
|
20
|
-
- a concept the feature introduces, into `***definitions***`, following `
|
|
20
|
+
- a concept the feature introduces, into `***definitions***`, following `definitions.md`, defined in the same change as the functional spec that first uses it;
|
|
21
21
|
- a technology-free policy the answer states, into `***implementation reqs***`;
|
|
22
|
-
- the functional spec for the feature, or the change to one already written, following `
|
|
22
|
+
- the functional spec for the feature, or the change to one already written, following `func-specs.md` - its wording, and the checks of *Adding a functional spec*. Write it as a git diff of the `.plain` file(s): `diff --git a/<file> b/<file>`, `--- a/<file>`, `+++ b/<file>`, then the hunks with a few lines of unchanged context. Paths are relative to the project root.
|
|
23
23
|
3. **Write it with `change_plain`.** It applies the diff and starts a render spec diff job for it in the same call - whatever the change touches, a definition alone included. Write every change the answer calls for before the next question - `ask_user` refuses it until then - and any you decide yourself beside them. Move straight on to the next question; never wait for a build.
|
|
24
24
|
|
|
25
25
|
**One answer, at least one change.** A follow-up about the same feature - an edge case, a validation rule - is its own answer and its own change to that feature's spec. An answer that describes two features is two changes, both written before the next question. A change never carries both an answer and something you decided: what you decide is a change of its own.
|
|
@@ -87,10 +87,10 @@ The feature, walked question by question. Run this loop while the questioning le
|
|
|
87
87
|
1. **Ask** one product question with `ask_user`.
|
|
88
88
|
2. The user **answers**.
|
|
89
89
|
3. **Make the spec change** the answer calls for, as one git diff of the `.plain` file(s) - across every section it needs:
|
|
90
|
-
- a concept it introduces, into `***definitions***` - written the way `
|
|
91
|
-
- a policy it states - error handling, a retry, a data format, a library not already in the module or its imports - into `***implementation reqs***`, the way `
|
|
92
|
-
- the functional spec it adds, or the change to one already written, the way `
|
|
93
|
-
- with conformance tests on - test reqs of the module's own or imported, and a conformance testing script turri finds - an acceptance test under its functional spec when the answer states one concrete verification (`
|
|
90
|
+
- a concept it introduces, into `***definitions***` - written the way `definitions.md` says, and defined in the same change as the functional spec that first uses it;
|
|
91
|
+
- a policy it states - error handling, a retry, a data format, a library not already in the module or its imports - into `***implementation reqs***`, the way `impl-reqs.md` says;
|
|
92
|
+
- the functional spec it adds, or the change to one already written, the way `func-specs.md` says: its wording rules, its complexity check (`analyze-if-func-spec-too-complex` - at most 200 lines of code; a spec too big is split *with the user*, as the next question) and its conflict check (`analyze-func-specs`, over the new spec and every existing one in the chain). Follow those rules and skills for what the text is; the diff is the only thing that writes it.
|
|
93
|
+
- with conformance tests on - test reqs of the module's own or imported, and a conformance testing script turri finds - an acceptance test under its functional spec when the answer states one concrete verification (`func-specs.md`, *Acceptance tests*), and a test req only when the answer changes how conformance tests run (`test-reqs.md`). With conformance off, none. Write it as a git diff: `diff --git a/<file> b/<file>`, `--- a/<file>`, `+++ b/<file>`, then the hunks with a few lines of unchanged context, paths from the project root. A new functional spec goes where it belongs in build order - after what it builds on, usually at the end.
|
|
94
94
|
4. **Write it with `change_plain` at once**, before anything else. It applies the diff and starts a render spec diff job for it; with conformance on, its conformance tests follow it. An answer that covers several behaviours is a change for each: write them all. Then the changes for what you decide yourself around it, if any. Say in one line what went into the spec - "added `:Note:` and functional spec 7" - and what became of the build, as the tool says, then ask the next question. Never wait for a build, and never ask the user to approve a change.
|
|
95
95
|
|
|
96
96
|
**One answer, at least one change.** A follow-up about the same behaviour - an edge case, a validation rule - is its own answer and its own change. An answer that describes two behaviours is two changes, both written before the next question. A change never carries both an answer and something you decided: what you decide is a change of its own.
|
|
@@ -70,10 +70,10 @@ Trace the issue from the generated code back to the specs. There are five possib
|
|
|
70
70
|
| Root Cause | Symptom | Fix |
|
|
71
71
|
|------------|---------|-----|
|
|
72
72
|
| **Ambiguous spec** | The spec is correct in intent, but vague enough that the renderer interpreted it differently than intended. | Add explicit detail to the spec to eliminate the ambiguity. |
|
|
73
|
-
| **Missing spec** | The desired behavior is not covered by any spec. The renderer had no guidance and either did nothing or made an arbitrary choice. | Add a new functional spec
|
|
73
|
+
| **Missing spec** | The desired behavior is not covered by any spec. The renderer had no guidance and either did nothing or made an arbitrary choice. | Add a new functional spec, checked as `func-specs.md` says (*Adding a functional spec*). |
|
|
74
74
|
| **Conflicting specs** | Two specs contradict each other, causing the renderer to produce inconsistent behavior. | Use the `resolve-spec-conflict` skill. |
|
|
75
75
|
| **Incorrect spec** | The spec explicitly describes the wrong behavior. The renderer implemented it faithfully, but the spec itself is wrong. | Rewrite the spec to describe the correct behavior. |
|
|
76
|
-
| **Missing implementation req** | The spec is correct, but the implementation req doesn't provide enough guidance for the renderer to produce the right code (e.g., missing library, missing architectural constraint, missing platform detail). | Add or update the implementation req
|
|
76
|
+
| **Missing implementation req** | The spec is correct, but the implementation req doesn't provide enough guidance for the renderer to produce the right code (e.g., missing library, missing architectural constraint, missing platform detail). | Add or update the implementation req, per `impl-reqs.md`. |
|
|
77
77
|
|
|
78
78
|
### How to diagnose
|
|
79
79
|
|
|
@@ -90,15 +90,15 @@ Trace the issue from the generated code back to the specs. There are five possib
|
|
|
90
90
|
|
|
91
91
|
## Phase 4 — Fix the Specs
|
|
92
92
|
|
|
93
|
-
Apply the fix based on the diagnosed root cause
|
|
93
|
+
Apply the fix based on the diagnosed root cause:
|
|
94
94
|
|
|
95
|
-
| Root Cause |
|
|
95
|
+
| Root Cause | How |
|
|
96
96
|
|------------|-------------|
|
|
97
97
|
| Ambiguous spec | Edit the spec inline — add sub-bullets or reword for clarity |
|
|
98
|
-
| Missing spec | `
|
|
98
|
+
| Missing spec | `func-specs.md`, *Adding a functional spec* |
|
|
99
99
|
| Conflicting specs | `resolve-spec-conflict` |
|
|
100
100
|
| Incorrect spec | Edit the spec inline — rewrite the incorrect part |
|
|
101
|
-
| Missing implementation req | `
|
|
101
|
+
| Missing implementation req | `impl-reqs.md` |
|
|
102
102
|
|
|
103
103
|
### Fix guidelines
|
|
104
104
|
|
|
@@ -61,7 +61,7 @@ Run cycles until the goal is met - or you are stuck - and at most twenty. Each c
|
|
|
61
61
|
- **Not the spec's** - a bug the agent is working through, a missing tool or package, a flaky service, turri itself. Leave the build to it, note it for the report, and keep watching. Stopping it would throw its work away for nothing.
|
|
62
62
|
5. **When the builds finish**, read `spec_findings`, and write into the spec every assumption about what the software does that a user, a caller or a test can see - as the build assumed it, unless that is not what the spec meant - so the next build does not have to guess. An assumption about how it is built inside - a library, a file layout, a name - stays out. A diagnosis that says the fix is in the spec is written; one that says code, environment or turri is noted. Then the next cycle: what failed, and what the new diffs changed, is rendered again.
|
|
63
63
|
|
|
64
|
-
**Writing a fix.** A git diff of the `.plain` file(s), paths from the project root, a few lines of context, with `change_plain`. One diff per concern - a functionality's missing rules together, a concept and what it means together - never one diff for everything. Put each where it belongs: a rule of one functionality into its functional spec, a policy for many into `***implementation reqs***`, a term into `***definitions***`, following `
|
|
64
|
+
**Writing a fix.** A git diff of the `.plain` file(s), paths from the project root, a few lines of context, with `change_plain`. One diff per concern - a functionality's missing rules together, a concept and what it means together - never one diff for everything. Put each where it belongs: a rule of one functionality into its functional spec, a policy for many into `***implementation reqs***`, a term into `***definitions***`, following `definitions.md`, `func-specs.md` and `impl-reqs.md` for how it is written. Each diff is built as it is written: what is left to build is worked out again from the spec - only what it changes is rendered again.
|
|
65
65
|
|
|
66
66
|
**When you are stuck, stop.** The same functionality struggling three times after you clarified the spec for it is not something the spec can settle: stop maturing it, and report it. Two cycles in a row with nothing newly built and nothing newly settled: stop, and report what is open. Twenty cycles: stop, and report.
|
|
67
67
|
|
|
@@ -35,7 +35,7 @@ The bullet, section, or `.plain` file to resolve.
|
|
|
35
35
|
4. **Route each fact** by the *Section ownership* table in `module-structure.md`. Where a fact resists the table, apply the question it encodes: **would a caller of the finished software observe this?** Yes → `***functional specs***`. No, it is how the result is reached → `***implementation reqs***`. It says what a term means → `***definitions***`. It shapes `:ConformanceTests:` → `***test reqs***`.
|
|
36
36
|
5. **Split a fact that carries both a mechanism and its consequence.** The consequence is observable and becomes the functional spec; the mechanism becomes the implementation req. *"Sends the same idempotency key on every retry, so a retried write creates at most one record"* is two facts, not one.
|
|
37
37
|
6. **Give each moved fact a subject that exists in the built system.** A fact leaving a functional spec often loses its subject: name the component that owns the behavior, and add it to `***definitions***` if it is not defined yet. `:Implementation:` is the whole codebase — use it only for a fact that holds everywhere.
|
|
38
|
-
7. **
|
|
38
|
+
7. **Write each fact into its owning section** by that section's rule — `definitions.md`, `impl-reqs.md`, `test-reqs.md`, the acceptance tests in `func-specs.md`. A fact moving *into* `***functional specs***` goes through `func-specs.md` (*Adding a functional spec*): its complexity and conflict checks run before it is written in.
|
|
39
39
|
8. **Remove each fact from where it no longer belongs.** If a bullet is left stating nothing observable, delete the bullet; do not leave a stub. Deleting the last bullet of a section deletes the section.
|
|
40
40
|
9. **Verify nothing was lost and nothing was duplicated.** Walk every fact from the original text and confirm it appears in exactly one section. A fact that now reads as obvious in its new home is still a cut decision — make it deliberately, per `concise-specs.md`.
|
|
41
41
|
10. **Run `validate`** on the module. Moving facts changes the renderable surface; do not finish while it reports errors.
|
|
@@ -43,8 +43,8 @@ The bullet, section, or `.plain` file to resolve.
|
|
|
43
43
|
|
|
44
44
|
## Error Handling
|
|
45
45
|
|
|
46
|
-
-
|
|
47
|
-
-
|
|
46
|
+
- **The complexity check finds the moved fact too complex** → the fact was a whole spec in disguise; run `break-down-func-spec` on it, then place the resulting specs.
|
|
47
|
+
- **The conflict check reports a conflict** → resolve it with `resolve-spec-conflict` **before** removing the fact from its old section, so no version of it is lost in between.
|
|
48
48
|
- **A fact appears to belong to two sections** → it is two facts; split it per step 5. If it still resists, it is a mechanism whose consequence has not been written down — write the consequence, and the split follows.
|
|
49
49
|
- **The owning section does not exist in the file** → create it in canonical order. An import module carries no `***functional specs***` at all (see `import-modules.md`), so an observable fact found there belongs on the root module that imports it.
|
|
50
50
|
- **The move empties a functional spec** → delete the spec rather than leaving a placeholder, and check whether any acceptance test nested under it must move or go with it.
|
|
@@ -58,7 +58,7 @@ The bullet, section, or `.plain` file to resolve.
|
|
|
58
58
|
- [ ] Every fact from the original text appears in exactly one section, or was deliberately cut
|
|
59
59
|
- [ ] No fact was reworded into a different meaning while being moved
|
|
60
60
|
- [ ] Each moved fact names a subject that exists in the built system
|
|
61
|
-
- [ ] Every fact moved into `***functional specs***`
|
|
61
|
+
- [ ] Every fact moved into `***functional specs***` passed the complexity and conflict checks of `func-specs.md`
|
|
62
62
|
- [ ] No `:UnitTests:` fact outside `***implementation reqs***`, no `:ConformanceTests:` fact outside `***test reqs***`
|
|
63
63
|
- [ ] Sections are in canonical order and every referenced concept is defined before use
|
|
64
64
|
- [ ] Emptied bullets and sections were removed, not left as stubs
|
|
@@ -4,7 +4,7 @@ description: >-
|
|
|
4
4
|
Resolve a conflict between two functional specs in a ***plain spec file. Use
|
|
5
5
|
when conformance tests for a previously passing spec start failing after a new
|
|
6
6
|
spec is rendered, or when a potential conflict is detected while adding a new
|
|
7
|
-
functional spec (
|
|
7
|
+
functional spec (the conflict check of `func-specs.md`).
|
|
8
8
|
allowed-tools: [read, write, edit, bash, ls, grep, find]
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ allowed-tools: [read, write, edit, bash, ls, grep, find]
|
|
|
14
14
|
|
|
15
15
|
A conflict exists (or is suspected) when:
|
|
16
16
|
- Conformance tests for a **previously passing** functional spec begin to fail after a new spec is rendered.
|
|
17
|
-
- A new spec being added
|
|
17
|
+
- A new spec being added appears to contradict an existing spec.
|
|
18
18
|
- Two specs make incompatible assertions about the same behavior, data, or state.
|
|
19
19
|
|
|
20
20
|
## Workflow
|
|
@@ -76,7 +76,7 @@ After editing:
|
|
|
76
76
|
3. Check that chronological ordering still makes sense (earlier specs should not depend on later ones).
|
|
77
77
|
4. If resolving via test adjustments, verify the `***test reqs***` or `***acceptance tests***` changes are appropriate.
|
|
78
78
|
|
|
79
|
-
## Prevention (
|
|
79
|
+
## Prevention (while adding a functional spec)
|
|
80
80
|
|
|
81
81
|
Before adding a new spec, run through this quick conflict check:
|
|
82
82
|
|
|
@@ -64,7 +64,7 @@ Set the module up and start the first build - on your own, no questions.
|
|
|
64
64
|
2. **Unit tests.** A `:UnitTests:` requirement - the framework, and how they are run - unless the imported stack already sets it, and the unit testing script. Keep one turri already finds (named in `config.turri.yaml`, or the one `run_unittests*.sh` in the root or `test_scripts/`); otherwise write `test_scripts/run_unittests_<language>.sh` by following the `implement-unit-testing-script` skill. Never link it from the specs. The script runs the stack's static checks with the unit tests - the formatter in check mode, the linter, the type checker - and they count as the tests do.
|
|
65
65
|
3. **Conformance tests: off.** Keep a `conformance-tests:` decision the project's config already holds - `config.turri.yaml`, or the old `config.yaml`. Otherwise write `conformance-tests: false` into `config.turri.yaml`, changing nothing else in it - a project with only a `config.yaml` has it copied to `config.turri.yaml` first, and `config.yaml` is never written - and write no `***test reqs***`, import no standard library conformance template, and write no conformance testing script. Only when the user asked for conformance tests, turn them on instead: `conformance-tests: true`, the `***test reqs***` - `:ConformanceTests:` requirements following `genome/rules/test-reqs.md`, or the stack's standard library conformance template imported when the stack is from it - and `test_scripts/run_conformance_tests_<language>.sh`, by following the `implement-conformance-testing-script` skill, unless turri already finds one.
|
|
66
66
|
4. Run `validate` on every module you wrote, and fix what it finds.
|
|
67
|
-
5. **The first spec.** Write the module's first functional spec with `change_plain`: the smallest thing that runs and shows something - the server answers one request (`GET /` with the app's name), the command-line tool prints its usage, the page shows the app's name, the library exposes one call with a fixed result. It holds no product logic, so its build only sets the project up and lands fast - and its pulse is not reviewed. Follow `
|
|
67
|
+
5. **The first spec.** Write the module's first functional spec with `change_plain`: the smallest thing that runs and shows something - the server answers one request (`GET /` with the app's name), the command-line tool prints its usage, the page shows the app's name, the library exposes one call with a fixed result. It holds no product logic, so its build only sets the project up and lands fast - and its pulse is not reviewed. Follow `func-specs.md` for its wording, and keep it to that one observable result.
|
|
68
68
|
|
|
69
69
|
`change_plain` takes a git diff of the `.plain` file(s): `diff --git a/<file> b/<file>`, `--- a/<file>`, `+++ b/<file>`, then the hunks with a few lines of context, paths from the project root. It applies the change and queues its build. Go straight on to the next step - never wait for a build.
|
|
70
70
|
|
|
@@ -74,7 +74,7 @@ Write the first slices of what the user described, each a spec diff, while the f
|
|
|
74
74
|
|
|
75
75
|
**Only what the user described.** Every slice comes from something the user said the software does. When they said only what kind of software it is, write no slice: the step writes nothing, and the handover invites them to say what it should do first.
|
|
76
76
|
|
|
77
|
-
1. **The main slice.** The one thing the user said the software is for, on its happy path - the half-built main function a developer writes first and runs. Its concepts go into `***definitions***` in the same change, following `
|
|
77
|
+
1. **The main slice.** The one thing the user said the software is for, on its happy path - the half-built main function a developer writes first and runs. Its concepts go into `***definitions***` in the same change, following `definitions.md`; its functional spec follows `func-specs.md`, placed where it fits.
|
|
78
78
|
2. **One more slice at most** - the next thing the user described, also on its happy path. Stop there: two slices beyond the first spec. What the user says once they have tried the first ones decides the rest, and slices written far ahead are slices to rework.
|
|
79
79
|
3. **Write each with `change_plain`**, one after another - never wait for a build. Never change a `.plain` file in this step by any other means. Correct a change you find wrong once written with a diff and `fixes_earlier`, never by editing the file.
|
|
80
80
|
|
package/package.json
CHANGED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: add-acceptance-test
|
|
3
|
-
description: >-
|
|
4
|
-
Add acceptance tests under a functional spec in a ***plain spec file. Use
|
|
5
|
-
when the user wants to add verification criteria for a specific functional
|
|
6
|
-
spec, or after adding a functional spec that needs testable success criteria.
|
|
7
|
-
allowed-tools: [read, write, edit, bash, ls, grep, find]
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# Add Acceptance Test
|
|
11
|
-
|
|
12
|
-
## Workflow
|
|
13
|
-
|
|
14
|
-
1. **Identify the target `.plain` file and the functional spec** to attach the acceptance test to. If ambiguous, ask the user.
|
|
15
|
-
2. **Read the file** to understand the functional spec, existing acceptance tests (if any), and the `***test reqs***` section (acceptance tests are implemented according to test reqs).
|
|
16
|
-
3. **Draft the acceptance test(s)** following the rules below.
|
|
17
|
-
4. **Nest them** under the target functional spec using a `***acceptance tests***` subsection.
|
|
18
|
-
5. **Read the file again** to confirm correct placement, indentation, and syntax.
|
|
19
|
-
|
|
20
|
-
## When to Add Acceptance Tests
|
|
21
|
-
|
|
22
|
-
- The functional spec's correct behavior is **non-obvious** or easily misinterpreted.
|
|
23
|
-
- The spec involves **edge cases**, boundary conditions, or specific numeric outcomes.
|
|
24
|
-
- The user explicitly requests verification criteria.
|
|
25
|
-
- The spec was added via the `add-functional-spec` skill and warrants testable success criteria.
|
|
26
|
-
|
|
27
|
-
## Format
|
|
28
|
-
|
|
29
|
-
Acceptance tests are nested under the functional spec they verify, using a `***acceptance tests***` subsection:
|
|
30
|
-
|
|
31
|
-
```plain
|
|
32
|
-
***functional specs***
|
|
33
|
-
|
|
34
|
-
- :Task: items are processed in batches of 100.
|
|
35
|
-
|
|
36
|
-
***acceptance tests***
|
|
37
|
-
- Processing 250 :Task: items should result in 3 batches.
|
|
38
|
-
|
|
39
|
-
- Each batch should contain at most 100 items.
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Key formatting rules:
|
|
43
|
-
- The `***acceptance tests***` header is indented under the functional spec it belongs to.
|
|
44
|
-
- Each test bullet is indented under the `***acceptance tests***` header.
|
|
45
|
-
- Multiple acceptance tests can be listed under a single functional spec.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
## Rules
|
|
49
|
-
|
|
50
|
-
### Conformance with the Functional Spec
|
|
51
|
-
|
|
52
|
-
An acceptance test is essentially an **example that illustrates** the functional spec — it clarifies intent by showing a concrete scenario. It may imply minor code changes, but those should not be substantial. The acceptance test **must be consistent with** the functional spec it is nested under. If the acceptance test asserts behavior that contradicts, narrows, or extends the functional spec in ways not implied by it, the system will reject it as a conflicting acceptance test. Before writing, re-read the parent functional spec and ensure every assertion in the acceptance test is a direct, logical consequence of what the spec states.
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
Functional spec:
|
|
56
|
-
- :Resource: items are returned sorted by creation date in descending order.
|
|
57
|
-
|
|
58
|
-
Good (consistent):
|
|
59
|
-
- The first :Resource: in the response should have the most recent creation date.
|
|
60
|
-
|
|
61
|
-
Bad (contradicts the spec — the spec says descending, not ascending):
|
|
62
|
-
- The first :Resource: in the response should have the oldest creation date.
|
|
63
|
-
|
|
64
|
-
Bad (extends beyond the spec — the spec says nothing about limiting results):
|
|
65
|
-
- The response should contain at most 50 :Resource: items.
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### Scope
|
|
69
|
-
|
|
70
|
-
Each acceptance test verifies a specific, observable aspect of the functional spec it's nested under. Do not test behavior from other functional specs.
|
|
71
|
-
|
|
72
|
-
### Testability
|
|
73
|
-
|
|
74
|
-
Every acceptance test must describe a concrete, verifiable outcome — not a vague quality. The test should be implementable as an automated conformance test.
|
|
75
|
-
|
|
76
|
-
```
|
|
77
|
-
Good: - The response should contain exactly 3 items.
|
|
78
|
-
Bad: - The response should be correct.
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Language Agnosticism
|
|
82
|
-
|
|
83
|
-
Like functional specs, acceptance tests must be written in terms of behavior and outcomes — not language-specific constructs.
|
|
84
|
-
|
|
85
|
-
### Relationship to Test Reqs
|
|
86
|
-
|
|
87
|
-
Acceptance tests extend conformance tests and are implemented according to the `***test reqs***` specification. They do not replace test reqs — they add spec-specific verification on top of the general testing framework defined there.
|
|
88
|
-
|
|
89
|
-
## Validation Checklist
|
|
90
|
-
|
|
91
|
-
- [ ] Every assertion is a direct logical consequence of the parent functional spec
|
|
92
|
-
- [ ] No assertion contradicts, narrows, or extends beyond the parent spec
|
|
93
|
-
- [ ] Acceptance test illustrates the spec via example, not introducing substantial new behavior
|
|
94
|
-
- [ ] Nested under the correct functional spec
|
|
95
|
-
- [ ] Indentation is correct (`***acceptance tests***` indented under the spec)
|
|
96
|
-
- [ ] Each test describes a concrete, verifiable outcome
|
|
97
|
-
- [ ] Trimmed per `concise-specs.md`: plain words, no obvious steps, no restatement of the parent spec
|
|
98
|
-
- [ ] Tests are scoped to the parent functional spec only
|
|
99
|
-
- [ ] Written in language-agnostic terms
|
|
100
|
-
- [ ] No duplication with existing acceptance tests on the same spec
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: add-concept
|
|
3
|
-
description: >-
|
|
4
|
-
Add a concept to the ***definitions*** section of a ***plain spec file. Use
|
|
5
|
-
when the user wants to define a new concept, entity, or domain term in a
|
|
6
|
-
.plain file.
|
|
7
|
-
allowed-tools: [read, write, edit, bash, ls, grep, find]
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# Add Concept
|
|
11
|
-
|
|
12
|
-
## Workflow
|
|
13
|
-
|
|
14
|
-
1. **Identify the target `.plain` file.** If ambiguous, ask the user.
|
|
15
|
-
2. **Read the file** to understand existing definitions, imports, and concepts.
|
|
16
|
-
3. **Validate the concept name** against the syntax rules below.
|
|
17
|
-
4. **Check for uniqueness** — the concept name must not already exist in the file or its imports.
|
|
18
|
-
5. **Check referenced concepts** — any `:ConceptName:` used in the definition must already be defined above it (in this file or via `import`/`requires`). Concept references must not form cycles (e.g., A references B and B references A).
|
|
19
|
-
6. **Check for circular references** — if the new concept references `:B:`, then `:B:` must not reference the new concept (directly or indirectly). Example of a circular definition to avoid:
|
|
20
|
-
```plain
|
|
21
|
-
- :Order: is placed by :Customer: and contains :OrderItem: entries.
|
|
22
|
-
- :Customer: is a user who has placed at least one :Order:.
|
|
23
|
-
```
|
|
24
|
-
Fix by removing the back-reference:
|
|
25
|
-
```plain
|
|
26
|
-
- :Customer: is a user of the system.
|
|
27
|
-
- :Order: is placed by :Customer: and contains :OrderItem: entries.
|
|
28
|
-
```
|
|
29
|
-
7. **Insert the concept** into the `***definitions***` section, after any concepts it references.
|
|
30
|
-
8. **Read the file again** to confirm correct placement and syntax.
|
|
31
|
-
|
|
32
|
-
## Concept Syntax Rules
|
|
33
|
-
|
|
34
|
-
- Wrapped in colons: `:ConceptName:`
|
|
35
|
-
- CamelCase, starting with an uppercase letter
|
|
36
|
-
- Valid characters: letters, digits, `+`, `-`, `.`, `_`
|
|
37
|
-
- Must be globally unique across the spec and all its imports
|
|
38
|
-
- Exported concepts from `requires` modules are **not transitive** — to reference an ancestor's export, list that ancestor in `requires`; if a concept is shared across branches, define it in a common import module instead
|
|
39
|
-
|
|
40
|
-
## Definition Format
|
|
41
|
-
|
|
42
|
-
A concept definition is a bullet in `***definitions***` that starts with the concept name:
|
|
43
|
-
|
|
44
|
-
```plain
|
|
45
|
-
***definitions***
|
|
46
|
-
|
|
47
|
-
- :ConceptName: is a description of what it represents.
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Attributes and constraints are nested sub-bullets:
|
|
51
|
-
|
|
52
|
-
```plain
|
|
53
|
-
***definitions***
|
|
54
|
-
|
|
55
|
-
- :Task: describes an activity that needs to be done by :User:. :Task: has:
|
|
56
|
-
- Name - a short description (required)
|
|
57
|
-
- Notes - additional details (optional)
|
|
58
|
-
- Due Date - completion deadline (optional)
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
## Validation Checklist
|
|
63
|
-
|
|
64
|
-
- [ ] Name uses `:CamelCase:` notation
|
|
65
|
-
- [ ] Name is globally unique (not defined elsewhere in the file or imports)
|
|
66
|
-
- [ ] Definition starts with the concept name
|
|
67
|
-
- [ ] All referenced concepts (`:OtherConcept:`) are already defined above
|
|
68
|
-
- [ ] No circular references between concepts
|
|
69
|
-
- [ ] Description is clear, concise, and language-agnostic
|
|
70
|
-
- [ ] Trimmed per `concise-specs.md`: one plain sentence, no restatement of the name, no rationale
|
|
71
|
-
- [ ] Placed inside a `***definitions***` section
|