@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.
Files changed (216) hide show
  1. package/README.md +6 -6
  2. package/dist/advisor-chat.d.ts +63 -0
  3. package/dist/advisor-chat.js +290 -0
  4. package/dist/background-skills.d.ts +53 -0
  5. package/dist/background-skills.js +121 -0
  6. package/dist/bedrock-region.d.ts +66 -0
  7. package/dist/bedrock-region.js +144 -0
  8. package/dist/btw.d.ts +1 -1
  9. package/dist/btw.js +1 -1
  10. package/dist/change-plain-cli.js +20 -13
  11. package/dist/chat-idle.d.ts +7 -0
  12. package/dist/chat-idle.js +20 -0
  13. package/dist/chats.d.ts +10 -0
  14. package/dist/chats.js +23 -0
  15. package/dist/cli-options.d.ts +1 -2
  16. package/dist/cli-options.js +2 -7
  17. package/dist/cli.js +11 -3
  18. package/dist/config-command.d.ts +14 -0
  19. package/dist/config-command.js +35 -15
  20. package/dist/config-edit.d.ts +3 -3
  21. package/dist/config-edit.js +16 -12
  22. package/dist/config.d.ts +54 -34
  23. package/dist/config.js +40 -44
  24. package/dist/conform-cli.js +12 -10
  25. package/dist/conformance-switch.d.ts +34 -0
  26. package/dist/conformance-switch.js +108 -0
  27. package/dist/cultivate-cli.js +15 -5
  28. package/dist/drift-cli.js +2 -0
  29. package/dist/extension.d.ts +15 -0
  30. package/dist/extension.js +260 -83
  31. package/dist/host-session.d.ts +26 -0
  32. package/dist/host-session.js +30 -2
  33. package/dist/host.d.ts +5 -2
  34. package/dist/host.js +7 -1
  35. package/dist/init-config.d.ts +1 -1
  36. package/dist/init-config.js +20 -11
  37. package/dist/loop-cli.d.ts +3 -3
  38. package/dist/loop-cli.js +13 -16
  39. package/dist/loop-tools.js +18 -10
  40. package/dist/model-check.d.ts +8 -3
  41. package/dist/model-check.js +13 -8
  42. package/dist/new-project.js +12 -8
  43. package/dist/{validate-cli.js → parse-cli.js} +11 -5
  44. package/dist/parse-tool.d.ts +9 -0
  45. package/dist/parse-tool.js +33 -0
  46. package/dist/pi-launch.js +1 -1
  47. package/dist/plain/check.d.ts +53 -6
  48. package/dist/plain/check.js +217 -24
  49. package/dist/plain/concepts.d.ts +8 -0
  50. package/dist/plain/concepts.js +66 -23
  51. package/dist/plain/cycles.d.ts +21 -0
  52. package/dist/plain/cycles.js +190 -0
  53. package/dist/plain/errors.d.ts +4 -0
  54. package/dist/plain/errors.js +7 -0
  55. package/dist/plain/files.d.ts +18 -1
  56. package/dist/plain/files.js +39 -2
  57. package/dist/plain/graph.d.ts +33 -4
  58. package/dist/plain/graph.js +60 -12
  59. package/dist/plain/highlight.d.ts +3 -2
  60. package/dist/plain/highlight.js +4 -3
  61. package/dist/plain/index.d.ts +8 -5
  62. package/dist/plain/index.js +8 -5
  63. package/dist/plain/liquid.js +1 -6
  64. package/dist/plain/markdown.d.ts +32 -3
  65. package/dist/plain/markdown.js +146 -24
  66. package/dist/plain/module-concepts.js +2 -2
  67. package/dist/plain/parser.d.ts +83 -28
  68. package/dist/plain/parser.js +381 -260
  69. package/dist/plain/plain.tmLanguage.json +29 -3
  70. package/dist/plain/project.d.ts +48 -0
  71. package/dist/plain/project.js +155 -0
  72. package/dist/plain/spec.d.ts +90 -28
  73. package/dist/plain/spec.js +107 -133
  74. package/dist/plain/test-plain-file.d.ts +59 -0
  75. package/dist/plain/test-plain-file.js +232 -0
  76. package/dist/regenerate/activity.d.ts +20 -9
  77. package/dist/regenerate/activity.js +11 -4
  78. package/dist/regenerate/advisor-records.d.ts +93 -0
  79. package/dist/regenerate/advisor-records.js +110 -0
  80. package/dist/regenerate/advisor-runs.d.ts +87 -0
  81. package/dist/regenerate/advisor-runs.js +327 -0
  82. package/dist/regenerate/base-folder.d.ts +68 -0
  83. package/dist/regenerate/base-folder.js +168 -0
  84. package/dist/regenerate/cases.d.ts +9 -6
  85. package/dist/regenerate/cases.js +70 -14
  86. package/dist/regenerate/change-view.d.ts +8 -3
  87. package/dist/regenerate/change-view.js +71 -22
  88. package/dist/regenerate/chunk-plan.d.ts +36 -15
  89. package/dist/regenerate/chunk-plan.js +165 -59
  90. package/dist/regenerate/conform.d.ts +3 -0
  91. package/dist/regenerate/conform.js +6 -5
  92. package/dist/regenerate/conformance-agents.d.ts +18 -39
  93. package/dist/regenerate/conformance-agents.js +60 -88
  94. package/dist/regenerate/conformance.d.ts +23 -13
  95. package/dist/regenerate/conformance.js +119 -82
  96. package/dist/regenerate/diff-view.d.ts +1 -1
  97. package/dist/regenerate/diff-view.js +20 -4
  98. package/dist/regenerate/drift.d.ts +47 -15
  99. package/dist/regenerate/drift.js +101 -30
  100. package/dist/regenerate/jobs.d.ts +2 -2
  101. package/dist/regenerate/jobs.js +1 -1
  102. package/dist/regenerate/ledger.d.ts +19 -0
  103. package/dist/regenerate/loop.d.ts +62 -43
  104. package/dist/regenerate/loop.js +472 -341
  105. package/dist/regenerate/paths.d.ts +4 -0
  106. package/dist/regenerate/paths.js +7 -1
  107. package/dist/regenerate/plain-palette.js +2 -0
  108. package/dist/regenerate/prompt.d.ts +57 -19
  109. package/dist/regenerate/prompt.js +157 -122
  110. package/dist/regenerate/records.d.ts +43 -12
  111. package/dist/regenerate/records.js +102 -88
  112. package/dist/regenerate/regenerate.js +29 -11
  113. package/dist/regenerate/regression.d.ts +4 -4
  114. package/dist/regenerate/regression.js +14 -10
  115. package/dist/regenerate/renames.d.ts +42 -0
  116. package/dist/regenerate/renames.js +185 -0
  117. package/dist/regenerate/requires.d.ts +1 -1
  118. package/dist/regenerate/requires.js +10 -3
  119. package/dist/regenerate/resources.d.ts +5 -3
  120. package/dist/regenerate/resources.js +4 -4
  121. package/dist/regenerate/scripts-being-written.d.ts +19 -0
  122. package/dist/regenerate/scripts-being-written.js +30 -0
  123. package/dist/regenerate/spec-map-view.d.ts +2 -2
  124. package/dist/regenerate/spec-map-view.js +46 -15
  125. package/dist/regenerate/spec-map.d.ts +27 -5
  126. package/dist/regenerate/spec-map.js +92 -60
  127. package/dist/regenerate/spec-steps.d.ts +48 -5
  128. package/dist/regenerate/spec-steps.js +213 -28
  129. package/dist/regenerate/state.d.ts +4 -3
  130. package/dist/regenerate/stop-report.d.ts +1 -1
  131. package/dist/regenerate/stop-report.js +10 -10
  132. package/dist/regenerate/test-advisor.d.ts +101 -0
  133. package/dist/regenerate/test-advisor.js +379 -0
  134. package/dist/regenerate/test-kinds.d.ts +71 -28
  135. package/dist/regenerate/test-kinds.js +110 -63
  136. package/dist/regenerate/test-scripts.d.ts +2 -0
  137. package/dist/regenerate/test-scripts.js +4 -0
  138. package/dist/regenerate/testing-steps.d.ts +41 -0
  139. package/dist/regenerate/testing-steps.js +110 -0
  140. package/dist/regenerate/testing.d.ts +1 -1
  141. package/dist/regenerate/testing.js +5 -4
  142. package/dist/regenerate/unit-review.d.ts +1 -1
  143. package/dist/regenerate/unit-review.js +3 -3
  144. package/dist/regenerate-cli.js +11 -12
  145. package/dist/release-agent.js +4 -0
  146. package/dist/release-cli.js +2 -0
  147. package/dist/release-tools.js +2 -0
  148. package/dist/run-report.d.ts +2 -2
  149. package/dist/run-report.js +4 -3
  150. package/dist/self-invocation.d.ts +1 -1
  151. package/dist/self-invocation.js +1 -1
  152. package/dist/sentinel.js +1 -1
  153. package/dist/setup.d.ts +10 -0
  154. package/dist/setup.js +52 -4
  155. package/dist/skill.d.ts +10 -0
  156. package/dist/skill.js +6 -0
  157. package/dist/skills.js +3 -1
  158. package/dist/spec-tools.js +21 -31
  159. package/dist/test-plain-files.d.ts +41 -0
  160. package/dist/test-plain-files.js +177 -0
  161. package/docs/README.md +3 -1
  162. package/docs/authoring-plain.md +46 -13
  163. package/docs/chats.md +3 -1
  164. package/docs/config.md +20 -15
  165. package/docs/deploy.md +1 -1
  166. package/docs/development.md +2 -1
  167. package/docs/headless.md +15 -18
  168. package/docs/hosting.md +28 -12
  169. package/docs/installation.md +1 -0
  170. package/docs/parser.md +88 -27
  171. package/docs/regenerating.md +87 -52
  172. package/docs/sentinel.md +1 -1
  173. package/docs/skills-and-gates.md +3 -1
  174. package/docs/test-advisor.md +110 -0
  175. package/docs/theming.md +1 -1
  176. package/docs/using.md +17 -15
  177. package/genome/rules/bullet-continuation.md +8 -8
  178. package/genome/rules/concise-specs-examples.md +111 -80
  179. package/genome/rules/concise-specs-integration-examples.md +56 -41
  180. package/genome/rules/concise-specs.md +17 -16
  181. package/genome/rules/definitions.md +5 -5
  182. package/genome/rules/examples/integration-embedded-testing/run_conformance_tests_java.sh +1 -1
  183. package/genome/rules/func-specs.md +69 -74
  184. package/genome/rules/impl-reqs.md +4 -4
  185. package/genome/rules/integration-embedded-testing.md +20 -20
  186. package/genome/rules/integration-embedded.md +31 -31
  187. package/genome/rules/integration-standalone.md +9 -9
  188. package/genome/rules/integrations.md +18 -18
  189. package/genome/rules/linked-resources.md +19 -16
  190. package/genome/rules/module-structure.md +21 -14
  191. package/genome/rules/project-model.md +18 -17
  192. package/genome/rules/required-concepts.md +1 -1
  193. package/genome/rules/requires-modules.md +6 -5
  194. package/genome/rules/semantic-ids.md +49 -0
  195. package/genome/rules/stdlib.md +4 -5
  196. package/genome/rules/test-plain-files.md +130 -0
  197. package/genome/rules/test-reqs.md +8 -8
  198. package/genome/rules/turri-regeneration.md +23 -8
  199. package/genome/skills/analyze-2-func-specs/SKILL.md +36 -21
  200. package/genome/skills/analyze-func-specs/SKILL.md +46 -32
  201. package/genome/skills/break-down-func-spec/SKILL.md +91 -67
  202. package/genome/skills/consolidate-concepts/SKILL.md +10 -10
  203. package/genome/skills/convert-old-syntax/SKILL.md +68 -0
  204. package/genome/skills/convert-old-syntax/references/rubric.md +11 -0
  205. package/genome/skills/debug-specs/SKILL.md +62 -56
  206. package/genome/skills/implement-conformance-testing-script/SKILL.md +19 -15
  207. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +2 -2
  208. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +2 -2
  209. package/genome/skills/implement-unit-testing-script/SKILL.md +14 -10
  210. package/genome/skills/refactor-module/SKILL.md +35 -35
  211. package/genome/skills/resolve-section-ownership/SKILL.md +9 -9
  212. package/genome/skills/resolve-spec-conflict/SKILL.md +35 -29
  213. package/package.json +7 -6
  214. package/dist/regenerate/choose-conformance.d.ts +0 -32
  215. package/dist/regenerate/choose-conformance.js +0 -117
  216. /package/dist/{validate-cli.d.ts → parse-cli.d.ts} +0 -0
