@turri-dev/cli 0.1.27 → 0.1.28-next.d5f2680
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 +6 -6
- package/dist/advisor-chat.d.ts +63 -0
- package/dist/advisor-chat.js +290 -0
- package/dist/background-skills.d.ts +53 -0
- package/dist/background-skills.js +121 -0
- package/dist/bedrock-region.d.ts +66 -0
- package/dist/bedrock-region.js +144 -0
- package/dist/btw.d.ts +1 -1
- package/dist/btw.js +1 -1
- package/dist/change-plain-cli.js +20 -13
- package/dist/chat-idle.d.ts +7 -0
- package/dist/chat-idle.js +20 -0
- package/dist/chats.d.ts +10 -0
- package/dist/chats.js +23 -0
- package/dist/cli-options.d.ts +1 -2
- package/dist/cli-options.js +2 -7
- package/dist/cli.js +11 -3
- package/dist/config-command.d.ts +14 -0
- package/dist/config-command.js +35 -15
- package/dist/config-edit.d.ts +3 -3
- package/dist/config-edit.js +16 -12
- package/dist/config.d.ts +54 -34
- package/dist/config.js +40 -44
- package/dist/conform-cli.js +12 -10
- package/dist/conformance-switch.d.ts +34 -0
- package/dist/conformance-switch.js +108 -0
- package/dist/cultivate-cli.js +15 -5
- package/dist/drift-cli.js +2 -0
- package/dist/extension.d.ts +15 -0
- package/dist/extension.js +260 -83
- package/dist/host-session.d.ts +26 -0
- package/dist/host-session.js +30 -2
- package/dist/host.d.ts +5 -2
- package/dist/host.js +7 -1
- package/dist/init-config.d.ts +1 -1
- package/dist/init-config.js +20 -11
- package/dist/loop-cli.d.ts +3 -3
- package/dist/loop-cli.js +13 -16
- package/dist/loop-tools.js +18 -10
- package/dist/model-check.d.ts +8 -3
- package/dist/model-check.js +13 -8
- package/dist/new-project.js +12 -8
- package/dist/{validate-cli.js → parse-cli.js} +11 -5
- package/dist/parse-tool.d.ts +9 -0
- package/dist/parse-tool.js +33 -0
- package/dist/pi-launch.js +1 -1
- package/dist/plain/check.d.ts +53 -6
- package/dist/plain/check.js +217 -24
- package/dist/plain/concepts.d.ts +8 -0
- package/dist/plain/concepts.js +66 -23
- package/dist/plain/cycles.d.ts +21 -0
- package/dist/plain/cycles.js +190 -0
- package/dist/plain/errors.d.ts +4 -0
- package/dist/plain/errors.js +7 -0
- package/dist/plain/files.d.ts +18 -1
- package/dist/plain/files.js +39 -2
- package/dist/plain/graph.d.ts +33 -4
- package/dist/plain/graph.js +60 -12
- package/dist/plain/highlight.d.ts +3 -2
- package/dist/plain/highlight.js +4 -3
- package/dist/plain/index.d.ts +8 -5
- package/dist/plain/index.js +8 -5
- package/dist/plain/liquid.js +1 -6
- package/dist/plain/markdown.d.ts +32 -3
- package/dist/plain/markdown.js +146 -24
- package/dist/plain/module-concepts.js +2 -2
- package/dist/plain/parser.d.ts +83 -28
- package/dist/plain/parser.js +381 -260
- package/dist/plain/plain.tmLanguage.json +29 -3
- package/dist/plain/project.d.ts +48 -0
- package/dist/plain/project.js +155 -0
- package/dist/plain/spec.d.ts +90 -28
- package/dist/plain/spec.js +107 -133
- package/dist/plain/test-plain-file.d.ts +59 -0
- package/dist/plain/test-plain-file.js +232 -0
- package/dist/regenerate/activity.d.ts +20 -9
- package/dist/regenerate/activity.js +11 -4
- package/dist/regenerate/advisor-records.d.ts +93 -0
- package/dist/regenerate/advisor-records.js +110 -0
- package/dist/regenerate/advisor-runs.d.ts +87 -0
- package/dist/regenerate/advisor-runs.js +327 -0
- package/dist/regenerate/base-folder.d.ts +68 -0
- package/dist/regenerate/base-folder.js +168 -0
- package/dist/regenerate/cases.d.ts +9 -6
- package/dist/regenerate/cases.js +70 -14
- package/dist/regenerate/change-view.d.ts +8 -3
- package/dist/regenerate/change-view.js +71 -22
- package/dist/regenerate/chunk-plan.d.ts +36 -15
- package/dist/regenerate/chunk-plan.js +165 -59
- package/dist/regenerate/conform.d.ts +3 -0
- package/dist/regenerate/conform.js +6 -5
- package/dist/regenerate/conformance-agents.d.ts +18 -39
- package/dist/regenerate/conformance-agents.js +60 -88
- package/dist/regenerate/conformance.d.ts +23 -13
- package/dist/regenerate/conformance.js +119 -82
- package/dist/regenerate/diff-view.d.ts +1 -1
- package/dist/regenerate/diff-view.js +20 -4
- package/dist/regenerate/drift.d.ts +47 -15
- package/dist/regenerate/drift.js +101 -30
- package/dist/regenerate/jobs.d.ts +2 -2
- package/dist/regenerate/jobs.js +1 -1
- package/dist/regenerate/ledger.d.ts +19 -0
- package/dist/regenerate/loop.d.ts +62 -43
- package/dist/regenerate/loop.js +472 -341
- package/dist/regenerate/paths.d.ts +4 -0
- package/dist/regenerate/paths.js +7 -1
- package/dist/regenerate/plain-palette.js +2 -0
- package/dist/regenerate/prompt.d.ts +57 -19
- package/dist/regenerate/prompt.js +157 -122
- package/dist/regenerate/records.d.ts +43 -12
- package/dist/regenerate/records.js +102 -88
- package/dist/regenerate/regenerate.js +29 -11
- package/dist/regenerate/regression.d.ts +4 -4
- package/dist/regenerate/regression.js +14 -10
- package/dist/regenerate/renames.d.ts +42 -0
- package/dist/regenerate/renames.js +185 -0
- package/dist/regenerate/requires.d.ts +1 -1
- package/dist/regenerate/requires.js +10 -3
- package/dist/regenerate/resources.d.ts +5 -3
- package/dist/regenerate/resources.js +4 -4
- package/dist/regenerate/scripts-being-written.d.ts +19 -0
- package/dist/regenerate/scripts-being-written.js +30 -0
- package/dist/regenerate/spec-map-view.d.ts +2 -2
- package/dist/regenerate/spec-map-view.js +46 -15
- package/dist/regenerate/spec-map.d.ts +27 -5
- package/dist/regenerate/spec-map.js +92 -60
- package/dist/regenerate/spec-steps.d.ts +48 -5
- package/dist/regenerate/spec-steps.js +213 -28
- package/dist/regenerate/state.d.ts +4 -3
- package/dist/regenerate/stop-report.d.ts +1 -1
- package/dist/regenerate/stop-report.js +10 -10
- package/dist/regenerate/test-advisor.d.ts +101 -0
- package/dist/regenerate/test-advisor.js +379 -0
- package/dist/regenerate/test-kinds.d.ts +71 -28
- package/dist/regenerate/test-kinds.js +110 -63
- package/dist/regenerate/test-scripts.d.ts +2 -0
- package/dist/regenerate/test-scripts.js +4 -0
- package/dist/regenerate/testing-steps.d.ts +41 -0
- package/dist/regenerate/testing-steps.js +110 -0
- package/dist/regenerate/testing.d.ts +1 -1
- package/dist/regenerate/testing.js +5 -4
- package/dist/regenerate/unit-review.d.ts +1 -1
- package/dist/regenerate/unit-review.js +3 -3
- package/dist/regenerate-cli.js +11 -12
- package/dist/release-agent.js +4 -0
- package/dist/release-cli.js +2 -0
- package/dist/release-tools.js +2 -0
- package/dist/run-report.d.ts +2 -2
- package/dist/run-report.js +4 -3
- package/dist/self-invocation.d.ts +1 -1
- package/dist/self-invocation.js +1 -1
- package/dist/sentinel.js +1 -1
- package/dist/setup.d.ts +10 -0
- package/dist/setup.js +52 -4
- package/dist/skill.d.ts +10 -0
- package/dist/skill.js +6 -0
- package/dist/skills.js +3 -1
- package/dist/spec-tools.js +21 -31
- package/dist/test-plain-files.d.ts +41 -0
- package/dist/test-plain-files.js +177 -0
- package/docs/README.md +3 -1
- package/docs/authoring-plain.md +46 -13
- package/docs/chats.md +3 -1
- package/docs/config.md +20 -15
- package/docs/deploy.md +1 -1
- package/docs/development.md +2 -1
- package/docs/headless.md +15 -18
- package/docs/hosting.md +28 -12
- package/docs/installation.md +1 -0
- package/docs/parser.md +88 -27
- package/docs/regenerating.md +87 -52
- package/docs/sentinel.md +1 -1
- package/docs/skills-and-gates.md +3 -1
- package/docs/test-advisor.md +110 -0
- package/docs/theming.md +1 -1
- package/docs/using.md +17 -15
- package/genome/rules/bullet-continuation.md +8 -8
- package/genome/rules/concise-specs-examples.md +111 -80
- package/genome/rules/concise-specs-integration-examples.md +56 -41
- package/genome/rules/concise-specs.md +17 -16
- package/genome/rules/definitions.md +5 -5
- package/genome/rules/examples/integration-embedded-testing/run_conformance_tests_java.sh +1 -1
- package/genome/rules/func-specs.md +69 -74
- package/genome/rules/impl-reqs.md +4 -4
- package/genome/rules/integration-embedded-testing.md +20 -20
- package/genome/rules/integration-embedded.md +31 -31
- package/genome/rules/integration-standalone.md +9 -9
- package/genome/rules/integrations.md +18 -18
- package/genome/rules/linked-resources.md +19 -16
- package/genome/rules/module-structure.md +21 -14
- package/genome/rules/project-model.md +18 -17
- package/genome/rules/required-concepts.md +1 -1
- package/genome/rules/requires-modules.md +6 -5
- package/genome/rules/semantic-ids.md +49 -0
- package/genome/rules/stdlib.md +4 -5
- package/genome/rules/test-plain-files.md +130 -0
- package/genome/rules/test-reqs.md +8 -8
- package/genome/rules/turri-regeneration.md +23 -8
- package/genome/skills/analyze-2-func-specs/SKILL.md +36 -21
- package/genome/skills/analyze-func-specs/SKILL.md +46 -32
- package/genome/skills/break-down-func-spec/SKILL.md +91 -67
- package/genome/skills/consolidate-concepts/SKILL.md +10 -10
- package/genome/skills/convert-old-syntax/SKILL.md +68 -0
- package/genome/skills/convert-old-syntax/references/rubric.md +11 -0
- package/genome/skills/debug-specs/SKILL.md +62 -56
- package/genome/skills/implement-conformance-testing-script/SKILL.md +19 -15
- package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +2 -2
- package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +2 -2
- package/genome/skills/implement-unit-testing-script/SKILL.md +14 -10
- package/genome/skills/refactor-module/SKILL.md +35 -35
- package/genome/skills/resolve-section-ownership/SKILL.md +9 -9
- package/genome/skills/resolve-spec-conflict/SKILL.md +35 -29
- package/package.json +7 -6
- package/dist/regenerate/choose-conformance.d.ts +0 -32
- package/dist/regenerate/choose-conformance.js +0 -117
- /package/dist/{validate-cli.d.ts → parse-cli.d.ts} +0 -0
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Conciseness and plain-language rules that keep
|
|
2
|
+
description: Conciseness and plain-language rules that keep ***plain reviewable by a human
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
# Rules for keeping `.plain`
|
|
5
|
+
# Rules for keeping `.plain` files concise
|
|
6
6
|
|
|
7
|
-
These rules apply to every section, to concept explanations, and to
|
|
7
|
+
These rules apply to every section, to concept explanations, and to scenarios in test plain files. `concise-specs-examples.md` holds a worked BAD to GOOD pair for each failure mode named here, and `concise-specs-integration-examples.md` covers the failure modes specific to integration specs.
|
|
8
8
|
|
|
9
9
|
## Why this matters
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
- Length is not a proxy for rigor:
|
|
11
|
+
- ***plain is the source of truth, so a human has to be able to review it
|
|
12
|
+
- Long, dense, or ornate ***plain is skipped rather than reviewed — unreviewed ***plain is unverified ***plain, however correct it happens to be
|
|
13
|
+
- Length is not a proxy for rigor: ***plain earns trust by being checkable, not by being thorough-looking
|
|
14
14
|
- Conciseness is about removing what carries no information, never about removing required detail — the deterministic-interface, disambiguation, and testability rules always win (see `func-specs.md`)
|
|
15
15
|
|
|
16
16
|
## Do not write the obvious
|
|
@@ -21,11 +21,11 @@ Do not write:
|
|
|
21
21
|
|
|
22
22
|
- Restatements of a concept's own name (`:UserEmail: is the email address of a :User:.` adds nothing beyond what `definitions.md` already requires the concept to carry)
|
|
23
23
|
- Universal software defaults: that invalid input is rejected, that errors are reported, that data is saved when saving is the point of the operation
|
|
24
|
-
- Rationale, motivation, benefits, or background —
|
|
24
|
+
- Rationale, motivation, benefits, or background — ***plain states what is, not why it was chosen
|
|
25
25
|
- Standard behavior of a technology already named in `***implementation reqs***` (an HTTP framework parses HTTP; a database driver opens connections)
|
|
26
26
|
- Restatements of a nearby bullet in different words, or of anything already stated in an `import`ed or `require`d module
|
|
27
|
-
- Anything about work the
|
|
28
|
-
- Meta-commentary about the
|
|
27
|
+
- Anything about work the ***plain is not about ("no changes to the existing UI")
|
|
28
|
+
- Meta-commentary about the ***plain itself ("this spec is intentionally small", "as described above")
|
|
29
29
|
|
|
30
30
|
Worked pairs for every item above — padding, rationale, defaults, technology behavior, meta-commentary, and duplication of an `import` — are in `concise-specs-examples.md`.
|
|
31
31
|
|
|
@@ -35,7 +35,7 @@ Worked pairs for every item above — padding, rationale, defaults, technology b
|
|
|
35
35
|
- Write short sentences: one clause plus, at most, one qualifier
|
|
36
36
|
- Use the same word for the same thing every time — synonym variety reads as two different things
|
|
37
37
|
- Do not use adverbs and adjectives that no test can check: `robust`, `seamless`, `efficient`, `scalable`, `comprehensive`, `modern`, `properly`, `gracefully`, `as appropriate`, `where applicable`, `best practices`. Either state the checkable fact (`a response is returned within 200 ms`) or delete the word
|
|
38
|
-
- Do not hedge: `should ideally`, `may optionally`, `typically`, `generally`, `if possible`. A spec states one behavior; a hedge tells the
|
|
38
|
+
- Do not hedge: `should ideally`, `may optionally`, `typically`, `generally`, `if possible`. A functional spec states one behavior; a hedge tells the coding agent to guess
|
|
39
39
|
|
|
40
40
|
| Do not write | Write |
|
|
41
41
|
|---|---|
|
|
@@ -52,20 +52,21 @@ Worked pairs for every item above — padding, rationale, defaults, technology b
|
|
|
52
52
|
|
|
53
53
|
## Keep the shape small
|
|
54
54
|
|
|
55
|
+
- The bullet rules here apply to `***definitions***`, `***implementation reqs***`, and `***test reqs***`; the body of a functional spec and of a scenario is free text
|
|
55
56
|
- One statement per bullet, one bullet per fact (see `bullet-continuation.md`)
|
|
56
57
|
- Nest a sub-bullet only to remove a real ambiguity; a sub-bullet that merely elaborates is filler
|
|
57
|
-
- Consecutive specs that share a subject are usually one
|
|
58
|
+
- Consecutive functional specs that share a subject are usually one: if a functional spec only tells part of the story of one operation, merge the set, lead with the operation's result, and demote the steps and failure modes to detail under it (see *One operation fragmented into several functional specs* in `concise-specs-integration-examples.md`)
|
|
58
59
|
- Tables, prose paragraphs, and code blocks do not belong in a section; external artifacts are linked from `resources/` (see `linked-resources.md`)
|
|
59
|
-
- A bullet that answers more than one of *what is it*, *what does it do*, *how is it built*, and *how is it tested* is not one fact — split it across the sections that own those facts, which reads better and is the only way
|
|
60
|
+
- A bullet that answers more than one of *what is it*, *what does it do*, *how is it built*, and *how is it tested* is not one fact — split it across the sections that own those facts, which reads better and is the only way each part is read where it belongs (see `module-structure.md`, and *Split one crowded bullet across its owning sections* in `concise-specs-examples.md`)
|
|
60
61
|
|
|
61
62
|
## Terse is not a defect
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
Finished ***plain usually reads as abrupt: clipped bullets, no connective tissue, no lead-ins. That is the intended shape, not something to smooth out afterwards.
|
|
64
65
|
|
|
65
66
|
- Add a word only to make a line correct, unambiguous, or checkable — never to make it read better
|
|
66
67
|
- Do not merge short bullets into one sentence for rhythm, and do not open a section or a bullet with a lead-in
|
|
67
|
-
- The bar is the other rules — correct, intent intact, reviewable, testable.
|
|
68
|
-
- Filler is not neutral: the
|
|
68
|
+
- The bar is the other rules — correct, intent intact, reviewable, testable. ***plain that clears them is finished however clipped it sounds
|
|
69
|
+
- Filler is not neutral: the coding agent reads every line as a requirement, so a line written for flow can invent one
|
|
69
70
|
|
|
70
71
|
## Review pass before writing to disk
|
|
71
72
|
|
|
@@ -76,4 +77,4 @@ Read the drafted lines once more and apply, in order:
|
|
|
76
77
|
3. **The duplication test** — cut anything already stated in this file, an `import`, or a `requires` chain
|
|
77
78
|
4. **The read-aloud test** — a line you cannot read aloud in one breath is either two facts or one padded one
|
|
78
79
|
|
|
79
|
-
If a cut would remove an interface detail, a boundary case, or a disambiguation, keep the fact and shorten the wording instead — see *Do not over-cut* in `concise-specs-examples.md` for what
|
|
80
|
+
If a cut would remove an interface detail, a boundary case, or a disambiguation, keep the fact and shorten the wording instead — see *Do not over-cut* in `concise-specs-examples.md` for what ***plain cut past its content looks like.
|
|
@@ -12,12 +12,12 @@ When writing or editing a `***definitions***` section in a `.plain` file, always
|
|
|
12
12
|
- Valid characters: letters, digits, `+`, `-`, `.`, `_`
|
|
13
13
|
|
|
14
14
|
## Uniqueness
|
|
15
|
-
- Concept names must be globally unique across the
|
|
15
|
+
- Concept names must be globally unique across the module and all its imports
|
|
16
16
|
- Check for collisions with concepts coming from `import` and `requires` modules before adding
|
|
17
17
|
|
|
18
18
|
## Predefined concepts (do not redefine)
|
|
19
19
|
- ***plain ships several predefined concepts that are available in every module without being defined
|
|
20
|
-
- Never add a `***definitions***` entry for any of them —
|
|
20
|
+
- Never add a `***definitions***` entry for any of them — turri treats redefinitions as conflicts
|
|
21
21
|
|
|
22
22
|
| Predefined concept | Meaning |
|
|
23
23
|
|--------------------|---------|
|
|
@@ -27,9 +27,9 @@ When writing or editing a `***definitions***` section in a `.plain` file, always
|
|
|
27
27
|
| `:plainTestReqs:` | Content of the `***test reqs***` section |
|
|
28
28
|
| `:Implementation:` | The system implementing `:plainFunctionality:` |
|
|
29
29
|
| `:plainImplementationCode:` | The generated implementation code |
|
|
30
|
-
| `:UnitTests:` |
|
|
31
|
-
| `:ConformanceTests:` |
|
|
32
|
-
| `:AcceptanceTest:` / `:AcceptanceTests:` |
|
|
30
|
+
| `:UnitTests:` | The unit tests the coding agent writes with each functional spec's code |
|
|
31
|
+
| `:ConformanceTests:` | The black-box tests written from the functional specs' conformance scenarios, run by the conformance testing script |
|
|
32
|
+
| `:AcceptanceTest:` / `:AcceptanceTests:` | The black-box tests written from the functional specs' acceptance scenarios, run by the conformance testing script |
|
|
33
33
|
|
|
34
34
|
## Conciseness
|
|
35
35
|
- A definition is one plain sentence plus, where needed, its attributes — see `concise-specs.md`
|
|
@@ -22,7 +22,7 @@ fi
|
|
|
22
22
|
current_dir=$(pwd)
|
|
23
23
|
|
|
24
24
|
# Resolve the conformance tests folder to an absolute path ($2 may be relative
|
|
25
|
-
# on older
|
|
25
|
+
# on older harnesses; turri passes it as an absolute path).
|
|
26
26
|
case "$2" in
|
|
27
27
|
/*) CONFORMANCE_TESTS_SOURCE="$2" ;;
|
|
28
28
|
*) CONFORMANCE_TESTS_SOURCE="$current_dir/$2" ;;
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Rules for writing ***functional specs***
|
|
2
|
+
description: Rules for writing ***functional specs*** in .plain files
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# Rules for writing `***functional specs***`
|
|
6
6
|
|
|
7
7
|
When writing or editing a `***functional specs***` section in a `.plain` file, always follow these rules:
|
|
8
8
|
|
|
9
|
+
## Shape
|
|
10
|
+
- Each functional spec is a `# <func-id>` heading followed by its body; the func-id follows `semantic-ids.md`
|
|
11
|
+
- The body is free text that describes the behaviour: its first line states it, and prose or `- ` bullets under that line add the detail
|
|
12
|
+
- No body line starts with `# ` (that starts the next functional spec) or with `***`
|
|
13
|
+
- A functional spec's test scenarios live in its test plain file, never in this section (see `test-plain-files.md`)
|
|
14
|
+
|
|
9
15
|
## Voice
|
|
10
16
|
- Write each functional spec as a **statement of fact** — present tense, indicative mood — describing what the software *is* or *does* once built, not as a command telling a developer what to build
|
|
11
17
|
- **Name a concrete subject**: an actor (`A :User: can …`), a named component or concept (`:PdfRenderer: lays out …`, `:Order: processing depends on …`), or the affected data in passive voice (`All :Resource: items are returned`)
|
|
12
18
|
- **Avoid the vague subject "The system …"** — it says nothing about *which* part does the work. Prefer the concrete component/concept, or passive voice with the affected concept as the subject
|
|
13
|
-
- **Never open a spec with an imperative** like "Implement …", "Add …", "Create …", "Show …", "Display …", "Build …" — those read as instructions, not
|
|
19
|
+
- **Never open a functional spec with an imperative** like "Implement …", "Add …", "Create …", "Show …", "Display …", "Build …" — those read as instructions, not as what the software does
|
|
14
20
|
- Do **not** use "should" / "should be able to" in a functional spec — that is requirement-modal voice; state the fact directly
|
|
15
21
|
|
|
16
22
|
BAD — imperative commands, or the vague "The system":
|
|
@@ -18,11 +24,14 @@ BAD — imperative commands, or the vague "The system":
|
|
|
18
24
|
```plain
|
|
19
25
|
***functional specs***
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
# entry-point
|
|
28
|
+
Implement the entry point for :App:.
|
|
22
29
|
|
|
23
|
-
-
|
|
30
|
+
# show-task-list
|
|
31
|
+
The system shows :TaskList:.
|
|
24
32
|
|
|
25
|
-
-
|
|
33
|
+
# add-task
|
|
34
|
+
Add :Task:.
|
|
26
35
|
```
|
|
27
36
|
|
|
28
37
|
GOOD — statements of fact with concrete subjects:
|
|
@@ -30,71 +39,75 @@ GOOD — statements of fact with concrete subjects:
|
|
|
30
39
|
```plain
|
|
31
40
|
***functional specs***
|
|
32
41
|
|
|
33
|
-
|
|
42
|
+
# entry-point
|
|
43
|
+
:App: has an entry point.
|
|
34
44
|
|
|
35
|
-
-
|
|
45
|
+
# show-task-list
|
|
46
|
+
The :TaskList: is displayed.
|
|
36
47
|
|
|
37
|
-
|
|
48
|
+
# add-task
|
|
49
|
+
A :User: can add a :Task:. Only valid :Task: items are added.
|
|
38
50
|
```
|
|
39
51
|
|
|
40
52
|
## Conciseness
|
|
41
|
-
- A functional spec that a human will not read is not reviewed, so every
|
|
53
|
+
- A functional spec that a human will not read is not reviewed, so every one must be as short as its content allows — see `concise-specs.md`
|
|
42
54
|
- Cut anything obvious, any rationale, and every uncheckable adjective; keep every interface detail, boundary case, and disambiguation
|
|
43
55
|
- Shorten the wording, never the facts: the rules below always win over brevity
|
|
44
56
|
|
|
45
57
|
## Complexity limit
|
|
46
58
|
- The complexity limit is about breaking software into small, independently understandable behavior slices that people and AI can reason about, implement, and test reliably
|
|
47
59
|
- The current mechanism for enforcing the complexity limit is that each functional spec must imply a **maximum of 200 changed lines of code**.
|
|
48
|
-
- Smaller slices produce focused test failures, reduce hidden coupling and regression surface, and make review and incremental
|
|
49
|
-
- If a spec is too large, use `break-down-func-spec` to split it into multiple smaller, independent
|
|
50
|
-
- Judge a spec's size yourself before inserting it: estimate the code it implies - new files, functions, data model changes, UI components, error paths, boilerplate, its unit tests - and treat more than ~150 lines as too big, leaving the
|
|
51
|
-
- Signs a spec is too big - one is not proof, several are:
|
|
60
|
+
- Smaller slices produce focused test failures, reduce hidden coupling and regression surface, and make review and incremental regeneration more predictable
|
|
61
|
+
- If a functional spec is too large, use `break-down-func-spec` to split it into multiple smaller, independent ones
|
|
62
|
+
- Judge a functional spec's size yourself before inserting it: estimate the code it implies - new files, functions, data model changes, UI components, error paths, boilerplate, its unit tests - and treat more than ~150 lines as too big, leaving the coding agent headroom
|
|
63
|
+
- Signs a functional spec is too big - one is not proof, several are:
|
|
52
64
|
- more than one independently testable behavior ("create, edit, delete and archive")
|
|
53
65
|
- more than three new constructs at once - data structures, UI components, endpoints
|
|
54
66
|
- several modes or conditional paths, each with its own behavior
|
|
55
67
|
- core behavior bundled with cross-cutting concerns - retries, pagination, caching, logging
|
|
56
68
|
- a whole screen with several interactive elements and state transitions
|
|
57
69
|
- multi-step transformations, joins or aggregations across entities
|
|
58
|
-
- a substantial technical component it must build as well as use - an engine, parser, scheduler, layout algorithm, state machine, sync mechanism; it counts toward the limit, and goes in a spec of its own before the one that uses it
|
|
59
|
-
- Use `analyze-func-specs` to check a spec (or a batch of
|
|
70
|
+
- a substantial technical component it must build as well as use - an engine, parser, scheduler, layout algorithm, state machine, sync mechanism; it counts toward the limit, and goes in a functional spec of its own before the one that uses it
|
|
71
|
+
- Use `analyze-func-specs` to check a functional spec (or a batch of them) against all relevant existing ones in a single batched call; use `resolve-spec-conflict` for each conflicting pair it reports
|
|
60
72
|
|
|
61
73
|
## First-spec bootstrap cost
|
|
62
74
|
- The first functional spec in a new root module carries implicit implementation cost even when its text describes little behavior
|
|
63
|
-
- The
|
|
64
|
-
- Count that bootstrap work toward the 200-changed-line limit; it is not free setup outside the spec
|
|
65
|
-
- Make the first spec the module's simplest useful, independently observable capability
|
|
66
|
-
- The first spec must still imply a testable outcome; setup alone is not a functional spec
|
|
75
|
+
- The coding agent may need to create the project structure, package metadata, framework configuration, entry point, initial source files, and unit-test infrastructure before implementing the behavior
|
|
76
|
+
- Count that bootstrap work toward the 200-changed-line limit; it is not free setup outside the functional spec
|
|
77
|
+
- Make the first functional spec the module's simplest useful, independently observable capability
|
|
78
|
+
- The first functional spec must still imply a testable outcome; setup alone is not a functional spec
|
|
67
79
|
- Prefer one minimal entry point or public operation with a deterministic result that can be invoked and verified
|
|
68
|
-
- Defer persistence, integrations, multiple interfaces, branching workflows, and cross-cutting behavior until later specs can build on the generated baseline
|
|
69
|
-
- A spec may start on its happy path and be hardened later - validation, edge cases and errors added to it by changing it - once the software has been tried; it must still say exactly what it does for the input it covers
|
|
80
|
+
- Defer persistence, integrations, multiple interfaces, branching workflows, and cross-cutting behavior until later functional specs can build on the generated baseline
|
|
81
|
+
- A functional spec may start on its happy path and be hardened later - validation, edge cases and errors added to it by changing it - once the software has been tried; it must still say exactly what it does for the input it covers
|
|
70
82
|
- This extra bootstrap cost applies when no previous implementation baseline exists; a module that continues from a `requires` module may already inherit the necessary scaffold
|
|
71
83
|
|
|
72
84
|
## Chronological ordering
|
|
73
|
-
-
|
|
74
|
-
- The
|
|
75
|
-
- A new spec can reference behavior from earlier
|
|
85
|
+
- Functional specs are regenerated incrementally, top to bottom
|
|
86
|
+
- The coding agent has **no knowledge of later functional specs** — only those before it are in context
|
|
87
|
+
- A new functional spec can reference behavior from earlier ones but cannot assume anything about those that come after it
|
|
76
88
|
- Functional specs from `requires` modules are treated as previous requirements — transitively, across the whole ancestor chain
|
|
77
|
-
- This order is about what a spec may assume, not what a change costs: turri regenerates a change as a
|
|
89
|
+
- This order is about what a functional spec may assume, not what a change costs: turri regenerates a change as a ***plain diff wherever it sits (`turri-regeneration.md`)
|
|
78
90
|
|
|
79
91
|
## No conflicts
|
|
80
|
-
-
|
|
81
|
-
- Before adding, review all existing specs and verify compatibility
|
|
92
|
+
- A new functional spec must not contradict any existing one
|
|
93
|
+
- Before adding, review all existing functional specs and verify compatibility
|
|
82
94
|
- If ambiguity exists, add explicit detail to eliminate any conflicting interpretation
|
|
83
95
|
|
|
84
96
|
## Adding a functional spec
|
|
85
97
|
Every new functional spec - one or a batch - is checked before it is written into the file:
|
|
86
98
|
1. Draft it, then trim it per `concise-specs.md` to the shortest wording that keeps every fact
|
|
87
99
|
2. Judge its size against the complexity limit; when it is too big, split it with `break-down-func-spec` and check each part from step 1
|
|
88
|
-
3. Check it for conflicts with **one** `analyze-func-specs` call over the new spec and every existing
|
|
89
|
-
4.
|
|
100
|
+
3. Check it for conflicts with **one** `analyze-func-specs` call over the new functional spec and every existing one 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
|
|
101
|
+
4. Pick its func-id per `semantic-ids.md`, unique in the module - and in the batch
|
|
102
|
+
5. Only then write it in, where it belongs (see Placement), as its `# <func-id>` heading and body - with no test plain file, unless the person asks for its tests (see `test-plain-files.md`)
|
|
90
103
|
|
|
91
|
-
A batch is checked one spec at a time, in order: each
|
|
104
|
+
A batch is checked one functional spec at a time, in order: each one's conflict check includes those of the batch already written in. Never write the whole batch in first and check it afterwards - a bad functional spec already in the file skews every later check. A few functional specs are no reason to skip a check.
|
|
92
105
|
|
|
93
106
|
## Placement
|
|
94
|
-
Put a new spec where it fits the module as it reads, not at the end by default:
|
|
95
|
-
- **Below every spec it builds on** - each one whose behaviour it references or extends, and the first to use each concept it relies on
|
|
96
|
-
- **Above every spec that builds on it** - one that already assumes what it adds
|
|
97
|
-
- **Within those bounds, beside the specs of its feature** - usually straight after the last one it extends
|
|
107
|
+
Put a new functional spec where it fits the module as it reads, not at the end by default:
|
|
108
|
+
- **Below every functional spec it builds on** - each one whose behaviour it references or extends, and the first to use each concept it relies on
|
|
109
|
+
- **Above every functional spec that builds on it** - one that already assumes what it adds
|
|
110
|
+
- **Within those bounds, beside the functional specs of its feature** - usually straight after the last one it extends
|
|
98
111
|
- **At the end** only when it starts something new or fits nowhere better
|
|
99
112
|
|
|
100
113
|
## Language agnosticism
|
|
@@ -102,68 +115,50 @@ Put a new spec where it fits the module as it reads, not at the end by default:
|
|
|
102
115
|
- Avoid language-specific terminology: generics syntax, framework annotations, language-specific collection types, decorator syntax, base-class keywords, framings like "POJO" or "dataclass"
|
|
103
116
|
- General technical terms that are not language-specific are fine: null values, JSON types, HTTP status codes, REST endpoints, etc.
|
|
104
117
|
- **Naming concrete components is encouraged.** Functional specs can and should refer to concrete domain components, services, or entities (e.g., `:PaymentProcessor:`, `:UserRepository:`, `:DataConverter:`) and their operations (e.g., `:ChargeCard:`, `:FindById:`), pinning down their inputs, outputs, and error behavior. Those names are part of the public contract and survive a language switch. What they must **not** do is bake in how the contract is realized (`@staticmethod`, `class Foo extends Bar`, `List<T>`, `async def`, etc.)
|
|
105
|
-
- **Litmus test:** if the project switched from Python to Java (or vice versa), would the functional spec read correctly with only `***implementation reqs***` updated? If yes,
|
|
118
|
+
- **Litmus test:** if the project switched from Python to Java (or vice versa), would the functional spec read correctly with only `***implementation reqs***` updated? If yes, it is language-agnostic. If the functional spec itself would need rewording, the construct belongs in implementation reqs.
|
|
106
119
|
|
|
107
120
|
## Disambiguation
|
|
108
|
-
- Each functional spec must be unambiguous — the
|
|
109
|
-
- If
|
|
110
|
-
-
|
|
111
|
-
- Even with
|
|
121
|
+
- Each functional spec must be unambiguous — the coding agent should have only one reasonable interpretation
|
|
122
|
+
- If the statement line is not enough to fully disambiguate the behavior, add `- ` bullets or sentences under it to add detail
|
|
123
|
+
- The detail clarifies the statement - it does not introduce separate behaviour
|
|
124
|
+
- Even with the detail, the functional spec must still imply ≤ 200 lines of code
|
|
112
125
|
|
|
113
126
|
## Testability
|
|
114
127
|
- Every functional spec must describe behavior that can be verified through an observable interface
|
|
115
128
|
- State the triggering input or action and the deterministic outcome a test can observe
|
|
116
129
|
- Include relevant outputs, state changes, errors, or externally visible side effects
|
|
117
130
|
- Do not rely on generated implementation details as the only way to verify the behavior
|
|
118
|
-
- If a black-box conformance
|
|
119
|
-
- Testability does not require an acceptance test; acceptance tests are reserved for full workflows
|
|
131
|
+
- If a black-box conformance scenario could not be written from the functional spec, make the behavior more explicit
|
|
120
132
|
|
|
121
133
|
## Deterministic interface
|
|
122
|
-
-
|
|
134
|
+
- Functional specs must be detailed enough that a developer can use the built software without reading the generated code
|
|
123
135
|
- All external interfaces must be explicit: REST endpoint paths and HTTP methods, CLI command names and arguments, file formats, message schemas, etc.
|
|
124
|
-
- Never leave interface details up to the
|
|
136
|
+
- Never leave interface details up to the coding agent's discretion
|
|
125
137
|
|
|
126
138
|
## Encapsulation
|
|
127
|
-
-
|
|
139
|
+
- Behaviour must be self-contained in the functional spec's text
|
|
128
140
|
- `requires` modules only pass on functional specs and `exported_concepts` — never implementation reqs, so do not rely on implementation reqs to convey behavior
|
|
129
141
|
- Behavior that downstream modules need must be expressed in functional specs, not elsewhere
|
|
130
142
|
|
|
131
|
-
##
|
|
132
|
-
-
|
|
133
|
-
-
|
|
134
|
-
-
|
|
135
|
-
- Each acceptance test must be a direct logical consequence of the parent spec — it illustrates, not extends
|
|
136
|
-
- Acceptance tests must describe concrete, verifiable outcomes — not vague qualities
|
|
137
|
-
- Acceptance tests must not contradict, narrow, or extend beyond the parent spec
|
|
138
|
-
|
|
139
|
-
```plain
|
|
140
|
-
Functional spec:
|
|
141
|
-
- :Resource: items are returned sorted by creation date in descending order.
|
|
142
|
-
|
|
143
|
-
Good - follows from the spec:
|
|
144
|
-
- After three :Resource: items are created one after another, listing them returns the last one created first.
|
|
145
|
-
|
|
146
|
-
Bad - contradicts it (the spec says descending):
|
|
147
|
-
- The first :Resource: listed is the oldest.
|
|
148
|
-
|
|
149
|
-
Bad - extends it (the spec says nothing about a limit):
|
|
150
|
-
- At most 50 :Resource: items are listed.
|
|
151
|
-
```
|
|
143
|
+
## Test scenarios live in test plain files
|
|
144
|
+
- A module never holds a `***conformance tests***` or `***acceptance tests***` section, nested or top-level
|
|
145
|
+
- A functional spec's conformance and acceptance scenarios go into its test plain file, `tests/<module>/<func-id>.plain`, and are written only when the person asks for tests (see *Writing scenarios* in `test-plain-files.md`)
|
|
146
|
+
- A functional spec and its test plain file change together, in the same ***plain diff: a new one gets none, unless its tests are asked for; a changed one has its scenarios, if any, reviewed; a split, moved, renamed or deleted one takes its test plain file, if it has one, with it (see *Keeping test plain files in step* in `test-plain-files.md`)
|
|
152
147
|
|
|
153
148
|
## Format
|
|
154
149
|
|
|
155
150
|
```plain
|
|
156
151
|
***functional specs***
|
|
157
152
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
- A :User: can add a :Task:. Only valid :Task: items are added.
|
|
153
|
+
# entry-point
|
|
154
|
+
:App: has an entry point.
|
|
161
155
|
|
|
162
|
-
-
|
|
163
|
-
|
|
164
|
-
- The :Message: is appended to the end of the :Conversation:.
|
|
165
|
-
- All :Participant: members of the :Conversation: can see the new :Message:.
|
|
156
|
+
# add-task
|
|
157
|
+
A :User: can add a :Task:. Only valid :Task: items are added.
|
|
166
158
|
|
|
167
|
-
|
|
168
|
-
|
|
159
|
+
# send-message
|
|
160
|
+
A :User: can send a :Message: to a :Conversation:.
|
|
161
|
+
- A :Message: must have non-empty content.
|
|
162
|
+
- The :Message: is appended to the end of the :Conversation:.
|
|
163
|
+
- All :Participant: members of the :Conversation: can see the new :Message:.
|
|
169
164
|
```
|
|
@@ -14,7 +14,7 @@ When writing or editing an `***implementation reqs***` section in a `.plain` fil
|
|
|
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
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
|
-
- The
|
|
17
|
+
- The coding agent reads how to write the unit tests **only** from `***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
|
|
@@ -32,13 +32,13 @@ When writing or editing an `***implementation reqs***` section in a `.plain` fil
|
|
|
32
32
|
- Behavior and features → `***functional specs***`
|
|
33
33
|
- Concept definitions → `***definitions***`
|
|
34
34
|
- **Conformance-test guidance** → `***test reqs***`
|
|
35
|
-
- **
|
|
35
|
+
- **Test scenarios**, conformance and acceptance → the functional spec's test plain file (see `test-plain-files.md`)
|
|
36
36
|
|
|
37
37
|
## Unit tests vs conformance tests (common mistake)
|
|
38
38
|
- Unit-test guidance (`:UnitTests:` framework, structure, mocking) goes **here**, not in `***test reqs***`
|
|
39
39
|
- `***test reqs***` is exclusively for `:ConformanceTests:` — framework, execution command, mocking policy, environment setup
|
|
40
|
-
- Putting unit-test guidance in `***test reqs***` is one of the most common authoring mistakes; the
|
|
41
|
-
- Do not link the unit testing script here (or anywhere in the
|
|
40
|
+
- Putting unit-test guidance in `***test reqs***` is one of the most common authoring mistakes; the regenerated code will silently miss those requirements because the coding agent reads unit-test guidance only from `***implementation reqs***`
|
|
41
|
+
- Do not link the unit testing script here (or anywhere in the ***plain; a link to it is ignored). turri finds it in the project root - `unittests-script:` in `config.turri.yaml`, else the one `run_unittests*.sh` in the root, else the one in `test_scripts/` - and shows it to the coding agent itself. Describe the framework and run command here in words
|
|
42
42
|
|
|
43
43
|
## Encapsulation warning
|
|
44
44
|
- `requires` modules only pass on functional specs and `exported_concepts` — never implementation reqs
|
|
@@ -4,7 +4,7 @@ description: Rules for authoring the two test scripts that an embedded ***plain
|
|
|
4
4
|
|
|
5
5
|
# Rules for embedded-integration test scripts
|
|
6
6
|
|
|
7
|
-
When an embedded integration ships its two `test_scripts/` (unit, conformance), these rules apply on top of the contracts in the corresponding `implement-*-testing-script` skills. `project-model.md` covers the
|
|
7
|
+
When an embedded integration ships its two `test_scripts/` (unit, conformance), these rules apply on top of the contracts in the corresponding `implement-*-testing-script` skills. `project-model.md` covers the regenerating and testing workflow.
|
|
8
8
|
|
|
9
9
|
## Staging model (read this first)
|
|
10
10
|
|
|
@@ -24,7 +24,7 @@ This deliberately writes into the host's `src/main/...` and `src/test/...` (or t
|
|
|
24
24
|
|
|
25
25
|
This rule covers the **mechanics each script must obey** regardless of language: argument handling, exit codes, idempotency, path resolution, output parsing, and the "what NOT to put here" guard rails. The language-specific install / test commands come from the skills; the contract below is invariant.
|
|
26
26
|
|
|
27
|
-
## What the `.plain`
|
|
27
|
+
## What the `.plain` file must declare
|
|
28
28
|
|
|
29
29
|
The two scripts are generated from facts in the integration's spec. For an embedded integration, those facts cannot be inferred — they have to be **declared explicitly** in the right section, partitioned by which predefined concept they describe:
|
|
30
30
|
|
|
@@ -77,7 +77,7 @@ These reqs feed `run_conformance_tests_<lang>`. At minimum, declare:
|
|
|
77
77
|
2. **`:ConformanceTests:` framework and execution command** — `mvn test --no-transfer-progress`, `pytest`, `npm test`, `go test ./...`, etc., with any flags / profiles the project requires
|
|
78
78
|
3. **Fully qualified `:ConformanceTests:` package** (or path / pattern) used to scope discovery, if the runner needs one
|
|
79
79
|
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)
|
|
80
|
-
5. **`:ConformanceTests:` pass criteria** — the strict criteria from [*Pass criteria (strict)*](#pass-criteria-strict): at least one test ran AND zero failures / errors / skipped. Reaffirm this in the
|
|
80
|
+
5. **`:ConformanceTests:` pass criteria** — the strict criteria from [*Pass criteria (strict)*](#pass-criteria-strict): at least one test ran AND zero failures / errors / skipped. Reaffirm this in the ***plain so the script's author knows the runner must parse the test tool's stdout
|
|
81
81
|
6. **`:ConformanceTests:` build / install needs** — anything the conformance project needs before `mvn test` (or equivalent) will work: the host build / install command the script runs first, dependencies, fixtures, schema files, generated stubs
|
|
82
82
|
|
|
83
83
|
Author the conformance facts as one or more entries, phrased in terms of `:ConformanceTests:`:
|
|
@@ -115,10 +115,10 @@ output=$(mvn test --no-transfer-progress 2>&1)
|
|
|
115
115
|
|
|
116
116
|
- **The paths must agree across reqs.** The `:UnitTests:` source path, the `:UnitTests:` package, and the integration source path describe the same module from three angles. Same for the `:ConformanceTests:` location and its package. A mismatch (e.g. test path `src/test/java/com/example/foo` but test package `com.example.bar`) silently produces a green build with stale or zero tests
|
|
117
117
|
- **Paths are host-relative**, not absolute. `MAIN_PROJECT_FOLDER` comes from `HOST_CODEBASE_ROOT` (declared in the configuration concept); the paths above join onto it
|
|
118
|
-
- **The
|
|
119
|
-
- **Each fact lives in one place.** If two `***implementation reqs***` entries declare slightly different `:UnitTests:` paths (or two `***test reqs***` entries declare slightly different `:ConformanceTests:` packages), the
|
|
120
|
-
- **Never duplicate a fact across sections.** `:UnitTests:` facts belong **only** in `***implementation reqs***`; `:ConformanceTests:` facts belong **only** in `***test reqs***`. The two groups never overlap — the
|
|
121
|
-
- **For non-Java languages**, the facts have language-specific equivalents — Python: `src/foo/`, `tests/foo/`, `tests.foo`; Node: `src/foo/`, `test/foo/`, `test/foo/**/*.test.ts`. The `implement-*-testing-script` skills know the mapping per language, but the
|
|
118
|
+
- **The coding agent's output folder `$1` mirrors the same layout.** `$1/<integration source path>/*` exists because the coding agent emits the generated code into the same package directories it'll be copied into — the `cp -R` is a straight overlay, not a path translation
|
|
119
|
+
- **Each fact lives in one place.** If two `***implementation reqs***` entries declare slightly different `:UnitTests:` paths (or two `***test reqs***` entries declare slightly different `:ConformanceTests:` packages), the coding agent can't tell which to use. Author each group as a tight cluster (one bullet with sub-bullets) so a future reviewer sees them together
|
|
120
|
+
- **Never duplicate a fact across sections.** `:UnitTests:` facts belong **only** in `***implementation reqs***`; `:ConformanceTests:` facts belong **only** in `***test reqs***`. The two groups never overlap — the agents read each from its own section
|
|
121
|
+
- **For non-Java languages**, the facts have language-specific equivalents — Python: `src/foo/`, `tests/foo/`, `tests.foo`; Node: `src/foo/`, `test/foo/`, `test/foo/**/*.test.ts`. The `implement-*-testing-script` skills know the mapping per language, but the ***plain still has to declare the host-relative paths and packages so the skill knows what to put in the script bodies
|
|
122
122
|
|
|
123
123
|
## Common contract (both scripts)
|
|
124
124
|
|
|
@@ -131,17 +131,17 @@ Both scripts are invoked by turri with positional arguments, on the person's mac
|
|
|
131
131
|
- `69` — unrecoverable environment failure (missing toolchain, cannot enter working folder, install failed)
|
|
132
132
|
- Any other non-zero code — propagated verbatim from the underlying build / test tool
|
|
133
133
|
|
|
134
|
-
turri passes `$1` (and `$2` for the conformance runner) as **absolute paths** (older
|
|
134
|
+
turri passes `$1` (and `$2` for the conformance runner) as **absolute paths** (older harnesses passed relative ones). Never build a derived path by concatenating a raw argument (`.tmp/$1`, `<lang>_$1`, `$current_dir/$2`) — with an absolute argument that produces a doubled path (`/project//abs/path/...`). Use the argument as-is where a path is needed, take its `basename` when naming a scratch folder, and resolve `$2` to absolute (if it isn't already) before any `cd`
|
|
135
135
|
3. **Echo the toolchain home at the top** — the first thing a developer checks when CI breaks. For Java: `JAVA_HOME`. For Python: the active interpreter (`python --version` / `which python`). For Node: `node --version`. For Go: `go env GOROOT`. Pick the variable whose value most often explains "why does it work locally but not on the CI runner?"
|
|
136
136
|
4. **Respect `VERBOSE=1`.** Gate chatty diagnostic prints behind `if [ "${VERBOSE:-}" = "1" ]` (and the PowerShell equivalent). Errors and key step markers print unconditionally
|
|
137
|
-
5. **Resolve paths relative to the script, not `$PWD`.** Use `"$(cd "$(dirname "$0")/<relative-path-to-anchor>" && pwd)"`. Hard-coded `../../` chains break the moment
|
|
137
|
+
5. **Resolve paths relative to the script, not `$PWD`.** Use `"$(cd "$(dirname "$0")/<relative-path-to-anchor>" && pwd)"`. Hard-coded `../../` chains break the moment turri's `cwd` changes
|
|
138
138
|
6. **Create destination directories before copying.** `mkdir -p` before any `cp -R` / `rsync` / `robocopy` — most copy commands do not create intermediate directories and fail silently in some shells
|
|
139
139
|
7. **Scope destructive operations narrowly.** Any `rm -rf` (or `Remove-Item -Recurse -Force`) targets only the module's own package path inside the working folder — never the host's `src/`, `target/`, `node_modules/`, `build/`, or `dist/` at the project root. The conformance script cleans the host's build-output directory (e.g. `./target`) only as part of its own build / install step, and removes its system-temp scratch folder on exit
|
|
140
140
|
8. **Print where you are before you `cd`.** `echo "Moving to: $DIR"` saves an hour of debugging when paths are wrong. PowerShell: `Write-Host "Moving to: $DIR"`
|
|
141
141
|
|
|
142
142
|
## 1. `run_unittests_<lang>` — copy into the host, then run unit tests there
|
|
143
143
|
|
|
144
|
-
Receives one positional argument: the
|
|
144
|
+
Receives one positional argument: the build output folder (`plain_modules/<module>/code/`, absolute).
|
|
145
145
|
|
|
146
146
|
Purpose: stage the generated code **into the host codebase at the module's package path** and run the module's unit tests + language-appropriate quality gates against the host project from inside the host root.
|
|
147
147
|
|
|
@@ -162,17 +162,17 @@ Required steps:
|
|
|
162
162
|
Hard rules:
|
|
163
163
|
|
|
164
164
|
- **Self-contained.** The script stages `$1` itself on every run; it never relies on another script having run first
|
|
165
|
-
- **Never run the full test suite** when scoping is possible. A per-module script that runs the entire host's tests wastes minutes on every
|
|
165
|
+
- **Never run the full test suite** when scoping is possible. A per-module script that runs the entire host's tests wastes minutes on every regeneration
|
|
166
166
|
|
|
167
167
|
## 2. `run_conformance_tests_<lang>` — copy into the host, build it, then run the external suite
|
|
168
168
|
|
|
169
|
-
Receives two positional arguments: the
|
|
169
|
+
Receives two positional arguments: the build output folder (`$1`, `plain_modules/<module>/code/`) and the conformance-tests folder (`$2`, `plain_modules/<module>/tests/` — the module's whole conformance suite), both absolute.
|
|
170
170
|
|
|
171
|
-
Purpose: stage the generated code into the host, build / install the host, and run the whole conformance suite in `$2` against that build. The conformance suite is a separate project that consumes the integration as a dependency from a local cache (`~/.m2`, `node_modules`, the language equivalent), so the script installs the host itself first — otherwise the suite links against whatever was last built, which may not be the
|
|
171
|
+
Purpose: stage the generated code into the host, build / install the host, and run the whole conformance suite in `$2` against that build. The conformance suite is a separate project that consumes the integration as a dependency from a local cache (`~/.m2`, `node_modules`, the language equivalent), so the script installs the host itself first — otherwise the suite links against whatever was last built, which may not be the most recent regenerated code. turri runs it once per check, and its exit code decides whether the conformance tests pass.
|
|
172
172
|
|
|
173
173
|
Required steps:
|
|
174
174
|
|
|
175
|
-
1. Validate `$1` and `$2`. Resolve `$2` to an absolute path if it isn't one already (
|
|
175
|
+
1. Validate `$1` and `$2`. Resolve `$2` to an absolute path if it isn't one already (turri passes it absolute; older harnesses passed it relative to the invocation directory)
|
|
176
176
|
2. Resolve the host codebase root from the configured env var, `rm -rf` the module's main + test package directories under the host's source tree, `mkdir -p` the destination directories, and copy `$1/src/...` into the host's source tree at the module's package path — **the same staging as `run_unittests`**
|
|
177
177
|
3. `cd` into the host codebase root, verify with an explicit exit-code check
|
|
178
178
|
4. Clean the host's build-output directory before compiling — stale class / object files from a previous build cause confusing link-time mismatches when the contract has changed. Maven: `rm -rf ./target`. Cargo: `cargo clean -p <pkg>`. Go: `go clean -cache` (usually unnecessary, but mention if applicable). For npm projects with incremental builds disabled, wipe the relevant `dist/` / `build/` folder
|
|
@@ -195,7 +195,7 @@ Required steps:
|
|
|
195
195
|
- Bash: `output=$(mvn test --no-transfer-progress 2>&1)` (or the language equivalent)
|
|
196
196
|
- PowerShell: `$output = & <cmd> 2>&1 | Out-String`
|
|
197
197
|
10. **Parse the captured output strictly** (see *Pass criteria* below) — don't trust the test tool's exit code alone
|
|
198
|
-
11. On the failure path: print the captured output unconditionally so
|
|
198
|
+
11. On the failure path: print the captured output unconditionally so turri (and the user) can see what failed
|
|
199
199
|
12. On the success path: print the output only if `VERBOSE=1`
|
|
200
200
|
|
|
201
201
|
### Secrets and `.env` handling
|
|
@@ -238,15 +238,15 @@ These are the **only** valid pass criteria. Anything outside this list is a fail
|
|
|
238
238
|
|
|
239
239
|
Failure cases — each must be detected explicitly:
|
|
240
240
|
|
|
241
|
-
- `Tests run: 0` (or the language equivalent) → **failure**.
|
|
241
|
+
- `Tests run: 0` (or the language equivalent) → **failure**. turri must never be told "green" when nothing ran. Exit `1` per the shared testing-script rules (the "no tests discovered" exit code)
|
|
242
242
|
- Any non-zero `Failures:`, `Errors:`, or `Skipped:` count → **failure**. Dump the captured output and propagate the test tool's exit code
|
|
243
243
|
- The test tool exited non-zero but the summary line shows `Tests run: 0` → still a `1` (no-tests-discovered), not the tool's own exit code
|
|
244
244
|
|
|
245
|
-
**Why parse stdout instead of trusting the test tool's exit code.** Every major test runner returns `0` when zero test classes match a filter. Maven Surefire, pytest with no collected tests, `go test ./pkg/that/has/no/_test.go/files`, Jest with an empty pattern — all green-by-default.
|
|
245
|
+
**Why parse stdout instead of trusting the test tool's exit code.** Every major test runner returns `0` when zero test classes match a filter. Maven Surefire, pytest with no collected tests, `go test ./pkg/that/has/no/_test.go/files`, Jest with an empty pattern — all green-by-default. turri's contract is "tests must run AND must pass" — the exit code alone cannot express that.
|
|
246
246
|
|
|
247
247
|
## Cross-cutting rules
|
|
248
248
|
|
|
249
|
-
- **No secrets in scripts.** Read credentials from env vars
|
|
249
|
+
- **No secrets in scripts.** Read credentials from env vars turri (or the user's shell) already sets. If a required env var is missing, fail fast with a clear `Error: $FOO is required for ...` and exit `69`. Never hardcode an API key, never read from a checked-in file
|
|
250
250
|
- **Mirror the package / module path exactly.** A typo in the package segment (e.g. one wrong directory in `com/example/foo/...` or `host_pkg/foo/bar/...`) makes `rm -rf` silently do nothing and the subsequent copy put files in the wrong place. Both produce a **green** build with stale code. Derive the package path from the `host-codebase` concept; never retype it inline
|
|
251
251
|
- **Don't add cleverness to the script that belongs in the build.** If you're tempted to `grep` the test output for more than the pass/fail summary, change the test or the test-runner config instead. The script is a thin contract — keep it that way
|
|
252
252
|
- **Don't use shortcut profiles that skip quality gates.** Maven's `-Pfast`, Gradle's `-x check`, npm's `--ignore-scripts`, pytest's `--no-cov`, `-DskipTests` anywhere except the conformance script's two build / install steps (the host install and the conformance project's compile, where the tests run right after) — all defeat the purpose of these scripts. The build's full quality gate (tests + lint + coverage thresholds) must run for unit and conformance
|
|
@@ -267,7 +267,7 @@ Use them as a template when adding a new embedded integration in Java / Maven
|
|
|
267
267
|
1. Copy the two scripts from a working embedded-integration module into the project's `test_scripts/`
|
|
268
268
|
2. Search-and-replace the package segment everywhere it appears — including the test-filter argument (the most commonly missed spot)
|
|
269
269
|
3. `chmod +x` both (and verify ACLs on Windows for the `.ps1` siblings)
|
|
270
|
-
4. Do not link them from the
|
|
271
|
-
5. Smoke-test by running each script manually with the
|
|
270
|
+
4. Do not link them from the ***plain: turri finds them in the project root - `config.turri.yaml` (`unittests-script:`, `conformance-tests-script:`), else the one of each kind in the root, else in `test_scripts/` - and shows them to the agents itself. If `test_scripts/` ends up with two scripts of one kind, name the one to use in `config.turri.yaml`.
|
|
271
|
+
5. Smoke-test by running each script manually with the build output folder as `$1` (and the conformance-tests folder as `$2` for the conformance runner). Confirm exit codes match what turri expects
|
|
272
272
|
|
|
273
273
|
For non-Java languages, the skills [`implement-unit-testing-script`](../skills/implement-unit-testing-script/SKILL.md), and [`implement-conformance-testing-script`](../skills/implement-conformance-testing-script/SKILL.md) adapt the contract above to Python, Node.js, Go, Rust, Flutter, and others. Always route script creation through these skills so the cross-cutting rules above are applied uniformly.
|