@turri-dev/cli 0.1.27 → 0.1.28-next.d5f2680
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/advisor-chat.d.ts +63 -0
- package/dist/advisor-chat.js +290 -0
- package/dist/background-skills.d.ts +53 -0
- package/dist/background-skills.js +121 -0
- package/dist/bedrock-region.d.ts +66 -0
- package/dist/bedrock-region.js +144 -0
- package/dist/btw.d.ts +1 -1
- package/dist/btw.js +1 -1
- package/dist/change-plain-cli.js +20 -13
- package/dist/chat-idle.d.ts +7 -0
- package/dist/chat-idle.js +20 -0
- package/dist/chats.d.ts +10 -0
- package/dist/chats.js +23 -0
- package/dist/cli-options.d.ts +1 -2
- package/dist/cli-options.js +2 -7
- package/dist/cli.js +11 -3
- package/dist/config-command.d.ts +14 -0
- package/dist/config-command.js +35 -15
- package/dist/config-edit.d.ts +3 -3
- package/dist/config-edit.js +16 -12
- package/dist/config.d.ts +54 -34
- package/dist/config.js +40 -44
- package/dist/conform-cli.js +12 -10
- package/dist/conformance-switch.d.ts +34 -0
- package/dist/conformance-switch.js +108 -0
- package/dist/cultivate-cli.js +15 -5
- package/dist/drift-cli.js +2 -0
- package/dist/extension.d.ts +15 -0
- package/dist/extension.js +260 -83
- package/dist/host-session.d.ts +26 -0
- package/dist/host-session.js +30 -2
- package/dist/host.d.ts +5 -2
- package/dist/host.js +7 -1
- package/dist/init-config.d.ts +1 -1
- package/dist/init-config.js +20 -11
- package/dist/loop-cli.d.ts +3 -3
- package/dist/loop-cli.js +13 -16
- package/dist/loop-tools.js +18 -10
- package/dist/model-check.d.ts +8 -3
- package/dist/model-check.js +13 -8
- package/dist/new-project.js +12 -8
- package/dist/{validate-cli.js → parse-cli.js} +11 -5
- package/dist/parse-tool.d.ts +9 -0
- package/dist/parse-tool.js +33 -0
- package/dist/pi-launch.js +1 -1
- package/dist/plain/check.d.ts +53 -6
- package/dist/plain/check.js +217 -24
- package/dist/plain/concepts.d.ts +8 -0
- package/dist/plain/concepts.js +66 -23
- package/dist/plain/cycles.d.ts +21 -0
- package/dist/plain/cycles.js +190 -0
- package/dist/plain/errors.d.ts +4 -0
- package/dist/plain/errors.js +7 -0
- package/dist/plain/files.d.ts +18 -1
- package/dist/plain/files.js +39 -2
- package/dist/plain/graph.d.ts +33 -4
- package/dist/plain/graph.js +60 -12
- package/dist/plain/highlight.d.ts +3 -2
- package/dist/plain/highlight.js +4 -3
- package/dist/plain/index.d.ts +8 -5
- package/dist/plain/index.js +8 -5
- package/dist/plain/liquid.js +1 -6
- package/dist/plain/markdown.d.ts +32 -3
- package/dist/plain/markdown.js +146 -24
- package/dist/plain/module-concepts.js +2 -2
- package/dist/plain/parser.d.ts +83 -28
- package/dist/plain/parser.js +381 -260
- package/dist/plain/plain.tmLanguage.json +29 -3
- package/dist/plain/project.d.ts +48 -0
- package/dist/plain/project.js +155 -0
- package/dist/plain/spec.d.ts +90 -28
- package/dist/plain/spec.js +107 -133
- package/dist/plain/test-plain-file.d.ts +59 -0
- package/dist/plain/test-plain-file.js +232 -0
- package/dist/regenerate/activity.d.ts +20 -9
- package/dist/regenerate/activity.js +11 -4
- package/dist/regenerate/advisor-records.d.ts +93 -0
- package/dist/regenerate/advisor-records.js +110 -0
- package/dist/regenerate/advisor-runs.d.ts +87 -0
- package/dist/regenerate/advisor-runs.js +327 -0
- package/dist/regenerate/base-folder.d.ts +68 -0
- package/dist/regenerate/base-folder.js +168 -0
- package/dist/regenerate/cases.d.ts +9 -6
- package/dist/regenerate/cases.js +70 -14
- package/dist/regenerate/change-view.d.ts +8 -3
- package/dist/regenerate/change-view.js +71 -22
- package/dist/regenerate/chunk-plan.d.ts +36 -15
- package/dist/regenerate/chunk-plan.js +165 -59
- package/dist/regenerate/conform.d.ts +3 -0
- package/dist/regenerate/conform.js +6 -5
- package/dist/regenerate/conformance-agents.d.ts +18 -39
- package/dist/regenerate/conformance-agents.js +60 -88
- package/dist/regenerate/conformance.d.ts +23 -13
- package/dist/regenerate/conformance.js +119 -82
- package/dist/regenerate/diff-view.d.ts +1 -1
- package/dist/regenerate/diff-view.js +20 -4
- package/dist/regenerate/drift.d.ts +47 -15
- package/dist/regenerate/drift.js +101 -30
- package/dist/regenerate/jobs.d.ts +2 -2
- package/dist/regenerate/jobs.js +1 -1
- package/dist/regenerate/ledger.d.ts +19 -0
- package/dist/regenerate/loop.d.ts +62 -43
- package/dist/regenerate/loop.js +472 -341
- package/dist/regenerate/paths.d.ts +4 -0
- package/dist/regenerate/paths.js +7 -1
- package/dist/regenerate/plain-palette.js +2 -0
- package/dist/regenerate/prompt.d.ts +57 -19
- package/dist/regenerate/prompt.js +157 -122
- package/dist/regenerate/records.d.ts +43 -12
- package/dist/regenerate/records.js +102 -88
- package/dist/regenerate/regenerate.js +29 -11
- package/dist/regenerate/regression.d.ts +4 -4
- package/dist/regenerate/regression.js +14 -10
- package/dist/regenerate/renames.d.ts +42 -0
- package/dist/regenerate/renames.js +185 -0
- package/dist/regenerate/requires.d.ts +1 -1
- package/dist/regenerate/requires.js +10 -3
- package/dist/regenerate/resources.d.ts +5 -3
- package/dist/regenerate/resources.js +4 -4
- package/dist/regenerate/scripts-being-written.d.ts +19 -0
- package/dist/regenerate/scripts-being-written.js +30 -0
- package/dist/regenerate/spec-map-view.d.ts +2 -2
- package/dist/regenerate/spec-map-view.js +46 -15
- package/dist/regenerate/spec-map.d.ts +27 -5
- package/dist/regenerate/spec-map.js +92 -60
- package/dist/regenerate/spec-steps.d.ts +48 -5
- package/dist/regenerate/spec-steps.js +213 -28
- package/dist/regenerate/state.d.ts +4 -3
- package/dist/regenerate/stop-report.d.ts +1 -1
- package/dist/regenerate/stop-report.js +10 -10
- package/dist/regenerate/test-advisor.d.ts +101 -0
- package/dist/regenerate/test-advisor.js +379 -0
- package/dist/regenerate/test-kinds.d.ts +71 -28
- package/dist/regenerate/test-kinds.js +110 -63
- package/dist/regenerate/test-scripts.d.ts +2 -0
- package/dist/regenerate/test-scripts.js +4 -0
- package/dist/regenerate/testing-steps.d.ts +41 -0
- package/dist/regenerate/testing-steps.js +110 -0
- package/dist/regenerate/testing.d.ts +1 -1
- package/dist/regenerate/testing.js +5 -4
- package/dist/regenerate/unit-review.d.ts +1 -1
- package/dist/regenerate/unit-review.js +3 -3
- package/dist/regenerate-cli.js +11 -12
- package/dist/release-agent.js +4 -0
- package/dist/release-cli.js +2 -0
- package/dist/release-tools.js +2 -0
- package/dist/run-report.d.ts +2 -2
- package/dist/run-report.js +4 -3
- package/dist/self-invocation.d.ts +1 -1
- package/dist/self-invocation.js +1 -1
- package/dist/sentinel.js +1 -1
- package/dist/setup.d.ts +10 -0
- package/dist/setup.js +52 -4
- package/dist/skill.d.ts +10 -0
- package/dist/skill.js +6 -0
- package/dist/skills.js +3 -1
- package/dist/spec-tools.js +21 -31
- package/dist/test-plain-files.d.ts +41 -0
- package/dist/test-plain-files.js +177 -0
- package/docs/README.md +3 -1
- package/docs/authoring-plain.md +46 -13
- package/docs/chats.md +3 -1
- package/docs/config.md +20 -15
- package/docs/deploy.md +1 -1
- package/docs/development.md +2 -1
- package/docs/headless.md +15 -18
- package/docs/hosting.md +28 -12
- package/docs/installation.md +1 -0
- package/docs/parser.md +88 -27
- package/docs/regenerating.md +87 -52
- package/docs/sentinel.md +1 -1
- package/docs/skills-and-gates.md +3 -1
- package/docs/test-advisor.md +110 -0
- package/docs/theming.md +1 -1
- package/docs/using.md +17 -15
- package/genome/rules/bullet-continuation.md +8 -8
- package/genome/rules/concise-specs-examples.md +111 -80
- package/genome/rules/concise-specs-integration-examples.md +56 -41
- package/genome/rules/concise-specs.md +17 -16
- package/genome/rules/definitions.md +5 -5
- package/genome/rules/examples/integration-embedded-testing/run_conformance_tests_java.sh +1 -1
- package/genome/rules/func-specs.md +69 -74
- package/genome/rules/impl-reqs.md +4 -4
- package/genome/rules/integration-embedded-testing.md +20 -20
- package/genome/rules/integration-embedded.md +31 -31
- package/genome/rules/integration-standalone.md +9 -9
- package/genome/rules/integrations.md +18 -18
- package/genome/rules/linked-resources.md +19 -16
- package/genome/rules/module-structure.md +21 -14
- package/genome/rules/project-model.md +18 -17
- package/genome/rules/required-concepts.md +1 -1
- package/genome/rules/requires-modules.md +6 -5
- package/genome/rules/semantic-ids.md +49 -0
- package/genome/rules/stdlib.md +4 -5
- package/genome/rules/test-plain-files.md +130 -0
- package/genome/rules/test-reqs.md +8 -8
- package/genome/rules/turri-regeneration.md +23 -8
- package/genome/skills/analyze-2-func-specs/SKILL.md +36 -21
- package/genome/skills/analyze-func-specs/SKILL.md +46 -32
- package/genome/skills/break-down-func-spec/SKILL.md +91 -67
- package/genome/skills/consolidate-concepts/SKILL.md +10 -10
- package/genome/skills/convert-old-syntax/SKILL.md +68 -0
- package/genome/skills/convert-old-syntax/references/rubric.md +11 -0
- package/genome/skills/debug-specs/SKILL.md +62 -56
- package/genome/skills/implement-conformance-testing-script/SKILL.md +19 -15
- package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +2 -2
- package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +2 -2
- package/genome/skills/implement-unit-testing-script/SKILL.md +14 -10
- package/genome/skills/refactor-module/SKILL.md +35 -35
- package/genome/skills/resolve-section-ownership/SKILL.md +9 -9
- package/genome/skills/resolve-spec-conflict/SKILL.md +35 -29
- package/package.json +7 -6
- package/dist/regenerate/choose-conformance.d.ts +0 -32
- package/dist/regenerate/choose-conformance.js +0 -117
- /package/dist/{validate-cli.d.ts → parse-cli.d.ts} +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { modulesScratchDir } from "./paths.js";
|
|
2
|
-
import { ACCEPTANCE_TESTS, DEFINITIONS, FUNCTIONAL_REQUIREMENTS, NON_FUNCTIONAL_REQUIREMENTS, REQUIRED_FUNCTIONAL_SPECS, TEST_REQUIREMENTS, } from "../plain/spec.js";
|
|
2
|
+
import { ACCEPTANCE_TESTS, CONFORMANCE_TESTS, DEFINITIONS, FUNCTIONAL_REQUIREMENTS, NON_FUNCTIONAL_REQUIREMENTS, REQUIRED_FUNCTIONAL_SPECS, TEST_REQUIREMENTS, } from "../plain/spec.js";
|
|
3
3
|
import { codeCopyOf, isCodeResource } from "./resources.js";
|
|
4
|
-
import {
|
|
4
|
+
import { conformanceLabel, scenarioLabel, scenariosOf, scenarioText } from "./test-kinds.js";
|
|
5
5
|
import { codeCasesBlock, conformanceCasesBlock } from "./cases.js";
|
|
6
6
|
import { marksRegenerateAgain } from "./records.js";
|
|
7
|
-
import { resourcesChanged } from "./spec-steps.js";
|
|
7
|
+
import { resourcesChanged, scenarioLines } from "./spec-steps.js";
|
|
8
8
|
/**
|
|
9
9
|
* Everything already in the code: the required modules' functional specs, bottom of the
|
|
10
10
|
* chain first, then this module's own earlier ones. Null when there is nothing.
|
|
@@ -13,17 +13,17 @@ import { resourcesChanged } from "./spec-steps.js";
|
|
|
13
13
|
* that does not know what exists re-implements it; a test writer that does not know it
|
|
14
14
|
* cannot set up what a functionality depends on; a fixer that does not know it breaks it.
|
|
15
15
|
*/
|
|
16
|
-
function alreadyImplemented(moduleName, own, required) {
|
|
16
|
+
function alreadyImplemented(moduleName, own, funcIds, required) {
|
|
17
17
|
if (own.length === 0 && required.length === 0)
|
|
18
18
|
return null;
|
|
19
|
-
const entries = [...required, ...own.map((spec, index) => ({ module: moduleName,
|
|
19
|
+
const entries = [...required, ...own.map((spec, index) => ({ module: moduleName, funcId: funcIds[index] ?? "", spec }))];
|
|
20
20
|
return `<already implemented>\n${functionalitiesByModule(entries, moduleName, "implemented")}\n</already implemented>`;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* Functional specs grouped by the module they belong to - in the order the modules are built on
|
|
24
|
-
* one another, the current module marked - and each tagged with its module and its id there. A codebase holds the
|
|
25
|
-
* functionalities of every module it is built on, and
|
|
26
|
-
*
|
|
24
|
+
* one another, the current module marked - and each tagged with its module and its func-id there. A codebase holds the
|
|
25
|
+
* functionalities of every module it is built on, and a func-id is unique only in its module, so a func-id alone can
|
|
26
|
+
* be ambiguous: `base` and `app` may each have an `export`.
|
|
27
27
|
* (the reference implementation's implemented functional requirements prompt section, as tags.)
|
|
28
28
|
*/
|
|
29
29
|
export function functionalitiesByModule(entries, currentModule, status) {
|
|
@@ -34,14 +34,14 @@ export function functionalitiesByModule(entries, currentModule, status) {
|
|
|
34
34
|
.map((module) => {
|
|
35
35
|
const items = entries
|
|
36
36
|
.filter((entry) => entry.module === module)
|
|
37
|
-
.map((entry) => `<functionality module="${entry.module}" id="${entry.
|
|
37
|
+
.map((entry) => `<functionality module="${entry.module}" id="${entry.funcId}"${status !== undefined ? ` status="${status}"` : ""}>\n${entry.spec}\n</functionality>`);
|
|
38
38
|
return `<module name="${module}"${module === currentModule ? ' role="current"' : ""}>\n${items.join("\n\n")}\n</module>`;
|
|
39
39
|
})
|
|
40
40
|
.join("\n\n");
|
|
41
41
|
}
|
|
42
|
-
/** "
|
|
43
|
-
export function functionalityOf(
|
|
44
|
-
return `
|
|
42
|
+
/** "functional spec `app:add-task`": a functional spec, named so that no other module's can be meant. */
|
|
43
|
+
export function functionalityOf(funcId, moduleName) {
|
|
44
|
+
return `functional spec \`${moduleName}:${funcId}\``;
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
47
|
* How to read a ***plain specification: what each section is, and what the predefined concepts
|
|
@@ -66,24 +66,29 @@ export function specPrimer(options) {
|
|
|
66
66
|
? "- <test reqs>: how the conformance tests are written and run."
|
|
67
67
|
: "- <test reqs>: how the conformance tests are written and run. They are not given to you: the conformance tests\n" +
|
|
68
68
|
" are written apart from the code, from the specification.",
|
|
69
|
-
"- <functional specs>: what the system does, one functionality at a time,
|
|
70
|
-
'
|
|
71
|
-
" in the code.",
|
|
69
|
+
"- <functional specs>: what the system does, one functionality at a time, in order, each built on the ones before",
|
|
70
|
+
' it. Each functional spec is a <functionality module="..." id="...">, its id the func-id it has in its module; those',
|
|
71
|
+
" in <already implemented> are in the code.",
|
|
72
72
|
"- Modules: a ***plain specification is split into modules, each a .plain file of its own. Modules are how the",
|
|
73
73
|
" specification is written, in ***plain's own syntax - not how the code is laid out. A module can require others:",
|
|
74
74
|
" it is built on their code, in one codebase with them, so the codebase holds their definitions, implementation",
|
|
75
75
|
" reqs and functionalities as well as its own. A module can also import others: those hold only definitions and",
|
|
76
76
|
" reqs - shared ones, never functional specs or code of their own - and what a module imports is its own. Every",
|
|
77
77
|
" section reaches you grouped under the module each item belongs to - <module name=\"...\">, the modules in the",
|
|
78
|
-
" order they are built on one another, the current one marked role=\"current\".
|
|
79
|
-
"
|
|
80
|
-
"
|
|
78
|
+
" order they are built on one another, the current one marked role=\"current\". A func-id is unique only in its",
|
|
79
|
+
" module, so a functional spec is always given with its module and its func-id there, `<module>:<func-id>`:",
|
|
80
|
+
" `base:export` and `app:export` are two different functionalities.",
|
|
81
81
|
"- You work only in the codebase of the current module: it is all you can reach, and it already holds the code of",
|
|
82
82
|
" every module it requires. Organise and write the code as the <implementation reqs> say - its layout, its",
|
|
83
83
|
" structure, its conventions - never by the ***plain modules: they say where the specification puts an item,",
|
|
84
84
|
" not where its code goes.",
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
...(options.testReqs
|
|
86
|
+
? [
|
|
87
|
+
"- <conformance tests> and <acceptance tests>: under a functional spec, its scenarios, each under its",
|
|
88
|
+
" `# <scenario-id>`: what its conformance tests check, and the checks its implementation must pass end to end.",
|
|
89
|
+
" They carry the same authority as the functional spec itself.",
|
|
90
|
+
]
|
|
91
|
+
: []),
|
|
87
92
|
"- <linked resources>: files the specification refers to as `[resource]name`. They are part of the specification.",
|
|
88
93
|
" A linked resource is not in your workspace. When the code needs what one holds while it runs - a schema it",
|
|
89
94
|
" validates against, a version it reports - it keeps exactly one copy, at the path its code-copy names in the",
|
|
@@ -93,6 +98,8 @@ export function specPrimer(options) {
|
|
|
93
98
|
" code-copy - is code that lives elsewhere, linked so you know what your code plugs into: build on it as the",
|
|
94
99
|
" specification says, and never copy it, nor recreate it or what it belongs to.",
|
|
95
100
|
" An image among them is attached to your first message, numbered in the order they are listed: look at it.",
|
|
101
|
+
" One marked in-codebase is in your codebase already, at that path - it came from the base folder: use it from",
|
|
102
|
+
" there, and never copy it or make another.",
|
|
96
103
|
"- <spec change>: a change to the specification, section by section, each section in its own tag - what it adds,",
|
|
97
104
|
" what it changes (before and now), and what it removes.",
|
|
98
105
|
"",
|
|
@@ -165,7 +172,7 @@ export const ERROR_CAUSE_RULES = [
|
|
|
165
172
|
];
|
|
166
173
|
/** A section's tag - its name in every prompt: `<implementation reqs>`, `<acceptance tests>`. */
|
|
167
174
|
export function sectionTag(key) {
|
|
168
|
-
return key === ACCEPTANCE_TESTS ? "acceptance tests" : key;
|
|
175
|
+
return key === ACCEPTANCE_TESTS ? "acceptance tests" : key === CONFORMANCE_TESTS ? "conformance tests" : key;
|
|
169
176
|
}
|
|
170
177
|
export function section(key, items) {
|
|
171
178
|
if (items.length === 0)
|
|
@@ -196,9 +203,35 @@ function linkedResourcesSection(resources) {
|
|
|
196
203
|
return null;
|
|
197
204
|
// An image is not text: the prompt says where it is - attached to the first message, by number - and what type.
|
|
198
205
|
// A text resource has one home in the codebase, should the code need it: its path, made relative to the codebase.
|
|
199
|
-
const rendered = resources.map((resource) => `<resource name="${resource.text}" path="${resource.target}"${resource.image !== undefined ? ` type="${resource.image.mimeType}"` : isCodeResource(resource.target) ? ' kind="code"' : ` code-copy="${codeCopyOf(resource.target)}"`}>\n${resource.content}\n</resource>`);
|
|
206
|
+
const rendered = resources.map((resource) => `<resource name="${resource.text}" path="${resource.target}"${resource.image !== undefined ? ` type="${resource.image.mimeType}"` : ""}${resource.inCodebase !== undefined ? ` in-codebase="${resource.inCodebase}"` : resource.image !== undefined ? "" : isCodeResource(resource.target) ? ' kind="code"' : ` code-copy="${codeCopyOf(resource.target)}"`}>\n${resource.content}\n</resource>`);
|
|
200
207
|
return `<linked resources>\n${rendered.join("\n\n")}\n</linked resources>`;
|
|
201
208
|
}
|
|
209
|
+
/** How many files of the base folder a coding agent is shown by name: the rest are counted. */
|
|
210
|
+
const BASE_LISTING = 200;
|
|
211
|
+
/**
|
|
212
|
+
* The base folder a codebase started from, for its coding agents (base-folder.ts): that it did, and the files that came
|
|
213
|
+
* from it - code to build on, files to use, or both: the block says neither, for it may be either.
|
|
214
|
+
*/
|
|
215
|
+
export function baseFolderBlock(base) {
|
|
216
|
+
if (base === undefined)
|
|
217
|
+
return null;
|
|
218
|
+
const shown = base.files.slice(0, BASE_LISTING);
|
|
219
|
+
const more = base.files.length - shown.length;
|
|
220
|
+
return [
|
|
221
|
+
`<base folder name="${base.folder}">`,
|
|
222
|
+
`This codebase started from a copy of the base folder ${base.folder}. Whatever it holds - code to build on, files to`,
|
|
223
|
+
"use, or both - the specification may refer to, in words or by linking into it. These files came from it, and are here still:",
|
|
224
|
+
...shown.map((file) => `- ${file}`),
|
|
225
|
+
...(more > 0 ? [`- ... and ${more} more`] : []),
|
|
226
|
+
"</base folder>",
|
|
227
|
+
].join("\n");
|
|
228
|
+
}
|
|
229
|
+
/** The rule for what came from the base folder, for an agent that changes the code: it stays, used where it is. */
|
|
230
|
+
export const BASE_FOLDER_RULES = [
|
|
231
|
+
"- What came from the base folder stays, used where it is, unless a functional spec asks otherwise: code in it is",
|
|
232
|
+
" built on - its structure, conventions and tests kept, its tests passing - and a file in it is used from its path,",
|
|
233
|
+
" never copied, moved or made again.",
|
|
234
|
+
];
|
|
202
235
|
/** How to work, for any agent writing code in this codebase from a spec. `mechanical`: the job writes no new tests. */
|
|
203
236
|
function workingRules(hasCodebase, mechanical = false) {
|
|
204
237
|
return [
|
|
@@ -235,7 +268,15 @@ export function reviewedSpec(input) {
|
|
|
235
268
|
"",
|
|
236
269
|
moduleSection(DEFINITIONS, specifications[DEFINITIONS] ?? [], input.moduleName, input.modules),
|
|
237
270
|
moduleSection(NON_FUNCTIONAL_REQUIREMENTS, specifications[NON_FUNCTIONAL_REQUIREMENTS] ?? [], input.moduleName, input.modules),
|
|
238
|
-
alreadyImplemented(input.moduleName, functionalities, required),
|
|
271
|
+
alreadyImplemented(input.moduleName, functionalities, input.funcIds, required),
|
|
272
|
+
// What came from the base folder is the codebase's start, not this work: kept, it is neither scope crept in nor left over.
|
|
273
|
+
...(input.base !== undefined
|
|
274
|
+
? [
|
|
275
|
+
baseFolderBlock(input.base),
|
|
276
|
+
"What came from the base folder is not this work's: a file from it that no functional spec names is kept as it is -",
|
|
277
|
+
"not scope crept in, nor something left to clean up. A change to it, or its removal, that no functional spec asks for is.",
|
|
278
|
+
]
|
|
279
|
+
: []),
|
|
239
280
|
"<new in this work>",
|
|
240
281
|
specChangeBlock(input.change ?? "(the change is not known)"),
|
|
241
282
|
"</new in this work>",
|
|
@@ -249,12 +290,28 @@ export function reviewedSpec(input) {
|
|
|
249
290
|
*/
|
|
250
291
|
const RAW_CHANGE_NOTE = "The change could not be told section by section, so it is the diff of the .plain files, as the person made it. There,\n" +
|
|
251
292
|
"each section is headed by its name in stars: ***definitions*** is <definitions>, ***implementation reqs*** is\n" +
|
|
252
|
-
"<implementation reqs>, ***test reqs*** is <test reqs>, ***functional specs*** is <functional specs>,
|
|
253
|
-
"
|
|
293
|
+
"<implementation reqs>, ***test reqs*** is <test reqs>, and ***functional specs*** is <functional specs>, where each\n" +
|
|
294
|
+
"functional spec is a `# <func-id>` heading and its text under it.";
|
|
295
|
+
/** The same, for a conformance agent: a functional spec's scenarios are in a test plain file of their own. */
|
|
296
|
+
const RAW_CHANGE_NOTE_SCENARIOS = `${RAW_CHANGE_NOTE}\nA test plain file - tests/<module>/<func-id>.plain, its module: and func_id: at its top - holds one functional\n` +
|
|
297
|
+
"spec's scenarios: ***conformance tests*** is its <conformance tests> and ***acceptance tests*** its <acceptance tests>,\n" +
|
|
298
|
+
"each scenario a `# <scenario-id>` heading and its text.";
|
|
299
|
+
/**
|
|
300
|
+
* A raw diff of the .plain files without the hunks of test plain files: a coding agent never sees scenarios, which are
|
|
301
|
+
* the conformance tests'. A test plain file is told by its own frontmatter - `func_id:` - since its folder is the
|
|
302
|
+
* project's to name.
|
|
303
|
+
*/
|
|
304
|
+
export function withoutTestPlainFiles(diff) {
|
|
305
|
+
return diff
|
|
306
|
+
.split(/^(?=diff --git )/m)
|
|
307
|
+
.filter((file) => !/^[ +-]func_id:/m.test(file))
|
|
308
|
+
.join("");
|
|
309
|
+
}
|
|
254
310
|
/** A change in its tag: told section by section, or - when it could not be - the raw diff, with which tag each heading is. */
|
|
255
|
-
export function specChangeBlock(change) {
|
|
311
|
+
export function specChangeBlock(change, scenarios = false) {
|
|
256
312
|
const raw = /^diff --git |^@@ |^[+-]{3} /m.test(change);
|
|
257
|
-
|
|
313
|
+
const shown = raw && !scenarios ? withoutTestPlainFiles(change) : change;
|
|
314
|
+
return `<spec change>\n${raw ? `${scenarios ? RAW_CHANGE_NOTE_SCENARIOS : RAW_CHANGE_NOTE}\n\n` : ""}${shown.trim()}\n</spec change>`;
|
|
258
315
|
}
|
|
259
316
|
/** The sections as the change is told, in the order a spec has them. Test reqs are the conformance tests', not the code's. */
|
|
260
317
|
const CHANGE_SECTIONS = [
|
|
@@ -263,7 +320,7 @@ const CHANGE_SECTIONS = [
|
|
|
263
320
|
{ key: FUNCTIONAL_REQUIREMENTS, title: "functional specs" },
|
|
264
321
|
{ key: "required functional specs", title: "functional specs of the modules this one requires" },
|
|
265
322
|
];
|
|
266
|
-
/** A changed item's text: its markdown, and its
|
|
323
|
+
/** A changed item's text: its markdown - a functional spec's body, named above it - and its scenarios under it, where the tree has them. */
|
|
267
324
|
function itemText(serialized) {
|
|
268
325
|
if (serialized === undefined)
|
|
269
326
|
return "";
|
|
@@ -276,13 +333,8 @@ function itemText(serialized) {
|
|
|
276
333
|
}
|
|
277
334
|
if (typeof item === "string")
|
|
278
335
|
return item;
|
|
279
|
-
const { markdown, [ACCEPTANCE_TESTS]:
|
|
280
|
-
|
|
281
|
-
// Each test is an item of the tree, its text in its markdown - as spec-steps.ts `itemText` reads it.
|
|
282
|
-
const testText = (test) => (typeof test === "string" ? test : (test?.markdown ?? JSON.stringify(test)));
|
|
283
|
-
if (Array.isArray(tests) && tests.length > 0)
|
|
284
|
-
lines.push(" <acceptance tests>", ...tests.map((test) => ` ${testText(test).replace(/\n/g, "\n ")}`), " </acceptance tests>");
|
|
285
|
-
return lines.join("\n");
|
|
336
|
+
const { markdown, [CONFORMANCE_TESTS]: conformance, [ACCEPTANCE_TESTS]: acceptance } = (item ?? {});
|
|
337
|
+
return [markdown ?? JSON.stringify(item), ...scenarioLines("conformance tests", conformance), ...scenarioLines("acceptance tests", acceptance)].join("\n");
|
|
286
338
|
}
|
|
287
339
|
const indent = (text, by) => text.split("\n").map((line) => `${by}${line}`).join("\n");
|
|
288
340
|
/** A changed item, read back: undefined when its line is not one. */
|
|
@@ -297,7 +349,7 @@ const parsed = (serialized) => {
|
|
|
297
349
|
/**
|
|
298
350
|
* A spec change as an agent reads it: section by section, what was added, what changed - before and now - and what
|
|
299
351
|
* was removed. A definition taken out and put back reworded, or moved, is one change to it, not two. Every item is
|
|
300
|
-
* named so no other module's can be meant: a functional spec by its module and
|
|
352
|
+
* named so no other module's can be meant: a functional spec by its module and func-id, and a definition or req of a
|
|
301
353
|
* module below by its module; `moduleName` is the module whose codebase it is - whose own items carry no module.
|
|
302
354
|
*/
|
|
303
355
|
export function describeSpecChange(changes, moduleName) {
|
|
@@ -309,14 +361,14 @@ export function describeSpecChange(changes, moduleName) {
|
|
|
309
361
|
const here = changes.filter((change) => change.section === key);
|
|
310
362
|
if (here.length === 0)
|
|
311
363
|
continue;
|
|
312
|
-
/** Which item it is: a functional spec by its module and
|
|
364
|
+
/** Which item it is: a functional spec by its module and func-id, a definition by its concept, and one of a module below with that module. */
|
|
313
365
|
const labelOf = (change, line) => {
|
|
314
366
|
const item = parsed(line);
|
|
315
367
|
const below = item?.module !== undefined && item.module !== moduleName ? ` of module \`${item.module}\`` : "";
|
|
316
368
|
if (key === FUNCTIONAL_REQUIREMENTS)
|
|
317
|
-
return moduleName !== undefined ? functionalityOf(
|
|
369
|
+
return moduleName !== undefined ? functionalityOf(item?.id ?? "", moduleName) : `functional spec \`${item?.id ?? ""}\``;
|
|
318
370
|
if (key === REQUIRED_FUNCTIONAL_SPECS)
|
|
319
|
-
return item?.module !== undefined && item.
|
|
371
|
+
return item?.module !== undefined && item.id !== undefined ? functionalityOf(item.id, item.module) : `functional spec \`${item?.id ?? ""}\`${below}`;
|
|
320
372
|
if (key === DEFINITIONS)
|
|
321
373
|
return `${conceptOf(itemText(line)) ?? `item ${change.position}`}${below}`;
|
|
322
374
|
return `item ${change.position}${below}`;
|
|
@@ -417,7 +469,7 @@ export function buildSpecDiffPrompt(input) {
|
|
|
417
469
|
...input.required,
|
|
418
470
|
...specifications[FUNCTIONAL_REQUIREMENTS].map((spec, index) => ({
|
|
419
471
|
module: input.moduleName,
|
|
420
|
-
|
|
472
|
+
funcId: input.funcIds[index] ?? "",
|
|
421
473
|
spec,
|
|
422
474
|
})),
|
|
423
475
|
];
|
|
@@ -427,7 +479,9 @@ export function buildSpecDiffPrompt(input) {
|
|
|
427
479
|
"",
|
|
428
480
|
input.empty
|
|
429
481
|
? "Nothing is built yet: the working directory is empty, and the change is the whole specification."
|
|
430
|
-
:
|
|
482
|
+
: input.base !== undefined && input.funcIds.length === 0 && input.required.length === 0
|
|
483
|
+
? "Nothing is built from the specification yet: the working directory holds what the base folder had (<base folder> below), and the change is the whole specification."
|
|
484
|
+
: "The working directory holds the code built so far, from the specs below - the specs before the change.",
|
|
431
485
|
"The specification the code is built from follows - its functional specs in <already implemented> - and then",
|
|
432
486
|
"<spec change>, the change to it, section by section: the specification below with the change applied is what the",
|
|
433
487
|
"code has to do once you are done. Your task is to apply the change to the code - everything it adds, changes and",
|
|
@@ -437,19 +491,21 @@ export function buildSpecDiffPrompt(input) {
|
|
|
437
491
|
moduleSection(NON_FUNCTIONAL_REQUIREMENTS, specifications[NON_FUNCTIONAL_REQUIREMENTS], input.moduleName, input.modules),
|
|
438
492
|
all.length === 0 ? null : `<already implemented>\n${functionalitiesByModule(all, input.moduleName, "implemented")}\n</already implemented>`,
|
|
439
493
|
input.codebase ? `<codebase>\n${input.codebase}\n</codebase>` : null,
|
|
494
|
+
baseFolderBlock(input.base),
|
|
440
495
|
linkedResourcesSection(input.linkedResources),
|
|
441
496
|
input.changes !== undefined && input.changes.length > 0
|
|
442
497
|
? specChangeBlock(describeSpecChange(input.changes, input.moduleName))
|
|
443
|
-
: `<spec change>\n${RAW_CHANGE_NOTE}\n\n${input.diff.trim()}\n</spec change>`,
|
|
498
|
+
: `<spec change>\n${RAW_CHANGE_NOTE}\n\n${withoutTestPlainFiles(input.diff).trim()}\n</spec change>`,
|
|
444
499
|
"",
|
|
445
500
|
...(input.cases !== undefined
|
|
446
|
-
? codeCasesBlock(input.cases)
|
|
501
|
+
? codeCasesBlock(input.cases, input.base !== undefined)
|
|
447
502
|
: [
|
|
448
503
|
"- Implement what the change adds. Update what it changes. Remove what it removes - its code and its",
|
|
449
504
|
" unit tests - where nothing that remains still needs it.",
|
|
450
505
|
"- A change to a definition or an implementation req reaches every functional spec that relies on it. Follow it there.",
|
|
451
506
|
]),
|
|
452
507
|
"- Everything the change does not touch must keep working, and its tests passing.",
|
|
508
|
+
...(input.base !== undefined ? BASE_FOLDER_RULES : []),
|
|
453
509
|
...workingRules(Boolean(input.codebase), input.cases?.mechanical === true),
|
|
454
510
|
];
|
|
455
511
|
return parts.filter((part) => part !== null).join("\n");
|
|
@@ -468,7 +524,7 @@ export function buildConformancePrompt(input) {
|
|
|
468
524
|
const forChange = input.diff !== undefined;
|
|
469
525
|
const target = functionalities[functionalities.length - 1];
|
|
470
526
|
if (target === undefined && !forChange)
|
|
471
|
-
throw new Error(`
|
|
527
|
+
throw new Error(`Functional spec ${input.funcId} has no specification text.`);
|
|
472
528
|
const parts = [
|
|
473
529
|
specPrimer({ testReqs: true }),
|
|
474
530
|
`You are writing conformance tests for the \`${input.moduleName}\` specification.`,
|
|
@@ -492,12 +548,11 @@ export function buildConformancePrompt(input) {
|
|
|
492
548
|
"tests folder and nothing else - so do not look for it: no searching parent folders, absolute paths or /tmp.",
|
|
493
549
|
]),
|
|
494
550
|
"An agent that explored the code wrote down what you need of it, in <how to invoke it>: how it is",
|
|
495
|
-
"built and run, how each functionality is reached from outside, what it needs around it
|
|
496
|
-
"
|
|
497
|
-
"
|
|
498
|
-
"
|
|
499
|
-
"
|
|
500
|
-
"starting point: where it and the specification differ, the specification is right.",
|
|
551
|
+
"built and run, how each functionality is reached from outside, and what it needs around it. Write the",
|
|
552
|
+
"conformance tests from this prompt - the specification, its scenarios and that account - and what is in your",
|
|
553
|
+
"tests folder: the tests already there show how the suite is built and run. Every assertion comes from the",
|
|
554
|
+
"scenarios and the specification, never from what the account says the code does. Where the code and the",
|
|
555
|
+
"specification disagree, the test follows the specification and fails.",
|
|
501
556
|
"The conformance testing script at the top of this prompt is how your tests are built and run: read what it",
|
|
502
557
|
"builds or installs before your tests run, and so what they can depend on or start to reach the software.",
|
|
503
558
|
"Write the tests' own build - its dependencies, how it starts the software - to fit that script.",
|
|
@@ -530,24 +585,24 @@ export function buildConformancePrompt(input) {
|
|
|
530
585
|
// user registered before one logs in - so its tests can set that up through the same
|
|
531
586
|
// public entry points. Only the functionality below is under test. For a diff, every
|
|
532
587
|
// functionality is the spec as it now stands.
|
|
533
|
-
alreadyImplemented(input.moduleName, input.diff !== undefined ? functionalities : functionalities.slice(0, -1), input.required ?? []),
|
|
588
|
+
alreadyImplemented(input.moduleName, input.diff !== undefined ? functionalities : functionalities.slice(0, -1), input.funcIds, input.required ?? []),
|
|
534
589
|
];
|
|
535
590
|
const resources = linkedResourcesSection(input.linkedResources);
|
|
536
591
|
if (resources !== null)
|
|
537
592
|
parts.push(resources);
|
|
538
593
|
parts.push(input.diff !== undefined
|
|
539
|
-
? specChangeBlock(input.diff)
|
|
540
|
-
: `<functionality module="${input.moduleName}" id="${input.
|
|
541
|
-
?
|
|
542
|
-
:
|
|
594
|
+
? specChangeBlock(input.diff, true)
|
|
595
|
+
: `<functionality module="${input.moduleName}" id="${input.funcId}">\n${target}\n</functionality>`, input.diff !== undefined
|
|
596
|
+
? touchedScenarios(input.moduleName, input.touched ?? [])
|
|
597
|
+
: scenariosBlock(input.moduleName, [{ funcId: input.funcId, conformance: specifications[CONFORMANCE_TESTS] ?? [], acceptance: specifications[ACCEPTANCE_TESTS] ?? [] }]), `<files in the build>\n${input.manifest.join("\n")}\n</files in the build>`, input.existingTests && input.existingTests.length > 0
|
|
543
598
|
? [
|
|
544
599
|
`<conformance tests already here>\n${input.existingTests.join("\n")}\n</conformance tests already here>`,
|
|
545
600
|
"",
|
|
546
601
|
"This directory holds the conformance tests of every functionality built so far - this module's",
|
|
547
602
|
"and those of the modules it requires, copied up with their code. Tests for other functionalities",
|
|
548
603
|
"must keep passing: leave them as they are. If tests for this functionality are among them, from an",
|
|
549
|
-
"earlier version of the specification,
|
|
550
|
-
"
|
|
604
|
+
"earlier version of the specification, bring them in line with its scenarios as they are now: a test for",
|
|
605
|
+
"each scenario, and none for a scenario taken out.",
|
|
551
606
|
].join("\n")
|
|
552
607
|
: null, "", ...(input.diff !== undefined
|
|
553
608
|
? [
|
|
@@ -555,24 +610,23 @@ export function buildConformancePrompt(input) {
|
|
|
555
610
|
"conformance tests in line with the specs as they now stand.",
|
|
556
611
|
"",
|
|
557
612
|
...(input.cases !== undefined
|
|
558
|
-
? conformanceCasesBlock(input.cases)
|
|
613
|
+
? conformanceCasesBlock(input.cases, input.moduleName)
|
|
559
614
|
: [
|
|
560
|
-
"-
|
|
561
|
-
" tests of
|
|
562
|
-
"-
|
|
563
|
-
"
|
|
564
|
-
" the tests check that - with or without a functional spec that uses it yet.",
|
|
615
|
+
"- Write tests for the scenarios the change adds, change the tests of the scenarios it changes, and remove",
|
|
616
|
+
" the tests of the scenarios it removes. Leave the tests of everything the change does not touch as they are.",
|
|
617
|
+
"- Where the change is to a definition, an implementation req or the test reqs, adapt the tests there are",
|
|
618
|
+
" to it: write no test that is not a scenario's.",
|
|
565
619
|
]),
|
|
566
|
-
"- A test is removed only because
|
|
620
|
+
"- A test is removed only because its scenario is gone, or no longer asks for what it checks. Say which, and why.",
|
|
567
621
|
]
|
|
568
622
|
: [
|
|
569
|
-
`Write conformance tests for ${functionalityOf(input.
|
|
623
|
+
`Write conformance tests for ${functionalityOf(input.funcId, input.moduleName)}.`,
|
|
570
624
|
"",
|
|
571
|
-
`- Test ${functionalityOf(input.
|
|
625
|
+
`- Test ${functionalityOf(input.funcId, input.moduleName)} only. What is listed as already implemented is there to be`,
|
|
572
626
|
" used - to set up the state a test needs - not tested again.",
|
|
573
627
|
]), "- Write them in your working directory - the module's tests folder - and nowhere else: never in the", " code folder, never beside the unit tests. That folder is the conformance suite; the harness runs it,", " and nothing else, as one. When it runs, the tests are put together with a copy of the build, so refer", " to the built files by the paths in <files in the build>, resolved against the current working", " directory rather than against your test file's own location.", "- Organise the tests however suits them - files, folders, shared helpers. Make it clear which", forChange
|
|
574
628
|
? " functionality a test covers, so its tests can be found and updated later."
|
|
575
|
-
: ` functionality a test covers, so the tests of ${functionalityOf(input.
|
|
629
|
+
: ` functionality a test covers, so the tests of ${functionalityOf(input.funcId, input.moduleName)} can be found and updated later.`, ...scenarioRules(input.moduleName, forChange ? undefined : input.funcId), "- Test observable behaviour only: output, exit codes, files produced, values returned by the", " public entry point. Never assert on internal names, private helpers or implementation detail.", "- <test reqs> say how conformance tests must be written and run. Follow them.", ...(input.invocation !== undefined
|
|
576
630
|
? [
|
|
577
631
|
"- Your shell holds the tests folder, and the code read only. Run the tests with run_conformance_tests:",
|
|
578
632
|
" it puts the whole suite together with a copy of the build and runs the project's conformance",
|
|
@@ -603,67 +657,46 @@ export function buildConformancePrompt(input) {
|
|
|
603
657
|
return parts.filter((part) => part !== null).join("\n");
|
|
604
658
|
}
|
|
605
659
|
/**
|
|
606
|
-
*
|
|
607
|
-
*
|
|
660
|
+
* Functional specs' scenarios as the conformance agent carries them out: each under its label, the conformance
|
|
661
|
+
* scenarios and then the acceptance ones, in the tag of each kind.
|
|
608
662
|
*/
|
|
609
|
-
function
|
|
610
|
-
const
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
const
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
"states, and labelled as it is numbered here - bring the ones already there in line with the change.",
|
|
619
|
-
].join("\n");
|
|
663
|
+
export function scenariosBlock(module, specs) {
|
|
664
|
+
const kind = (name) => specs.flatMap((spec) => scenariosOf(spec).filter((scenario) => scenario.kind === name).map((scenario) => scenarioText(spec.module ?? module, spec.funcId, scenario)));
|
|
665
|
+
const conformance = kind("conformance");
|
|
666
|
+
const acceptance = kind("acceptance");
|
|
667
|
+
const blocks = [
|
|
668
|
+
...(conformance.length > 0 ? [`<conformance tests>\n${conformance.join("\n\n")}\n</conformance tests>`] : []),
|
|
669
|
+
...(acceptance.length > 0 ? [`<acceptance tests>\n${acceptance.join("\n\n")}\n</acceptance tests>`] : []),
|
|
670
|
+
];
|
|
671
|
+
return blocks.length > 0 ? blocks.join("\n\n") : null;
|
|
620
672
|
}
|
|
621
|
-
/**
|
|
622
|
-
function
|
|
623
|
-
|
|
673
|
+
/** For a spec change: the scenarios of the functional specs it touches - each carried out, and labelled as it is here. */
|
|
674
|
+
function touchedScenarios(module, touched) {
|
|
675
|
+
const block = scenariosBlock(module, touched);
|
|
676
|
+
if (block === null)
|
|
624
677
|
return null;
|
|
625
|
-
const rendered = items.map((item, i) => `${acceptanceLabel(frid, i + 1)}: ${acceptanceText(item)}`);
|
|
626
|
-
return `<acceptance tests>\n${rendered.join("\n\n")}\n</acceptance tests>`;
|
|
627
|
-
}
|
|
628
|
-
/** The two kinds of test, for a spec change: each labelled with what it covers. */
|
|
629
|
-
function changeTestKinds() {
|
|
630
678
|
return [
|
|
631
|
-
"
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
" each as its own test, doing what it says, in files whose names say acceptance.",
|
|
637
|
-
`- Label each acceptance test with a comment right above it: "${acceptanceLabel("<id>", 1)}:" and the text`,
|
|
638
|
-
" of the acceptance test, numbered as the spec lists them.",
|
|
639
|
-
];
|
|
679
|
+
"The scenarios of the functional specs the change touches, as they are now:",
|
|
680
|
+
block,
|
|
681
|
+
"Each of these is carried out by at least one test of its own, doing every step it lists and asserting every",
|
|
682
|
+
"expectation it states, and labelled as it is here - bring the tests already there in line with the change.",
|
|
683
|
+
].join("\n");
|
|
640
684
|
}
|
|
641
|
-
/** What a conformance test covering no functional spec yet - a definition, a req - is labelled. */
|
|
642
|
-
export const CHANGE_LABEL = "conformance tests of the spec";
|
|
643
685
|
/**
|
|
644
|
-
*
|
|
645
|
-
*
|
|
686
|
+
* What the tests are, and how they are labelled (see test-kinds.ts): exactly the scenarios, at least one test each,
|
|
687
|
+
* and nothing invented beside them. `funcId`: the functional spec under test; for a spec change, those it touches.
|
|
646
688
|
*/
|
|
647
|
-
function
|
|
648
|
-
const
|
|
649
|
-
"- Conformance tests come from the functional spec itself: what it says the functionality does, its edge",
|
|
650
|
-
" cases, its errors - written as if no acceptance tests had been given. They do not copy the acceptance",
|
|
651
|
-
" tests, and do not stop where the acceptance tests stop.",
|
|
652
|
-
`- Label them: files whose names say conformance, each with a comment "${conformanceLabel(frid)}" at its top`,
|
|
653
|
-
" (for a spec change, the functionality each covers).",
|
|
654
|
-
];
|
|
655
|
-
if (acceptance === 0)
|
|
656
|
-
return conformance;
|
|
689
|
+
function scenarioRules(module, funcId) {
|
|
690
|
+
const id = funcId ?? "<func-id>";
|
|
657
691
|
return [
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
" of the acceptance test, numbered as above.",
|
|
692
|
+
"- The tests carry out the scenarios - those in <conformance tests> and <acceptance tests> - exactly: at least one",
|
|
693
|
+
" test for each, doing what it says and asserting what it expects. Write no test that is not a scenario's: no",
|
|
694
|
+
" edge case, error or behaviour of your own beyond them, however much the functional spec says - the scenarios",
|
|
695
|
+
" are what is tested.",
|
|
696
|
+
`- Label each file with a comment at its top naming the functional spec it tests: "${conformanceLabel(module, id)}" -`,
|
|
697
|
+
" a file that tests several has one such line for each.",
|
|
698
|
+
`- Label each test with a comment right above it naming the scenario it carries out: "${scenarioLabel("conformance", "<scenario-id>", module, id)}"`,
|
|
699
|
+
` or "${scenarioLabel("acceptance", "<scenario-id>", module, id)}".`,
|
|
667
700
|
];
|
|
668
701
|
}
|
|
669
702
|
/**
|
|
@@ -679,14 +712,15 @@ export function buildRegressionFixPrompt(input) {
|
|
|
679
712
|
specPrimer({ testReqs: false }),
|
|
680
713
|
`The conformance suite for \`${input.moduleName}\` is failing.`,
|
|
681
714
|
"",
|
|
682
|
-
`It covers
|
|
715
|
+
`It covers functional specs ${input.funcIds.join(", ")} of module \`${input.moduleName}\` together. A functional spec that passed`,
|
|
683
716
|
"on its own can still be broken by a later one, which is what this run is for.",
|
|
684
717
|
"",
|
|
685
718
|
moduleSection(DEFINITIONS, specifications[DEFINITIONS], input.moduleName, input.modules),
|
|
686
719
|
moduleSection(NON_FUNCTIONAL_REQUIREMENTS, specifications[NON_FUNCTIONAL_REQUIREMENTS], input.moduleName, input.modules),
|
|
687
720
|
// All of it is in the code, the required modules' functionalities included, and any of it
|
|
688
721
|
// may be what the latest change broke.
|
|
689
|
-
alreadyImplemented(input.moduleName, specifications[FUNCTIONAL_REQUIREMENTS], input.required ?? []),
|
|
722
|
+
alreadyImplemented(input.moduleName, specifications[FUNCTIONAL_REQUIREMENTS], input.funcIds, input.required ?? []),
|
|
723
|
+
baseFolderBlock(input.base),
|
|
690
724
|
`<conformance failure>\n${input.failure}\n</conformance failure>`,
|
|
691
725
|
"",
|
|
692
726
|
"Change the implementation so every functionality listed as already implemented works at the same time.",
|
|
@@ -696,6 +730,7 @@ export function buildRegressionFixPrompt(input) {
|
|
|
696
730
|
"- Do not special-case the test. Make the behaviour the specification describes actually true.",
|
|
697
731
|
"- Keep the existing unit tests passing. Run any tests you like with bash; before you finish, call",
|
|
698
732
|
" run_conformance_tests and run_unit_tests - the project's scripts, run as the harness runs them.",
|
|
733
|
+
...(input.base !== undefined ? BASE_FOLDER_RULES : []),
|
|
699
734
|
...INTEGRITY_RULES,
|
|
700
735
|
...ERROR_CAUSE_RULES,
|
|
701
736
|
"- Keep the build's identity as it is: its name, coordinates, version, package and main class. Change one only",
|