@@ -2,9 +2,9 @@
2
2
  name: refactor-module
3
3
  description: >-
4
4
  Split a large ***plain module into smaller modules grouped by logical domain.
5
- The resulting modules are connected via a requires chain so that functionality
5
+ The resulting modules are connected via a requires chain so that their behaviour
6
6
  is 100% preserved. Use when a module has become too large and its functional
7
- specs span multiple distinct concerns that would be clearer as separate modules.
7
+ functional specs span multiple distinct concerns that would be clearer as separate modules.
8
8
  allowed-tools: [read, write, edit, bash, ls, grep, find]
9
9
  ---
10
10
 
@@ -19,9 +19,9 @@ allowed-tools: [read, write, edit, bash, ls, grep, find]
19
19
 
20
20
  ## Guiding Principle
21
21
 
22
- The refactoring is purely structural. The **combined behavior** of the resulting modules must be **identical** to the original module. No functional spec is added, removed, or weakened. The split is semantic — grouping related specs together — not behavioral.
22
+ The refactoring is purely structural. The **combined behavior** of the resulting modules must be **identical** to the original module. No functional spec is added, removed, or weakened. The split is semantic — grouping related functional specs together — not behavioral.
23
23
 
24
- The spec is structural; the code is not. Once modules are split and specs move between them, the code already built no longer matches the module layout: specs move into modules the code was never built on, and no change to that code brings them in. **After a refactor, the whole requires chain is regenerated from scratch** — the existing code and conformance tests are taken out (their lineage keeps them) and every module is built again from the base of the chain upward. Say so up front: it is part of what the user agrees to (Phase 2e), and it is the last step of the skill (Phase 5).
24
+ The ***plain is structural; the code is not. Once modules are split and functional specs move between them, the code already built no longer matches the module layout: functional specs move into modules the code was never built on, and no change to that code brings them in. **After a refactor, the whole requires chain is regenerated from scratch** — the existing code and conformance tests are taken out (their lineage keeps them) and every module is built again from the base of the chain upward. Say so up front: it is part of what the user agrees to (Phase 2e), and it is the last step of the skill (Phase 5).
25
25
 
26
26
  ## Input
27
27
 
@@ -30,7 +30,7 @@ The `.plain` file to refactor, plus guidance from the user on the desired groupi
30
30
  ## Phase 1 — Analyze the Current Module
31
31
 
32
32
  1. **Read the entire `.plain` file** — frontmatter, definitions, implementation reqs, test reqs, and all functional specs. Also read any `import` and `requires` chains to understand the full context.
33
- 2. **Inventory the functional specs.** Number each spec and note which `:Concepts:` it references. Build a dependency map: which specs depend on earlier specs (by referencing behavior or state they introduced)?
33
+ 2. **Inventory the functional specs.** List each functional spec by its func-id and note which `:Concepts:` it references. Build a dependency map: which functional specs depend on earlier functional specs (by referencing behavior or state they introduced)?
34
34
  3. **Inventory the definitions.** For each concept, note which functional specs reference it. Identify concepts that are used across multiple logical groups vs. concepts used only within one group.
35
35
  4. **Identify logical groups.** Look for natural seams — clusters of functional specs that share concepts, represent a cohesive domain, or describe a single feature area. Common groupings:
36
36
  - Data model setup and CRUD operations
@@ -38,7 +38,7 @@ The `.plain` file to refactor, plus guidance from the user on the desired groupi
38
38
  - UI screens and navigation
39
39
  - Integrations and external interfaces
40
40
  - Statistics, reporting, and analytics
41
- 5. **Verify group independence.** Each group's specs should form a contiguous or near-contiguous block in chronological order. If a group's specs are scattered and interleaved with other groups, the split boundary may need adjustment.
41
+ 5. **Verify group independence.** Each group's functional specs should form a contiguous or near-contiguous block in chronological order. If a group's functional specs are scattered and interleaved with other groups, the split boundary may need adjustment.
42
42
 
43
43
  ## Phase 2 — Plan the Split
44
44
 
@@ -46,7 +46,7 @@ Present the proposed split to the user and get explicit confirmation before maki
46
46
 
47
47
  ### 2a. Define the module chain
48
48
 
49
- The modules form a `requires` chain that preserves the original chronological ordering of functional specs. The first module in the chain contains the earliest specs; each subsequent module `requires` the previous one and adds the next logical group.
49
+ The modules form a `requires` chain that preserves the original chronological ordering of functional specs. The first module in the chain contains the earliest functional specs; each subsequent module `requires` the previous one and adds the next logical group.
50
50
 
51
51
  ```
52
52
  original-module
@@ -61,9 +61,9 @@ If the original module already had `requires` or `import` dependencies, the firs
61
61
  ### 2b. Assign functional specs to modules
62
62
 
63
63
  Place each functional spec in exactly one module. The placement must respect chronological ordering:
64
- - Within each module, the specs appear in the same relative order as in the original.
65
- - Across the chain, the ordering is preserved: all specs in module A come before all specs in module B, which come before all specs in module C.
66
- - A spec **cannot** move to an earlier module than a spec it depends on.
64
+ - Within each module, the functional specs appear in the same relative order as in the original.
65
+ - Across the chain, the ordering is preserved: all functional specs in module A come before all functional specs in module B, which come before all functional specs in module C.
66
+ - A functional spec **cannot** move to an earlier module than a functional spec it depends on.
67
67
 
68
68
  ### 2c. Assign definitions to modules
69
69
 
@@ -71,7 +71,7 @@ For each concept, determine where it belongs:
71
71
 
72
72
  | Concept usage | Placement |
73
73
  |---------------|-----------|
74
- | Used only within one module's specs | Define in that module |
74
+ | Used only within one module's functional specs | Define in that module |
75
75
  | Used across multiple modules in the chain | Define in the first module that uses it, and add to that module's `exported_concepts` |
76
76
  | Already defined in an import template | Leave in the import — no change needed |
77
77
 
@@ -87,11 +87,11 @@ If many concepts are shared across all modules, consider creating a new import m
87
87
 
88
88
  Summarize for the user:
89
89
  - Number of resulting modules and their names
90
- - Which functional specs go in each module (listed by number or short description)
90
+ - Which functional specs go in each module (listed by func-id)
91
91
  - The `requires` chain order
92
92
  - Any new import module being created
93
93
  - Which concepts are exported from each module
94
- - Confirmation that all original specs are accounted for (none lost)
94
+ - Confirmation that all original functional specs are accounted for (none lost)
95
95
  - That the whole chain will be **regenerated from scratch** once the split is done: the code and conformance tests built so far are taken out (kept in the lineage) and everything is built again from the base module up — this takes as long and costs as much as building the original module did
96
96
 
97
97
  Get explicit user confirmation before proceeding — of the split and of regenerating from scratch.
@@ -108,10 +108,10 @@ If shared definitions or reqs are being moved to a new import template, create i
108
108
 
109
109
  Create the first module in the chain:
110
110
  1. Set the YAML frontmatter — inherit the original module's `import` references. Add `exported_concepts` for any concepts that downstream modules need.
111
- 2. Add the `***definitions***` section with concepts used by this module's specs and concepts that need to be exported.
111
+ 2. Add the `***definitions***` section with concepts used by this module's functional specs and concepts that need to be exported.
112
112
  3. Add `***implementation reqs***` and `***test reqs***` specific to this module (if not fully covered by the import template).
113
113
  4. Add the `***functional specs***` assigned to this module, preserving their original order and exact wording.
114
- 5. Carry over any `***acceptance tests***` nested under the moved functional specs.
114
+ 5. Move the test plain files of the moved functional specs into this module's folder, `tests/<module>/`, with `module:` set to the new module's name; func-ids and scenario text stay as they are.
115
115
 
116
116
  ### 3c. Create subsequent modules
117
117
 
@@ -121,12 +121,12 @@ For each subsequent module in the chain:
121
121
  3. Add `***definitions***` for concepts local to this module. Do **not** redefine concepts already available via `requires` (exported) or `import`.
122
122
  4. Add `***implementation reqs***` and `***test reqs***` specific to this module.
123
123
  5. Add the `***functional specs***` assigned to this module, preserving their original order and exact wording.
124
- 6. Carry over any `***acceptance tests***`.
124
+ 6. Move the test plain files of the moved functional specs the same way.
125
125
 
126
126
  ### 3d. Handle the original module file
127
127
 
128
128
  After all new modules are created:
129
- - If the original module is being fully replaced (all specs moved out), delete it or rename it to avoid confusion.
129
+ - If the original module is being fully replaced (all functional specs moved out), delete it or rename it to avoid confusion.
130
130
  - If the original module was required by other modules, update those modules to `require` the last module in the new chain instead — its accumulated code and previous functional specs cover the whole chain. Exported concepts are **not** transitive, though: if a downstream module references a concept now exported by an earlier module in the new chain, it must list that earlier module in its `requires` as well.
131
131
 
132
132
  ## Phase 4 — Verify
@@ -136,18 +136,18 @@ After all new modules are created:
136
136
  This is the most critical verification. Walk through every functional spec from the original module and confirm it appears in exactly one of the new modules. Nothing may be lost, weakened, modified, or left implicit.
137
137
 
138
138
  Checklist:
139
- - [ ] Total spec count across all new modules equals the original spec count
140
- - [ ] Each spec's text is identical to the original (no rewording)
141
- - [ ] Each spec's acceptance tests (if any) are carried over intact
139
+ - [ ] The functional specs across all new modules are as many as the original's
140
+ - [ ] Each functional spec's text is identical to the original (no rewording) and keeps its func-id
141
+ - [ ] Each functional spec's test plain file moved with it, with `module:` updated and scenarios intact
142
142
 
143
143
  ### 4b. Chronological ordering check
144
144
 
145
- Verify that the chronological order of all functional specs — when read across the requires chain from base to leaf — matches the original ordering exactly. A spec must not appear before a spec it depends on.
145
+ Verify that the chronological order of all functional specs — when read across the requires chain from base to leaf — matches the original ordering exactly. A functional spec must not appear before a functional spec it depends on.
146
146
 
147
147
  ### 4c. Concept availability check
148
148
 
149
149
  For each module, verify:
150
- - [ ] Every `:Concept:` referenced in its specs is either defined locally, available via `import`, or available via `exported_concepts` from a module listed in `requires`
150
+ - [ ] Every `:Concept:` referenced in its functional specs is either defined locally, available via `import`, or available via `exported_concepts` from a module listed in `requires`
151
151
  - [ ] `exported_concepts` includes every concept that downstream modules need
152
152
  - [ ] No concept name collisions between modules
153
153
 
@@ -158,18 +158,18 @@ For each new module:
158
158
  - [ ] YAML frontmatter is correctly formatted
159
159
  - [ ] `requires` and `import` paths are correct
160
160
  - [ ] Module file is at the repository root (not in `template/`)
161
- - [ ] Specs are language-agnostic
161
+ - [ ] Functional specs are language-agnostic
162
162
  - [ ] All external interfaces remain explicit
163
163
 
164
164
  ### 4e. Read all new modules
165
165
 
166
166
  Read each new `.plain` file in full and present the final structure to the user for approval. If the user requests changes, apply them and re-verify.
167
167
 
168
- Validate each new module with `turri validate <module>.plain` (or the `validate` tool) before going on: a module that does not parse cannot be regenerated.
168
+ Parse each new module with `turri parse <module>.plain` (or the `parse` tool) before going on: a module that does not parse cannot be regenerated.
169
169
 
170
170
  ## Phase 5 — Regenerate the Chain from Scratch
171
171
 
172
- The split moves specs between modules, so the code built from the original module cannot be patched into the new layout: the chain is regenerated from scratch. Do not try to keep or reuse the existing code, and do not regenerate only what looks changed — modules have moved, and a codebase built without a module it now requires has to be started over anyway.
172
+ The split moves functional specs between modules, so the code built from the original module cannot be patched into the new layout: the chain is regenerated from scratch. Do not try to keep or reuse the existing code, and do not regenerate only what looks changed — modules have moved, and a codebase built without a module it now requires has to be started over anyway.
173
173
 
174
174
  1. **Remind the user** what regenerating from scratch does — the code and conformance tests built so far are taken out, committed so the lineage keeps them, and the whole chain is built again from the base up — and that they already agreed to it in Phase 2e. Proceed only on that agreement.
175
175
  2. **Regenerate the tip of the chain from scratch, with its whole chain** — the last module, the one everything else is required by. From scratch for the tip alone is not enough: the modules below keep their code, and the tip starts from a copy of it, laid out for the old modules. With the whole chain, every module's code is taken out, the base's included, and the chain is built again from the bottom:
@@ -181,19 +181,19 @@ The split moves specs between modules, so the code built from the original modul
181
181
  ## Common Pitfalls
182
182
 
183
183
  ### Splitting too aggressively
184
- Creating many tiny modules with 1–2 specs each adds overhead without clarity. Aim for modules with 3–10 functional specs each, grouped around a cohesive theme.
184
+ Creating many tiny modules with 1–2 functional specs each adds overhead without clarity. Aim for modules with 3–10 functional specs each, grouped around a cohesive theme.
185
185
 
186
186
  ### Breaking chronological order
187
- Specs that set up foundational behavior (entry point, database init, core CRUD) must stay in the base module even if they touch concepts from multiple domains. Only split when specs are cleanly separable.
187
+ Functional specs that set up foundational behavior (entry point, database init, core CRUD) must stay in the base module even if they touch concepts from multiple domains. Only split when functional specs are cleanly separable.
188
188
 
189
189
  ### Forgetting exported_concepts
190
- If a concept defined in module A is referenced by a spec in module B (which requires A), the concept must be in A's `exported_concepts`. Missing exports cause rendering failures.
190
+ If a concept defined in module A is referenced by a functional spec in module B (which requires A), the concept must be in A's `exported_concepts`. Missing exports cause regeneration failures.
191
191
 
192
- ### Modifying spec text during the split
193
- This is a refactoring, not a rewrite. Spec text must be copied verbatim. If a spec needs rewording to work in its new module context, that is a sign the split boundary is wrong — adjust the grouping instead.
192
+ ### Modifying the ***plain during the split
193
+ This is a refactoring, not a rewrite. Functional specs must be copied verbatim. If one needs rewording to work in its new module context, that is a sign the split boundary is wrong — adjust the grouping instead.
194
194
 
195
- ### Losing acceptance tests
196
- Acceptance tests are nested under their parent functional spec. When moving a spec to a new module, its acceptance tests must move with it.
195
+ ### Losing test plain files
196
+ A test plain file binds to its functional spec by `module:` and `func_id:`, and lives in its module's folder. When a functional spec moves to a new module, its test plain file moves to `tests/<new module>/` with `module:` changed; otherwise `turri parse` reports a file bound to no functional spec, and a functional spec with no test plain file.
197
197
 
198
198
  ### Regenerating only what changed
199
199
  After a split the existing code was built for a module layout that no longer exists. Regenerating incrementally either stops at a codebase that has to be started over or builds on code laid out for the old modules. Regenerate the whole chain from scratch.
@@ -202,8 +202,8 @@ After a split the existing code was built for a module layout that no longer exi
202
202
 
203
203
  - [ ] User confirmed the split plan before execution, including regenerating the whole chain from scratch
204
204
  - [ ] All original functional specs are present in exactly one new module — none lost
205
- - [ ] Spec text is identical to the original — no rewording
206
- - [ ] Acceptance tests moved with their parent specs
205
+ - [ ] Every functional spec's text is identical to the original — no rewording
206
+ - [ ] Test plain files moved with their functional specs and bound to the new module
207
207
  - [ ] Chronological order preserved across the requires chain
208
208
  - [ ] Every referenced `:Concept:` is available in each module (local, import, or exported)
209
209
  - [ ] `exported_concepts` are correctly set on each module
@@ -213,6 +213,6 @@ After a split the existing code was built for a module layout that no longer exi
213
213
  - [ ] Original module removed or updated
214
214
  - [ ] Downstream modules (if any) updated to require the chain tip, plus any earlier chain modules whose exported concepts they reference
215
215
  - [ ] User approved the final result
216
- - [ ] Every new module validates
216
+ - [ ] Every new module parses
217
217
  - [ ] The tip of the chain regenerated from scratch with its whole chain, then any module that requires it
218
218
  - [ ] User told about the original module's leftover codebase, if there is one
@@ -1,26 +1,26 @@
1
1
  ---
2
2
  name: resolve-section-ownership
3
3
  description: >-
4
- Route every fact in a .plain bullet, section, or file to the section that owns it — splitting a bullet that carries several kinds of fact, and moving a misplaced one to where the renderer will read it. Use when a bullet answers more than one of what it is / what it does / how it is built / how it is tested, when a requirement looks like it is in the wrong section, or when auditing a file for section ownership. Not for a spec that is merely too large (use break-down-func-spec) or for two specs that contradict each other (use resolve-spec-conflict).
4
+ Route every fact in a .plain bullet, section, or file to the section that owns it — splitting a bullet that carries several kinds of fact, and moving a misplaced one to where turri will read it. Use when a bullet answers more than one of what it is / what it does / how it is built / how it is tested, when a requirement looks like it is in the wrong section, or when auditing a file for section ownership. Not for a functional spec that is merely too large (use break-down-func-spec) or for two that contradict each other (use resolve-spec-conflict).
5
5
  allowed-tools: [read, write, edit, ls, grep, find]
6
6
  ---
7
7
 
8
8
  # Resolve Section Ownership
9
9
 
10
- This is the ownership counterpart to `break-down-func-spec`. That skill splits one functional spec into several because it is **too large**; this one moves facts between sections because they are in the **wrong place**. The two are unrelated: a correctly placed spec can be too large, and a one-line bullet can be misplaced.
10
+ This is the ownership counterpart to `break-down-func-spec`. That skill splits one functional spec into several because it is **too large**; this one moves facts between sections because they are in the **wrong place**. The two are unrelated: a correctly placed functional spec can be too large, and a one-line bullet can be misplaced.
11
11
 
12
12
  ## When to Use
13
13
 
14
14
  - A bullet answers more than one of *what is it*, *what does it do*, *how is it built*, *how is it tested*.
15
15
  - A requirement states a mechanism (retry, cache, token refresh, connection handling) but sits in `***functional specs***`.
16
- - A `:UnitTests:` fact sits in `***test reqs***`, or a `:ConformanceTests:` fact sits in `***implementation reqs***` — the generators read only their own section, so the fact is silently ignored today.
16
+ - A `:UnitTests:` fact sits in `***test reqs***`, or a `:ConformanceTests:` fact sits in `***implementation reqs***` — the coding agent and the conformance agent each read only their own section, so the fact is silently ignored today.
17
17
  - A functional spec describes an external system rather than the software being built.
18
18
  - A whole file is being audited for placement.
19
19
 
20
20
  ## When Not to Use
21
21
 
22
- - The spec is correctly placed but too large → `break-down-func-spec`.
23
- - Two specs contradict each other → `analyze-func-specs`, then `resolve-spec-conflict`.
22
+ - The functional spec is correctly placed but too large → `break-down-func-spec`.
23
+ - Two functional specs contradict each other → `analyze-func-specs`, then `resolve-spec-conflict`.
24
24
  - The wording is merely verbose → trim per `concise-specs.md`; no fact changes section.
25
25
 
26
26
  ## Input
@@ -35,19 +35,19 @@ 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. **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.
38
+ 7. **Write each fact into its owning section** by that section's rule — `definitions.md`, `impl-reqs.md`, `test-reqs.md`, and for a test scenario its functional spec's test plain file, by *Writing scenarios* in `test-plain-files.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
- 10. **Run `validate`** on the module. Moving facts changes the renderable surface; do not finish while it reports errors.
41
+ 10. **Run `parse`** on the module. Moving facts changes what is regenerated; do not finish while it reports errors.
42
42
  11. **Read the file again** to confirm canonical section order (`***definitions***` → `***implementation reqs***` → `***test reqs***` → `***functional specs***`), correct syntax, and that every referenced concept is still defined before use.
