@turri-dev/cli 0.1.4-next.318a98a → 0.1.4-next.afc43a8
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/dist/ask.js +34 -15
- package/dist/cli-options.js +12 -6
- package/dist/config-edit.js +1 -0
- package/dist/config.js +5 -2
- package/dist/extension.js +26 -8
- package/dist/init-config.js +5 -0
- package/dist/loop-cli.js +13 -1
- package/dist/loop-tools.js +11 -5
- package/dist/pi.js +76 -19
- package/dist/question-dialog.js +1 -0
- package/dist/regenerate/activity.js +21 -0
- package/dist/regenerate/list-arguments.js +121 -0
- package/dist/regenerate/loop.js +21 -8
- package/dist/regenerate/regenerate.js +4 -2
- package/dist/regenerate/self-check.js +13 -6
- package/dist/regenerate/test-scripts.js +54 -10
- package/dist/regenerate/unit-review.js +1 -1
- package/dist/regenerate-cli.js +11 -5
- package/dist/review/live.js +2 -1
- package/dist/run-report.js +39 -1
- package/docs/authoring-plain.md +3 -1
- package/docs/config.md +3 -2
- package/docs/headless.md +33 -3
- package/docs/regenerating.md +32 -8
- package/docs/skills-and-gates.md +3 -1
- package/docs/using.md +20 -6
- package/genome/rules/func-specs.md +1 -0
- package/genome/rules/project-model.md +5 -3
- package/genome/rules/turri-regeneration.md +36 -0
- package/genome/skills/refactor-module/SKILL.md +24 -2
- package/package.json +1 -1
package/docs/headless.md
CHANGED
|
@@ -86,7 +86,10 @@ Useful options - `turri regenerate --help` lists all of them:
|
|
|
86
86
|
| `--judge-model <provider/id>` | `judge-model`: the judge and the test review; not given, the coding model |
|
|
87
87
|
| `--conformance-tests <all\|chosen\|module\|false>` | `conformance-tests`, with its values (`true` is `all`) |
|
|
88
88
|
| `--review <true\|false>` | `review`: whether the code and its tests are reviewed once they pass |
|
|
89
|
+
| `--mutation-testing <true\|false>` | `mutation-testing`: whether the coding agent and the reviewer have `can_it_fail` |
|
|
89
90
|
| `--stack <name>` | build with the stack's `config.turri.<name>.yaml` over `config.turri.yaml`; default, `TURRI_STACK`, else none |
|
|
91
|
+
| `--from-scratch` | delete the module's code and conformance tests (its lineage keeps them) and regenerate all of it |
|
|
92
|
+
| `--from-scratch-chain` | the same for every module of its requires chain, the base's included, built again from the bottom |
|
|
90
93
|
| `--start-over` | start over, unasked, a codebase built without a module it now requires - without a terminal, a run that needs it and lacks it stops |
|
|
91
94
|
| `--build-dir <dir>` | as the run ends, export the code there - see below |
|
|
92
95
|
| `--report <file.json>` | write [the run report](#the-run-report) there |
|
|
@@ -104,7 +107,8 @@ Conformance tests follow `conformance-tests:` in `config.turri.yaml`, or `--conf
|
|
|
104
107
|
The command exits `0` only when every module is complete: its code regenerated from the spec as it is
|
|
105
108
|
now, and its conformance tests written for what is built when they are on - no pulse failed, nothing
|
|
106
109
|
halted, nothing waiting for a start over. Anything else exits `1`, and the last lines say which
|
|
107
|
-
module is not complete, and why.
|
|
110
|
+
module is not complete, and why. A behaviour the spec leaves open that an agent had to decide is printed
|
|
111
|
+
as a `spec gap` under its pulse, with what was decided meanwhile. The log says, per functionality, what was built and whether its
|
|
108
112
|
tests passed.
|
|
109
113
|
|
|
110
114
|
| | |
|
|
@@ -150,6 +154,7 @@ changes meaning or goes; new fields may appear in the same version. Paths in `pu
|
|
|
150
154
|
"spec_file": "/work/app.plain", "project_dir": "/work", "build_dir": "/work/out", // build_dir: null without one
|
|
151
155
|
"conformance_tests": "all", // all | chosen | module | false
|
|
152
156
|
"review": false,
|
|
157
|
+
"mutation_testing": true,
|
|
153
158
|
"models": {
|
|
154
159
|
"harness": { "model": "…", "thinking": "medium" }, // the planner, the chooser
|
|
155
160
|
"coding": { "model": "…", "thinking": "low" },
|
|
@@ -165,7 +170,7 @@ changes meaning or goes; new fields may appear in the same version. Paths in `pu
|
|
|
165
170
|
"usage": {
|
|
166
171
|
"total": {
|
|
167
172
|
"input_tokens": 0, "output_tokens": 0, "cache_read_tokens": 0, "cache_write_tokens": 0, "cost_usd": 0,
|
|
168
|
-
"llm_calls": 0, "agent_turns": 0, "compactions": 0, "model_seconds": 0
|
|
173
|
+
"llm_calls": 0, "agent_turns": 0, "compactions": 0, "provider_retries": 0, "provider_stalls": 0, "turns_stopped": 0, "model_seconds": 0
|
|
169
174
|
},
|
|
170
175
|
"in_pulses": { }, // the pulses' usage added up - the same fields
|
|
171
176
|
"outside_pulses": { }, // the planner, the conformance chooser, a failed pulse's diagnosis
|
|
@@ -191,6 +196,16 @@ changes meaning or goes; new fields may appear in the same version. Paths in `pu
|
|
|
191
196
|
],
|
|
192
197
|
"codebases": ["plain_modules/app/code"]
|
|
193
198
|
},
|
|
199
|
+
"spec_gaps": [{ // [] when no agent met one
|
|
200
|
+
"module": "app", "pulse": 3, "pulse_id": "2a058729", "landed": true,
|
|
201
|
+
"question": "What happens to a contact archived in HubSpot after it was synced?",
|
|
202
|
+
"assumption": "An archived contact is left as synced - asserted in sync.test.ts, archived contacts"
|
|
203
|
+
}],
|
|
204
|
+
"turn_incidents": [ // [] when none
|
|
205
|
+
{ "kind": "provider_retry", "pulse_id": "2a058729", "role": "coding", "model": "…", "error": "…: 529 overloaded", "attempt": 1, "of": 6, "wait_seconds": 15.3 },
|
|
206
|
+
{ "kind": "provider_stall", "pulse_id": "2a058729", "role": "coding", "model": "…", "silent_seconds": 120 },
|
|
207
|
+
{ "kind": "stopped", "pulse_id": "5c1e0b2f", "role": "conformance explorer", "model": "…", "reason": "10 submit_exploration calls failed in a row" }
|
|
208
|
+
],
|
|
194
209
|
"build_dir_export": { "exported": true, "dir": "/work/out", "module": "app", "commit": "8036b3b", "files": 23 },
|
|
195
210
|
"logs": { "jobs_dir": ".turri/jobs", "debug_dir": ".turri/debug", "sessions_dir": ".turri/sessions" }
|
|
196
211
|
}
|
|
@@ -209,6 +224,21 @@ calls; a role or model turri could not tell is `unknown`.
|
|
|
209
224
|
stopped, or did not pass - and everything it wrote was undone. A pulse that failed is tried once more
|
|
210
225
|
before it counts as failed; both tries are the one pulse.
|
|
211
226
|
|
|
227
|
+
**Spec gaps.** A behaviour the spec leaves open that an agent met and decided on its own - reported with
|
|
228
|
+
`report_spec_gap` (see [regenerating](regenerating.md)). In the chat they are put to you as the pulse ends; a
|
|
229
|
+
headless run has no one to ask, so they are listed here, in the order the pulses started, and printed under the
|
|
230
|
+
pulse that met them. `assumption` is what the agent decided meanwhile, also in the codebase's notes'
|
|
231
|
+
assumptions while its pulse is `landed`; a pulse rolled back takes it out of the notes, but the question still
|
|
232
|
+
stands. Settle the ones you care about in the spec and run again.
|
|
233
|
+
|
|
234
|
+
**Turn incidents.** Each time the model provider failed for a moment and pi or turri waited it out before trying
|
|
235
|
+
the request again, each time the provider sent nothing back on a request for two minutes, and each turn turri
|
|
236
|
+
stopped itself - an agent going round in a circle, its calls failing again and again, its time up - after which the
|
|
237
|
+
run carried on. The provider failing or stalling is printed as it happens, in yellow, under the pulse; a stop is
|
|
238
|
+
the work's normal course and is only listed. They are counted in the usage as `provider_retries`,
|
|
239
|
+
`provider_stalls` and `turns_stopped`. Many of any point at the model, not the spec: a provider at its limits, or a
|
|
240
|
+
model too small for the role it was given.
|
|
241
|
+
|
|
212
242
|
**Completed functional specs** - the pass rate, the figure to compare runs by.
|
|
213
243
|
A functional spec is completed when the code record of the codebase the run delivers - the
|
|
214
244
|
furthest-built of the chain, the one `--build-dir` exports - as last committed, holds it as the spec has
|
|
@@ -227,7 +257,7 @@ and modules that are complete are skipped, so it picks up where it stopped - aft
|
|
|
227
257
|
provider outage, or a machine that went to sleep anyway. Whatever the stopped run left
|
|
228
258
|
half-written is undone first: each step starts from the module's last commit. A functionality whose spec has changed
|
|
229
259
|
since counts as not built, so editing the spec and re-running rebuilds what changed. `--from-scratch`
|
|
230
|
-
rebuilds
|
|
260
|
+
rebuilds the module; `--from-scratch-chain` rebuilds every module of its chain.
|
|
231
261
|
|
|
232
262
|
## Rebuilding one functionality
|
|
233
263
|
|
package/docs/regenerating.md
CHANGED
|
@@ -123,7 +123,22 @@ An agent that goes round in a circle - the same tool called with the same argume
|
|
|
123
123
|
nothing in between, or a look (read, grep, find, ls) made again with nothing changed since, however
|
|
124
124
|
many other looks came between, so the same answer comes back - is let through three times; the next
|
|
125
125
|
such call is refused with what is happening, and past six its turn is stopped, and the harness goes on
|
|
126
|
-
from there as after any turn. The arguments are compared whatever order they come in.
|
|
126
|
+
from there as after any turn. The arguments are compared whatever order they come in. So too an agent whose
|
|
127
|
+
calls to one tool fail ten times in a row, nothing going through - a call its arguments do not fit never reaches
|
|
128
|
+
any guard on the tools.
|
|
129
|
+
|
|
130
|
+
A turn turri stops itself - for any of these, or for its time, below - ends as any turn ends: what the agent said
|
|
131
|
+
stands, `[the turn was stopped: ...]` after it, and the caller does what it does when the agent handed nothing over
|
|
132
|
+
(the explorer's fallback, a nudge, a failed round). The abort that ended it is never taken for the provider
|
|
133
|
+
failing; an abort turri did not make still is. A stop is the work's normal course: it is in the pulse's activity
|
|
134
|
+
and log and the run report's `turn_incidents`, but not said in the chat or a headless run's console - those say
|
|
135
|
+
only the model provider failing or stalling.
|
|
136
|
+
|
|
137
|
+
A tool argument that is a list of objects - the explorer's `interfaces` and `plan`, a reviewer's `problems` - is
|
|
138
|
+
what small models get wrong most. Before a call's arguments are checked, a list sent as JSON text, entries sent as
|
|
139
|
+
JSON text, one object for the list, or a list written inside another argument's text
|
|
140
|
+
(`...</tests_reach_it><plan>[...]</plan>`) are taken as the list; what still is not one is refused saying which
|
|
141
|
+
argument, what was sent, each entry's fields and an example (`list-arguments.ts`).
|
|
127
142
|
|
|
128
143
|
The agents with one thing to decide have a budget of tool calls: the judge 30, the test review and the
|
|
129
144
|
explorer 40. Past it every tool but the one that hands the decision over refuses, telling it to decide
|
|
@@ -245,12 +260,18 @@ use each:
|
|
|
245
260
|
- **`my_diff`**: the diff of the code folder from the commit the job started from, new files whole - exactly
|
|
246
261
|
what the reviewer is shown. Read before handing the work in: every part of the change in it, and nothing else.
|
|
247
262
|
- **`can_it_fail`**: whether the unit tests catch a bug. The agent gives one change to a code file - a
|
|
248
|
-
condition turned round, a value changed - and the unit testing script runs
|
|
249
|
-
|
|
263
|
+
condition turned round, a value changed - and the unit testing script runs with it. Where the testing scripts
|
|
264
|
+
run on a copy (`testing-scripts-run-on: copy`), the change is made to a fresh copy and the code itself is never
|
|
265
|
+
touched. In place, the default, it is made to the code itself, so a script that finds the code from its own path
|
|
266
|
+
sees it; the file is put back as it was once the run ends - passed, failed, hung, the script failing to start, the
|
|
267
|
+
script rewriting the file, turri exiting. Killed outright, the next unit of work starts from the last commit anyway.
|
|
268
|
+
It never runs beside another call of the agent's, so no edit lands while the bug is in. What the script does
|
|
269
|
+
beyond the code - a package copied into a host codebase - it does with the bug in, until the next test run puts the
|
|
270
|
+
real code there. If every test still passes, no test catches that bug. Six
|
|
250
271
|
runs a job. A bug often makes the code hang instead - a loop that never ends - so a run may take three times
|
|
251
272
|
as long as the last passing run of the unit tests, within 15 and 60 seconds, and one that does not finish is
|
|
252
|
-
reported as a hang, not as a test that caught it.
|
|
253
|
-
|
|
273
|
+
reported as a hang, not as a test that caught it. `mutation-testing: false` in the [config](config.md) - or
|
|
274
|
+
`turri regenerate --mutation-testing false` - takes it away, from the reviewer too.
|
|
254
275
|
- **`start_service`**, **`service_logs`**, **`stop_service`**: a server or a worker it built, started in the
|
|
255
276
|
background on this machine, behind the same walls as its shell - the command check, the module's environment, the
|
|
256
277
|
OS sandbox, the audit while it comes up - to try from outside with `curl` as a client would. Whatever the stack: the
|
|
@@ -561,7 +582,8 @@ does not find them:
|
|
|
561
582
|
testing-scripts-run-on: copy
|
|
562
583
|
```
|
|
563
584
|
|
|
564
|
-
`can_it_fail`
|
|
585
|
+
`can_it_fail` works either way: on a copy it changes the copy; in place it changes the code for the one run and puts
|
|
586
|
+
it back.
|
|
565
587
|
|
|
566
588
|
### When the environment lacks something
|
|
567
589
|
|
|
@@ -718,7 +740,7 @@ with no agent and no testing script. Moving specs into a module the code was not
|
|
|
718
740
|
change to the code brings that module's code in, so the codebase stops: it has to be started over - its code
|
|
719
741
|
and conformance tests taken out, committed so its history keeps them, and the chain built again from the
|
|
720
742
|
bottom. That is never done unasked. In the chat the model asks the person, saying why, and calls
|
|
721
|
-
`regenerate` with `from_scratch` once they agree; `turri regenerate` and `spec-diff` ask at the terminal, and
|
|
743
|
+
`regenerate` with `from_scratch: "module"` once they agree; `turri regenerate` and `spec-diff` ask at the terminal, and
|
|
722
744
|
`--start-over` agrees in advance - with no terminal and no flag, the run stops there, exit 1, saying so.
|
|
723
745
|
|
|
724
746
|
## Conformance tests
|
|
@@ -1111,7 +1133,9 @@ are the next agent's, and a gap is yours. An agent reports one with `report_spec
|
|
|
1111
1133
|
and the assumption it made meanwhile; turri writes that assumption into the notes' assumptions, so the code built on
|
|
1112
1134
|
it is known for what it is. The gaps a pulse's agents report are said in its report - "Spec gaps its agents met ... Put
|
|
1113
1135
|
each to the user", each with its assumption - so the conversation asks you, and writes the ones you decide into the
|
|
1114
|
-
spec; the pulse that builds the answer finds the assumption it replaces in the notes, and the tests it names.
|
|
1136
|
+
spec; the pulse that builds the answer finds the assumption it replaces in the notes, and the tests it names.
|
|
1137
|
+
A headless run has no one to ask: it prints each gap under its pulse, and lists them in its run report's
|
|
1138
|
+
`spec_gaps` ([running unattended](headless.md#the-run-report)). However many gaps a pulse's agents report, they
|
|
1115
1139
|
are put to you - never a reason to stop the pulse; the tool is guarded like any other. A notes
|
|
1116
1140
|
file from before keeps no spec gaps section: its lines are dropped as it is read.
|
|
1117
1141
|
|
package/docs/skills-and-gates.md
CHANGED
|
@@ -133,7 +133,9 @@ change the step makes and puts its findings on the executor's next tool result.
|
|
|
133
133
|
- **Interview the user.** `ask_user` puts one question to the person. In the TUI it is a dialog;
|
|
134
134
|
from the CLI the options are numbered. Offering choices is required, not optional - a call with
|
|
135
135
|
neither `options` nor `free_form: true` is refused - and every list carries "Something else…".
|
|
136
|
-
`multi_select: true`
|
|
136
|
+
`multi_select: true` gives every option a box, ticked and unticked as it is chosen - a pick made by mistake is
|
|
137
|
+
undone by choosing it again - until they choose Done; what they type is one more box, ticked. "Something
|
|
138
|
+
else…", "Chat about this" and Done are no boxes. The skill's agent talks in a
|
|
137
139
|
session of its own that the person never sees, so what the person must read to answer - the brief
|
|
138
140
|
to confirm, the plan to approve - it passes as `ask_user`'s `context`, shown above the question in
|
|
139
141
|
the dialog; `brood`, `spawn` and `bud` pass their briefs so. The agents are told to keep it to what can be taken in at
|
package/docs/using.md
CHANGED
|
@@ -50,7 +50,7 @@ where it stopped. A project can have skills of its own, in `.turri/skills/` or `
|
|
|
50
50
|
|
|
51
51
|
| tool | |
|
|
52
52
|
| --- | --- |
|
|
53
|
-
| `regenerate` | regenerate a module and its chain from the spec as it is now - after any change to it, by any means: what is left to regenerate is planned into pulses of one to three functional specs, each with the definitions and reqs it uses, and a pulse regenerating what the spec no longer wants is stopped. With functionalities named, those are regenerated though their spec did not change - rewritten or started over, planned into pulses as any change is; with `from_scratch`, the whole module, its code deleted first - only when you ask, or agree |
|
|
53
|
+
| `regenerate` | regenerate a module and its chain from the spec as it is now - after any change to it, by any means: what is left to regenerate is planned into pulses of one to three functional specs, each with the definitions and reqs it uses, and a pulse regenerating what the spec no longer wants is stopped. With functionalities named, those are regenerated though their spec did not change - rewritten or started over, planned into pulses as any change is; with `from_scratch`, the whole module, its code deleted first - `"chain"` for every module of its requires chain too, built again from the bottom - only when you ask, or agree |
|
|
54
54
|
| `drift` | what is left to regenerate: how far the code and its conformance tests have drifted from the spec, starting nothing |
|
|
55
55
|
| `glimpse` | the pulse a module's codebases would start next, and the whole prompt its coding agent would get - starting nothing |
|
|
56
56
|
| `steer` | say how the work is planned - which functional specs go together, what first - for the project or one module, for the session; the next plan follows it, beside what AGENTS.md says under a heading naming the queue |
|
|
@@ -63,7 +63,7 @@ where it stopped. A project can have skills of its own, in `.turri/skills/` or `
|
|
|
63
63
|
| `lineage` | a module's lineage: what each regeneration and conformance run changed in it, and what it was regenerated from |
|
|
64
64
|
| `cultivate` | run a gated skill, its steps and review gates enforced |
|
|
65
65
|
| `release`, `activate` | try what is regenerated: release it to `dist/<module>` and activate it on this machine, installing what it needs - see [deploy](deploy.md) |
|
|
66
|
-
| `ask_user` | put a question to you as a dialog to pick from - several at once, "Something else…" to type, or "Chat about this" to talk it over first; Esc in either goes back to the options |
|
|
66
|
+
| `ask_user` | put a question to you as a dialog to pick from - several at once, each a box you tick and untick, "Something else…" to type, or "Chat about this" to talk it over first; Esc in either goes back to the options |
|
|
67
67
|
| `web_search`, `web_fetch` | search the web and read a page as text - documentation, an API, an error; `curl` and the like run in its `bash` |
|
|
68
68
|
|
|
69
69
|
What each render does, in order, is in [regenerating the code](regenerating.md).
|
|
@@ -238,7 +238,7 @@ come waits for a free slot, and says so.
|
|
|
238
238
|
is laid over `config.turri.yaml` - its testing scripts, toolchains, models - for the session; a pulse already
|
|
239
239
|
running keeps the stack it started with. The chat model switches it too when you ask. See
|
|
240
240
|
[stacks](config.md#stacks).
|
|
241
|
-
- **`/regenerate [module | file.plain] [functionality ...] [from scratch] [how to cut the work]`** regenerates a module from its spec as it is now, as
|
|
241
|
+
- **`/regenerate [module | file.plain] [functionality ...] [from scratch [whole chain]] [how to cut the work]`** regenerates a module from its spec as it is now, as
|
|
242
242
|
the `regenerate` tool does: what is left to regenerate is planned into pulses - one functional spec at a time, a few
|
|
243
243
|
together or the whole module in one, as the planner judges - and the first starts. Words after the module are
|
|
244
244
|
guidance for that plan (`/regenerate app models first`). A module's name typed with spaces for its underscores is
|
|
@@ -246,8 +246,13 @@ come waits for a free slot, and says so.
|
|
|
246
246
|
`config.turri.yaml` names, else the folder's top modules, to pick from. Asked for from scratch - `from scratch`,
|
|
247
247
|
`start over`, `delete the module` - it asks first, then deletes the module's code and conformance tests in every
|
|
248
248
|
codebase where they live, committed so `/lineage` keeps them, and regenerates the whole module from its spec,
|
|
249
|
-
built though nothing in it changed: `/regenerate shorty from scratch`. The
|
|
250
|
-
|
|
249
|
+
built though nothing in it changed: `/regenerate shorty from scratch`. The modules below it keep their code, and
|
|
250
|
+
the module starts again from a copy of the code below it. Asked for its chain too - `/regenerate shorty from scratch,
|
|
251
|
+
the whole chain` - the code of every module of its requires chain is deleted, the base's included, and the whole
|
|
252
|
+
chain is regenerated from the bottom: what to do after modules were split, merged or moved, when the code below was
|
|
253
|
+
laid out for modules that are no more. The chat's `regenerate` does the same with `from_scratch: "module"` or
|
|
254
|
+
`"chain"`, when you ask for it; `turri regenerate --from-scratch` or `--from-scratch-chain` on the command line, not
|
|
255
|
+
with `--dry-run`.
|
|
251
256
|
Functionalities named after the module - `/regenerate shorty 3 5` - are regenerated though their spec did not
|
|
252
257
|
change, on the model chosen for functionalities: as `turri regenerate shorty.plain 3 5` does, and the chat's
|
|
253
258
|
`regenerate` with `functionalities`.
|
|
@@ -390,7 +395,15 @@ To change pi's own default, in `~/.pi/agent/settings.json`:
|
|
|
390
395
|
```
|
|
391
396
|
|
|
392
397
|
A provider failure - no credits, bad key, rate limit - is raised with the provider's own message,
|
|
393
|
-
rather than surfacing as an agent that said nothing.
|
|
398
|
+
rather than surfacing as an agent that said nothing. One that passes - overloaded, rate limited, unreachable,
|
|
399
|
+
timed out - is waited out first, after pi's own retries: six more tries, the wait doubled each time from 15
|
|
400
|
+
seconds up to five minutes (15s, 30s, 1m, 2m, 4m, 5m, a tenth either way so parallel jobs do not all come back
|
|
401
|
+
at once), the agent carrying on where it was. Each wait - pi's own retries too - is shown as it happens - a
|
|
402
|
+
notification in the chat and the job panel's status, a yellow line in a headless run - and listed in the run
|
|
403
|
+
report's `turn_incidents`. So is a provider stalling: a request to the model that nothing has come back on for two
|
|
404
|
+
minutes (`TURRI_PROVIDER_STALL`, in seconds; 0 never), said once for each silence while the turn goes on waiting.
|
|
405
|
+
A turn turri stops itself - its time up, the agent going round in a circle - is the work's normal course and is not
|
|
406
|
+
said, only listed.
|
|
394
407
|
|
|
395
408
|
## Module history
|
|
396
409
|
|
|
@@ -453,6 +466,7 @@ turri regenerate <file.plain> # regenerate what the code is not bui
|
|
|
453
466
|
turri glimpse <file.plain> # plan it, and print the first job's prompt - starts nothing
|
|
454
467
|
turri regenerate <file.plain> 2 # regenerate functionality 2 again, changed or not
|
|
455
468
|
turri regenerate <file.plain> --from-scratch # delete the module's code and tests (its lineage keeps them), regenerate all of it
|
|
469
|
+
turri regenerate <file.plain> --from-scratch-chain # the same for every module of its requires chain, from the bottom
|
|
456
470
|
turri spec-diff <file.plain> <diff> # apply a spec diff, and regenerate it
|
|
457
471
|
turri conform <file.plain> 1 # black-box tests for functionality 1
|
|
458
472
|
turri lineage <module> # what each regeneration changed in a module, and when
|
|
@@ -65,6 +65,7 @@ GOOD — statements of fact with concrete subjects:
|
|
|
65
65
|
- The renderer has **no knowledge of future specs** — only previously rendered specs are in context
|
|
66
66
|
- A new spec can reference behavior from earlier specs but cannot assume anything about specs that come after it
|
|
67
67
|
- Functional specs from `requires` modules are treated as previous requirements — transitively, across the whole ancestor chain
|
|
68
|
+
- This order is about what a spec may assume, not what a change costs: turri regenerates a change as a spec diff wherever it sits (`turri-regeneration.md`)
|
|
68
69
|
|
|
69
70
|
## No conflicts
|
|
70
71
|
- The new spec must not contradict any existing functional spec
|
|
@@ -75,9 +75,11 @@ Parameters are key-value pairs; the template reads them as `{{ variable_name }}`
|
|
|
75
75
|
|
|
76
76
|
## When an earlier test fails after a render
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
Each functional spec is written knowing the ones before it and none after it - a required module's
|
|
79
|
+
specs count as before - so a spec may rely on what earlier ones say, never on later ones. This is
|
|
80
|
+
about what a spec may assume, not what a change costs (`turri-regeneration.md`). After each
|
|
81
|
+
render every conformance test so far runs again. A test that passed before and fails now means one
|
|
82
|
+
of:
|
|
81
83
|
|
|
82
84
|
1. the new code does not satisfy its spec;
|
|
83
85
|
2. the test does not test its spec accurately;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: How turri regenerates the code from a spec change - by spec diff, in the chain's tip - so a spec is placed by what it means, never by what regenerating it would cost
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# How turri regenerates the code
|
|
6
|
+
|
|
7
|
+
The other rules say what a spec means. This one says what turri does with a change to it, so that
|
|
8
|
+
where a change goes is never decided by a wrong idea of what it costs.
|
|
9
|
+
|
|
10
|
+
## A change is regenerated as a spec diff
|
|
11
|
+
|
|
12
|
+
- turri regenerates the code from spec diffs: what changed between the spec the code was built from
|
|
13
|
+
and the spec now
|
|
14
|
+
- A functional spec added, changed or taken out is that change alone, wherever it sits - first, in the
|
|
15
|
+
middle or last of its module
|
|
16
|
+
- The specs around it are not regenerated because their position or numbering moved, and nothing after
|
|
17
|
+
it is built again. A spec inserted in the middle is one addition
|
|
18
|
+
- "Specs render top to bottom, each knowing only the ones before it" is about what a spec may assume
|
|
19
|
+
(`func-specs.md`), not about what a change costs
|
|
20
|
+
|
|
21
|
+
## A change is regenerated in the chain's tip
|
|
22
|
+
|
|
23
|
+
- A chain's code lives in its tip - the furthest module built on it. The modules below it keep the
|
|
24
|
+
code they were built with
|
|
25
|
+
- A change to any module of the chain, the base's included, is regenerated in the tip's code - not in
|
|
26
|
+
the module the change was made in
|
|
27
|
+
- Putting a change in a lower module costs no more than putting it in the tip, and saves nothing
|
|
28
|
+
either
|
|
29
|
+
|
|
30
|
+
## So place a spec by what it means
|
|
31
|
+
|
|
32
|
+
- Put a functional spec where it belongs: in the module that owns the concern, at the point in its
|
|
33
|
+
order where what it relies on has been said
|
|
34
|
+
- Never put a spec at the end of a module, or in the tip, only to spare regeneration - it spares none
|
|
35
|
+
- What does cost more is asked for outright, never brought on by placement: regenerating a functional
|
|
36
|
+
spec again, or a module or chain from scratch
|
|
@@ -21,6 +21,8 @@ allowed-tools: [read, write, edit, bash, ls, grep, find]
|
|
|
21
21
|
|
|
22
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.
|
|
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).
|
|
25
|
+
|
|
24
26
|
## Input
|
|
25
27
|
|
|
26
28
|
The `.plain` file to refactor, plus guidance from the user on the desired grouping (or ask the user to confirm your proposed grouping).
|
|
@@ -90,8 +92,9 @@ Summarize for the user:
|
|
|
90
92
|
- Any new import module being created
|
|
91
93
|
- Which concepts are exported from each module
|
|
92
94
|
- Confirmation that all original specs are accounted for (none lost)
|
|
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
|
|
93
96
|
|
|
94
|
-
Get explicit user confirmation before proceeding.
|
|
97
|
+
Get explicit user confirmation before proceeding — of the split and of regenerating from scratch.
|
|
95
98
|
|
|
96
99
|
## Phase 3 — Execute the Split
|
|
97
100
|
|
|
@@ -162,6 +165,19 @@ For each new module:
|
|
|
162
165
|
|
|
163
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.
|
|
164
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.
|
|
169
|
+
|
|
170
|
+
## Phase 5 — Regenerate the Chain from Scratch
|
|
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.
|
|
173
|
+
|
|
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
|
+
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:
|
|
176
|
+
- in the chat: the `regenerate` tool on the tip's `.plain` file with `from_scratch: "chain"`, or `/regenerate <tip> from scratch, the whole chain`;
|
|
177
|
+
- on the command line: `turri regenerate <tip>.plain --from-scratch-chain`.
|
|
178
|
+
3. **Modules that require the chain** (updated in 3d) are regenerated after it, from scratch too (`from_scratch: "module"`): the modules they require are not the ones their code was built on. When the tip's whole chain is regenerated, a module built on top of it is a chain of its own — regenerating it from scratch with its whole chain instead covers the tip's chain too, in one go.
|
|
179
|
+
4. **The original module's codebase** (`plain_modules/<original-module>/`), when the original module was deleted or renamed, is no longer built from anything. Tell the user it is there; it is theirs to delete. Do not delete it unasked.
|
|
180
|
+
|
|
165
181
|
## Common Pitfalls
|
|
166
182
|
|
|
167
183
|
### Splitting too aggressively
|
|
@@ -179,9 +195,12 @@ This is a refactoring, not a rewrite. Spec text must be copied verbatim. If a sp
|
|
|
179
195
|
### Losing acceptance tests
|
|
180
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.
|
|
181
197
|
|
|
198
|
+
### Regenerating only what changed
|
|
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.
|
|
200
|
+
|
|
182
201
|
## Validation Checklist
|
|
183
202
|
|
|
184
|
-
- [ ] User confirmed the split plan before execution
|
|
203
|
+
- [ ] User confirmed the split plan before execution, including regenerating the whole chain from scratch
|
|
185
204
|
- [ ] All original functional specs are present in exactly one new module — none lost
|
|
186
205
|
- [ ] Spec text is identical to the original — no rewording
|
|
187
206
|
- [ ] Acceptance tests moved with their parent specs
|
|
@@ -194,3 +213,6 @@ Acceptance tests are nested under their parent functional spec. When moving a sp
|
|
|
194
213
|
- [ ] Original module removed or updated
|
|
195
214
|
- [ ] Downstream modules (if any) updated to require the chain tip, plus any earlier chain modules whose exported concepts they reference
|
|
196
215
|
- [ ] User approved the final result
|
|
216
|
+
- [ ] Every new module validates
|
|
217
|
+
- [ ] The tip of the chain regenerated from scratch with its whole chain, then any module that requires it
|
|
218
|
+
- [ ] User told about the original module's leftover codebase, if there is one
|