@turri-dev/cli 0.0.0-stage → 0.1.1

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 (315) hide show
  1. package/.pi/themes/turri-dark.json +80 -0
  2. package/.pi/themes/turri-light.json +82 -0
  3. package/LICENSE +21 -0
  4. package/README.md +272 -2
  5. package/assets/jellyfish/dark-00.png +0 -0
  6. package/assets/jellyfish/dark-01.png +0 -0
  7. package/assets/jellyfish/dark-02.png +0 -0
  8. package/assets/jellyfish/dark-03.png +0 -0
  9. package/assets/jellyfish/dark-04.png +0 -0
  10. package/assets/jellyfish/dark-05.png +0 -0
  11. package/assets/jellyfish/dark-06.png +0 -0
  12. package/assets/jellyfish/dark-07.png +0 -0
  13. package/assets/jellyfish/dark-08.png +0 -0
  14. package/assets/jellyfish/dark-09.png +0 -0
  15. package/assets/jellyfish/dark-10.png +0 -0
  16. package/assets/jellyfish/dark-11.png +0 -0
  17. package/assets/jellyfish/dark-12.png +0 -0
  18. package/assets/jellyfish/dark-13.png +0 -0
  19. package/assets/jellyfish/dark-14.png +0 -0
  20. package/assets/jellyfish/fallback.txt +252 -0
  21. package/assets/jellyfish/light-00.png +0 -0
  22. package/assets/jellyfish/light-01.png +0 -0
  23. package/assets/jellyfish/light-02.png +0 -0
  24. package/assets/jellyfish/light-03.png +0 -0
  25. package/assets/jellyfish/light-04.png +0 -0
  26. package/assets/jellyfish/light-05.png +0 -0
  27. package/assets/jellyfish/light-06.png +0 -0
  28. package/assets/jellyfish/light-07.png +0 -0
  29. package/assets/jellyfish/light-08.png +0 -0
  30. package/assets/jellyfish/light-09.png +0 -0
  31. package/assets/jellyfish/light-10.png +0 -0
  32. package/assets/jellyfish/light-11.png +0 -0
  33. package/assets/jellyfish/light-12.png +0 -0
  34. package/assets/jellyfish/light-13.png +0 -0
  35. package/assets/jellyfish/light-14.png +0 -0
  36. package/bin/turri.mjs +29 -0
  37. package/dist/ask.js +149 -0
  38. package/dist/brand.js +50 -0
  39. package/dist/btw.js +174 -0
  40. package/dist/chat-models.js +37 -0
  41. package/dist/chat-skills.js +18 -0
  42. package/dist/cli.js +178 -0
  43. package/dist/config-command.js +197 -0
  44. package/dist/config-edit.js +367 -0
  45. package/dist/config.js +489 -0
  46. package/dist/conform-cli.js +29 -0
  47. package/dist/cultivate-cli.js +110 -0
  48. package/dist/drift-cli.js +25 -0
  49. package/dist/environment.js +70 -0
  50. package/dist/extension.js +2372 -0
  51. package/dist/genome.js +301 -0
  52. package/dist/graph.js +246 -0
  53. package/dist/identity.js +35 -0
  54. package/dist/init-config.js +511 -0
  55. package/dist/judge.js +62 -0
  56. package/dist/lineage-cli.js +13 -0
  57. package/dist/loop-cli.js +132 -0
  58. package/dist/loop-tools.js +225 -0
  59. package/dist/mature-tools.js +193 -0
  60. package/dist/model-check.js +117 -0
  61. package/dist/module-report.js +9 -0
  62. package/dist/pi-launch.js +31 -0
  63. package/dist/pi.js +813 -0
  64. package/dist/plain/check.js +76 -0
  65. package/dist/plain/concepts.js +213 -0
  66. package/dist/plain/errors.js +43 -0
  67. package/dist/plain/files.js +57 -0
  68. package/dist/plain/highlight.js +195 -0
  69. package/dist/plain/index.js +15 -0
  70. package/dist/plain/liquid.js +129 -0
  71. package/dist/plain/markdown.js +208 -0
  72. package/dist/plain/parser.js +752 -0
  73. package/dist/plain/plain.tmLanguage.json +124 -0
  74. package/dist/plain/spec.js +291 -0
  75. package/dist/plain/stdlib.js +44 -0
  76. package/dist/question-dialog.js +125 -0
  77. package/dist/questioning.js +109 -0
  78. package/dist/quiet.js +125 -0
  79. package/dist/regenerate/activity.js +187 -0
  80. package/dist/regenerate/agent-env.js +190 -0
  81. package/dist/regenerate/agent-shell.js +114 -0
  82. package/dist/regenerate/arbiter.js +133 -0
  83. package/dist/regenerate/audit.js +203 -0
  84. package/dist/regenerate/cases.js +83 -0
  85. package/dist/regenerate/change-view.js +102 -0
  86. package/dist/regenerate/choose-conformance.js +117 -0
  87. package/dist/regenerate/chunk-plan.js +625 -0
  88. package/dist/regenerate/codebase.js +75 -0
  89. package/dist/regenerate/command-check.js +312 -0
  90. package/dist/regenerate/compaction.js +20 -0
  91. package/dist/regenerate/confine.js +310 -0
  92. package/dist/regenerate/conform.js +133 -0
  93. package/dist/regenerate/conformance-agents.js +955 -0
  94. package/dist/regenerate/conformance.js +936 -0
  95. package/dist/regenerate/conversation-writes.js +100 -0
  96. package/dist/regenerate/credentials.js +88 -0
  97. package/dist/regenerate/debug-log.js +228 -0
  98. package/dist/regenerate/debugger.js +90 -0
  99. package/dist/regenerate/delivery.js +19 -0
  100. package/dist/regenerate/diagnose-job.js +40 -0
  101. package/dist/regenerate/diagnose.js +81 -0
  102. package/dist/regenerate/diff-view.js +240 -0
  103. package/dist/regenerate/drift.js +194 -0
  104. package/dist/regenerate/engine.js +118 -0
  105. package/dist/regenerate/environment-error.js +220 -0
  106. package/dist/regenerate/job-log.js +102 -0
  107. package/dist/regenerate/job-panel.js +336 -0
  108. package/dist/regenerate/jobs-tree.js +300 -0
  109. package/dist/regenerate/jobs.js +427 -0
  110. package/dist/regenerate/lanes.js +32 -0
  111. package/dist/regenerate/lineage.js +384 -0
  112. package/dist/regenerate/loop.js +1435 -0
  113. package/dist/regenerate/masking.js +95 -0
  114. package/dist/regenerate/notes.js +397 -0
  115. package/dist/regenerate/os-sandbox.js +243 -0
  116. package/dist/regenerate/paths.js +165 -0
  117. package/dist/regenerate/plain-palette.js +83 -0
  118. package/dist/regenerate/prompt.js +704 -0
  119. package/dist/regenerate/records.js +294 -0
  120. package/dist/regenerate/regenerate.js +598 -0
  121. package/dist/regenerate/regression.js +181 -0
  122. package/dist/regenerate/release.js +262 -0
  123. package/dist/regenerate/requires.js +241 -0
  124. package/dist/regenerate/resources.js +164 -0
  125. package/dist/regenerate/self-check.js +111 -0
  126. package/dist/regenerate/services.js +155 -0
  127. package/dist/regenerate/shell.js +319 -0
  128. package/dist/regenerate/side-panel.js +278 -0
  129. package/dist/regenerate/spec-map-view.js +574 -0
  130. package/dist/regenerate/spec-map.js +561 -0
  131. package/dist/regenerate/spec-steps.js +527 -0
  132. package/dist/regenerate/state.js +10 -0
  133. package/dist/regenerate/steer.js +91 -0
  134. package/dist/regenerate/steering.js +119 -0
  135. package/dist/regenerate/stop-report.js +161 -0
  136. package/dist/regenerate/submit-work.js +71 -0
  137. package/dist/regenerate/test-kinds.js +124 -0
  138. package/dist/regenerate/test-scripts.js +695 -0
  139. package/dist/regenerate/testing.js +406 -0
  140. package/dist/regenerate/transcript-view.js +1 -0
  141. package/dist/regenerate/unit-gate.js +20 -0
  142. package/dist/regenerate/unit-review.js +347 -0
  143. package/dist/regenerate/web.js +256 -0
  144. package/dist/regenerate/workspace.js +99 -0
  145. package/dist/regenerate-cli.js +68 -0
  146. package/dist/release-agent.js +114 -0
  147. package/dist/release-cli.js +131 -0
  148. package/dist/release-tools.js +148 -0
  149. package/dist/review/live.js +165 -0
  150. package/dist/rules.js +47 -0
  151. package/dist/self-invocation.js +110 -0
  152. package/dist/setup.js +245 -0
  153. package/dist/skill-progress.js +78 -0
  154. package/dist/skill.js +149 -0
  155. package/dist/skills.js +74 -0
  156. package/dist/spec-diff-cli.js +37 -0
  157. package/dist/spec-tools.js +155 -0
  158. package/dist/stack.js +158 -0
  159. package/dist/stacks.js +97 -0
  160. package/dist/stdlib.js +100 -0
  161. package/dist/terminal-images.js +46 -0
  162. package/dist/tools.js +242 -0
  163. package/dist/validate-cli.js +52 -0
  164. package/docs/README.md +58 -0
  165. package/docs/authoring-plain.md +245 -0
  166. package/docs/config.md +353 -0
  167. package/docs/deploy.md +109 -0
  168. package/docs/development.md +75 -0
  169. package/docs/headless.md +148 -0
  170. package/docs/images/how-turri-works.svg +50 -0
  171. package/docs/images/turri-banner.png +0 -0
  172. package/docs/installation.md +118 -0
  173. package/docs/parser.md +108 -0
  174. package/docs/regenerating.md +1116 -0
  175. package/docs/sandbox.md +233 -0
  176. package/docs/skills-and-gates.md +254 -0
  177. package/docs/theming.md +76 -0
  178. package/docs/using.md +454 -0
  179. package/genome/rules/bullet-continuation.md +69 -0
  180. package/genome/rules/concise-specs-examples.md +431 -0
  181. package/genome/rules/concise-specs-integration-examples.md +270 -0
  182. package/genome/rules/concise-specs.md +80 -0
  183. package/genome/rules/definitions.md +107 -0
  184. package/genome/rules/examples/integration-embedded-testing/run_conformance_tests_java.sh +163 -0
  185. package/genome/rules/examples/integration-embedded-testing/run_unittests_java.sh +51 -0
  186. package/genome/rules/exported-concepts.md +39 -0
  187. package/genome/rules/func-specs.md +129 -0
  188. package/genome/rules/impl-reqs.md +68 -0
  189. package/genome/rules/import-modules.md +48 -0
  190. package/genome/rules/integration-embedded-testing.md +276 -0
  191. package/genome/rules/integration-embedded.md +171 -0
  192. package/genome/rules/integration-standalone.md +135 -0
  193. package/genome/rules/integrations.md +137 -0
  194. package/genome/rules/linked-resources.md +69 -0
  195. package/genome/rules/module-structure.md +105 -0
  196. package/genome/rules/project-model.md +88 -0
  197. package/genome/rules/required-concepts.md +44 -0
  198. package/genome/rules/requires-modules.md +80 -0
  199. package/genome/rules/stdlib.md +73 -0
  200. package/genome/rules/test-reqs.md +57 -0
  201. package/genome/skills/add-acceptance-test/SKILL.md +100 -0
  202. package/genome/skills/add-concept/SKILL.md +71 -0
  203. package/genome/skills/add-functional-spec/SKILL.md +84 -0
  204. package/genome/skills/add-functional-specs/SKILL.md +118 -0
  205. package/genome/skills/add-implementation-requirement/SKILL.md +86 -0
  206. package/genome/skills/add-resource/SKILL.md +105 -0
  207. package/genome/skills/add-template/SKILL.md +64 -0
  208. package/genome/skills/add-test-requirement/SKILL.md +73 -0
  209. package/genome/skills/analyze-2-func-specs/SKILL.md +101 -0
  210. package/genome/skills/analyze-func-specs/SKILL.md +123 -0
  211. package/genome/skills/analyze-if-func-spec-too-complex/SKILL.md +211 -0
  212. package/genome/skills/break-down-func-spec/SKILL.md +205 -0
  213. package/genome/skills/brood/SKILL.md +229 -0
  214. package/genome/skills/brood/references/intent.md +35 -0
  215. package/genome/skills/brood/references/product.md +101 -0
  216. package/genome/skills/brood/references/stack.md +61 -0
  217. package/genome/skills/brood/references/testing.md +56 -0
  218. package/genome/skills/bud/SKILL.md +148 -0
  219. package/genome/skills/bud/references/checklist.md +44 -0
  220. package/genome/skills/bud/references/intent.md +30 -0
  221. package/genome/skills/check-plain-env/SKILL.md +285 -0
  222. package/genome/skills/consolidate-concepts/SKILL.md +192 -0
  223. package/genome/skills/create-import-module/SKILL.md +104 -0
  224. package/genome/skills/create-requires-module/SKILL.md +109 -0
  225. package/genome/skills/debug-specs/SKILL.md +188 -0
  226. package/genome/skills/implement-conformance-testing-script/SKILL.md +238 -0
  227. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_cypress.ps1 +337 -0
  228. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_golang.ps1 +111 -0
  229. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +136 -0
  230. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.ps1 +103 -0
  231. package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +150 -0
  232. package/genome/skills/implement-unit-testing-script/SKILL.md +160 -0
  233. package/genome/skills/implement-unit-testing-script/assets/run_unittests_flutter.ps1 +87 -0
  234. package/genome/skills/implement-unit-testing-script/assets/run_unittests_golang.ps1 +73 -0
  235. package/genome/skills/implement-unit-testing-script/assets/run_unittests_java.sh +72 -0
  236. package/genome/skills/implement-unit-testing-script/assets/run_unittests_python.ps1 +81 -0
  237. package/genome/skills/implement-unit-testing-script/assets/run_unittests_python.sh +98 -0
  238. package/genome/skills/implement-unit-testing-script/assets/run_unittests_react.ps1 +87 -0
  239. package/genome/skills/init-plain-project/SKILL.md +117 -0
  240. package/genome/skills/init-plain-project/references/checklist.md +30 -0
  241. package/genome/skills/mature/SKILL.md +126 -0
  242. package/genome/skills/refactor-module/SKILL.md +196 -0
  243. package/genome/skills/resolve-section-ownership/SKILL.md +64 -0
  244. package/genome/skills/resolve-spec-conflict/SKILL.md +96 -0
  245. package/genome/skills/spawn/SKILL.md +163 -0
  246. package/package.json +68 -4
  247. package/stdlib/backend/common.plain +25 -0
  248. package/stdlib/backend/conformance/common.plain +12 -0
  249. package/stdlib/backend/conformance/go-gin.plain +9 -0
  250. package/stdlib/backend/conformance/go-nethttp.plain +9 -0
  251. package/stdlib/backend/conformance/java-springboot.plain +9 -0
  252. package/stdlib/backend/conformance/python-django.plain +9 -0
  253. package/stdlib/backend/conformance/python-fastapi.plain +9 -0
  254. package/stdlib/backend/conformance/python-flask.plain +9 -0
  255. package/stdlib/backend/conformance/rust-axum.plain +9 -0
  256. package/stdlib/backend/conformance/typescript-express.plain +9 -0
  257. package/stdlib/backend/conformance/typescript-fastify.plain +9 -0
  258. package/stdlib/backend/conformance/typescript-nestjs.plain +9 -0
  259. package/stdlib/backend/go-gin.plain +18 -0
  260. package/stdlib/backend/go-nethttp.plain +18 -0
  261. package/stdlib/backend/java-springboot.plain +19 -0
  262. package/stdlib/backend/python-django.plain +19 -0
  263. package/stdlib/backend/python-fastapi.plain +23 -0
  264. package/stdlib/backend/python-flask.plain +23 -0
  265. package/stdlib/backend/rust-axum.plain +17 -0
  266. package/stdlib/backend/typescript-express.plain +19 -0
  267. package/stdlib/backend/typescript-fastify.plain +19 -0
  268. package/stdlib/backend/typescript-nestjs.plain +19 -0
  269. package/stdlib/cli/common.plain +17 -0
  270. package/stdlib/cli/conformance/common.plain +11 -0
  271. package/stdlib/cli/conformance/go-cobra.plain +9 -0
  272. package/stdlib/cli/conformance/go-flag.plain +9 -0
  273. package/stdlib/cli/conformance/java-picocli.plain +9 -0
  274. package/stdlib/cli/conformance/python-argparse.plain +9 -0
  275. package/stdlib/cli/conformance/python-click.plain +9 -0
  276. package/stdlib/cli/conformance/python-typer.plain +9 -0
  277. package/stdlib/cli/conformance/rust-clap.plain +9 -0
  278. package/stdlib/cli/conformance/typescript-commander.plain +9 -0
  279. package/stdlib/cli/go-cobra.plain +14 -0
  280. package/stdlib/cli/go-flag.plain +14 -0
  281. package/stdlib/cli/java-picocli.plain +15 -0
  282. package/stdlib/cli/python-argparse.plain +18 -0
  283. package/stdlib/cli/python-click.plain +16 -0
  284. package/stdlib/cli/python-typer.plain +16 -0
  285. package/stdlib/cli/rust-clap.plain +14 -0
  286. package/stdlib/cli/typescript-commander.plain +17 -0
  287. package/stdlib/frontend/angular.plain +17 -0
  288. package/stdlib/frontend/common.plain +17 -0
  289. package/stdlib/frontend/conformance/angular.plain +5 -0
  290. package/stdlib/frontend/conformance/common.plain +11 -0
  291. package/stdlib/frontend/conformance/react-vite.plain +5 -0
  292. package/stdlib/frontend/conformance/sveltekit-spa.plain +5 -0
  293. package/stdlib/frontend/conformance/vue-vite.plain +5 -0
  294. package/stdlib/frontend/react-vite.plain +16 -0
  295. package/stdlib/frontend/sveltekit-spa.plain +16 -0
  296. package/stdlib/frontend/vue-vite.plain +16 -0
  297. package/stdlib/lang/go.plain +13 -0
  298. package/stdlib/lang/java.plain +12 -0
  299. package/stdlib/lang/python.plain +18 -0
  300. package/stdlib/lang/rust.plain +12 -0
  301. package/stdlib/lang/typescript.plain +13 -0
  302. package/stdlib/library/common.plain +15 -0
  303. package/stdlib/library/conformance/common.plain +9 -0
  304. package/stdlib/library/conformance/go.plain +9 -0
  305. package/stdlib/library/conformance/java-gradle.plain +9 -0
  306. package/stdlib/library/conformance/java-maven.plain +9 -0
  307. package/stdlib/library/conformance/python.plain +9 -0
  308. package/stdlib/library/conformance/rust.plain +9 -0
  309. package/stdlib/library/conformance/typescript.plain +9 -0
  310. package/stdlib/library/go.plain +12 -0
  311. package/stdlib/library/java-gradle.plain +13 -0
  312. package/stdlib/library/java-maven.plain +13 -0
  313. package/stdlib/library/python.plain +13 -0
  314. package/stdlib/library/rust.plain +12 -0
  315. package/stdlib/library/typescript.plain +15 -0
@@ -0,0 +1,1116 @@
1
+ # Regenerating the code
2
+
3
+ What happens when a spec is turned into code - in which order, by which agents, and what has to
4
+ be true before the harness moves on. The order is the harness's, not the agents': an agent writes
5
+ code or tests, and the harness decides what runs next and whether the work is done.
6
+
7
+ ## Where things go
8
+
9
+ A spec is built in its **project**: the nearest folder, from the spec's own up, that holds a
10
+ `config.turri.yaml`, a stack's `config.turri.<stack>.yaml`, the old `config.yaml` or a `plain_modules/` -
11
+ or, with none, the spec's own folder. That is where its
12
+ `plain_modules/` is, its `config.turri.yaml` read and its testing scripts found, wherever turri was
13
+ started: a project that keeps its specs in `plain/`, with `plain/config.turri.yaml` and
14
+ `plain/plain_modules/`, builds `plain/hubspot.plain` in `plain/plain_modules/hubspot/`, named from
15
+ the folder above. Links in a spec are relative to the spec.
16
+
17
+ Every path below is in the project. What the person writes:
18
+
19
+ | | |
20
+ | --- | --- |
21
+ | `config.turri.yaml`, `config.turri.<stack>.yaml` | the project config, and each stack's, laid over it while the stack is chosen - see [the project config](config.md) |
22
+ | `test_scripts/run_unittests_<lang>.sh`, `test_scripts/run_conformance_tests_<lang>.sh` | the testing scripts, the only judges of pass or fail - their static checks included, the formatter, linter and type checker - where `config.turri.yaml` names them, else in the project folder, else in `test_scripts/` - see [below](#the-testing-scripts) |
23
+ | `AGENTS.md` | optional: a section whose heading names the queue steers how the work is cut - see [how the work is cut into jobs](#how-the-work-is-cut-into-jobs) |
24
+
25
+ What a module is - each module's folder, its own git history:
26
+
27
+ | | |
28
+ | --- | --- |
29
+ | `plain_modules/<module>/code/` | the implementation and its unit tests |
30
+ | `plain_modules/<module>/tests/` | the black-box conformance tests, organised however suits them |
31
+ | `plain_modules/<module>/code/.turri.json` | the code record: the spec the code is built from - see [below](#what-the-code-is-built-from) |
32
+ | `plain_modules/<module>/tests/.turri.json` | the tests record: what the conformance tests are written for - see [below](#what-the-code-is-built-from) |
33
+ | `plain_modules/<module>/code/.turri-notes.md` | the working notes of the agents that work on the code - coding agents, reviewers, the code fixer, the repair agent - see [below](#working-notes) |
34
+ | `plain_modules/<module>/tests/.turri-notes.md` | the conformance tests' own working notes: the conformance agent's, its runs' attempts, what its reviews let go, its pulses - never read by a coding agent |
35
+ | `plain_modules/<module>/.plaingit` | the module's history: code, tests and both records, committed together - see [using](using.md#module-history) |
36
+
37
+ A module that `requires` another starts from a copy of that module's code and tests, and builds on
38
+ top of it; the latest module built in a chain is where later changes to any module of the chain
39
+ are made. What that code implements comes with it, as built: the other module's definitions and
40
+ implementation reqs, tagged with it, and its functional specs, as ones the new module inherits. A
41
+ definition or req of the module's own spec that a module below already has, word for word, is not new
42
+ work for it: the code implements it already.
43
+
44
+ The harness's scratch - each ignores itself, and is never part of a module's history:
45
+
46
+ | | |
47
+ | --- | --- |
48
+ | `plain_modules/.turri/` | what turri keeps beside the code - see [sandbox](sandbox.md#what-turri-keeps-beside-the-code) |
49
+ | `plain_modules/.turri/cache/` | the package caches, so a dependency is fetched once |
50
+ | `plain_modules/.turri/scripts/` | the copies each testing script run happens in, one folder a run |
51
+ | `plain_modules/.turri/logs/` | the whole output of each run or command an agent was shown cut short, by time and what ran - read by agents only through `read_output` |
52
+ | `.turri/jobs/` | each job's log: its diff, its stages, its agents and what they cost, and which walls were up under its agents' commands |
53
+ | `.turri/debug/` | each agent's log: its prompt, every tool call and every answer |
54
+ | `.turri/sessions/` | the agents' saved sessions |
55
+ | `.turri/runs/<skill>/` | a gated skill's run: what an interrupted one resumes from, and its gates' evidence |
56
+ | `.turri/deploy/` | the output of what `deploy` started |
57
+ | `dist/<module>/` | what `deploy` puts out: the module's code as its last commit has it, replaced whole each time - see [deploy](deploy.md) |
58
+
59
+ ### Parts on different stacks
60
+
61
+ One project can hold modules that share nothing but a common module - a Python backend and a React
62
+ frontend side by side, each importing `base`, neither requiring the other. Each stack gets its testing
63
+ scripts, models and conformance in its own `config.turri.<stack>.yaml`, laid over `config.turri.yaml`
64
+ while it is chosen - `/stack backend` in the chat, `--stack backend` on the command line: see
65
+ [the project config](config.md#stacks).
66
+
67
+ ## One job
68
+
69
+ Every piece of work on the code is a job of the work loop (see [a whole module](#a-whole-module)) - in the chat, a
70
+ **pulse** - the side panel's **regen** is the spec with how much of it the code has been regenerated from (`spec-map.ts`),
71
+ and its pulses every one of them - while the code and this page call it a job: a
72
+ spec diff that takes the code from the spec it is built from to the spec the job ends on. To see what
73
+ the first jobs would be told:
74
+
75
+ ```bash
76
+ turri regenerate <file.plain> --dry-run # plan the work, print each codebase's first prompt, start nothing
77
+ ```
78
+
79
+ ### What the agent is given
80
+
81
+ The prompt, and nothing else - the agent cannot read the `.plain` files. Every prompt for an agent
82
+ that builds, tests or judges from the spec starts with how to read it: what each section is for
83
+ (the implementation reqs bind the whole codebase; acceptance tests carry the same authority as
84
+ their functionality) and what the predefined concepts mean - `:Implementation:`, `:UnitTests:`,
85
+ `:ConformanceTests:` and the rest, used in every spec and defined in none. It also says how a
86
+ failure is fixed without hiding it: no changing test data to get a pass, no mocking the system
87
+ under test, no skipping or silencing a failing test. It holds the definitions
88
+ and implementation reqs in scope, every functionality already built (the required modules' too)
89
+ marked as implemented, a map of the codebase as it stands, the contents of any linked resources,
90
+ and the change to build, section by section, with what to do with each functional spec it touches
91
+ (see [what a job is given](#what-a-job-is-given-and-what-it-records)):
92
+
93
+ ```
94
+ <definitions> … </definitions>
95
+ <implementation reqs> … </implementation reqs>
96
+ <already implemented> … </already implemented>
97
+ <codebase> … </codebase>
98
+ <linked resources> … </linked resources>
99
+ <spec change> … </spec change>
100
+ ```
101
+
102
+ The test reqs and the acceptance tests are not in it: they are the conformance agents'.
103
+
104
+ Every section has one name, its tag's, in every prompt: how to read the spec introduces each one as
105
+ `<definitions>`, `<implementation reqs>`, `<test reqs>`, `<functional specs>` (each functional spec
106
+ a `<functionality module="…" id="…">`), `<acceptance tests>`, `<linked resources>` and
107
+ `<spec change>`, and the prompts' own words call each section by that name. The `***definitions***`
108
+ headings of a `.plain` file appear only where a spec change could not be told section by section
109
+ and the agent is given the raw diff: it is then told which tag each heading is. A spec in full -
110
+ the planner's, the spec-steps agent's, the conformance agents' - is laid out in the same tags.
111
+
112
+ A module that `requires` another inherits its functional specs; one that `import`s another
113
+ inherits its definitions, implementation reqs and test reqs.
114
+
115
+ Template search order: the plain file's own directory, then a sibling `template/`, then
116
+ `--template-dir`, then `PLAIN_TEMPLATE_DIRS`.
117
+
118
+ An agent that goes round in a circle - the same tool called with the same arguments again and again,
119
+ nothing in between, or a look (read, grep, find, ls) made again with nothing changed since, however
120
+ many other looks came between, so the same answer comes back - is let through three times; the next
121
+ such call is refused with what is happening, and past six its turn is stopped, and the harness goes on
122
+ from there as after any turn. The arguments are compared whatever order they come in.
123
+
124
+ The agents with one thing to decide have a budget of tool calls: the judge 30, the test review and the
125
+ explorer 40. Past it every tool but the one that hands the decision over refuses, telling it to decide
126
+ with what it knows; past twice the budget its turn is stopped. Handing the decision over starts the
127
+ count again - a reviewer kept for the next review gets its whole budget for it. And every turn of an agent a render
128
+ starts has two minutes (`turn-limit:` in the [config](config.md), in seconds; 0 for none). When they are up its turn ends at its next
129
+ request to the model - never in the middle of one, which the provider bills whole, uncached, for an answer thrown
130
+ away: what is running then, the model answering or a tool, finishes first, within a grace of a minute
131
+ (TURRI_TURN_GRACE) after which it is ended where it is. The harness takes it from there - it runs the tests, and
132
+ judges.
133
+ A code fix has to build and pass the code's unit tests before the conformance suite runs again: one
134
+ that does not goes straight back to the coding agent, with the output, rather than to a judge. So is an agent whose calls to one tool fail ten times in a row with nothing going through
135
+ in between - arguments the tool refuses never reach it, so however they are reworded, no call-by-call
136
+ check sees them. A note's section is taken in any wording (`where`, "Where things are"), and one that is
137
+ no section is refused with the four that are.
138
+
139
+ ### The tests must actually pass
140
+
141
+ While it works, the agent runs tests however it likes with `bash` - one file, one case, any
142
+ configuration - in the [sandbox](sandbox.md). Before it finishes, it calls `run_unit_tests`: a final
143
+ check that takes no command and runs the project's unit testing script exactly as the harness will.
144
+ But a job is not done on the agent's run, whatever it ran: after each turn **the harness
145
+ runs the unit testing script itself**, and only that run counts (see
146
+ [the testing scripts](#the-testing-scripts)). It sends the agent back, up to 20 times, when:
147
+
148
+ - **The harness's run of the unit testing script fails** - its output goes back to the agent, with how
149
+ to fix it, as every failure an agent is sent back with does (unit tests, a conformance run, a test or
150
+ code the judge found wrong): understand the failure from its whole trace; find the root cause in the
151
+ lines it points at, against the spec; reproduce it with that one test; fix the cause; check it with
152
+ that test and then the whole suite, the run that counts; and leave the cause and the fix in the notes.
153
+ **The same failure three times running** - the same fingerprint of the run, its numbers, paths and ids
154
+ left out, as a conformance run counts it - and a **debugger** looks at it with fresh eyes: an agent of its
155
+ own (`src/regenerate/debugger.ts`), on the `debugger` role's model, else a stronger one than the coding agent's - the
156
+ judge model when `judge-model` is set, else the harness model - with a new session,
157
+ that reads the failing run, the tests, the code, the build files and the unit testing script, and the web,
158
+ and changes nothing. It hands over the root cause and the fix - which files, what to change - and the
159
+ coding agent gets them with the failure, told to make that fix rather than another variation on what it
160
+ tried. An agent circles a cause it has not thought of - an in-memory database every connection opens
161
+ empty, a test runner that leaves the code off its path - and this is the way out. The rounds go on as
162
+ before, up to 20; should the same failure come round three times again, the debugger looks again.
163
+ - **It goes round in circles in its own runs.** An agent stuck on a failure can try the same few changes in
164
+ turn - three signatures of a stand-in function, say - and run the tests after each, dozens of times in one
165
+ turn. Its own `run_unit_tests` runs are watched (`createLoopWatch` in `test-scripts.ts`): the code folder back
166
+ exactly as it was at an earlier failing run, its notes aside, or six failing runs in a row the same way, is a
167
+ loop. The first time, the run tells it so - stop editing, read the code under test where the failure points,
168
+ then make the one change the cause calls for. The second time, its turn is ended there, and the debugger looks
169
+ at once, without waiting for three rounds. A passing run clears it.
170
+ - **Tests went missing.** The test files present before the turn are inventoried and compared
171
+ afterwards; a deleted file or a file that lost cases is challenged by name.
172
+ - **The static checks fail** - when the unit testing script runs them, it exits 80 for the tests passing and its
173
+ checks not, and the agent is sent back saying so, with the findings (see [the static checks](#the-static-checks)).
174
+ They share the same 20 rounds - a static check is part of what "the unit tests pass" means here, not a gate after it.
175
+ - **It wrote nothing.** A turn can end with the agent having only thought the problem through, and
176
+ the code folder as it found it (notes aside). That leaves nothing to test or review. So before the
177
+ tests run, the agent is told to stop planning and write a draft: its best guess at what the spec
178
+ asks, the code and its unit tests, with any assumption put in the notes. A draft that is wrong
179
+ comes back from the tests and the review; nothing written cannot. It is asked once, to write the
180
+ change or say why it needs no code: one that only rewords a spec may need none. After that, the
181
+ turn is taken as what it did.
182
+
183
+ **Long output.** A testing script's run is shown whole up to 16,000 characters. Past that the agent is shown its
184
+ failures, each with the 20 lines after it - its trace - its counts (`Tests run:`, `Ran 3 tests`, `BUILD FAILURE`) and
185
+ its last 80 lines, with DEBUG and TRACE logging left out and each gap marked: on the hycu runs, 73% less to carry, every
186
+ failing run's failures still there. Any other output an agent is shown is whole up to 60,000 characters, and past that
187
+ its end. The whole of it is kept in `plain_modules/.turri/logs/`, and the cut names it by an id:
188
+ the agent reads it with `read_output` - a range of lines, or the lines matching a pattern, each with its number -
189
+ which reads those kept outputs and nothing else. A command in its shell cut short by pi is kept the same way. No
190
+ output points at a path: the file it is in is outside what the agent may reach.
191
+
192
+ A test may go only when it asserts nothing meaningful - it cannot fail, exactly duplicates
193
+ another, or tests something the spec does not require. Inconvenient, slow or failing are not
194
+ grounds. Justified removals are reported, not silent. The baseline is taken before the agent
195
+ starts, so breaking an earlier functionality's test is caught too.
196
+
197
+ ### The static checks
198
+
199
+ The static checks - the formatter in check mode, the linter, the type checker - are the testing scripts' own. There is
200
+ no script for them apart: each testing script runs them on what it tests, in the environment it has just set up, and
201
+ they count as its tests do. The unit testing script checks the code; the conformance testing script checks the tests
202
+ alone, against the build it has staged and installed, so tests that reach the code - a library's, through its package -
203
+ are checked where they resolve, never on their own. A compiled language's type check is its compiler, which the tests
204
+ already run; its formatter and linter are the script's to add. turri does not care which tools: the scripts name them,
205
+ and the `implement-unit-testing-script` and `implement-conformance-testing-script` skills say which each language takes.
206
+
207
+ - **Exit 80 says which failed.** A script runs its checks and its tests both, and reports both. When the tests fail it
208
+ exits as they did; when they pass and only the checks do not, it exits 80 (`STATIC_CHECKS_FAILED` in
209
+ `test-scripts.ts`). The agent sent back with an exit 80 is told the tests pass and the checks do not, to fix each
210
+ finding at its cause, never to silence one (`# type: ignore`, `eslint-disable`, a rule turned off in the checker's
211
+ configuration), and that a formatting finding goes by running the formatter.
212
+ - **In a code pulse**, an exit 80 is one of the unit tests' 20 rounds. Still failing after the last, the work is rolled
213
+ back, as for failing unit tests, and its report says it was the static checks.
214
+ - **In a conformance run**, an exit 80 goes straight to the conformance agent: the findings are in the tests, so no judge
215
+ is asked whether the code or the tests are wrong, and no code fixer is sent. Two fixes in a row that change nothing
216
+ stop the run, as for any other failure. The [regression run](#conformance-tests-in-the-work-loop) stops at an exit
217
+ 80 rather than repair the code: its repair agent may not touch the tests.
218
+ - **The formatting is the agents'.** The harness formats nothing: the scripts check, and leave their inputs as they
219
+ found them. Every agent that writes code or tests is told to run, in its shell, the formatter its script checks with,
220
+ on the files it changes, before the final run.
221
+ - **A toolchain missing** where the checks run - exit 69, 127, `command not found` - stops the pulse as it does for the
222
+ tests: the person installs it, the agents install nothing.
223
+
224
+ ### Checking its own work
225
+
226
+ The coding agent has tools to check its work before the harness and the reviewer do. None of them decides
227
+ anything - the unit testing script, run by the harness, still does - and its task says when to
228
+ use each:
229
+
230
+ - **`copy_resource`**: a linked resource copied whole, byte for byte, into the agent's own folder - at its code-copy
231
+ path, or where it says inside its folder. A resource is shown in the prompt cut at 8,000 characters, saying how long
232
+ it is whole, and the file itself is outside the agent's walls: it copies the resource the code or the tests need as
233
+ a file, or one it has to read whole, rather than type it out. The conformance agent has it too, into the tests folder.
234
+ A resource that is code - a source file or a build manifest (`requirements.txt`, `package.json`, `pom.xml`, ...) - is
235
+ never copied: it is code that lives elsewhere, a host's module the code plugs into, linked so the agent knows what it
236
+ builds on. The prompt marks it `kind="code"`, with no code-copy, and `copy_resource` refuses it.
237
+ - **`my_diff`**: the diff of the code folder from the commit the job started from, new files whole - exactly
238
+ what the reviewer is shown. Read before handing the work in: every part of the change in it, and nothing else.
239
+ - **`can_it_fail`**: whether the unit tests catch a bug. The agent gives one change to a code file - a
240
+ condition turned round, a value changed - and the unit testing script runs on a fresh copy of the code with
241
+ it; the code itself is never touched. If every test still passes, no test catches that bug. Six
242
+ runs a job. A bug often makes the code hang instead - a loop that never ends - so a run may take three times
243
+ as long as the last passing run of the unit tests, within 15 and 60 seconds, and one that does not finish is
244
+ reported as a hang, not as a test that caught it. Only where the testing scripts run on a copy
245
+ (`testing-scripts-run-on: copy`): in place, the default, there is no copy to change.
246
+ - **`start_service`**, **`service_logs`**, **`stop_service`**: a server or a worker it built, started in the
247
+ background on this machine, behind the same walls as its shell - the command check, the module's environment, the
248
+ OS sandbox, the audit while it comes up - to try from outside with `curl` as a client would. Whatever the stack: the
249
+ agent gives the command that starts it and how to tell it is up - the port it listens on, or a line its log prints.
250
+ It is up once the port answers and it is still running a moment later (a port something else holds answers too); one
251
+ that exits first or is not up in time is reported with what it printed. Its log is in `plain_modules/.turri/services/`,
252
+ read through `service_logs`. Three at once; each runs in a process group of its own, outliving the command that
253
+ started it, and is stopped with everything it started on `stop_service`, when the agent's session ends, and in any
254
+ case when its pulse ends. The code fixer of a conformance run has them too; the explorers, which only read, do not.
255
+
256
+ The reviewer has `can_it_fail` too, three runs a review session: a test it doubts can fail, it checks, and
257
+ raises as bad with the bug it missed.
258
+
259
+ ### The code and its unit tests are reviewed
260
+
261
+ Passing unit tests prove only what they check, and a coding agent is quick to write tests that check
262
+ next to nothing - that a function exists, that a result is not empty, that a status is 200 - or code
263
+ that no test reaches. So, with `review: true` in the [config](config.md), once the unit testing script
264
+ passes a reviewer on the judge model reads what the work wrote, beside the spec, and changes nothing. It
265
+ reviews both halves. The review is off by default - `review: false`, or the key left out - and so is the
266
+ conformance tests' review: the work goes on once its tests pass.
267
+
268
+ - **The code.** Every behaviour, edge case, validation rule and error the spec states for this work
269
+ is implemented as the spec says it, with nothing left as a stub, a placeholder or a hard-coded
270
+ answer. The code keeps to the implementation reqs and does not break what was already built. A
271
+ behaviour with no code for it is raised as not implemented. Such a problem is of kind `wrong`.
272
+ - **The unit tests.** Every behaviour, edge
273
+ case and error the spec states for this work has a test asserting the exact outcome the spec says,
274
+ that fails when it breaks; that no test only checks something exists, asserts nothing, is skipped
275
+ or swallows a failure; that the unit under test is never mocked - only what is outside it; and that
276
+ the tests are deterministic. A test that is not there is `missing`, a weak one is `bad`.
277
+
278
+ What the change adds or changes is what needs code and tests, and a change that adds no behaviour
279
+ needs neither. Code written another way than the reviewer would have written it is not a
280
+ problem, as long as it does what the spec says.
281
+
282
+ The review is told what to inspect, so it does not have to guess. One reviewer does every review of
283
+ the work - one session for the loop (see [agent sessions](#agent-sessions)) - so a review after the
284
+ first starts from what it already read and raised. Its instructions hold:
285
+
286
+ - **The spec as the coding agent had it**, laid out the same way: how to read a spec,
287
+ `<definitions>`, `<implementation reqs>` and `<already implemented>`. What this work built is
288
+ apart, in `<new in this work>`: the `<spec change>`, section by section.
289
+
290
+ And each review is shown:
291
+
292
+ - **The code the work wrote**, the first time: a diff of the code folder from the module's last
293
+ commit, where every unit of work starts. It covers code and tests, and new files are shown whole.
294
+ Lockfiles and the harness's own files are left out. Past 80,000 characters it is cut, and the files
295
+ left out are named, to be read whole.
296
+ - **What changed since its last review**, every time after: the harness takes a snapshot of the code
297
+ folder at each review - a git tree in `.plaingit`, no commit, the module's index untouched - and
298
+ shows the diff from it. With it, the problems of the last review that went to the coding agent, and
299
+ what the arbiter let go of it, not to be raised again.
300
+ - **The coding agent's account.** The coding agent ends each turn that goes to review with
301
+ `submit_work`: what it did and why, and for each problem the last review raised, by its number,
302
+ fixed or declined, why, and the files. It is a claim, and the reviewer is told so: it checks it
303
+ against the diff, which the harness takes itself - a problem said to be fixed that the code does not
304
+ fix is still a problem, and one declined is weighed on its reason. An account that leaves a problem
305
+ unanswered sends the coding agent back once; with no account at all, the reviewer is told so and goes
306
+ by the diff.
307
+
308
+ The reviewer is the exacting developer, opinionated about everything: it raises every problem it
309
+ finds, however small. Its problems go back to the coding agent, the unit testing script has to pass
310
+ again, and the next review checks those problems first rather than starting over. A problem that
311
+ leaves a behaviour of the spec not implemented, implemented wrong or untested - no test, or one that
312
+ cannot fail - is **blocking** and worked on first.
313
+
314
+ The work is reviewed twice at most. The first review that sends it back goes to the coding agent as it
315
+ is. The second, **the arbiter** weighs before it reaches the coding agent: the distinguished engineer, on the judge model, read-only, given the same spec and
316
+ code diff as the reviewer, the tests and every review so far. It rules on each problem. It upholds a problem when a behaviour the spec states for this work is
317
+ not implemented, implemented other than the spec says, or untested, or when a test cannot fail: the
318
+ reviewer is right, and the coding agent fixes it. It dismisses a problem that is out of scope or a
319
+ nitpick: the test already tests the behaviour, it is another case of one already covered, it is a
320
+ matter of style, or the code is written another way but does what the spec says. Only what it
321
+ upholds goes back. What it dismisses is let go, with why, in the working notes' pitfalls. When it
322
+ upholds nothing, the work is approved as it is. The review optimises the code and its tests; it never stops the work - whether it is done is the
323
+ unit testing script's to say. What the second review sends back is worked on once, and then the work
324
+ goes on without another review - once its unit tests pass, which they still must. The review is
325
+ told that behaviour is what a functional spec, an acceptance test or a req states: a page or a component only a definition names has no code yet. The
326
+ conformance tests are reviewed as black-box tests (see [conformance tests](#conformance-tests)).
327
+
328
+ Every time a review sends tests back, the agent that fixes them also leaves the lesson in the
329
+ working notes' pitfalls: not the fix, but the kind of test the review found weak or missing and how
330
+ to write it instead - "tests assert the exact response body, never only that one came back". One
331
+ that fixes the tests and leaves no lesson is asked once more. Every later agent on the codebase
332
+ starts from the notes, and is told to write its tests so they would pass those reviews the first
333
+ time - so the reviews of the next functionalities have less to send back, and finish sooner.
334
+
335
+ ### Then
336
+
337
+ Once the unit tests pass and are reviewed, the job lands: the code record becomes the spec the job
338
+ ends on, and a commit is made to the module's history. The conformance tests are not run here: they are
339
+ the conformance track's, and its job for what this one built runs next, before anything is built on it
340
+ (see [conformance tests in the work loop](#conformance-tests-in-the-work-loop)). A job that does not pass
341
+ is undone instead - see [below](#what-the-code-is-built-from). A job that lands ends its report with the
342
+ offer to try it - "Want to try it? Just ask me" in the chat, `turri release <spec>` on the command
343
+ line - and trying it is [deploy](deploy.md)'s, not the job's. Conformance jobs that land make the same
344
+ offer.
345
+
346
+ ## A whole module
347
+
348
+ ```bash
349
+ turri regenerate <file.plain>
350
+ ```
351
+
352
+ Rendering a module - `regenerate` in a conversation, `turri regenerate` on the command line - is
353
+ not a job of its own, and nothing is queued: the work loop (`src/regenerate/loop.ts`) works out what is left
354
+ to build, has it planned into jobs, and runs
355
+ the first. What is left is the difference between what a codebase's code is built from - its code
356
+ record - and the spec of its requires chain as the `.plain` files have it now. When a job ends, or the
357
+ spec changes, it is worked out again; a plan is kept only while the spec and the record it was cut from
358
+ stay as they were.
359
+
360
+ Code accumulates up a `requires` chain: a module is built on a copy of the code of the one it requires.
361
+ So a chain's codebase is its furthest-built module - its tip - and its record holds the whole chain: the
362
+ definitions and implementation reqs of the modules below, each tagged with its module, their functional
363
+ specs among the ones it inherits, and its own. A change to a module below is made there. The codebases
364
+ below the tip are left as they were, their records saying what they are built from; one is brought up
365
+ to its own spec again only when a module not built yet is to start from it - the module below first,
366
+ then the new one on a copy of its code. With no module of a chain built, it is built bottom first, a
367
+ module waiting while the one it is built on has work left or a job running.
368
+
369
+ A module already built from the spec as it is gets nothing. A job that does not land is rolled back, and
370
+ halts its codebase: nothing more runs there until the spec changes or the module is asked for again. On
371
+ the command line, `turri regenerate` runs until nothing more can start, one line as each job starts and
372
+ ends, and exits 1 when any failed.
373
+
374
+ ### How the work is cut into jobs
375
+
376
+ A job that renders the whole of a new spec is too big to build well, and a render per functional spec,
377
+ the first carrying every definition and req, is no better: most of the work lands in one job. So the
378
+ work is cut from the functional specs outward (`chunk-plan.ts`), in three steps:
379
+
380
+ 1. **Which functional specs go together** - the new ones, and those [regenerated again](#what-a-job-is-given-and-what-it-records).
381
+ An agent groups them, by default: fewer, fuller pulses, as each costs a coding session, a test run and a review.
382
+ What builds one feature goes together - the feature, its edge cases and the specs that build on it, a component and
383
+ the parts only it uses - up to `max-specs-per-pulse` (3 unset), only ones next to each other in the same module; a
384
+ spec goes alone only when it is truly independent or very large on its own. Each is shown with its module and its id there, and a number of its own to answer with: a codebase
385
+ regenerates the functional specs of the modules it is built on too, and each module numbers its own from 1.
386
+ 2. **The definitions each group uses**, in code: the concepts its functional specs name, and the
387
+ concepts those definitions name in turn. A definition goes with the first group that uses it; later
388
+ groups have it built. One nothing uses goes with the last.
389
+ 3. **Where each new implementation req goes.** An agent places each with the group it is about - or with
390
+ the first, when it is about everything (the language, the framework).
391
+
392
+ Changes to what is built - an item edited or taken out, a functional spec built worded differently - go
393
+ first, in a job of their own. Every answer is checked: every new functional spec once, in order, next to
394
+ each other, at most `max-specs-per-pulse`; every req placed once. One that does not hold goes back to its agent, twice at
395
+ most, and then the plan is a functional spec a job with every req in the first. A group whose functional specs
396
+ and the definitions they bring pass `max-lines-per-pulse` (120 unset) is split into as few pulses as fit - its
397
+ functional specs kept together in runs, in order, as long as each run stays within it, `Comments (1 of 2)`, `Comments
398
+ (2 of 2)` - not a functional spec a job; its reqs do not count, as a split
399
+ leaves them with its first job whatever happens. The planner runs on the chat's model in a conversation, and on the
400
+ harness model under `turri regenerate`. No agent reviews its plan: the harness checks it - every
401
+ change in exactly one job, the spec holding together after each, the last ending on the spec as it is.
402
+
403
+ Each planned job knows its cases - which functional specs it adds, changes (their text, or a concept they
404
+ use) and takes out, or none: reqs and definitions only - and the loop says them, with each job's title,
405
+ where the person looks (`drift`, `pulses`, and what `regenerate` returns).
406
+
407
+ **Steering.** How you want the work cut and ordered - "build the batch worker's helpers with the worker",
408
+ "models first" - goes to the grouping and placement agents with every plan, as a strong preference: it
409
+ never overrides the limits and checks. It comes from three places, each labelled with where it came from:
410
+ the conversation (`steer`, for the whole project or one module, for the session); the project's
411
+ `AGENTS.md`, every section whose heading names the queue (`## Queue guidance`), read afresh with every plan;
412
+ and whatever asks for the work - `regenerate` and `brood`'s `write_spec_diff`
413
+ take a `guidance` of their own, which the loop keeps with that module.
414
+
415
+ A plan is kept until the spec, what it starts from or its steering changes. `steer` alone plans nothing: the
416
+ next look does - a `regenerate`, a job ending, the spec changing. Then the work not running yet is planned again
417
+ to follow it, a running job going on as it is. Where a plan did not do as asked, it says so, and what `regenerate`
418
+ returns lists it under "what the plan did not do as asked": each wish an agent did not follow, with why (both
419
+ tools take a `notes` for that), a grouping or placement that did not hold, with what was wrong, and a group
420
+ split for its size. The conversation tells the person that, rather than guessing.
421
+
422
+ ### When the spec changes
423
+
424
+ A spec change is a notice, not a diff to run: **`regenerate`**, called after the spec was edited by any means -
425
+ the file tools, a skill, you in an editor - has the loop work out the work again. A job running goes on
426
+ while every change it makes is still part of the work, measured from the same record; one that is making
427
+ something the spec no longer wants is stopped, rolled back, and the work planned again - a fixed rule, no
428
+ agent. Say a module of 50 functionalities is rendering and the spec changes while functionality 25 builds:
429
+ 25 goes on if the change leaves it as it is, and the work after it is planned again from what 25 lands.
430
+ A job stopped so says it was turri, not you, and what changed under it - the functional spec that reads
431
+ otherwise now, or the file it links that holds something else (`whyNotWanted`).
432
+
433
+ **A change inside what the running job regenerates steers it** (`steering.ts`), before any of that: a functional
434
+ spec it regenerates reworded or given a sub-bullet, a definition or an implementation req it is given edited, a
435
+ file one of them links edited - a change to an item it already has, never an item added or removed. Its
436
+ coding agent is told, in the same shape as its first change (`describeSpecChange`): in its turn when it is in
437
+ one, else as its next turn once the step it is at ends - a test run, a review - even when the tests passed
438
+ or the review approved; edits made before it is told are one steer, the newest of each item. The unit tests
439
+ run again after it, and a review still to come sees the change as steered, within its two reviews. The job's
440
+ target moves with it: it lands built from the spec as it was steered to. A definition or req that functional
441
+ specs built before the job use too is told to the agent but kept out of the record, so those specs - and
442
+ this job's with them - are patched by the next job. What else changed is the next job's; a change that is
443
+ partly a steer is split. Two steers a job: a third goes the way above, stopped or - with `allow-to-stop-jobs:
444
+ false` - left to the next job. Conformance jobs are not steered: they are planned from what the code lands.
445
+ A steer shows in the job's view in the panel (what it regenerates now), in the transcript (`⇢ steered job …`),
446
+ under the job in `regenerate`'s answer, and in the job's report.
447
+
448
+ With `allow-to-stop-jobs: false` in `config.turri.yaml` it is not stopped: it runs to its end and lands what it
449
+ was regenerating, and the next job regenerates what changed since as a patch on top of it. Something lands as soon as
450
+ it can, and the software evolves job by job - the first build of an integration lands and throws, the next
451
+ patch fills in what was missing - at the cost of regenerating what the spec has already moved on from. Your own
452
+ `halt` stops a job either way.
453
+ `brood`'s `write_spec_diff` makes an edit and gives the notice in one call, and so does `turri spec-diff` on
454
+ the command line. What is left to regenerate, without regenerating it, is `drift`.
455
+
456
+ ### Regenerating a functionality
457
+
458
+ `regenerate` with functional specs named regenerates them again, changed or not: each is taken out of the record
459
+ of every codebase it is built in - committed, so the record says it is not built - and they are brought up
460
+ to their spec, which regenerates it. A functionality whose spec changed needs none of it: `regenerate`
461
+ regenerates it by itself.
462
+
463
+ `turri regenerate <file.plain> 2` does the same on the command line.
464
+
465
+ ### The testing scripts
466
+
467
+ Whether something is done is never the agent's call, and never a command it chose. It is the
468
+ project's own testing scripts, run by the harness the same way every time:
469
+
470
+ | Script | Run as | Decides |
471
+ | --- | --- | --- |
472
+ | `test_scripts/run_unittests_<lang>.sh` | `run_unittests_<lang>.sh <build>` | whether the unit tests pass, and the code's static checks with them - exit 80 when only the checks fail (see [the static checks](#the-static-checks)) |
473
+ | `test_scripts/run_conformance_tests_<lang>.sh` | `run_conformance_tests_<lang>.sh <build> <tests>` | whether the conformance tests pass - the whole suite in `plain_modules/<module>/tests`, every functionality's and those carried up from below, at once - and the tests' static checks with them, exit 80 when only the checks fail |
474
+ | `test_scripts/prepare_environment_<lang>.sh` - optional | `prepare_environment_<lang>.sh <build>`, before every run of the conformance testing script | nothing on its own: it readies the environment the conformance tests run in - a `mvn install` of the build, say - and when it fails, the conformance tests are not run and the run fails as the preparation's |
475
+
476
+ The `implement-unit-testing-script` and `implement-conformance-testing-script` skills write them.
477
+ They are looked for at the project root - the folder that holds `plain_modules` - in this order:
478
+
479
+ 1. `config.turri.yaml` - with the chosen stack's `config.turri.<stack>.yaml` over it, for a project
480
+ whose parts are on different stacks - naming them by path from the root:
481
+
482
+ ```yaml
483
+ unittests-script: test_scripts/run_unittests.sh
484
+ conformance-tests-script: test_scripts/run_conformance_tests.sh
485
+ ```
486
+
487
+ 2. the root itself: the one `run_unittests*.sh` and `run_conformance_tests*.sh` there;
488
+ 3. `test_scripts/`: the one of each there.
489
+
490
+ The same `config.turri.yaml` holds the project's other defaults - `module`, `model`, `conformance-tests` -
491
+ for [unattended runs](headless.md). A folder holding two of a kind is not guessed between: name the
492
+ one to use in `config.turri.yaml`, or in each stack's own file. The
493
+ scripts are not linked from the specs; a link to one is ignored.
494
+
495
+ They are required: a build with no unit testing script, or with conformance on and no conformance
496
+ testing script, stops before it starts and says which skill adds it.
497
+
498
+ **The prepare script** is codeplain's, and optional: turri never writes one, and runs one the project has -
499
+ `prepare-environment-script:` in the config, else the one `prepare_environment*.sh` at the root, else in
500
+ `test_scripts/` - on the build, before every run of the conformance testing script: the harness's own, and the agents'
501
+ `run_conformance_tests`. Both get the same build folder - the code in place, or the same fresh copy - so what it sets up
502
+ for that build, the conformance testing script finds. With conformance off it is not run. The conformance agents are
503
+ shown it, before the conformance testing script.
504
+
505
+ **Where they run.** On this machine, as you would run them: unfenced - no sandbox, no command check, no audit - in
506
+ your own environment with this machine's toolchains, turri's model providers' API keys alone left out. They are yours,
507
+ and whatever they do is your doing. That is the only way the two scripts are ever run: the harness's own runs, and the
508
+ agents' `run_unit_tests` and `run_conformance_tests`, which run them exactly as the harness does - through the host
509
+ runner, in a process group of their own, so the time limit and a stopped job end the script and all it started. A
510
+ toolchain the script needs and this machine lacks - exit 69, exit 127, or a `command not found` / `failed to run
511
+ command` in its output (`missingToolchain`) - is yours to install, never the agent's: the agent is told to report it
512
+ with `report_environment_error` rather than work around it, and the pulse stops at the harness's first run of either
513
+ script - unit or conformance - that cannot find it, rolled back, saying what to install (see
514
+ [when the environment lacks something](#when-the-environment-lacks-something)). The code and the tests an agent wrote run unfenced inside the script too: what an agent runs with its own
515
+ shell is fenced, what your script runs is not - an accepted gap.
516
+
517
+ **A script that does not fit where it runs.** When a line of the script itself fails - a command or file it names is
518
+ not there, or not runnable, as bash reports it (`run_unittests.sh: line 6: /usr/libexec/java_home: No such file or
519
+ directory`, a macOS-only line run in Linux) - the agent's output starts with a note that the line is the person's
520
+ script, not its code, and not to go looking for what it names; the person is told once, in the job's log, that the
521
+ script is theirs to fix. A failure of what the script runs is left alone: that may well be the code's.
522
+
523
+ **What they run on.** By default, the code in place: the project's own script at its own path, from the project's
524
+ folder, on the real build and tests folders. A script that finds things from its own path - an integration embedded in
525
+ a host codebase, whose scripts merge the generated code into the host and find the host from where they sit - finds
526
+ them. What the script does to the host - copying the package into it - it does, as it is written to.
527
+
528
+ `testing-scripts-run-on: copy` in the project's `config.turri.yaml` runs them on a fresh copy of the code instead, and of the
529
+ whole conformance suite, in `plain_modules/.turri/scripts/`, named for its module and the run, with the project's script
530
+ copied in beside it: the scripts work in `/tmp/<lang>_<basename of the build>`, and every module's build is called
531
+ `code`, so two modules testing at once never share that folder, build output stays out of the code, and nothing a test
532
+ writes reaches it. A script copied there no longer sits beside the project, so one that finds things from its own path
533
+ does not find them:
534
+
535
+ ```yaml
536
+ # plain/config.turri.yaml
537
+ testing-scripts-run-on: copy
538
+ ```
539
+
540
+ `can_it_fail` needs a copy to change, so an agent has it only where the scripts run on one.
541
+
542
+ ### When the environment lacks something
543
+
544
+ No agent installs anything on the machine, and none makes up a credential. When the machine lacks what the work needs,
545
+ the pulse stops instead - rolled back, as any failed pulse is - its module's later pulses wait, unrelated modules go on,
546
+ and you are told:
547
+
548
+ > **d365_version_api stopped: the environment lacks JDK 21.**
549
+ > Needed by: `run_unittests.sh` (it could not find `java`).
550
+ > To fix: install java on this machine, so the testing script finds it on its PATH.
551
+ > Then re-run: `turri regenerate d365_version_api.plain`, or say "resume" in the chat.
552
+
553
+ It is raised two ways:
554
+
555
+ - **by an agent**, which calls `report_environment_error` - only the agents that write and run code have it: the
556
+ coding agent, the code fixer, the repair agent and the conformance agent; explorers, reviewers and judges observe,
557
+ and never stop a pulse this way -
558
+ with what is missing, what needs it and the command that showed it. Its shell runs behind walls the testing scripts
559
+ do not, so what failed there may run here: the harness first runs the testing script itself - the unit one, the
560
+ conformance one for the conformance agent. If it passes, the report does not stand: the agent is told the machine has
561
+ what the work needs and goes on. If it cannot find its toolchain, the report stands. If it fails otherwise, the agent
562
+ is shown its output once, and a report made again after that stands. A report that stands ends its turn, the pulse
563
+ stops, and what it said goes to you as it is;
564
+ - **by the harness itself**: a testing script - the unit or the conformance one, in a code pulse, a conformance pulse or
565
+ the whole-suite run - that cannot find its toolchain (exit 69 or 127, `command not found`), or
566
+ a credential `agent-env:` names that is not there when the pulse starts - before any agent does. What the harness
567
+ found it works out at once - the diagnosis, not after a second failure - to say how to fix it on this machine.
568
+
569
+ **Hidden by turri's own sandbox, not missing.** An agent's commands run behind the OS sandbox, which reads only the
570
+ toolchain folders it knows; a toolchain kept somewhere else - a version manager's install it does not recognise - is
571
+ on the machine, but out of the agent's sight. When a report names a file that is on this machine, outside the project
572
+ and the system's folders (`sandboxGapOf` in `environment-error.ts`), the stop says so, and the fix is a line of config,
573
+ not an install:
574
+
575
+ > **lunch stopped: turri's sandbox kept its agents from reading `…/mise/installs/node/24.16.0/lib/node_modules/npm/bin/npm-cli.js` - it is on this machine; nothing is missing.**
576
+ > To fix: let the agents read that toolchain - add its folder to `toolchains:` in config.turri.yaml, keeping what is there: `toolchains: [/Users/…/mise/installs/node/24.16.0]`. Nothing needs installing.
577
+
578
+ **The conversation heals it.** Told of the stop, it never regenerates the module again before the cause is fixed - a pulse
579
+ stopped on its environment stops the same way again - and fixes what it can:
580
+
581
+ - **hidden by the sandbox**: it adds the folder to `toolchains:` itself, says so in a line, and resumes;
582
+ - **a toolchain or a tool missing** - a JDK, Maven, Go, uv: it looks first for one installed off the PATH - Homebrew's opt
583
+ folders, `/Library/Java/JavaVirtualMachines`, mise, asdf, sdkman, nvm - then asks you, with the exact command for this
584
+ machine (`brew install openjdk@21`, `mise use -g java@21`), and on your yes runs it in its shell, checks the command is
585
+ found now as the testing script would find it, and resumes. One installed where turri's own PATH does not reach needs
586
+ turri restarted, and it says so. On a no - or where it cannot do it, sudo with a password, a licence - it tells you
587
+ exactly what to do;
588
+ - **a credential missing**: never made up - you are told where `agent-env:` reads it from.
589
+
590
+ Either way the pulse is not tried again: no second run would find what is missing. The message is in the chat, at the
591
+ end of `turri regenerate`, and in the job's log; after the fix the pulse runs again from the start. The re-run line names the spec that was regenerated, as the folder it was run from reaches it.
592
+
593
+ ### What a job is given, and what it records
594
+
595
+ Every job is a spec diff: the agent that renders it is given the spec the code is built from - its
596
+ functional specs in `<already implemented>` - and the change to it, in `<spec change>`, section by
597
+ section - not the raw diff: each of `<definitions>`, `<implementation reqs>` and `<functional specs>` in
598
+ its own tag, `<definitions change="1 added, 2 changed">`, saying what is added, what changed with its text
599
+ before and now, and what is removed, measured from what is built to the spec the job ends on. A
600
+ definition is itself by its concept: one reworded or moved is shown as changed, not as removed and added.
601
+ Test reqs and acceptance tests are for conformance only: the code record holds neither, and no coding
602
+ agent is shown them.
603
+
604
+ **Every part of the spec is given with its module.** A codebase is built from the spec of its whole requires chain,
605
+ and each module numbers its functional specs from 1, so every agent is shown each section grouped under the module
606
+ each item belongs to - `<module name="base">`, then `<module name="app" role="current">` - as `<already implemented>`
607
+ groups the functional specs (`moduleSection`, `functionalitiesByModule` in `prompt.ts`). A module's own items, and
608
+ what it imports, are the current module's. `<spec change>` names a functional spec as "functionality 2 of module
609
+ `app`", and a definition or req of a module below with its module; each case line does too ("fs 2 of module `app`").
610
+ The primer every agent reads first says that modules are how the \*\*\*plain spec is written, not how the code is laid
611
+ out: the agent works only in the current module's codebase, which holds the code of every module it requires, and
612
+ organises the code as the implementation reqs say.
613
+
614
+ It is told, too, what to do with each functional spec the job touches, by its case (`src/regenerate/cases.ts`): a
615
+ fresh project is set up first, with its unit tests where the unit
616
+ testing script runs them; a new functional spec is built and unit tested; a changed one - its text, or a concept
617
+ it uses - is changed in place, its code and tests to match, never built again from scratch; one regenerated again is
618
+ replaced, not patched - rewritten or started over, what it replaces taken out; one taken out has its
619
+ code and the tests only it had removed. A job holding several cases has a line for each. A job that touches no
620
+ functional spec - implementation reqs, or definitions none uses - is mechanical: the code adapts, no new test is
621
+ written, and an existing one may change only mechanically, never what it asserts. The unit test review holds each
622
+ part to its case, and a mechanical job only to its reqs and to no test removed or weakened. A conformance job's
623
+ agent and its reviewer are told the same, for the tests:
624
+
625
+ | case | when | code | conformance |
626
+ | --- | --- | --- | --- |
627
+ | fresh | the module requires none and nothing is built | set up the project and its unit tests where the unit testing script runs them, then build | set up `tests/` so the conformance testing script, which brings the tests together with `code/`, runs them, then write |
628
+ | add | a functional spec is new | build it and write its unit tests | write its tests |
629
+ | patch | its text changed, or a concept it uses did | change the existing code and tests to match - never build it again from scratch | rewrite its existing tests to match |
630
+ | again | `regenerate` named it: it is built, and marked in the code record to be regenerated again | replace its implementation - rewrite it or start it over, doing what the spec says now; no second implementation beside the old, nothing of it left unused; its unit tests may be rewritten | none: its tests stay as they are |
631
+ | delete | a functional spec is gone | take out its code and the tests only it had | take out its tests |
632
+ | mechanical | no functional spec is touched - only reqs, or definitions none uses | adapt the code; write no new test; an existing one may change only mechanically - an import, a fixture, its setup - never what it asserts | the same, for test reqs, definitions or implementation reqs alone |
633
+
634
+ **Regenerating again.** `regenerate` with functionalities named regenerates them again though their spec did not change -
635
+ made better, on another model, after many patches. Each is marked in the code record of every codebase it is built
636
+ in (`regenerate_again`, committed), and nothing else changes: the record now differs from the spec at that item, so the
637
+ work loop plans it as it plans any change. A functional spec of a module below is regenerated again where its code
638
+ lives - the codebase at the tip of each chain built on it, never the module's own codebase left behind - marked
639
+ among that codebase's required functional specs. The planner groups the ones regenerated again as it groups new ones - up
640
+ to three a job, only those next to each other in one module together - and the job is given the definitions and
641
+ implementation reqs as every job is; `<spec change>` lists each under "To regenerate again", with its text as it is now. The job that regenerates it
642
+ records it as the spec has it, without the mark. Its conformance tests compare its text, which did not change: they
643
+ stay as they are, and are not rewritten.
644
+
645
+ A functional spec is patched when a concept it uses changed as well as when its own text did: the
646
+ harness follows each functional spec's concepts through the definitions. Fresh is only where nothing
647
+ exists: a module that requires another starts from what it inherits, and its first job adds or patches.
648
+
649
+ **Linked resources.** A file the spec links is part of it, so what it holds is compared too: each linked
650
+ resource is hashed on its own (sha256 of its content) beside its link, in the trees the loop compares and in
651
+ both records. A change to the file - an API surface `openapi.yaml` defines - changes the item that links it,
652
+ with no change to the `.plain` text: a functional spec linking it is patched, and a definition linking it
653
+ patches every functional spec using its concept. The job's diff has a hunk of its own for each such file,
654
+ under the file's name - shown as a file of its own where the job is shown - saying which item links it, in which
655
+ spec file (`resources/hubspot/openapi.yaml, linked by :HubSpotRestAPI: in hubspot.plain`), and that its content
656
+ changed, with both hashes; the agent is told which file holds something else now, beside the item's
657
+ unchanged text, and reads the file as it is now in `<linked resources>`. The records keep the hash, not the
658
+ content, so what the file held before is not shown. A record written before resources were hashed is taken
659
+ as built from the files as they are now: the loop hashes its links and commits it, building nothing again.
660
+
661
+ **Where a linked resource goes in the code.** A linked resource is not in the agent's workspace; it reaches the agent
662
+ only in `<linked resources>`. Each text resource is given a `code-copy` - its path, without steps up - and the
663
+ agent is told that when the code needs what the resource holds while it runs, it keeps exactly one copy there (or
664
+ where the implementation reqs put such files) and reads it from there, and otherwise copies none, so one file is
665
+ not written to every place it might be read from.
666
+
667
+ **Linked images.** A linked `.png`, `.jpg` or `.jpeg` is an image, not text (`resources.ts`). The coding agent
668
+ and the conformance agent are sent it with their first message - and again after each compaction, which sums
669
+ the conversation up without its images - and `<linked resources>` lists it with its type and its number among
670
+ the attachments (`<resource name="checkout mockup" path="resources/checkout.png" type="image/png">`). Their
671
+ model has to read images: a job whose spec links one refuses a model that does not before any agent starts
672
+ (`refuseIfModelIsBlind`; `createExecutor` refuses pi's default model the same way), saying which model and to
673
+ set `coding-model` to one that reads images or describe the image in text. An image over 5 MB stops the job,
674
+ naming the file. The reviewers do not see linked resources, text or images. An image is hashed like any linked
675
+ file, so a new mockup patches the functional specs that link it.
676
+
677
+ A job lands once its unit tests pass and are reviewed: the code record becomes the spec the job ends on,
678
+ committed with the code. Its conformance tests are not the code job's: they are a track of their own
679
+ ([conformance tests in the work loop](#conformance-tests-in-the-work-loop)).
680
+
681
+ A change that renders nothing - definitions moved to a common module, reqs reordered, specs moved between
682
+ modules of the chain - is recorded, not rendered: the spec is recorded as it is now laid out and committed,
683
+ with no agent and no testing script. Moving specs into a module the code was not built on is different: no
684
+ change to the code brings that module's code in, so the codebase stops: it has to be started over - its code
685
+ and conformance tests taken out, committed so its history keeps them, and the chain built again from the
686
+ bottom. That is never done unasked. In the chat the model asks the person, saying why, and calls
687
+ `regenerate` with `from_scratch` once they agree; `turri regenerate` and `spec-diff` ask at the terminal, and
688
+ `--start-over` agrees in advance - with no terminal and no flag, nothing more is built there.
689
+
690
+ ## Conformance tests
691
+
692
+ The unit tests are written by the agent that wrote the code. Conformance tests are the other half:
693
+ black box, end to end, written from the spec.
694
+
695
+ ```bash
696
+ turri conform <file.plain> # every functional spec the code is built from
697
+ turri conform <file.plain> 1 3 # functional specs 1 and 3
698
+ ```
699
+
700
+ They follow the code: a functional spec gets conformance tests once its code is built. Conformance is
701
+ off by default: `conformance-tests: all` (or `chosen`, or `module`) in the [config](config.md) turns it on, for modules
702
+ with `***test reqs***`, and `conform` asks for it in a session. Once a codebase has conformance tests,
703
+ they are always run and kept passing, whether or not the current render writes new ones, and they
704
+ are carried up to the modules built on top of it.
705
+
706
+ ### Conformance tests in the work loop
707
+
708
+ In the work loop, conformance is a track beside the code's. What the conformance tests are written for is
709
+ recorded apart - `tests/.turri.json`: the functional specs they test, as built, with their acceptance
710
+ tests, the definitions and implementation reqs they were written against, and the test reqs they follow -
711
+ and the work is from that record to what they are to be: of the functional specs the code is built from,
712
+ those chosen - every one, or those `conform` names - as the spec has them, with its test reqs. A
713
+ functional spec whose code is behind the spec - built from other text, or not in the code record at all, as while
714
+ `regenerate` regenerates it again by name - keeps its tests until the code lands; they are taken out only once the spec and the
715
+ code have both dropped it. The harness cuts the work into jobs, and no agent is asked: every functional spec
716
+ tested - added or changed, asked for by `conform`, chosen, or left by the code jobs - is in one conformance job, a
717
+ module's own together, as far as a guardrail lets: a new job begins only where the next functional spec would take
718
+ the job's functional specs and the definitions they bring past 120 lines. The reqs they are written against go
719
+ with the first job, and do not count. When the person asks for it - one at a time, separately - `conform`'s
720
+ `one_by_one` (`turri conform --one-by-one`) makes it a job a functional spec instead, until conformance tests are asked
721
+ for again without it. And when the person asks for them in pulses of their own grouping - 1-3 and 4-6 - `conform`'s
722
+ `groups` gives each group a job of its own: a job never takes functional specs of two groups, and within a group the
723
+ guardrail still cuts. Only work that
724
+ touches no functional spec at all, the test reqs changed say, is a job without one. A module's conformance jobs run
725
+ on its lane once its code is built - every code job of it landed - so the module is tested once, as built: one
726
+ explorer, one run of the whole suite, rather than a conformance cycle after each code job; and they pass before
727
+ anything is built on it. Until then they are not planned, but what is planned lists them last - `conformance tests -
728
+ planned once the code is built` - wherever they are on for the whole module, so asking for them is seen to have worked;
729
+ `conform` asked again for a module they are on for already says so, and changes nothing.
730
+
731
+ A conformance job is a spec diff's conformance run: the tests of its change written, changed or taken out,
732
+ a failure judged - the test or the code wrong - and fixed, then the whole suite with the unit tests, the
733
+ tests the module inherits with them. The run that passed already was of the whole suite - the module's tests
734
+ folder holds the chain's, copied up - so the suite is run once more only when the code or the tests changed after
735
+ it passed with the unit tests; otherwise it is not run again. Passing, the tests record is written and committed with the tests;
736
+ otherwise all of it - code fixes included - is rolled back, and the module halts until the spec or the code
737
+ changes, or `conform` asks again: its conformance tests, its code - nothing more is built on code whose conformance
738
+ tests did not pass - and every module built on it, which waits.
739
+
740
+ **Up the chain.** A module built on another starts from its code and its conformance tests, copied up, and its
741
+ conformance testing script runs those with its own. So a module waits for the one below it until that one's code
742
+ is built and its conformance tests - those wanted, chosen or scheduled - are written and pass; only then is its
743
+ codebase started from there.
744
+
745
+ **Who chooses, and when.** With `conformance-tests: all` every functional spec is tested, and with `false` none is
746
+ unless the person asks with `conform`, for the session. With `chosen` or `module`, every one with acceptance tests - the
747
+ author said what to check - and those the chooser picks: an agent on `harness-model` (or `models: chooser`), in the chat
748
+ and on the command line alike. It reads the module's spec and names those worth black-box tests - what a user or a
749
+ client relies on, not a detail the unit tests cover - and why.
750
+
751
+ - `chosen`: it is asked as each code pulse ends, as the pulse's last stage, of what that pulse regenerated that no
752
+ conformance test is for.
753
+ - `module`: it is asked once, when the module's last code pulse lands, of every functional spec of the module that is
754
+ built and has none - and it plans them too, into groups, each a conformance pulse of its own.
755
+
756
+ Either way the choice is made inside the pulse, so it is made - and its conformance pulse scheduled - before anything
757
+ can be built on the module: nothing ever has to be stopped for it. The pulse's report says what it chose and why
758
+ (`conformance: fs 1, 3 chosen - ...`), and the chat is told, not asked: it calls `conform` only when the person asks.
759
+ One the chooser passed over is not offered again while its text is the same. `conformance-budget:` caps how many of a
760
+ module's functional specs are chosen, beside those with acceptance tests - a count, or a share of them: every choice for
761
+ the module counts against it, and the chooser is told what is left and can choose no more; the person's own `conform`
762
+ is not limited. The ones named are added to those chosen before, and a functional spec that has conformance tests
763
+ keeps them: they are rewritten when it changes, never taken out because others were named.
764
+
765
+ **What the person asks for comes first.** `conform` changes the module named alone, never the modules below it. For a
766
+ module not regenerated yet - one above the module being regenerated, say - its tests are scheduled now and written once
767
+ its code is built, before anything is built on it. For a module already regenerated whose tests are not written, while
768
+ a module above it was started from it - its first pulse running, or code of its own built - the codebase above is
769
+ disposable: a pulse running there is stopped, whatever `allow-to-stop-jobs` says, as the person asked; the codebase is
770
+ deleted whole, its history with it; the tests are written in the module's own codebase; and the module above is
771
+ regenerated from it once they pass. Asked for tests it has already, nothing is touched.
772
+
773
+ **Scheduled ahead of the code.** `conform` may name functional specs whose code is not built yet:
774
+ each call schedules them as one group, shown at once in what is planned, after the module's last code job. Its
775
+ functional specs are chosen once the code record has every one as the spec has it, and its tests are written once
776
+ the module's code is built. A functional spec the spec does not have - built by no code job - or a module with no
777
+ test reqs is refused, and nothing is scheduled; one taken out of the spec later is dropped from its group.
778
+ Groups whose code is built by then are tested together, in one job with the rest, as far as the guardrail lets.
779
+
780
+ While a codebase's work is being planned into jobs, with nothing running there, what is planned says so - the
781
+ conformance tests of the groups being planned, or the work - rather than showing nothing until the plan is made.
782
+
783
+ **What a conformance job tests is built.** As a conformance job starts, the harness reads the code record,
784
+ `code/.turri.json`, and checks that it has every functional spec the job adds or changes tests for, as the
785
+ job has it. One it does not have stops the job before any agent runs: its report says which are not built, the
786
+ conformance tests halt, and the chat model tells the person. They are tried again once the code or the spec
787
+ changes. Code jobs and conformance jobs are planned apart, each track on its own: a job is one or the other. A module built on another starts with an empty tests record: the tests it inherits are the
788
+ module below's, and none of its own is written yet.
789
+
790
+ ### Conformance tests and acceptance tests, kept apart
791
+
792
+ The step writes two kinds of test, and never lets one stand in for the other:
793
+
794
+ | | Written from | Labelled |
795
+ | --- | --- | --- |
796
+ | Conformance tests | the functional spec itself - what it says the functionality does, its edge cases, its errors - as if no acceptance tests had been given | files whose names say conformance, each starting with a comment `conformance tests of functionality 3` |
797
+ | Acceptance tests | each acceptance test in the spec, implemented as a test of its own, doing what it says | files whose names say acceptance, each test with a comment `acceptance test 2 of functionality 3:` and the acceptance test's text |
798
+
799
+ Even when the acceptance tests seem to cover the functionality, the conformance tests are written
800
+ independently: tests drawn only from the acceptance tests check what the author thought to check,
801
+ and nothing the spec says beyond that. The acceptance tests reach the agent numbered, as their
802
+ labels number them.
803
+
804
+ The labels are checked, not trusted: before a passing run counts, the harness reads the tests and
805
+ sends the agent back for a functionality with no labelled conformance tests, or for any acceptance
806
+ test that has no test of its own. Each functionality has a label of its own, on a line of its own: a
807
+ file that tests several carries one line for each, and a label naming several at once - `conformance tests
808
+ of functionality 1, 2 and 3` - counts for the first alone. For a spec change that touches several
809
+ functionalities, everything missing - every functionality's - is asked for in one request, the agent told
810
+ to keep the labels there already, and the whole set checked again after each answer. Anyone reading the
811
+ tests - or the next agent - sees at a glance which is which, and which acceptance test a test implements.
812
+
813
+ ### Rendered apart from the code
814
+
815
+ The code and its conformance tests are rendered apart, each in its own folder (see
816
+ [the sandbox](sandbox.md#what-an-agent-can-reach)). The test author writes only the tests folder; its file
817
+ tools can read the code too, and it is told so - read access, never write access - and to take how the
818
+ software is reached from the code, never what it should do. Its shell holds the tests folder only. The
819
+ coding agent that fixes the code is told the same of the tests: it can read them, never change them.
820
+ Before the test author starts, an explorer - an agent in
821
+ the code's folder with the file tools alone: it reads the code, runs nothing and changes nothing - hands over everything
822
+ the author needs, in parts: how to build and run it; how the conformance tests reach it as the project's
823
+ conformance testing script runs them - the explorer is given the script, and says what it builds or
824
+ installs and what the tests depend on or start (a package, a module, an entry point, by its exact name);
825
+ how each functionality is reached from outside
826
+ (the command, or the route, method and the request and response fields); what it needs around it; and
827
+ a plan for the conformance tests, its expectations taken from the spec. The account is checked before
828
+ it is used: it has to say how the functionality under test is reached and what to test for it (for a
829
+ spec diff, some of the module the change touches), and the plan has to carry out every acceptance test
830
+ of it (for a spec diff, of every functionality the change touches), each named "acceptance test N", with
831
+ how each of its steps is done from outside and what it asserts. One that does not is sent back saying
832
+ what is missing. It is kept focused: the interface to what is under test, not a survey of the codebase, in
833
+ words rather than code, under 12,000 characters. Each hand-over ends its turn, and it hands over three
834
+ times at most. If it never completes it, what it wrote as it worked goes along with it, so nothing it
835
+ found is lost. The tests are written from that account and the spec, and every assertion comes from the
836
+ spec. `run_conformance_tests` puts
837
+ the whole suite together with a copy of the build in a throwaway directory, so
838
+ tests cannot accumulate state between attempts and nothing they write reaches the code.
839
+
840
+ While it writes the tests, the conformance agent can put a question to the explorer - `ask_explorer`, three
841
+ times a run: how a functionality is reached, what a field is called. A fresh explorer, in the code's folder,
842
+ given the account it handed over and the question, reads the code and answers in words; it runs and changes
843
+ nothing. And `my_diff` shows it the tests folder's diff from where the run started, as its reviewer is shown it.
844
+
845
+ ### When a conformance test fails
846
+
847
+ The harness runs the project's conformance testing script on the whole suite. When it passes, the
848
+ unit testing script runs too - and then, with `review: true` in the config, the review gate: a reviewer reads the tests this run added or
849
+ changed, and the code, and checks that they test black box - through the entry points the test reqs
850
+ allow, never mocking or replacing any part of the software under test - that every test asserts what
851
+ the spec says, with no placeholder that cannot fail, and that each acceptance test does every step it
852
+ lists and asserts every expectation it states. It must pass, as the suite and the unit tests must:
853
+ when it does not, the conformance agent gets exactly what is missing and what is bad, file by file, and
854
+ the round goes again. One reviewer does every review of the run, as the unit tests' does: the first time
855
+ it is shown the diff of the tests folder from the module's last commit, each time after the diff since its
856
+ last review, and every time the conformance agent's account through `submit_work` - checked against the
857
+ diff, never taken instead of it. The first review is asked for every problem at once; each after it is
858
+ given what the last one found, checks that first, and raises something new only when it is serious - a test that
859
+ cannot fail, mocks the software, or leaves out what the spec asks for. It asks only for what can be seen
860
+ from outside: where the spec says one part calls another, the outcome, never the call. The reviewer is
861
+ the exacting developer, as the unit tests' is, and marks each problem blocking or not: blocking when the
862
+ functionality is not yet tested black box - a test or an acceptance test missing, cut down or skipping
863
+ what it checks, the software mocked or not reached from outside, a test that cannot fail.
864
+
865
+ The tests are reviewed twice at most, as the unit tests are: the first review that sends them back goes to
866
+ the conformance agent as it is, and the second the arbiter weighs first, as it does the unit
867
+ tests' (see [the code and its unit tests are reviewed](#the-code-and-its-unit-tests-are-reviewed)): it upholds what leaves the
868
+ functionality not tested black box, and dismisses what is out of scope or a nitpick. Only what it
869
+ upholds goes back to the conformance agent; when it upholds nothing, the tests are approved as they
870
+ are, and what it let go is kept in the result and the notes' pitfalls. The review optimises the tests,
871
+ it does not stop the run: what the second review sends back is worked on once, and then the tests go on
872
+ without another review - once the suite and the unit tests pass, which they still must. All three passing
873
+ is done.
874
+
875
+ A spec diff's conformance run holds its tests to the same bar. The functionalities the change touches -
876
+ a line of their functional spec, or of one of their acceptance tests, added or removed - are worked
877
+ out from the diff. The conformance agent is shown their acceptance tests, numbered as they are labelled;
878
+ the run does not finish until each one is a labelled test of its own; and the review checks each of
879
+ them as it would a functionality's own.
880
+
881
+ A failing run's output goes to the judge and whoever fixes it whole when it is up to 60,000 characters,
882
+ and otherwise its last 60,000 - where a test run says what failed and why - with the file the whole of
883
+ it is kept in.
884
+
885
+ Why something failed is never lost. Every agent that writes or fixes code is told that where the code
886
+ catches an error and turns it into a response, a status, a result or a retry, it logs the error with its
887
+ whole trace, and what it hands on names the cause - never a bare "failed". When the output does not show
888
+ why the software failed, the judge says the code is what is wrong, for hiding it, and the coding agent
889
+ makes the cause show first, then fixes it. No agent may make the code behave differently when a test runs
890
+ it. Both the conformance agent
891
+ and the coding agent can run the conformance suite themselves, to reproduce a failure and check their
892
+ fix - three times a turn: the third ends the turn, and the harness runs it and judges. The conformance
893
+ agent is told that a failure of the software itself - it does not build or start, or does what the
894
+ spec says it must not - is not the tests' to work around. When it fails, a judge - an agent that reads
895
+ the code and the tests, changes neither, and holds both to the spec - decides which is wrong. It has the
896
+ file tools and the web (`web_search`, `web_fetch`), to look up what a service the code calls answers - no shell: it
897
+ judges from the code, the tests, the spec and the failing run's output, and its file tools write nothing:
898
+
899
+ - **the code:** the coding agent - in the code's folder, reading the tests but never changing them - fixes it,
900
+ and keeps its unit tests passing;
901
+ - **the tests:** the conformance agent corrects them to what the spec says;
902
+ - **the spec:** two functional specs cannot both hold, whatever the code does;
903
+ - **the environment:** neither the code nor the tests can fix it - only the person can, in what the run is given:
904
+ a credential missing, empty or rejected (a 401 from a provider for a token no test made up), an account or quota
905
+ a service refuses, a service the spec names that cannot be reached. What a test sets up itself - a credential, a
906
+ variable, a fixture - is the tests'.
907
+
908
+ The environment is judged what is wrong twice in a row before it counts. The first time, the conformance agent
909
+ checks that the tests do not cause it themselves and, when they do not, changes nothing; the second, the run
910
+ stops, and the person is told what to provide and where the run read it from - the testing scripts run in their own
911
+ environment, so a credential comes from their shell's variables or a `.env` the script loads.
912
+
913
+ When the code and the tests could both be wrong, the judge is told to choose the tests. A spec
914
+ conflict has to name the two functionalities, each by its module and id - they can be in different
915
+ modules, since a module's codebase and its conformance suite hold the functionalities of the modules
916
+ it requires too (functionality 1 of `accounts` and functionality 4 of `cognio`). In a functionality's
917
+ conformance run one of them must be the functionality under test - a conflict between two earlier ones would have
918
+ come up when the later of them was tested (a spec diff's run may name any two). One that breaks
919
+ these rules is sent back to the judge. A valid one is recorded, and the tests go back to the
920
+ conformance agent, so the next judgement is of a new run. It counts only once the same two
921
+ functionalities have been named three times. Then the run stops, and the person gets the conflict
922
+ whole: both functional specs as they read, and each time what could not hold. The conversation's
923
+ agent runs `analyze-2-func-specs` on the pair, then `resolve-spec-conflict` for the ways out, and
924
+ puts the decision to the person - it changes nothing in the spec before they have decided.
925
+
926
+ The judge holds only what the spec says against the code: anything it leaves open - a name,
927
+ coordinates, a version, a path, a package - is what the code already has, and the tests follow it.
928
+ The coding agents keep the build's identity - name, coordinates, version, package, main class - as it
929
+ is unless the spec asks for another. And the conformance agent is given the code's build files
930
+ (`pom.xml`, `package.json`, `pyproject.toml`, `go.mod`...) word for word, read by the harness: the one
931
+ place to take what its tests' build points at from, never a guess from a folder name.
932
+
933
+ When nothing changes - the same failure seen three times in the run, in a row or not, so a run
934
+ swinging between two failures counts too (runs that hang until the time limit count as well) - the
935
+ explorer is asked again, shown its last account and the failure,
936
+ for what the tests lack; most often it is how they reach the software. Its new account goes to the
937
+ conformance agent. If the same happens three rounds more, the run stops and says so, instead of
938
+ spending the rest of its 20 attempts on it. Two failures are the same once what changes from run to run is
939
+ taken out of their lines - numbers, times, paths, colour codes, and the ids a service makes up for each
940
+ response, a UUID or a correlation id. Nothing changes either when the agent sent to fix the code or the tests
941
+ changes no file: two such fixes in a row, and the run stops. The conformance agent has the testing script in its prompt,
942
+ and is told to fit the tests' own build to it.
943
+
944
+ Every attempt is written into the working notes' pitfalls by the harness as cause and effect - what
945
+ the run failed with, how it was judged, and which files the agent sent to fix it changed; the next
946
+ attempt's line says what came of it - and each judge reads them first, so it does not send a
947
+ failure the way that already failed. A run that does not pass is undone whole, its notes with it.
948
+
949
+ Then the suite runs again. A run stopped by its time limit goes back to the conformance agent without a judge: the
950
+ tests' environment is its. So does a run that exits 80 - the tests pass and only their static checks do not (see
951
+ [the static checks](#the-static-checks)): the findings are the tests'. A run whose script cannot find its
952
+ toolchain stops the pulse instead - see [when the environment lacks something](#when-the-environment-lacks-something).
953
+ Unit tests failing after the suite passes go to the coding agent. It goes round up to 20 times; still failing, the work is undone.
954
+
955
+ Before each run the harness checks for itself: both kinds of test are there and labelled, none of
956
+ them is in the code folder, and no test went missing without being justified.
957
+
958
+ Conformance and acceptance tests live in the module's `tests` folder and nowhere else. One found in
959
+ the code folder - by its label, or as a test file under a name or folder that says conformance or
960
+ acceptance - is sent back: to the agent writing the tests, to move it; to an agent writing the code,
961
+ to remove it, since those tests are not its to write. The conformance testing script refuses them too
962
+ (see `implement-conformance-testing-script`), so a suite in the wrong place fails rather than
963
+ passing unnoticed.
964
+
965
+ No agent runs the testing scripts itself. They are in its prompt so it knows what judges its work,
966
+ but they are not in its workspace: it calls `run_unit_tests` and `run_conformance_tests`, which run
967
+ them as the harness does. Its file tools refuse to write a copy of them, or a `.plain` spec, into the
968
+ codebase, and its working notes refuse a line telling the next agent to run them.
969
+
970
+ ### Verified
971
+
972
+ After rendering a hello-world Python spec's functionality 1, the conformance test runs
973
+ the app as a subprocess and asserts on stdout, exit code and time - no import of internals:
974
+
975
+ ```python
976
+ completed = subprocess.run([sys.executable, str(executable)], capture_output=True, text=True, timeout=1)
977
+ self.assertEqual(completed.returncode, 0, msg=completed.stderr)
978
+ self.assertEqual(completed.stdout.strip(), "hello, world")
979
+ ```
980
+
981
+ Code that prints `goodbye` instead fails the test; the agent fixes the code, and the harness's own
982
+ runs - the suite, then the unit tests - pass (`tests/regenerate/conformance-loop.test.ts`).
983
+
984
+ ## Agent sessions
985
+
986
+ An agent's task - the spec, how to read it, what to do, the rules, the working notes as they were - is
987
+ its **system prompt**, not its first message: every agent turri starts opens with a one-line
988
+ "begin". Compaction sums up the conversation and never the system prompt, so however long an agent
989
+ works, what it works from stays word for word as it was, and stays in the cached prefix of every call.
990
+ The one exception is a skill's executor, which is given a step at a time.
991
+
992
+ The agents that work through a job keep **one session for it**: the coding agent of a render or a spec
993
+ change, its unit test reviewer, the conformance agent, its test reviewer, the code fixer of a
994
+ conformance run, and the regression repair agent. The code fixer used to start fresh for every fix; now
995
+ each fix starts from what the ones before it tried. The agents whose value is having taken no side stay
996
+ fresh, given what they need as text: the arbiter, the judge that says whether the code, the tests or the
997
+ spec is wrong, the explorer, the planners, the diagnosis and a skill's review judges. A job that fails
998
+ and is retried is undone whole, and every agent of the retry starts fresh.
999
+
1000
+ An agent kept through a job re-reads everything it has done on every call. So between turns, once its
1001
+ conversation - what it has done, past its instructions - passes `compact-at` tokens (100,000 unless
1002
+ [the project config](config.md) says otherwise), the harness compacts it, with instructions for its role:
1003
+ the coding agent and the fixer keep what is done, what still fails and why, the decisions and every
1004
+ review problem's fate; a reviewer keeps every problem it raised and where each stands, and what it has
1005
+ already checked. pi's own compaction, when the context window is nearly full, stays on beneath it.
1006
+
1007
+ What each agent of a job did - its turns, its compactions, its tokens and cost - is at the end of the
1008
+ job's log in `.turri/jobs/`, and in `pulses`.
1009
+
1010
+ ## Working notes
1011
+
1012
+ Every job's agents start fresh, and without help each one would spend its first turns finding its
1013
+ bearings. So each agent working on a codebase - render, spec change, conformance, regression repair -
1014
+ starts with the notes the agents before it left, and before it finishes it updates them: a line
1015
+ added, changed or removed, never the whole thing rewritten. There are two sets: the code's, in `code/`, for the
1016
+ agents that change the code, and the conformance tests', in `tests/`, for the conformance agent. What one learns of
1017
+ testing the module black box - where the tests are, what they assume - would steer a coding agent towards the tests
1018
+ rather than the spec, so it is never in the code's notes; the judge, which weighs the tests against the code, reads
1019
+ both. Each set goes where its folder goes - copied up the chain, committed, rolled back. Six sections:
1020
+
1021
+ | | |
1022
+ | --- | --- |
1023
+ | Where things are | entry points, layout, where each functionality lives |
1024
+ | How to build, run and test | the commands that work, what had to be installed |
1025
+ | Assumptions | what an agent assumed where the spec is silent - a format, a default, a choice it leaves open |
1026
+ | Spec gaps | what the spec should say and does not - a behaviour the person would want to decide, as the question it leaves |
1027
+ | Pitfalls | what went wrong and what fixed it - and what the debugger found, filed by turri itself |
1028
+ | Pulses | written by turri alone, as each pulse ends: the last ten, a line each |
1029
+
1030
+ A pulse's line says what it regenerated, whether it landed, how it went - the rounds of the unit tests, the test runs, what
1031
+ the debugger found - how long it took, what it cost, and where its log is, for the whole of what its agents did:
1032
+
1033
+ ```
1034
+ - [2026-10-08 11:19 · hubspot pulse 2] HubSpot contact reading and mapping - landed; 4 rounds of the unit tests,
1035
+ 92 test runs; the debugger: the stand-in replaces a method, so it is given self · 7m 52s · $1.35 · log .turri/jobs/….log
1036
+ ```
1037
+
1038
+ It is written once anything the pulse did not land is rolled back, and committed - into the pulse's own commit when
1039
+ it landed, a commit of its own (`pulse 3 rolled back: …`) when it did not - so the next pulse, starting from the last
1040
+ commit, keeps it. `update_notes` refuses the section. What the debugger finds is filed in the pitfalls the moment it
1041
+ finds it, not left to the coding agent to write down.
1042
+
1043
+ The spec gaps a pulse's agents add are said in its report - "Spec gaps its agents met ... Put each to the user" - so
1044
+ the conversation asks you, and writes the ones you decide into the spec; the gaps stay in the notes, for the agents
1045
+ after, until then.
1046
+
1047
+ Stubborn on the specs, flexible on the assumptions: the spec is never an assumption and never
1048
+ copied into the notes, and where the two disagree the spec wins. An agent builds on the assumptions
1049
+ already there, and changes one the moment the code or the spec shows it wrong.
1050
+
1051
+ Every line says when and where it came from, stamped by the harness rather than written by the agent:
1052
+
1053
+ ```
1054
+ ## Assumptions
1055
+
1056
+ - [2026-09-24 16:39 · version_api 1] The version response's capabilities follow the JSON in the spec
1057
+ - [2026-09-24 16:52 · auth 1] Token responses carry `access_token` and `expires_in`
1058
+ ```
1059
+
1060
+ A line that is changed is stamped again, so an assumption one agent revised shows as newer than the
1061
+ ones around it. Where two lines disagree, the later one is right. A line that says nothing - "none",
1062
+ "N/A", "no new assumptions" - is refused: a section with nothing new is left alone.
1063
+
1064
+ Leaving notes is required, and only through the `update_notes` tool. The file tools refuse the
1065
+ notes file, and a change made to it any other way - from the shell, by a script - is undone. An agent
1066
+ that finishes without calling `update_notes` is asked again, up to three times; if it still has not,
1067
+ the activity log says so. The turn that asks is for the notes alone: the work is done - its testing script's run
1068
+ passed, and the agent is told so first, so its notes speak of work that succeeded - so every tool but `update_notes` is
1069
+ refused, and an agent that keeps calling them has its turn stopped. What
1070
+ landed is what the harness checked; nothing changes after it. Only work that lands is asked: a job whose code or tests do not pass - or whose
1071
+ testing script cannot run - is rolled back, notes and all, so its agent is not asked to leave any.
1072
+
1073
+ The notes are disposable - delete the file and nothing breaks; the next agent just explores a little
1074
+ more. They live in the code folder, so they are committed with it, reset with it after an
1075
+ interrupted run, and copied up with it to a module that requires this one. They are not part of the
1076
+ codebase: they are left out of the code map, the file lists and what `deploy` puts in `dist/`.
1077
+
1078
+ ## What the code is built from
1079
+
1080
+ Two records per module, each committed with what it describes in the module's `.plaingit`:
1081
+
1082
+ | | |
1083
+ | --- | --- |
1084
+ | `code/.turri.json` | the code record: the spec the code is built from - its whole requires chain's: the definitions and implementation reqs of the modules below, each tagged with its module, their functional specs among the ones it inherits, and its own - without the test reqs and the acceptance tests, which are for conformance only |
1085
+ | `tests/.turri.json` | the tests record: the functional specs the conformance tests are written for - of the code record's, with their acceptance tests - the definitions and implementation reqs they were written against, and the test reqs they follow |
1086
+
1087
+ Nothing about how a build went: whether tests passed and which files a job touched are in the
1088
+ history. And nothing else is stored: what is left to build is worked out from the records whenever a
1089
+ job ends or the spec changes - the code work from the code record to the spec now (`src/regenerate/drift.ts`),
1090
+ the conformance work from the tests record to what the tests are to be written for. Only the running
1091
+ job is kept; what the panel shows as planned is worked out again. The tests record never goes ahead of
1092
+ the code's: a conformance test exercises functionality, and only what is in the code can be tested.
1093
+
1094
+ What goes into them:
1095
+
1096
+ - **A code job landed:** the code record becomes the spec the job ends on.
1097
+ - **A conformance job landed:** the tests record becomes what its tests are written for.
1098
+ - **A module started from another's code:** that code's record, as a lower module's - see
1099
+ [where things go](#where-things-go) - and an empty tests record: the tests it inherits are the module
1100
+ below's.
1101
+ - **A functional spec named to `regenerate`:** it is marked to be regenerated again in the code record, so the next job regenerates it
1102
+ again; that job's record drops the mark.
1103
+
1104
+ A unit of work - a code job, a conformance job - lands whole or is undone whole. It starts from the
1105
+ module's last commit, putting back whatever an interrupted run left; a module with no commit yet is
1106
+ given one first. When it does not pass, the module goes back to that commit: its changes, the files it
1107
+ added and any commit it made on the way are gone, with the record they came with. Installed
1108
+ dependencies and caches stay. So the code, its tests and the records of what they were built from never
1109
+ disagree.
1110
+
1111
+ The record is the harness's alone. No agent writes it: the file tools refuse it, and what the
1112
+ harness records next is built on the record as its last commit has it, not the file on disk - so a
1113
+ change an agent's shell made to it is never carried on.
1114
+
1115
+ A record written by an earlier version of turri is read as the tree it describes, up to the
1116
+ first functionality that did not build; the next job writes it anew.