43
43
 
44
44
  ## Error Handling
45
45
 
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.
46
+ - **The complexity check finds the moved fact too complex** → the fact was a whole functional spec in disguise; run `break-down-func-spec` on it, then place the resulting functional specs.
47
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
- - **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.
50
+ - **The move empties a functional spec** → delete the functional spec rather than leaving a placeholder, and delete its test plain file with it, moving any scenario that still fits to the functional spec it now tests (*Keeping test plain files in step* in `test-plain-files.md`).
51
51
 
52
52
  ## Worked examples
53
53
 
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  name: resolve-spec-conflict
3
3
  description: >-
4
- Resolve a conflict between two functional specs in a ***plain spec file. Use
5
- when conformance tests for a previously passing spec start failing after a new
6
- spec is rendered, or when a potential conflict is detected while adding a new
4
+ Resolve a conflict between two functional specs in a .plain file. Use
5
+ when conformance tests for a previously passing functional spec start failing after a new
6
+ one is regenerated, or when a potential conflict is detected while adding a new
7
7
  functional spec (the conflict check of `func-specs.md`).
8
8
  allowed-tools: [read, write, edit, ls, grep, find]
9
9
  ---
@@ -13,15 +13,15 @@ allowed-tools: [read, write, edit, ls, grep, find]
13
13
  ## When This Applies
