@turri-dev/cli 0.1.27-next.763d091 → 0.1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/extension.js CHANGED
@@ -1364,14 +1364,14 @@ export function projectConfigBlock(root) {
1364
1364
  ...[
1365
1365
  config.module !== undefined && of !== "stack" ? `- module: ${config.module}${where} - the module to build when the user does not name one.` : undefined,
1366
1366
  config.conformanceTests === false
1367
- ? "- conformance-tests: false - conformance tests are OFF: renders write none and run none, unless the user asks for them in this conversation."
1367
+ ? "- conformance-tests: false - conformance tests are OFF: no new ones are written, unless the user asks for them in this conversation. The ones there are are kept up to date: a functional spec that has conformance tests and is regenerated - changed, regenerated again or taken out - gets a conformance pulse for it alone once its code lands. A functional spec with none gets none."
1368
1368
  : config.conformanceTests === "chosen"
1369
1369
  ? "- conformance-tests: chosen - conformance tests are on for the functional specs chosen: those with acceptance tests always, those the chooser picks as each code pulse ends from what it regenerated, and those the user asks for with conform. A conformance pulse starts once the module's code is built, before anything is built on it. Once chosen, a functional spec keeps them."
1370
1370
  : config.conformanceTests === "module"
1371
1371
  ? "- conformance-tests: module - conformance tests are on for the functional specs chosen: those with acceptance tests always, those the chooser picks - and plans into pulses - once the whole module is regenerated, and those the user asks for with conform. They run before anything is built on the module. Once chosen, a functional spec keeps them."
1372
1372
  : config.conformanceTests === true
1373
1373
  ? "- conformance-tests: all - conformance tests are on, for every functional spec of every module that has test reqs."
1374
- : "- conformance-tests: not set - conformance tests are OFF, as with false: renders write none and run none, unless the user asks for them in this conversation.",
1374
+ : "- conformance-tests: not set - conformance tests are OFF, as with false: no new ones are written, unless the user asks for them in this conversation; the ones there are are kept up to date - a functional spec that has them and is regenerated gets a conformance pulse for it alone once its code lands.",
1375
1375
  config.review === true
1376
1376
  ? "- review: true - the code and its tests are reviewed once they pass: two reviews at most, the arbiter weighing the second."
1377
1377
  : `- review: ${config.review === false ? "false" : "not set, so off"} - the code and its tests are not reviewed: a pulse lands once its tests pass.`,
@@ -65,7 +65,7 @@ export function conformanceCasesBlock(cases) {
65
65
  lines.push(`- Changed - its text, its acceptance tests, or a concept it uses: ${named(cases.patch)}.`, " Its conformance tests exist: rewrite them to what it says now. The tests of everything else stay as they are.");
66
66
  }
67
67
  if (cases.again.length > 0) {
68
- lines.push(`- Regenerated again - its code was built anew, and its conformance tests were written against the code it replaced: ${named(cases.again)}.`, " Its text did not change, but the code did: write its tests again for the new code - that they still pass is", " no sign they fit it. What they check that the specification says stays checked, as the new code is reached.", " What they check that the specification leaves open - a path, a field, a message, a format the old code chose", " and the specification never names - is the new code's choice now: rewrite those checks to what the new code", " does, or take them out. No test may hold the new code to what only the old code did. A run that leaves every", " test file labelled with it as it was is sent back. The tests of everything else stay as they are.");
68
+ lines.push(`- Regenerated again - its code was built anew, and its conformance tests were written against the code it replaced: ${named(cases.again)}.`, " Its text did not change, but the code did. Run its tests against the new code. Those that pass are tests of the", " new code too - conformance tests are black box - and are not rewritten. Fix what fails against the", " specification: what a failing test checks that the specification says stays checked, the test changed only as", " the new code needs it reached; what it checks that the specification leaves open - a path, a field, a message,", " a format the old code chose and the specification never names - is the new code's choice now: rewrite that", " check to what the new code does, or take it out. No test may hold the new code to what only the old code did.", " The tests of everything else stay as they are.");
69
69
  }
70
70
  if (cases.delete.length > 0)
71
71
  lines.push(`- Taken out - remove its conformance tests: ${named(cases.delete)}.`);
@@ -109,11 +109,6 @@ export interface RenderConformanceTestsResult {
109
109
  };
110
110
  /** The tests were sent back to be written and labelled, and never were: what was missing the last time. */
111
111
  unlabelled?: string[];
112
- /**
113
- * Of the functional specs the job regenerates again, those whose tests this run wrote - a test file labelled with it
114
- * added or changed. Only these have tests for the new code; the rest are still marked to regenerate again.
115
- */
116
- rewritten?: string[];
117
112
  /** The tests were optimised as far as REVIEW_ROUNDS reviews could take them: what the last one still suggested. */
118
113
  reviewWaived?: ReviewProblem[];
119
114
  /** The suite passed, but the tests never passed review: what the review last found. */
@@ -131,8 +126,6 @@ export interface RenderConformanceTestsResult {
131
126
  * and this refuses to start without one.
132
127
  */
133
128
  export declare function renderConformanceTests(options: RenderConformanceTestsOptions): Promise<RenderConformanceTestsResult>;
134
- /** Sent back when the tests of a functional spec regenerated again are as they were: they are to be written for the new code. */
135
- export declare function againPrompt(frids: string[]): string;
136
129
  /**
137
130
  * Why conformance tests did not land, in a line. Tests sent back to be labelled and never labelled may well pass: the
138
131
  * line says so, rather than that they failed.
@@ -10,7 +10,7 @@ import { firstLine, record } from "./ledger.js";
10
10
  import { createWorkLedger, describeAccounts, SUBMIT_WORK_NOTE, unanswered, unansweredPrompt } from "./submit-work.js";
11
11
  import { CONFORMANCE_COMPACTION } from "./compaction.js";
12
12
  import { NOTES_TURN, notesForSession, passedOutcome, readNotes, reflectOnReview, withNotes } from "./notes.js";
13
- import { acceptanceLabel, acceptanceText, labelledFiles, labelsPrompt, labelsPromptFor, misplacedConformanceTests, misplacedTestsPrompt, missingTestLabels } from "./test-kinds.js";
13
+ import { acceptanceLabel, acceptanceText, labelsPrompt, labelsPromptFor, misplacedConformanceTests, misplacedTestsPrompt, missingTestLabels } from "./test-kinds.js";
14
14
  import { createScriptTool, findTestScripts, projectRootFor, requireTestScripts, runConformanceScript, runUnitScript, failureSignature, STUCK_ROUNDS, scriptFailure, staticChecksOnly, withTestingScripts, } from "./test-scripts.js";
15
15
  import { createWebTools, WEB_TOOLS } from "./web.js";
16
16
  import { createMyDiffTool } from "./self-check.js";
@@ -345,19 +345,6 @@ export async function renderConformanceTests(options) {
345
345
  ? "turri is bringing the conformance tests in line with the spec change"
346
346
  : "turri is writing conformance tests from the spec");
347
347
  let response = await askConformance(BEGIN, options.onDelta);
348
- // The functional specs of this module the job regenerates again, and of those, the ones whose tests this run has
349
- // not written yet: no test file labelled with it added or changed since the run began.
350
- const againFrids = (options.cases?.again ?? []).filter((spec) => spec.module === undefined || spec.module === moduleName).map((spec) => spec.frid);
351
- const rewrittenAgain = () => {
352
- const changes = diffFiles(testsAtStart, digestFiles(conformanceDir));
353
- const touchedFiles = new Set([...changes.added, ...changes.changed]);
354
- return againFrids.filter((id) => labelledFiles(conformanceDir, id).some((file) => touchedFiles.has(file)));
355
- };
356
- const staleAgain = () => {
357
- const done = new Set(rewrittenAgain());
358
- return againFrids.filter((id) => !done.has(id));
359
- };
360
- let againAsks = 0;
361
348
  const maxRounds = options.maxRounds ?? DEFAULT_MAX_ROUNDS;
362
349
  let verified = false;
363
350
  let rounds = 0;
@@ -418,20 +405,6 @@ export async function renderConformanceTests(options) {
418
405
  continue;
419
406
  }
420
407
  }
421
- // Regenerated again: its tests were written against the code it replaced, and their passing says nothing of the new
422
- // code - they pass on what only the old code did as readily. Its tests have to be written again in this run.
423
- const stale = staleAgain();
424
- if (stale.length > 0) {
425
- if (againAsks >= LABEL_ASKS) {
426
- stage(`the tests of functionalit${stale.length === 1 ? "y" : "ies"} ${stale.join(", ")}, regenerated again, were sent back ${LABEL_ASKS} times to be written again, and still are not - stopping`);
427
- unlabelled = stale.map((id) => `The tests of functionality ${id}, regenerated again, were not written again for the new code: no test file labelled with it changed.`);
428
- break;
429
- }
430
- againAsks += 1;
431
- stage(`the tests of functionalit${stale.length === 1 ? "y" : "ies"} ${stale.join(", ")}, regenerated again, are as they were - the conformance agent writes them again`);
432
- response = await askConformance(againPrompt(stale), options.onDelta);
433
- continue;
434
- }
435
408
  // The suite is the tests folder: a conformance test in the code folder is in the wrong place,
436
409
  // and not the coding agent's to write.
437
410
  const misplaced = misplacedConformanceTests(buildDir);
@@ -857,7 +830,6 @@ export async function renderConformanceTests(options) {
857
830
  ...(stuck !== undefined ? { stuck } : {}),
858
831
  ...(escalation !== undefined ? { escalation } : {}),
859
832
  ...(unlabelled !== undefined ? { unlabelled } : {}),
860
- ...(againFrids.length > 0 ? { rewritten: rewrittenAgain() } : {}),
861
833
  ...(reviewWaived !== undefined ? { reviewWaived } : {}),
862
834
  ...(verified && green !== undefined ? { green } : {}),
863
835
  ...(!verified && lastReview !== undefined ? { review: lastReview } : {}),
@@ -870,18 +842,6 @@ export async function renderConformanceTests(options) {
870
842
  await fixerServices.stopAll();
871
843
  }
872
844
  }
873
- /** Sent back when the tests of a functional spec regenerated again are as they were: they are to be written for the new code. */
874
- export function againPrompt(frids) {
875
- const which = frids.length === 1 ? `functionality ${frids[0]}` : `functionalities ${frids.join(", ")}`;
876
- return [
877
- `${which[0].toUpperCase()}${which.slice(1)} ${frids.length === 1 ? "is" : "are"} regenerated again: ${frids.length === 1 ? "its" : "their"} code was built anew, and no test file labelled with ${frids.length === 1 ? "it" : "them"} has changed.`,
878
- "Tests that pass prove nothing here: they were written against the code it replaced, and pass on what only the old",
879
- "code did as readily as on what the specification says. Read the new code, and write the tests again for it: what",
880
- "the specification says, checked as the new code is reached; what it leaves open - a path, a field, a message, a",
881
- "format the old code chose - checked as the new code does it, or taken out. Keep each label. The tests of",
882
- "everything else stay as they are.",
883
- ].join("\n");
884
- }
885
845
  /**
886
846
  * Why conformance tests did not land, in a line. Tests sent back to be labelled and never labelled may well pass: the
887
847
  * line says so, rather than that they failed.
@@ -1,4 +1,3 @@
1
- import { type MarshalledPlainSource } from "../plain/spec.ts";
2
1
  import { type ChunkAgents } from "./chunk-plan.ts";
3
2
  import { type SpecGap } from "./notes.ts";
4
3
  import { type Job, type JobRegistry, type PulseCases } from "./jobs.ts";
@@ -388,12 +387,6 @@ export declare function describeModules(statuses: ModuleStatus[], options?: {
388
387
  }): string;
389
388
  /** The functional specs a pulse covers, by case, each with the module whose spec it is: a host's to light and mark. */
390
389
  export declare function pulseCases(cases: JobCases, moduleName: string): PulseCases;
391
- /**
392
- * What a conformance job records its tests are written for: its step's tree, but a functional spec of the module it
393
- * regenerates again keeps its mark unless the run wrote its tests - tests that passed as they were are still the old
394
- * code's, and still conformance work.
395
- */
396
- export declare function keepAgainMarks(tree: MarshalledPlainSource, cases: JobCases, moduleName: string, rewritten: string[]): MarshalledPlainSource;
397
390
  /**
398
391
  * A module's first pulse when it builds one functional spec - the project set up and the smallest thing that runs: it lands on its
399
392
  * unit tests alone, with no review. A reviewer, and an arbiter after it, on a scaffold is time spent before anything can
@@ -236,16 +236,19 @@ export function createWorkLoop(options) {
236
236
  * Which functional specs the conformance tests are for: every one - unless the config has them for the chosen ones,
237
237
  * or the conversation named some over a config that has them off. Then: those named, those with acceptance tests
238
238
  * when the config chooses, and those tested already - a choice is kept, and tests are never taken out because
239
- * other functional specs were named.
239
+ * other functional specs were named. Off in the config and not asked for: those tested already alone - their tests
240
+ * kept up to date, and none written for any other.
240
241
  */
241
242
  const chosenOf = (state, spec, tests) => {
242
243
  const named = state.conformance?.chosen;
243
244
  const choosing = configChosen(tipEntry(state).plainFile);
245
+ const tested = new Set((tests?.[FUNCTIONAL_REQUIREMENTS] ?? []).map((item) => item.frid));
246
+ if (state.conformance === undefined && !configConformance(tipEntry(state).plainFile))
247
+ return (frid) => tested.has(frid);
244
248
  if (!choosing && (state.conformance === undefined || named === undefined || configConformance(tipEntry(state).plainFile)))
245
249
  return undefined;
246
250
  if (choosing && state.conformance !== undefined && named === undefined)
247
251
  return undefined;
248
- const tested = new Set((tests?.[FUNCTIONAL_REQUIREMENTS] ?? []).map((item) => item.frid));
249
252
  const specs = spec.tree[FUNCTIONAL_REQUIREMENTS] ?? [];
250
253
  const accepted = (frid) => (specs[Number(frid) - 1]?.[ACCEPTANCE_TESTS] ?? []).length > 0;
251
254
  return (frid) => tested.has(frid) || named?.has(frid) === true || (choosing && accepted(frid));
@@ -326,10 +329,21 @@ export function createWorkLoop(options) {
326
329
  return [];
327
330
  });
328
331
  };
329
- /** Whether a codebase's conformance tests are written: asked for, or on in the config - with test reqs to write them from, and code to test. */
330
- const conformanceWanted = (state, spec) => (state.conformance !== undefined || configConformance(tipEntry(state).plainFile)) &&
331
- (spec.tree[TEST_REQUIREMENTS] ?? []).length > 0 &&
332
- readRecord(tipEntry(state).buildDir) !== null;
332
+ /**
333
+ * Whether a codebase's conformance tests are written: asked for, or on in the config - with test reqs to write them
334
+ * from, and code to test. Off and not asked for, the tests there are are still kept up to date: wanted when a
335
+ * functional spec that has conformance tests was added, changed, regenerated again or taken out in the code - the
336
+ * work then is for those alone (chosenOf). Work for the test reqs or definitions alone does not start it.
337
+ */
338
+ const conformanceWanted = (state, spec) => {
339
+ if ((spec.tree[TEST_REQUIREMENTS] ?? []).length === 0 || readRecord(tipEntry(state).buildDir) === null)
340
+ return false;
341
+ if (state.conformance !== undefined || configConformance(tipEntry(state).plainFile))
342
+ return true;
343
+ const tested = testedOf(state);
344
+ const cases = casesOf(tested, workOf("conformance", tested, state, spec), { module: tipEntry(state).moduleName });
345
+ return cases.add.length + cases.patch.length + cases.again.length + cases.delete.length > 0;
346
+ };
333
347
  /**
334
348
  * The functional specs a conformance job is scheduled for, as the spec has them now - refused when one is not in
335
349
  * the spec, or the module has no test reqs to write tests from: no code job would build it, or no test be written.
@@ -1679,7 +1693,7 @@ const defaultConformanceRunner = async (job, onDelta) => {
1679
1693
  onDelta,
1680
1694
  });
1681
1695
  if (result.passed) {
1682
- writeTestsRecord(result.conformanceDir, keepAgainMarks(job.planned.step.tree, job.planned.cases, job.moduleName, result.conformance.rewritten ?? []));
1696
+ writeTestsRecord(result.conformanceDir, job.planned.step.tree);
1683
1697
  landWork(job.buildDir, `conformance tests: ${job.planned.title}`);
1684
1698
  }
1685
1699
  return { landed: result.passed, report: describeSpecDiffConformance(result), ...(result.specGaps !== undefined ? { specGaps: result.specGaps } : {}) };
@@ -1689,18 +1703,6 @@ export function pulseCases(cases, moduleName) {
1689
1703
  const of = (specs) => specs.map((spec) => ({ module: spec.module ?? moduleName, frid: spec.frid }));
1690
1704
  return { add: of(cases.add), patch: of(cases.patch), again: of(cases.again), delete: of(cases.delete) };
1691
1705
  }
1692
- /**
1693
- * What a conformance job records its tests are written for: its step's tree, but a functional spec of the module it
1694
- * regenerates again keeps its mark unless the run wrote its tests - tests that passed as they were are still the old
1695
- * code's, and still conformance work.
1696
- */
1697
- export function keepAgainMarks(tree, cases, moduleName, rewritten) {
1698
- const stale = new Set(cases.again.filter((spec) => (spec.module ?? moduleName) === moduleName && !rewritten.includes(spec.frid)).map((spec) => spec.frid));
1699
- if (stale.size === 0)
1700
- return tree;
1701
- const items = tree[FUNCTIONAL_REQUIREMENTS] ?? [];
1702
- return { ...tree, [FUNCTIONAL_REQUIREMENTS]: items.map((item) => (item.frid !== undefined && stale.has(item.frid) ? { ...item, [REGENERATE_AGAIN]: true } : item)) };
1703
- }
1704
1706
  /**
1705
1707
  * A module's first pulse when it builds one functional spec - the project set up and the smallest thing that runs: it lands on its
1706
1708
  * unit tests alone, with no review. A reviewer, and an arbiter after it, on a scaffold is time spent before anything can
@@ -21,11 +21,6 @@ export declare function acceptanceText(item: string): string;
21
21
  * test file carries it, and each acceptance test no test is labelled as implementing.
22
22
  */
23
23
  export declare function missingTestLabels(testsDir: string, frid: string, acceptanceTests: string[]): string[];
24
- /**
25
- * The test files that carry a functionality's labels - its conformance tests' or any of its acceptance tests'. The
26
- * harness's own files beside them - the notes, the record - are not tests, whatever they mention.
27
- */
28
- export declare function labelledFiles(testsDir: string, frid: string): string[];
29
24
  /** Sent back when the labels are missing: which, and how to label them. */
30
25
  export declare function labelsPrompt(frid: string, missing: string[], empty?: boolean, hasAcceptance?: boolean): string;
31
26
  /**
@@ -54,24 +54,6 @@ export function missingTestLabels(testsDir, frid, acceptanceTests) {
54
54
  });
55
55
  return missing;
56
56
  }
57
- /**
58
- * The test files that carry a functionality's labels - its conformance tests' or any of its acceptance tests'. The
59
- * harness's own files beside them - the notes, the record - are not tests, whatever they mention.
60
- */
61
- export function labelledFiles(testsDir, frid) {
62
- const id = frid.replace(/\./g, "\\.");
63
- const label = new RegExp(`(conformance tests|acceptance test \\d+) of functionality ${id}(?![0-9.]*[0-9])`);
64
- return listFiles(testsDir).filter((file) => {
65
- if (file.split(/[\\/]/).at(-1).startsWith(".turri"))
66
- return false;
67
- try {
68
- return label.test(normalise(readFileSync(join(testsDir, file), "utf8")));
69
- }
70
- catch {
71
- return false;
72
- }
73
- });
74
- }
75
57
  /** Sent back when the labels are missing: which, and how to label them. */
76
58
  export function labelsPrompt(frid, missing, empty = false, hasAcceptance = true) {
77
59
  return labelsPromptFor([{ frid, missing }], empty, hasAcceptance);
package/docs/config.md CHANGED
@@ -83,7 +83,7 @@ models: # each agent role's model, thinking and tur
83
83
  | `harness-model` | the model `turri` starts on - the one you talk to - and, in the conversation, the planner that cuts the work into jobs (on whatever model the chat is on when it plans); under `turri regenerate`, the planner too | [pi](https://pi.dev)'s configured model |
84
84
  | `coding-model` | every regeneration: functionalities, \*\*\*plain diffs, conformance tests, repairs, planning \*\*\*plain diffs, the explorer | `harness-model` |
85
85
  | `judge-model` | the judge and the test review of a conformance run | `coding-model` |
86
- | `conformance-tests` | `all` (or `true`): conformance tests for every functional spec of every module with test reqs, written once each module's code is built, before anything is built on it. `chosen`: for the functional specs chosen - every one with acceptance tests, and those the chooser picks as each code pulse ends, from what that pulse regenerated. `module`: the same, but the chooser is asked once, when the whole module is regenerated, and plans the conformance pulses too. Under both, the choice is made inside the pulse, before anything is built on the module, and the pulse's report says what was chosen and why; those the person asks for with `conform` are written too; once chosen, a functional spec keeps them, and they are rewritten when it changes - see [who chooses, and when](regenerating.md#conformance-tests-in-the-work-loop). `false`: none written, and none of the existing ones run - until the conversation asks with `conform` | `false` |
86
+ | `conformance-tests` | `all` (or `true`): conformance tests for every functional spec of every module with test reqs, written once each module's code is built, before anything is built on it. `chosen`: for the functional specs chosen - every one with acceptance tests, and those the chooser picks as each code pulse ends, from what that pulse regenerated. `module`: the same, but the chooser is asked once, when the whole module is regenerated, and plans the conformance pulses too. Under both, the choice is made inside the pulse, before anything is built on the module, and the pulse's report says what was chosen and why; those the person asks for with `conform` are written too; once chosen, a functional spec keeps them, and they are rewritten when it changes - see [who chooses, and when](regenerating.md#conformance-tests-in-the-work-loop). `false`: no new ones written - until the conversation asks with `conform` - and the existing ones kept up to date: a functional spec that has conformance tests and is regenerated gets a conformance pulse for it alone once its code lands | `false` |
87
87
  | `conformance-budget` | under `conformance-tests: chosen` or `module`: how many of a module's functional specs may be chosen for conformance tests, beside those with acceptance tests - a count (`2`) or a share of its functional specs (`30%`, rounded up, at least one). Every choice for the module counts, whenever it was made; the chooser is told what is left, and can choose no more. Your own `conform` is not limited. A stack's `config.turri.<stack>.yaml` can set its own | no limit |
88
88
  | `review` | `true` or `false`: whether the code and its unit tests - and the conformance tests - are reviewed once they pass: two reviews at most, the second weighed by the arbiter; off, a job lands once its tests pass. A module's first pulse of one functional spec - the project set up and the smallest thing that runs - lands on its unit tests with no review - see [regenerating the code](regenerating.md#the-code-and-its-unit-tests-are-reviewed) | `false` |
89
89
  | `mutation-testing` | `true` or `false`: whether the coding agent and the reviewer have `can_it_fail` - one change put in the code for one run of the unit testing script, to see that a test catches it; on a copy of the code, or in place and put back after the run (see [regenerating the code](regenerating.md#checking-its-own-work)). `turri regenerate --mutation-testing false` for one run | `true` |
@@ -170,7 +170,7 @@ A job keeps the model it was queued with: choosing another holds for what is que
170
170
 
171
171
  ## Conformance tests
172
172
 
173
- `conformance-tests:` is the one switch, and the chat and every regeneration follow it. `false` turns them off entirely: no conformance tests are written, the ones already in a codebase are not run, and no agent is shown the conformance testing script. No key is the same as `false`: conformance tests are off by default. `all` (or `true`) means on wherever a module has `***test reqs***` - a module without them has nothing to write conformance tests from, so it writes none, but still keeps the codebase's existing ones passing. Asked in the conversation (`conform`), or with `--conformance-tests all|chosen|module|false` on `turri regenerate` and `change-plain` - for that run, the file left as it is - a regeneration does otherwise.
173
+ `conformance-tests:` is the one switch, and the chat and every regeneration follow it. `false` writes no new conformance tests, and keeps the ones there are up to date: a functional spec that has conformance tests - it is in `tests/.turri.json` - and is added, changed, regenerated again or taken out in the code gets a conformance pulse once its code lands, for it alone, the whole suite run with it. A functional spec with none gets none, though others of its module have them, and a module with none gets no conformance pulse at all. No key is the same as `false`: conformance tests are off by default. `all` (or `true`) means on wherever a module has `***test reqs***` - a module without them has nothing to write conformance tests from, so it writes none, but still keeps the codebase's existing ones passing. Asked in the conversation (`conform`), or with `--conformance-tests all|chosen|module|false` on `turri regenerate` and `change-plain` - for that run, the file left as it is - a regeneration does otherwise.
174
174
 
175
175
  The chat writes `conformance-tests: false` into a new project unless you ask for tests.
176
176
 
@@ -224,7 +224,7 @@ The same `config.turri.yaml` holds the project's other defaults - `module`, `mod
224
224
 
225
225
  They are required: a build with no unit testing script, or with conformance on and no conformance testing script, stops before it starts and says which skill adds it.
226
226
 
227
- **The prepare script** is optional: turri never writes one, and runs one the project has - `prepare-environment-script:` in the config, else the one `prepare_environment*.sh` at the root, else in `test_scripts/` - on the build, before every run of the conformance testing script: the harness's own, and the agents' `run_conformance_tests`. Both get the same build folder - the code in place, or the same fresh copy - so what it sets up for that build, the conformance testing script finds. With conformance off it is not run. Every agent shown the conformance testing script - the explorer, the conformance agent, the judge, the code fixer and the repair agent - is shown it too, before the conformance testing script.
227
+ **The prepare script** is optional: turri never writes one, and runs one the project has - `prepare-environment-script:` in the config, else the one `prepare_environment*.sh` at the root, else in `test_scripts/` - on the build, before every run of the conformance testing script: the harness's own, and the agents' `run_conformance_tests`. Both get the same build folder - the code in place, or the same fresh copy - so what it sets up for that build, the conformance testing script finds. With conformance off it runs only in a conformance pulse that keeps existing tests up to date. Every agent shown the conformance testing script - the explorer, the conformance agent, the judge, the code fixer and the repair agent - is shown it too, before the conformance testing script.
228
228
 
229
229
  **Where they run.** On this machine, as you would run them: unfenced - no sandbox, no command check, no audit - in your own environment with this machine's toolchains, turri's model providers' API keys alone left out. They are yours, 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 agents' `run_unit_tests` and `run_conformance_tests`, which run them exactly as the harness does - through the host runner, in a process group of their own, so the time limit and a stopped job end the script and all it started. A toolchain the script needs and this machine lacks - exit 69, exit 127, or a run that ended on a `command not found` / `failed to run command`, the last line it printed (`missingToolchain`) - is yours to install. Only on that evidence: a `command not found` earlier in the output, the run going on after it and failing for its own reasons, is a warning - a shell profile's, an optional tool probed for - and the failure is the agent's to fix. A missing toolchain is yours to install, never the agent's: the agent is told to report it with `report_environment_error` rather than work around it, and the pulse stops at the harness's first run of either script - unit or conformance - that cannot find it, rolled back, saying what to install (see [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 shell is fenced, what your script runs is not - an accepted gap.
230
230
 
@@ -284,11 +284,11 @@ It is told, too, what to do with each functional spec the job touches, by its ca
284
284
  | 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 |
285
285
  | add | a functional spec is new | build it and write its unit tests | write its tests |
286
286
  | 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 |
287
- | again | `regenerate` named it: it is built, and marked in the code record to be regenerated again | take its implementation out and build it anew, doing what \*\*\*plain says now - the old code already doing it is no reason to keep it; no second implementation beside the old, nothing of it left unused; its unit tests written anew. A coding agent that writes nothing is sent back twice to build it anew, and then the pulse does not land | its tests were written against the code it replaced, and pass on what only the old code did as readily: written again for the new code - what they check that \*\*\*plain says stays checked, and what they check that \*\*\*plain leaves open - a path, a field, a message the old code chose - is rewritten to what the new code does, or taken out. A run that leaves every test file labelled with it as it was is sent back, three times at most, and then does not land |
287
+ | again | `regenerate` named it: it is built, and marked in the code record to be regenerated again | take its implementation out and build it anew, doing what \*\*\*plain says now - the old code already doing it is no reason to keep it; no second implementation beside the old, nothing of it left unused; its unit tests written anew. A coding agent that writes nothing is sent back twice to build it anew, and then the pulse does not land | its tests were written against the code it replaced: run against the new code - black box, those that pass are its tests too, and are not rewritten; one that fails is judged against \*\*\*plain like any failure: what it checks that \*\*\*plain says stays checked, and what it checks that \*\*\*plain leaves open - a path, a field, a message the old code chose - is rewritten to what the new code does, or taken out |
288
288
  | delete | a functional spec is gone | take out its code and the tests only it had | take out its tests |
289
289
  | 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 |
290
290
 
291
- **Regenerating again.** `regenerate` with functionalities named regenerates them again though their \*\*\*plain did not change - made better, on another model, after many patches. Each is marked in the code record of every codebase it is built in (`regenerate_again`, committed), and nothing else changes: the record now differs from \*\*\*plain at that item, so the work loop plans it as it plans any change. A functional spec of a module below is regenerated again where its code lives - the codebase at the tip of each chain built on it, never the module's own codebase left behind - marked among that codebase's required functional specs. The planner groups the ones regenerated again as it groups new ones - up to three a job, only those next to each other in one module together - and the job is given the definitions and 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 records it as \*\*\*plain has it, without the mark. Its conformance tests are marked with it, in the tests record of the codebase whose own functional spec it is: they were written against the code being replaced, and may hold the new code to what only the old code chose - `/healthcheck` where \*\*\*plain says only that there is a health check, and the new code answers `/health`. While the code regenerates they stay as they are; once it lands, the mark is conformance work like any change, and a conformance job writes them again, in the again case above, and runs the whole suite. That they pass is not taken for written again: the run lands only once a test file labelled with it was added or changed in it, and the tests record drops the mark only of a functional spec whose tests the run wrote. Until it lands, regen shows its tests as written for an earlier build, and they are not counted as conformance tested.
291
+ **Regenerating again.** `regenerate` with functionalities named regenerates them again though their \*\*\*plain did not change - made better, on another model, after many patches. Each is marked in the code record of every codebase it is built in (`regenerate_again`, committed), and nothing else changes: the record now differs from \*\*\*plain at that item, so the work loop plans it as it plans any change. A functional spec of a module below is regenerated again where its code lives - the codebase at the tip of each chain built on it, never the module's own codebase left behind - marked among that codebase's required functional specs. The planner groups the ones regenerated again as it groups new ones - up to three a job, only those next to each other in one module together - and the job is given the definitions and 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 records it as \*\*\*plain has it, without the mark. Its conformance tests are marked with it, in the tests record of the codebase whose own functional spec it is: they were written against the code being replaced, and may hold the new code to what only the old code chose - `/healthcheck` where \*\*\*plain says only that there is a health check, and the new code answers `/health`. While the code regenerates they stay as they are; once it lands, the mark is conformance work like any change - with `conformance-tests: false` too, its tests being there - and a conformance job runs them on the new code, in the again case above, with the whole suite. The mark means its tests have not yet run on its new code: the job drops it once the whole suite passes, and one that does not land keeps it. Until it lands, regen shows its tests as written for an earlier build, and they are not counted as conformance tested.
292
292
 
293
293
  A functional spec is patched when a concept it uses changed as well as when its own text did: the harness follows each functional spec's concepts through the definitions. Fresh is only where nothing exists: a module that requires another starts from what it inherits, and its first job adds or patches.
294
294
 
@@ -321,7 +321,7 @@ A conformance job is a \*\*\*plain diff's conformance run: the tests of its chan
321
321
 
322
322
  **Up the chain.** A module built on another starts from its code and its conformance tests, copied up, and its conformance testing script runs those with its own. So a module waits for the one below it until that one's code is built and its conformance tests - those wanted, chosen or scheduled - are written and pass; only then is its codebase started from there.
323
323
 
324
- **Who chooses, and when.** With `conformance-tests: all` every functional spec is tested, and with `false` none is unless the person asks with `conform`, for the session. With `chosen` or `module`, every one with acceptance tests - the author said what to check - and those the chooser picks: an agent on `harness-model` (or `models: chooser`), in the chat and on the command line alike. It reads the module's \*\*\*plain and names those worth black-box tests - what a user or a client relies on, not a detail the unit tests cover - and why.
324
+ **Who chooses, and when.** With `conformance-tests: all` every functional spec is tested, and with `false` none is unless the person asks with `conform`, for the session - but the tests there are are kept up to date: a functional spec in the tests record that a code pulse added, changed, regenerated again or took out gets a conformance pulse once its code lands, for it alone. Work for the test reqs or definitions alone starts none, and a functional spec with no conformance tests never gets them so. A module waits for that pulse below it, and drift shows it, as any conformance work. With `chosen` or `module`, every one with acceptance tests - the author said what to check - and those the chooser picks: an agent on `harness-model` (or `models: chooser`), in the chat and on the command line alike. It reads the module's \*\*\*plain and names those worth black-box tests - what a user or a client relies on, not a detail the unit tests cover - and why.
325
325
 
326
326
  - `chosen`: it is asked as each code pulse ends, as the pulse's last stage, of what that pulse regenerated that no conformance test is for.
327
327
  - `module`: it is asked once, when the module's last code pulse lands, of every functional spec of the module that is built and has none - and it plans them too, into groups, each a conformance pulse of its own.
@@ -473,7 +473,7 @@ What goes into them:
473
473
  - **A code job landed:** the code record becomes the \*\*\*plain description the job ends on.
474
474
  - **A conformance job landed:** the tests record becomes what its tests are written for.
475
475
  - **A module started from another's code:** that code's record, as a lower module's - see [where things go](#where-things-go) - and an empty tests record: the tests it inherits are the module below's.
476
- - **A functional spec named to `regenerate`:** it is marked to be regenerated again in the code record, so the next job regenerates it again; that job's record drops the mark. Its conformance tests, when it has them, are marked in the tests record too, and the conformance job that writes them again for the new code drops that mark - only once a test file labelled with it changed in the run, never because the old tests still pass.
476
+ - **A functional spec named to `regenerate`:** it is marked to be regenerated again in the code record, so the next job regenerates it again; that job's record drops the mark. Its conformance tests, when it has them, are marked in the tests record too, and the conformance job that runs them on the new code drops that mark once the whole suite passes.
477
477
 
478
478
  A unit of work - a code job, a conformance job - lands whole or is undone whole. It starts from the module's last commit, putting back whatever an interrupted run left; a module with no commit yet is given one first. When it does not pass, the module goes back to that commit: its changes, the files it added and any commit it made on the way are gone, with the record they came with. Installed dependencies and caches stay. So the code, its tests and the records of what they were built from never disagree.
479
479
 
package/docs/using.md CHANGED
@@ -88,7 +88,7 @@ A regeneration takes minutes, so in the TUI every tool that regenerates starts t
88
88
  - **What these commands show you, the chat knows.** What `/regenerate` and `/halt activated` tell you - \*\*\*plain that does not parse, the pulses planned, a server halted - stays in the chat under the command, and since a slash command runs outside the conversation, it is put in the conversation as well: say "fix it" next and turri knows what you are looking at. Once `/regenerate` has started pulses, turri says so in the chat too - what runs and what is planned, and that you need not wait for it - without starting anything more for it; a module already up to date gets the plan's answer alone. A halted pulse reaches it as every pulse's end does.
89
89
  - **Nothing is queued.** What is left to build is worked out from what each codebase is built from and \*\*\*plain as it is now - again whenever a pulse ends or \*\*\*plain changes - and the first pulse of it runs; see [a whole module](regenerating.md#a-whole-module). Changes that overlap never pile up: the next pulse builds \*\*\*plain as it is. The pulses planned after the one running are listed behind it, as queued, and so is each module waiting for the one it is built on - "waits for base" - until it can be planned. A change inside what the running pulse regenerates - a functional spec it regenerates reworded or given a sub-bullet, a definition or req it is given, a file they link - steers it: its agent is told, and it lands \*\*\*plain as it is now there, twice a pulse at most. Otherwise a pulse building something \*\*\*plain no longer wants is stopped and rolled back - unless `allow-to-stop-jobs: false` in `config.turri.yaml`, which has it land first and the change regenerated on top. To drop something, take it out of \*\*\*plain - one \*\*\*plain diff. Stopping a pulse leaves its change in \*\*\*plain: the codebase waits until its \*\*\*plain changes or it is asked for again.
90
90
  - **A change to a module below** is made in the codebase at the tip of the chain, where its code lives; the codebase below is left as it was, and is brought up to its own \*\*\*plain only when a new module is to start from it. \*\*\*plain moved into a module the code was not built on stops the codebase: no change to its code brings that module in, so it has to be started over - its code and conformance tests taken out, kept in its history, and built again from the bottom of the chain. That is never done unasked: the chat asks you, saying why, and regenerates it from scratch once you agree; on the command line `turri regenerate` asks at the terminal, and `--start-over` agrees in advance.
91
- - **Conformance tests are a track of their own.** A code pulse lands once its unit tests pass and are reviewed. Then, before the next one builds on it, a conformance pulse writes and runs the tests of what it built - from the test reqs and acceptance tests - with the whole suite the module inherits, and, where one fails, fixes the test or the code, whichever is wrong; what they are written for is recorded in `tests/.turri.json`. With `conformance-tests: false` none is written until you ask - `conform`, for a module or some of its functional specs. A conformance pulse that does not pass is undone whole and halts the conformance tests alone: the code goes on being built.
91
+ - **Conformance tests are a track of their own.** A code pulse lands once its unit tests pass and are reviewed. Then, before the next one builds on it, a conformance pulse writes and runs the tests of what it built - from the test reqs and acceptance tests - with the whole suite the module inherits, and, where one fails, fixes the test or the code, whichever is wrong; what they are written for is recorded in `tests/.turri.json`. With `conformance-tests: false` none is written until you ask - `conform`, for a module or some of its functional specs - but those there are are kept up to date: a functional spec that has conformance tests and is regenerated gets a conformance pulse for it alone. A conformance pulse that does not pass is undone whole and halts the conformance tests alone: the code goes on being built.
92
92
  - **A pulse that fails** - its work errors, or it does not pass - is run once more; one stopped on what only you can fix - the machine lacks something, a testing script no code could pass - is not. Failing again, it stops, and so does every pulse queued behind it on the same module, without running - the other modules' pulses go on. The harness then works out why: an agent that can read the project's \*\*\*plain, code, tests, testing scripts and logs, and turri's own source, skills and rules, says what happened, why, whether the fix belongs in \*\*\*plain, the environment, the code or turri itself, and exactly what to do.
93
93
  - **When a pulse finishes** the transcript shows its line - `✓`, `✗` or `■`, its module, kind and number, how long it took and what it cost, never what it regenerated - `✓ shorty · conformance pulse 4 finished after 3m 47s · 488.6k tok · $0.02` - and the chat, which gets its whole report, reacts then and there, whatever else is running or queued, without waiting for you to speak: at once when it is idle, else as soon as the reply it is in ends. It does what the project's guidance says to do when a pulse finishes - release what was built, say - or tells you what finished and what it means. Ask to try it ("let me try it") and the chat releases what is built to `dist/<module>` and starts it on your machine, even while other pulses run. See [deploy](deploy.md). The chat reacts to it then and there, whatever else is running or queued, without waiting for you to speak - at once when it is idle, else as soon as the reply it is in ends: it does what the project's guidance says to do when a pulse finishes (release what was built, say), or tells you in a line or two what finished.
94
94
  - **When a pulse stops** - a gate still failing after 20 attempts - it says where it stopped, why in plain words, and what to change in \*\*\*plain - which section, and how. Running the same build again picks up from there.
@@ -97,7 +97,7 @@ In `print`, `json` and `rpc` modes the process ends when the answer is written,
97
97
 
98
98
  ## The project's config.turri.yaml
99
99
 
100
- The chat reads the project's `config.turri.yaml` afresh every turn and follows it: its agent is told what it sets, and the tools that regenerate default to it - `module` when you ask to build without naming one, `conformance-tests: false` to regenerate without conformance tests (none written, none of the existing ones run) unless you ask for them, `coding-model` for what regenerations run on, and the testing scripts. `harness-model` is what `turri` starts on. What you ask for in the conversation wins. Every key, what happens without it, and how the models inherit: [the project config](config.md).
100
+ The chat reads the project's `config.turri.yaml` afresh every turn and follows it: its agent is told what it sets, and the tools that regenerate default to it - `module` when you ask to build without naming one, `conformance-tests: false` to regenerate without writing new conformance tests unless you ask for them (the ones there are kept up to date), `coding-model` for what regenerations run on, and the testing scripts. `harness-model` is what `turri` starts on. What you ask for in the conversation wins. Every key, what happens without it, and how the models inherit: [the project config](config.md).
101
101
 
102
102
  A project whose parts are on different stacks gives each stack its own `config.turri.<stack>.yaml` beside `config.turri.yaml` - `config.turri.backend.yaml`, `config.turri.frontend.yaml` - with its testing scripts, models and conformance over the project's. A stack named after its module builds it - `config.turri.backend.yaml` builds `backend.plain` - with nothing to choose, so a backend and a frontend are each built with their own, side by side; for a stack named otherwise the chat's model passes it as `stack`, or choose one for the session with `/stack backend`. The chat is told each stack's and which is chosen, and the status bar shows it. See [stacks](config.md#stacks).
103
103
 
@@ -26,7 +26,8 @@ The other rules say what a spec means. This one says what turri does with a chan
26
26
  - A definition changed patches every functional spec that uses its concept, directly or through other definitions. So does a change to a linked resource: the spec or definition linking it is changed though its text is not. A widely used definition is the costly edit - not a spec's position
27
27
  - Implementation reqs alone, or definitions no functional spec uses, are a mechanical change: the code adapts, and no test is written or changes what it asserts
28
28
  - Test reqs and acceptance tests reach the conformance tests only, never the code
29
- - A functional spec regenerated again by name has its code taken out and built anew - never left as it was, even where it already does what the spec says; a pulse that changes nothing does not land. Its conformance tests are written again once its new code lands: what they check that the spec leaves open - a path, a field, a message the old code chose - goes by the new code. Old tests that still pass are not enough: a conformance pulse that leaves them as they were does not land
29
+ - A functional spec regenerated again by name has its code taken out and built anew - never left as it was, even where it already does what the spec says; a pulse that changes nothing does not land. Its conformance tests, when it has them, are run on its new code once it lands: those that pass are kept as they are; one that fails is judged against the spec - what it checks that the spec leaves open, a path, a field, a message the old code chose, goes by the new code
30
+ - `conformance-tests: false` writes no new conformance tests, but keeps those there are up to date: a functional spec that has conformance tests and is changed, regenerated again or taken out gets a conformance pulse for it alone once its code lands. One with none gets none
30
31
  - Definitions moved to a common module and reqs reordered are recorded, not rendered
31
32
  - A functional spec written on its happy path and hardened later - its validation, edge cases and errors added to it - is patched in place each time: growing a spec a step at a time costs no more than writing it whole up front
32
33
  - A module's first pulse, when it builds one functional spec - the project set up and the smallest thing that runs - lands on its unit tests with no review
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@turri-dev/cli",
3
- "version": "0.1.27-next.763d091",
3
+ "version": "0.1.27",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {