@bendyline/gilde 0.1.80 → 0.1.82
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/authoring/chat-models/qwen3.8-27b-q4.json +27 -9
- package/authoring/tactical/books/bug-fix-tdd.json +2 -2
- package/authoring/tactical/books/dependency-upgrade.json +1 -1
- package/authoring/tactical/books/refactor-module.json +4 -4
- package/authoring/tactical/books/test-suite-backfill.json +2 -2
- package/authoring/tactical/wave.json +8 -8
- package/data/chat-models/index.json +1 -1
- package/data/chat-models/qw/qwen3.8-27b-q4/manifest.json +35 -12
- package/data/chat-models/qw/qwen3.8-27b-q4/versions/1.0.5/manifest.json +116 -0
- package/data/chat-models/raw-index.json +1 -1
- package/data/craftbook-templates/bu/bug-fix-tdd/versions/2.0.5/craftbook.json +736 -0
- package/data/craftbook-templates/bu/bug-fix-tdd/versions/2.0.5/test.json +221 -0
- package/data/craftbook-templates/de/dependency-upgrade/versions/1.0.5/craftbook.json +625 -0
- package/data/craftbook-templates/de/dependency-upgrade/versions/1.0.5/test.json +235 -0
- package/data/craftbook-templates/index.json +1 -1
- package/data/craftbook-templates/po/powerpoint-deck/versions/1.7.16/craftbook.json +485 -0
- package/data/craftbook-templates/po/powerpoint-deck/versions/1.7.16/test.json +265 -0
- package/data/craftbook-templates/raw-index.json +1 -1
- package/data/craftbook-templates/re/refactor-module/versions/2.0.5/craftbook.json +699 -0
- package/data/craftbook-templates/re/refactor-module/versions/2.0.5/test.json +241 -0
- package/data/craftbook-templates/te/test-suite-backfill/versions/2.0.5/craftbook.json +596 -0
- package/data/craftbook-templates/te/test-suite-backfill/versions/2.0.5/test.json +195 -0
- package/package.json +1 -1
- package/schemas/craftbook-doc.schema.json +15 -0
- package/schemas/craftbook-template-version.schema.json +15 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"title": "Test backfill proven by mutants",
|
|
4
|
+
"objective": "The craftbook drives a risk-ranked backfill of an untested date-range module. The oracle proves the new tests bite: three seeded mutations (an exclusive boundary, a duration off-by-one, overlap collapsed to containment) are applied in copies and the model's suite must fail at least two of them while staying green on the real tree — with the module under test byte-identical to the fixture.",
|
|
5
|
+
"tags": [
|
|
6
|
+
"code",
|
|
7
|
+
"tests",
|
|
8
|
+
"coverage",
|
|
9
|
+
"tactical-fleet"
|
|
10
|
+
],
|
|
11
|
+
"prompt": "Use the Test Suite Backfill craftbook: src/date-range.js schedules bookings across the product and has no tests at all — tests/ only covers the formatter. Backfill a meaningful suite for the date-range module in the existing test layout, highest-risk behavior first: its bounds are inclusive on both ends and an inverted range must throw.",
|
|
12
|
+
"setup": {
|
|
13
|
+
"projectName": "Booking Ranges",
|
|
14
|
+
"about": "A tiny scheduling library. Tests run with `npm run test` (node --test). src/date-range.js is untested; src/format.js has an existing test that shows the layout and style.",
|
|
15
|
+
"files": [
|
|
16
|
+
{
|
|
17
|
+
"path": "package.json",
|
|
18
|
+
"content": "{\n \"name\": \"booking-ranges\",\n \"private\": true,\n \"version\": \"1.0.0\",\n \"type\": \"module\",\n \"scripts\": {\n \"test\": \"node --test\"\n }\n}\n"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"path": "src/date-range.js",
|
|
22
|
+
"content": "// Inclusive [start, end] day ranges. Days are ISO strings like '2026-03-14'.\nconst DAY_MS = 86400000;\n\nfunction dayValue(day) {\n if (typeof day !== 'string' || !/^\\d{4}-\\d{2}-\\d{2}$/.test(day)) {\n throw new Error(`invalid day: ${day}`);\n }\n const value = Date.parse(`${day}T00:00:00Z`);\n if (Number.isNaN(value)) throw new Error(`invalid day: ${day}`);\n return value;\n}\n\nfunction assertRange(range) {\n const start = dayValue(range.start);\n const end = dayValue(range.end);\n if (start > end) {\n throw new Error(`invalid range: ${range.start} is after ${range.end}`);\n }\n return { start, end };\n}\n\nexport function overlaps(a, b) {\n const ra = assertRange(a);\n const rb = assertRange(b);\n return ra.start <= rb.end && rb.start <= ra.end;\n}\n\nexport function containsDay(range, day) {\n const r = assertRange(range);\n const d = dayValue(day);\n return d >= r.start && d <= r.end;\n}\n\nexport function durationDays(range) {\n const r = assertRange(range);\n return Math.round((r.end - r.start) / DAY_MS) + 1;\n}\n"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"path": "src/format.js",
|
|
26
|
+
"content": "export function slugify(text) {\n return String(text)\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"path": "tests/format.test.mjs",
|
|
30
|
+
"content": "import assert from 'node:assert/strict';\nimport { test } from 'node:test';\nimport { slugify } from '../src/format.js';\n\ntest('slugify collapses spaces and punctuation', () => {\n assert.equal(slugify('Walnut writing desk!'), 'walnut-writing-desk');\n});\n\ntest('slugify trims stray dashes', () => {\n assert.equal(slugify(' --Oak shelf-- '), 'oak-shelf');\n});\n"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"path": "tests/verify-backfill.mjs",
|
|
34
|
+
"content": "import assert from 'node:assert/strict';\nimport { execFileSync } from 'node:child_process';\nimport { cpSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst root = process.cwd();\nconst ORACLE = 'verify-backfill.mjs';\n\n// Bare `node --test` discovery: finds tests/**/*.test.* from cwd and skips\n// dot-directories, so the .oracle-* mutant copies never leak into a run.\n// (A literal `--test tests/` directory argument no longer resolves on\n// modern Node - it is treated as a module path.)\nfunction runSuite(cwd) {\n try {\n execFileSync(process.execPath, ['--test'], { cwd, stdio: 'pipe', timeout: 30000 });\n return 0;\n } catch (err) {\n return typeof err.status === 'number' ? err.status : 1;\n }\n}\n\n// 1) New tests exist in the real layout and target the date-range module.\nconst testFiles = readdirSync(join(root, 'tests'), { recursive: true })\n .map(String)\n .filter((f) => /\\.test\\.(mjs|js|cjs)$/.test(f) && !f.endsWith('format.test.mjs'));\nassert.ok(testFiles.length >= 1, 'no new test file found in tests/');\nconst newTestText = testFiles.map((f) => readFileSync(join(root, 'tests', f), 'utf8')).join('\\n');\nassert.ok(/date-range/.test(newTestText), 'the new tests never reference the date-range module');\nconsole.log('BACKFILL_ORACLE new tests found');\n\n// 2) The suite is green on the real tree.\nassert.equal(runSuite(root), 0, 'the suite must pass on the real tree');\nconsole.log('BACKFILL_ORACLE suite green');\n\n// 3) Seeded defects in copies must make the new suite fail - proof the tests bite.\nconst source = readFileSync(join(root, 'src', 'date-range.js'), 'utf8');\nfunction mutantCaught(name, mutate) {\n const mroot = join(root, `.oracle-${name}`);\n rmSync(mroot, { recursive: true, force: true });\n mkdirSync(mroot, { recursive: true });\n cpSync(join(root, 'src'), join(mroot, 'src'), { recursive: true });\n cpSync(join(root, 'tests'), join(mroot, 'tests'), { recursive: true });\n rmSync(join(mroot, 'tests', ORACLE), { force: true });\n cpSync(join(root, 'package.json'), join(mroot, 'package.json'));\n const mutated = mutate(source);\n assert.notEqual(mutated, source, `mutation ${name} failed to apply - src/date-range.js was altered`);\n writeFileSync(join(mroot, 'src', 'date-range.js'), mutated);\n const caught = runSuite(mroot) !== 0;\n console.log(`BACKFILL_ORACLE mutant ${name} ${caught ? 'caught' : 'MISSED'}`);\n return caught;\n}\n\nconst caught = [\n mutantCaught('boundary', (s) => s.replace('rb.start <= ra.end', 'rb.start < ra.end')),\n mutantCaught('duration', (s) => s.replace('/ DAY_MS) + 1', '/ DAY_MS)')),\n mutantCaught('containment', (s) => s.replace('ra.start <= rb.end && rb.start <= ra.end', 'ra.start <= rb.start && rb.end <= ra.end')),\n].filter(Boolean).length;\nassert.ok(caught >= 2, `the new tests caught only ${caught}/3 seeded defects - they do not pin real behavior`);\nconsole.log(`BACKFILL_ORACLE mutants ${caught}/3`);\nconsole.log('BACKFILL_ORACLE done');\n",
|
|
35
|
+
"surface": "harness"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"mocks": [],
|
|
40
|
+
"success": {
|
|
41
|
+
"summary": "New tests for the date-range module live in the real layout, the whole suite is green on the untouched tree, and the tests catch at least two of three seeded mutations — with every fleet artifact present and honestly cited.",
|
|
42
|
+
"deliverables": [
|
|
43
|
+
{
|
|
44
|
+
"path": "{{task.dir}}/risk-map.md",
|
|
45
|
+
"kind": "markdown-notes",
|
|
46
|
+
"artifact": true,
|
|
47
|
+
"minBytes": 500,
|
|
48
|
+
"checks": [
|
|
49
|
+
{
|
|
50
|
+
"kind": "contains",
|
|
51
|
+
"file": "{{task.dir}}/risk-map.md",
|
|
52
|
+
"pattern": "^##\\s+Modules[\\s\\S]*^##\\s+Risks ranked[\\s\\S]*^##\\s+Chosen targets",
|
|
53
|
+
"flags": "im",
|
|
54
|
+
"label": "risk-map sections in order"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"kind": "contains",
|
|
58
|
+
"file": "{{task.dir}}/risk-map.md",
|
|
59
|
+
"pattern": "src/date-range\\.js",
|
|
60
|
+
"label": "names the real target module"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"kind": "citationsResolve",
|
|
64
|
+
"file": "{{task.dir}}/risk-map.md",
|
|
65
|
+
"minCitations": 2,
|
|
66
|
+
"artifact": true
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"path": "{{task.dir}}/test-notes.md",
|
|
72
|
+
"kind": "markdown-notes",
|
|
73
|
+
"artifact": true,
|
|
74
|
+
"minBytes": 600,
|
|
75
|
+
"checks": [
|
|
76
|
+
{
|
|
77
|
+
"kind": "contains",
|
|
78
|
+
"file": "{{task.dir}}/test-notes.md",
|
|
79
|
+
"pattern": "^##\\s+Tests added[\\s\\S]*^##\\s+Behaviors pinned[\\s\\S]*^##\\s+How each test would catch a realistic break",
|
|
80
|
+
"flags": "im",
|
|
81
|
+
"label": "test-notes sections in order"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"kind": "citationsResolve",
|
|
85
|
+
"file": "{{task.dir}}/test-notes.md",
|
|
86
|
+
"minCitations": 2,
|
|
87
|
+
"artifact": true
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"path": "{{task.dir}}/verification.md",
|
|
93
|
+
"kind": "markdown-notes",
|
|
94
|
+
"artifact": true,
|
|
95
|
+
"minBytes": 400,
|
|
96
|
+
"checks": [
|
|
97
|
+
{
|
|
98
|
+
"kind": "contains",
|
|
99
|
+
"file": "{{task.dir}}/verification.md",
|
|
100
|
+
"pattern": "^##\\s+Suite[\\s\\S]*^##\\s+Coverage summary[\\s\\S]*^##\\s+Result",
|
|
101
|
+
"flags": "im",
|
|
102
|
+
"label": "verification sections in order"
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"path": "{{task.dir}}/review.md",
|
|
108
|
+
"kind": "markdown-report",
|
|
109
|
+
"artifact": true,
|
|
110
|
+
"minBytes": 400,
|
|
111
|
+
"checks": [
|
|
112
|
+
{
|
|
113
|
+
"kind": "contains",
|
|
114
|
+
"file": "{{task.dir}}/review.md",
|
|
115
|
+
"pattern": "Verdict:\\s*(?:PASS|REVISE)",
|
|
116
|
+
"flags": "i",
|
|
117
|
+
"label": "explicit reviewer verdict"
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
],
|
|
122
|
+
"checks": [
|
|
123
|
+
{
|
|
124
|
+
"kind": "nodeRuns",
|
|
125
|
+
"file": "tests/format.test.mjs"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"kind": "nodeScriptPasses",
|
|
129
|
+
"script": "tests/verify-backfill.mjs",
|
|
130
|
+
"timeoutMs": 120000,
|
|
131
|
+
"requiredOutput": [
|
|
132
|
+
{
|
|
133
|
+
"pattern": "BACKFILL_ORACLE new tests found",
|
|
134
|
+
"label": "new tests exist in the real layout"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"pattern": "BACKFILL_ORACLE suite green",
|
|
138
|
+
"label": "the whole suite passes on the real tree"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"pattern": "BACKFILL_ORACLE mutants [23]/3",
|
|
142
|
+
"label": "the new tests catch seeded defects"
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
"taskNotes": {
|
|
148
|
+
"minBytes": 120,
|
|
149
|
+
"checks": [
|
|
150
|
+
{
|
|
151
|
+
"kind": "contains",
|
|
152
|
+
"file": "task-notes.md",
|
|
153
|
+
"pattern": "\\bDONE\\b[\\s\\S]*(npm\\s+run\\s+test|node\\s+--test)",
|
|
154
|
+
"flags": "i",
|
|
155
|
+
"label": "DONE note names the real test command"
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
},
|
|
159
|
+
"taskGraph": {
|
|
160
|
+
"requireCraftbookTask": true,
|
|
161
|
+
"requireTerminalStep": true
|
|
162
|
+
},
|
|
163
|
+
"unchangedFixtures": [
|
|
164
|
+
"package.json",
|
|
165
|
+
"src/date-range.js",
|
|
166
|
+
"src/format.js",
|
|
167
|
+
"tests/format.test.mjs"
|
|
168
|
+
]
|
|
169
|
+
},
|
|
170
|
+
"rubric": {
|
|
171
|
+
"artifact": {
|
|
172
|
+
"path": "{{task.dir}}/test-notes.md",
|
|
173
|
+
"kind": "markdown"
|
|
174
|
+
},
|
|
175
|
+
"axes": [
|
|
176
|
+
{
|
|
177
|
+
"name": "Risk-driven targeting",
|
|
178
|
+
"description": "The tests pin the behaviors whose silent breakage costs most — inclusive bounds, duration arithmetic, the invalid-range throw — following the risk map rather than the easiest paths."
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"name": "Tests that bite",
|
|
182
|
+
"description": "Each test asserts real values, errors, and edge cases a wrong implementation would fail; no tautologies, and seeded mutations to the module are actually caught."
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"name": "Layout fidelity and honesty",
|
|
186
|
+
"description": "Tests follow the existing layout and style, the suite result comes from real runs, the module under test is untouched, and uncovered targets are deferred honestly."
|
|
187
|
+
}
|
|
188
|
+
]
|
|
189
|
+
},
|
|
190
|
+
"qualityFocus": [
|
|
191
|
+
"mutation-proof regression guards",
|
|
192
|
+
"risk-ranked coverage",
|
|
193
|
+
"enforced review of assertions"
|
|
194
|
+
]
|
|
195
|
+
}
|
package/package.json
CHANGED
|
@@ -70,6 +70,11 @@
|
|
|
70
70
|
"kind": {
|
|
71
71
|
"type": "string",
|
|
72
72
|
"const": "user"
|
|
73
|
+
},
|
|
74
|
+
"instructions": {
|
|
75
|
+
"type": "string",
|
|
76
|
+
"minLength": 1,
|
|
77
|
+
"description": "Explain exactly what the person needs to do and how to confirm they are ready: for example, add a launch date to the task description, then confirm it in the reply. Address the person as \"you\". Include this whenever assigning work to the user; never just say \"open the task\"."
|
|
73
78
|
}
|
|
74
79
|
},
|
|
75
80
|
"required": [
|
|
@@ -598,6 +603,11 @@
|
|
|
598
603
|
"kind": {
|
|
599
604
|
"type": "string",
|
|
600
605
|
"const": "user"
|
|
606
|
+
},
|
|
607
|
+
"instructions": {
|
|
608
|
+
"type": "string",
|
|
609
|
+
"minLength": 1,
|
|
610
|
+
"description": "Explain exactly what the person needs to do and how to confirm they are ready: for example, add a launch date to the task description, then confirm it in the reply. Address the person as \"you\". Include this whenever assigning work to the user; never just say \"open the task\"."
|
|
601
611
|
}
|
|
602
612
|
},
|
|
603
613
|
"required": [
|
|
@@ -4057,6 +4067,11 @@
|
|
|
4057
4067
|
"kind": {
|
|
4058
4068
|
"type": "string",
|
|
4059
4069
|
"const": "user"
|
|
4070
|
+
},
|
|
4071
|
+
"instructions": {
|
|
4072
|
+
"type": "string",
|
|
4073
|
+
"minLength": 1,
|
|
4074
|
+
"description": "Explain exactly what the person needs to do and how to confirm they are ready: for example, add a launch date to the task description, then confirm it in the reply. Address the person as \"you\". Include this whenever assigning work to the user; never just say \"open the task\"."
|
|
4060
4075
|
}
|
|
4061
4076
|
},
|
|
4062
4077
|
"required": [
|
|
@@ -182,6 +182,11 @@
|
|
|
182
182
|
"kind": {
|
|
183
183
|
"type": "string",
|
|
184
184
|
"const": "user"
|
|
185
|
+
},
|
|
186
|
+
"instructions": {
|
|
187
|
+
"type": "string",
|
|
188
|
+
"minLength": 1,
|
|
189
|
+
"description": "Explain exactly what the person needs to do and how to confirm they are ready: for example, add a launch date to the task description, then confirm it in the reply. Address the person as \"you\". Include this whenever assigning work to the user; never just say \"open the task\"."
|
|
185
190
|
}
|
|
186
191
|
},
|
|
187
192
|
"required": [
|
|
@@ -3426,6 +3431,11 @@
|
|
|
3426
3431
|
"kind": {
|
|
3427
3432
|
"type": "string",
|
|
3428
3433
|
"const": "user"
|
|
3434
|
+
},
|
|
3435
|
+
"instructions": {
|
|
3436
|
+
"type": "string",
|
|
3437
|
+
"minLength": 1,
|
|
3438
|
+
"description": "Explain exactly what the person needs to do and how to confirm they are ready: for example, add a launch date to the task description, then confirm it in the reply. Address the person as \"you\". Include this whenever assigning work to the user; never just say \"open the task\"."
|
|
3429
3439
|
}
|
|
3430
3440
|
},
|
|
3431
3441
|
"required": [
|
|
@@ -3635,6 +3645,11 @@
|
|
|
3635
3645
|
"kind": {
|
|
3636
3646
|
"type": "string",
|
|
3637
3647
|
"const": "user"
|
|
3648
|
+
},
|
|
3649
|
+
"instructions": {
|
|
3650
|
+
"type": "string",
|
|
3651
|
+
"minLength": 1,
|
|
3652
|
+
"description": "Explain exactly what the person needs to do and how to confirm they are ready: for example, add a launch date to the task description, then confirm it in the reply. Address the person as \"you\". Include this whenever assigning work to the user; never just say \"open the task\"."
|
|
3638
3653
|
}
|
|
3639
3654
|
},
|
|
3640
3655
|
"required": [
|