14
14
 
15
15
  A conflict exists (or is suspected) when:
16
- - Conformance tests for a **previously passing** functional spec begin to fail after a new spec is rendered.
17
- - A new spec being added appears to contradict an existing spec.
18
- - Two specs make incompatible assertions about the same behavior, data, or state.
16
+ - Conformance tests for a **previously passing** functional spec begin to fail after a new one is regenerated.
17
+ - A new functional spec being added appears to contradict an existing functional spec.
18
+ - Two functional specs make incompatible assertions about the same behavior, data, or state.
19
19
 
20
20
  ## Workflow
21
21
 
22
22
  ### Step 1: Identify the Conflicting Pair
23
23
 
24
- Read the `.plain` file and pinpoint the two specs in tension. If the conflict was detected via a conformance test failure, also read the failing test and the generated implementation in `plain_modules/` to understand what behavior changed.
24
+ Read the `.plain` file and pinpoint the two functional specs in tension. If the conflict was detected via a conformance test failure, also read the failing test and the generated implementation in `plain_modules/` to understand what behavior changed.
25
25
 
26
26
  ### Step 2: Diagnose the Root Cause
27
27
 
@@ -29,68 +29,74 @@ There are three possible outcomes — determine which one applies **before** mak
29
29
 
30
30
  | Outcome | Symptom | Fix |
31
31
  |---------|---------|-----|
32
- | **Implementation is incorrect** | Generated code doesn't match the spec's intent. The specs themselves are fine. | Clarify the ambiguous spec so the renderer interprets it correctly. Re-render. |
33
- | **Conformance tests are incorrect** | The tests don't accurately verify the spec. The implementation is actually correct. | Adjust `***test reqs***` or `***acceptance tests***` to guide better test generation. Re-render. |
34
- | **Requirements truly conflict** | The two specs are inherently contradictory — no implementation can satisfy both. | One or both specs must be revised. See Step 3. |
32
+ | **Implementation is incorrect** | Generated code doesn't match the functional spec's intent. The functional specs themselves are fine. | Clarify the ambiguous functional spec so the coding agent interprets it correctly. Regenerate. |
33
+ | **Conformance tests are incorrect** | The tests don't accurately verify the functional spec. The implementation is actually correct. | Adjust `***test reqs***`, or a scenario in the test plain file (*Writing scenarios* in `test-plain-files.md`), to guide better test generation. Regenerate. |
34
+ | **Requirements truly conflict** | The two functional specs are inherently contradictory — no implementation can satisfy both. | One or both functional specs must be revised. See Step 3. |
35
35
 
36
36
  **How to diagnose:**
37
37
  1. Read both functional specs carefully. Can a single implementation satisfy both simultaneously?
38
- 2. If yes → the specs are compatible; the issue is ambiguity (outcome 1) or bad tests (outcome 2).
38
+ 2. If yes → the functional specs are compatible; the issue is ambiguity (outcome 1) or bad tests (outcome 2).
39
39
  3. If no → the requirements truly conflict (outcome 3).
40
40
 
41
41
  ### Step 3: Resolve the Conflict
42
42
 
43
43
  When the requirements truly conflict, choose a resolution strategy:
44
44
 
45
- **Strategy A: Add detail to disambiguate.** Often the specs aren't contradictory — they're just ambiguous enough that the renderer picks a conflicting interpretation. Adding explicit context to one or both specs eliminates the ambiguity.
45
+ **Strategy A: Add detail to disambiguate.** Often the functional specs aren't contradictory — they're just ambiguous enough that the coding agent picks a conflicting interpretation. Adding explicit context to one or both functional specs eliminates the ambiguity.
46
46
 
47
47
  Before (ambiguous):
48
48
  ```plain
49
49
  ***functional specs***
50
50
 
51
- - All :Resource: items are returned.
51
+ # list-resources
52
+ All :Resource: items are returned.
52
53
 
53
- - Only active :Resource: items are returned.
54
+ # list-active-resources
55
+ Only active :Resource: items are returned.
54
56
  ```
55
57
 
56
58
  After (disambiguated):
57
59
  ```plain
58
60
  ***functional specs***
59
61
 
60
- - All :Resource: items are returned when no filter is specified.
62
+ # list-resources
63
+ All :Resource: items are returned when no filter is specified.
61
64
 
62
- - When the "active" filter is specified, only active :Resource: items are returned.
65
+ # list-active-resources
66
+ When the "active" filter is specified, only active :Resource: items are returned.
63
67
  ```
64
68
 
65
- **Strategy B: Revise the newer spec.** If the new spec introduced the conflict, rewrite it to be compatible with the established behavior from earlier specs.
69
+ **Strategy B: Revise the newer functional spec.** If the new functional spec introduced the conflict, rewrite it to be compatible with the established behavior from earlier functional specs.
66
70
 
67
- **Strategy C: Revise the older spec.** If the older spec was under-specified and the new requirement reveals a better design, update the older spec. This is more disruptive — all conformance tests for that spec and everything after it may need re-rendering.
71
+ **Strategy C: Revise the older functional spec.** If the older functional spec was under-specified and the new requirement reveals a better design, update the older functional spec. This is more disruptive — the older one's code is patched in place, and the functional specs that rely on what it did may need changing too.
68
72
 
69
- **Strategy D: Merge into one spec.** If the two specs describe overlapping behavior, combine them into a single, clear spec. Remove the redundant one. Be mindful of the 200 LOC limit.
73
+ **Strategy D: Merge into one.** If the two functional specs describe overlapping behavior, combine them into a single, clear one. Remove the redundant one and its test plain file, moving any scenario that still fits into the kept functional spec's file. Be mindful of the 200 LOC limit.
70
74
 
71
75
  ### Step 4: Validate the Resolution
72
76
 
73
77
  After editing:
74
78
  1. Re-read the full `***functional specs***` section to confirm no new conflicts were introduced.
75
- 2. Check that any revised spec still respects the 200 LOC limit.
76
- 3. Check that chronological ordering still makes sense (earlier specs should not depend on later ones).
77
- 4. If resolving via test adjustments, verify the `***test reqs***` or `***acceptance tests***` changes are appropriate.
79
+ 2. Check that any revised functional spec still respects the 200 LOC limit.
80
+ 3. Check that chronological ordering still makes sense (earlier functional specs should not depend on later ones).
81
+ 4. If resolving via test adjustments, verify the `***test reqs***` or test plain file changes are appropriate.
82
+ 5. Bring the test plain file of every revised functional spec in step with its new text, in the same ***plain diff (*Keeping test plain files in step* in `test-plain-files.md`).
78
83
 
79
84
  ## Prevention (while adding a functional spec)
80
85
 
81
- Before adding a new spec, run through this quick conflict check:
86
+ Before adding a new functional spec, run through this quick conflict check:
82
87
 
83
- 1. List every existing functional spec that touches the same `:Concepts:` as the new spec.
84
- 2. For each, ask: "Can a single implementation satisfy both this existing spec and the new one?"
85
- 3. If any answer is "not obviously yes" — add explicit detail to the new spec to eliminate the ambiguity **before** inserting it.
88
+ 1. List every existing functional spec that touches the same `:Concepts:` as the new functional spec.
89
+ 2. For each, ask: "Can a single implementation satisfy both this existing functional spec and the new one?"
90
+ 3. If any answer is "not obviously yes" — add explicit detail to the new functional spec to eliminate the ambiguity **before** inserting it.
86
91
 
87
92
  ## Validation Checklist
88
93
 
89
94
  - [ ] Root cause diagnosed (implementation / tests / true conflict)
90
95
  - [ ] Resolution strategy chosen and applied
91
- - [ ] Revised specs are language-agnostic
92
- - [ ] Revised specs trimmed per `concise-specs.md` — added disambiguation stays as short as it can be
93
- - [ ] Revised specs each imply ≤ 200 LOC
96
+ - [ ] Revised functional specs are language-agnostic
97
+ - [ ] Revised functional specs trimmed per `concise-specs.md` — added disambiguation stays as short as it can be
98
+ - [ ] Revised functional specs each imply ≤ 200 LOC
94
99
  - [ ] No new conflicts introduced by the fix
95
100
  - [ ] Chronological ordering preserved
96
101
  - [ ] All referenced `:Concepts:` are still defined
102
+ - [ ] Test plain files of the revised functional specs in step with them (`test-plain-files.md`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@turri-dev/cli",
3
- "version": "0.1.27",
3
+ "version": "0.1.28-next.d5f2680",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {
@@ -33,20 +33,21 @@
33
33
  "mutation": "node scripts/mutation.mjs",
34
34
  "conform": "tsx src/conform-cli.ts",
35
35
  "regenerate": "tsx src/regenerate-cli.ts",
36
- "validate": "tsx src/validate-cli.ts",
36
+ "parse": "tsx src/parse-cli.ts",
37
37
  "doctor": "node bin/turri.mjs doctor",
38
38
  "build": "node scripts/build.mjs",
39
- "prepack": "npm run build",
40
- "grammar:sync": "node scripts/sync-plyn-grammar.mjs"
39
+ "prepack": "npm run build"
41
40
  },
42
41
  "dependencies": {
43
- "@earendil-works/pi-coding-agent": "^1.2.0",
44
- "@earendil-works/pi-tui": "^1.2.0",
42
+ "@earendil-works/pi-coding-agent": "1.4.0",
43
+ "@earendil-works/pi-tui": "1.4.0",
45
44
  "@langchain/langgraph": "1.4.15",
46
45
  "gray-matter": "^4.0.3",
47
46
  "js-yaml": "^5.4.2",
48
47
  "liquidjs": "^10.29.0",
49
48
  "mdast-util-from-markdown": "^2.0.3",
49
+ "mdast-util-gfm-table": "^2.0.0",
50
+ "micromark-extension-gfm-table": "^2.1.1",
50
51
  "remark-parse": "^11.0.0",
51
52
  "typebox": "^1.3.7",
52
53
  "unified": "^11.0.5"
@@ -1,32 +0,0 @@
1
- import type { TouchedSpec } from "./drift.ts";
2
- /**
3
- * Which functional specs get conformance tests, under `conformance-tests: chosen` or `module`, is this agent's to choose -
4
- * in the chat and on the command line alike, on the chooser's model. Under chosen it is asked as each code pulse ends,
5
- * of what that pulse regenerated; under module once, when the whole module is regenerated, and it plans the conformance
6
- * pulses too. It reads the module's spec and names the ones worth black-box tests, and why. Being asked inside the pulse,
7
- * the choice is made before anything can be built on the module: nothing has to be stopped for it.
8
- */
9
- export interface ConformanceChoice {
10
- frids: string[];
11
- why: string;
12
- /** Under module: the conformance pulses, each the functional specs it tests together. */
13
- groups?: string[][];
14
- }
15
- /** What the chooser is asked: the module's spec, and the functional specs to choose from. */
16
- export declare function choicePrompt(plainFile: string, specs: TouchedSpec[], spec: string, budget?: number, when?: "pulse" | "module"): string;
17
- /** Ask the chooser, on `model`. Nothing chosen when it does not answer, or answers with numbers not offered. */
18
- export declare function chooseConformance(options: {
19
- plainFile: string;
20
- specs: TouchedSpec[];
21
- model?: string;
22
- budget?: number;
23
- when?: "pulse" | "module";
24
- }): Promise<ConformanceChoice>;
25
- /**
26
- * The work loop's chooser, the chat's and the command line's alike: asked as a pulse ends, it asks chooseConformance on
27
- * the harness model. A functional spec passed over is not offered again for the same text - only once it changes.
28
- */
29
- export declare function conformanceChooser(options: {
30
- model: () => string | undefined;
31
- dryRun?: boolean;
32
- }): (plainFile: string, specs: TouchedSpec[], budget: number | undefined, when: "pulse" | "module") => Promise<ConformanceChoice | undefined>;
@@ -1,117 +0,0 @@
1
- import { readFileSync } from "node:fs";
2
- import { basename, dirname } from "node:path";
3
- import { defineTool } from "@earendil-works/pi-coding-agent";
4
- import { Type } from "typebox";
5
- import { ask, BEGIN, createExecutor } from "../pi.js";
6
- import { reportActivity } from "./activity.js";
7
- /** What the chooser is asked: the module's spec, and the functional specs to choose from. */
8
- export function choicePrompt(plainFile, specs, spec, budget, when = "pulse") {
9
- return [
10
- `You choose which functional specs of the ***plain module \`${basename(plainFile)}\` get black-box conformance tests.`,
11
- when === "module"
12
- ? "conformance-tests: module - the whole module is regenerated now, and these of its functional specs are built and no conformance test is for them or scheduled:"
13
- : "conformance-tests: chosen - a code pulse has just regenerated these, and no conformance test is for them or scheduled:",
14
- ...specs.map((touched) => `- fs ${touched.frid}: ${touched.text}`),
15
- "",
16
- `Decide which of them black-box conformance tests are worth it for - what a user or a client of ${basename(plainFile)} relies on,`,
17
- "not an internal detail its unit tests already cover - and say why. The rest stay without. A functional spec with",
18
- "acceptance tests always has them: it is not among these. Choosing none is an answer too.",
19
- ...(budget !== undefined
20
- ? [`Choose at most ${budget} - the module's conformance budget: rank them by what a client of the module relies on most, and say why the ones you choose come before the rest.`]
21
- : []),
22
- ...(when === "module"
23
- ? [
24
- "",
25
- "Plan them too: in groups, each a conformance pulse - the functional specs a client exercises together in one, those",
26
- "that share nothing apart. Every one you choose is in one group.",
27
- ]
28
- : []),
29
- "",
30
- `Call choose_conformance once, with the numbers of those you choose${when === "module" ? ", the groups" : ""} and why.`,
31
- "",
32
- `<spec file="${basename(plainFile)}">`,
33
- spec.trimEnd(),
34
- "</spec>",
35
- ].join("\n");
36
- }
37
- /** Ask the chooser, on `model`. Nothing chosen when it does not answer, or answers with numbers not offered. */
38
- export async function chooseConformance(options) {
39
- const planning = options.when === "module";
40
- let answer;
41
- const offered = new Set(options.specs.map((touched) => touched.frid));
42
- const tool = defineTool({
43
- name: "choose_conformance",
44
- label: "Choose the conformance tests",
45
- description: "The functional specs, by number, that get black-box conformance tests - none, some or all of those offered - and why.",
46
- parameters: Type.Object({
47
- frids: Type.Array(Type.String({ description: 'A functional spec\'s number, as offered - e.g. "2" or "3.1"' })),
48
- why: Type.String({ description: "Why these, and why not the rest" }),
49
- ...(planning ? { groups: Type.Array(Type.Array(Type.String()), { description: "The conformance pulses: each the numbers of the functional specs it tests together - every one chosen in one" }) } : {}),
50
- }),
51
- async execute(_id, params) {
52
- const { frids, why, groups } = params;
53
- if (planning && groups !== undefined) {
54
- const grouped = groups.flat();
55
- const outside = grouped.filter((frid) => !frids.includes(frid));
56
- const left = frids.filter((frid) => !grouped.includes(frid));
57
- if (outside.length > 0 || left.length > 0 || new Set(grouped).size !== grouped.length) {
58
- return { content: [{ type: "text", text: `Not recorded: every one chosen is in exactly one group, and nothing else is${outside.length > 0 ? ` - fs ${outside.join(", ")} grouped, not chosen` : ""}${left.length > 0 ? ` - fs ${left.join(", ")} chosen, in no group` : ""}. Call it again.` }], details: {} };
59
- }
60
- }
61
- const unknown = frids.filter((frid) => !offered.has(frid));
62
- if (options.budget !== undefined && new Set(frids).size > options.budget) {
63
- return { content: [{ type: "text", text: `Not recorded: the module's conformance budget allows ${options.budget}, and you chose ${new Set(frids).size}. Choose the ${options.budget} that matter most, and call it again.` }], details: {} };
64
- }
65
- if (unknown.length > 0) {
66
- return { content: [{ type: "text", text: `Not offered: fs ${unknown.join(", ")}. Choose from ${[...offered].join(", ")}, and call it again.` }], details: {} };
67
- }
68
- answer = { frids: [...new Set(frids)], why, ...(planning && groups !== undefined && groups.length > 0 ? { groups: groups.filter((group) => group.length > 0) } : {}) };
69
- return { content: [{ type: "text", text: "Recorded." }], details: {}, terminate: true };
70
- },
71
- });
72
- const session = await createExecutor({
73
- cwd: dirname(options.plainFile),
74
- customTools: [tool],
75
- tools: [tool.name],
76
- model: options.model,
77
- label: `${basename(options.plainFile, ".plain")} conformance chooser`,
78
- role: "chooser",
79
- task: choicePrompt(options.plainFile, options.specs, readFileSync(options.plainFile, "utf8"), options.budget, options.when),
80
- budget: { calls: 3, finish: [tool.name] },
81
- });
82
- try {
83
- await ask(session, BEGIN);
84
- if (answer === undefined)
85
- await ask(session, "You did not call choose_conformance. Call it now.");
86
- }
87
- finally {
88
- session.dispose();
89
- }
90
- if (answer === undefined) {
91
- reportActivity(` the conformance chooser gave no answer for ${basename(options.plainFile)}: none chosen`);
92
- return { frids: [], why: "the chooser gave no answer" };
93
- }
94
- return answer;
95
- }
96
- /**
97
- * The work loop's chooser, the chat's and the command line's alike: asked as a pulse ends, it asks chooseConformance on
98
- * the harness model. A functional spec passed over is not offered again for the same text - only once it changes.
99
- */
100
- export function conformanceChooser(options) {
101
- const offered = new Set();
102
- return async (plainFile, specs, budget, when) => {
103
- const fresh = specs.filter((touched) => !offered.has(`${plainFile}\n${touched.frid}\n${touched.text}`));
104
- if (fresh.length === 0 || options.dryRun === true)
105
- return undefined;
106
- for (const touched of fresh)
107
- offered.add(`${plainFile}\n${touched.frid}\n${touched.text}`);
108
- try {
109
- const model = options.model();
110
- return await chooseConformance({ plainFile, specs: fresh, when, ...(model !== undefined ? { model } : {}), ...(budget !== undefined ? { budget } : {}) });
111
- }
112
- catch (error) {
113
- reportActivity(` choosing the conformance tests of ${basename(plainFile)} failed: ${error instanceof Error ? error.message : String(error)}`);
114
- return undefined;
115
- }
116
- };
117
- }
File without changes