@bendyline/gilde 0.1.40 → 0.1.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/authoring/gstack/overlays/investigate.json +1 -0
  2. package/authoring/gstack/overlays/qa-only.json +1 -0
  3. package/authoring/gstack/wave.json +12 -2
  4. package/authoring/tactical/books/accessibility-retrofit.json +188 -0
  5. package/authoring/tactical/books/apply-review-findings.json +189 -0
  6. package/authoring/tactical/books/bug-fix-tdd.json +237 -0
  7. package/authoring/tactical/books/ci-pipeline.json +168 -0
  8. package/authoring/tactical/books/codemod-sweep.json +182 -0
  9. package/authoring/tactical/books/dependency-upgrade.json +196 -0
  10. package/authoring/tactical/books/flaky-test-fix.json +238 -0
  11. package/authoring/tactical/books/hotfix-flow.json +187 -0
  12. package/authoring/tactical/books/perf-optimization.json +219 -0
  13. package/authoring/tactical/books/refactor-module.json +217 -0
  14. package/authoring/tactical/books/schema-migration.json +192 -0
  15. package/authoring/tactical/books/test-suite-backfill.json +172 -0
  16. package/authoring/tactical/books/type-safety-pass.json +185 -0
  17. package/authoring/tactical/books/ux-update.json +178 -0
  18. package/authoring/tactical/evals/accessibility-retrofit.json +230 -0
  19. package/authoring/tactical/evals/apply-review-findings.json +290 -0
  20. package/authoring/tactical/evals/bug-fix-tdd.json +221 -0
  21. package/authoring/tactical/evals/ci-pipeline.json +227 -0
  22. package/authoring/tactical/evals/codemod-sweep.json +252 -0
  23. package/authoring/tactical/evals/dependency-upgrade.json +235 -0
  24. package/authoring/tactical/evals/flaky-test-fix.json +239 -0
  25. package/authoring/tactical/evals/hotfix-flow.json +220 -0
  26. package/authoring/tactical/evals/perf-optimization.json +235 -0
  27. package/authoring/tactical/evals/refactor-module.json +241 -0
  28. package/authoring/tactical/evals/schema-migration.json +225 -0
  29. package/authoring/tactical/evals/test-suite-backfill.json +197 -0
  30. package/authoring/tactical/evals/type-safety-pass.json +221 -0
  31. package/authoring/tactical/evals/ux-update.json +206 -0
  32. package/authoring/tactical/wave.json +89 -0
  33. package/data/chat-models/de/deepseek-r1-8b-q4/manifest.json +56 -1
  34. package/data/chat-models/gl/glm-5.2-754b-q2/manifest.json +56 -0
  35. package/data/chat-models/gp/gpt-oss-120b-q4/manifest.json +73 -1
  36. package/data/chat-models/gp/gpt-oss-20b-q4/manifest.json +77 -1
  37. package/data/chat-models/index.json +1 -1
  38. package/data/chat-models/ll/llama3.2-3b-q4/manifest.json +3 -1
  39. package/data/chat-models/mi/mistral-7b-q4/manifest.json +54 -3
  40. package/data/chat-models/mi/mistral-medium-3.5-128b-q4/manifest.json +76 -1
  41. package/data/craftbook-templates/ac/accessibility-retrofit/manifest.json +5 -4
  42. package/data/craftbook-templates/ac/accessibility-retrofit/versions/2.0.0/craftbook.json +451 -0
  43. package/data/craftbook-templates/ac/accessibility-retrofit/versions/2.0.0/test.json +231 -0
  44. package/data/craftbook-templates/al/alt-text-pass/manifest.json +5 -1
  45. package/data/craftbook-templates/ap/apply-review-findings/art.json +12 -0
  46. package/data/craftbook-templates/ap/apply-review-findings/logo.webp +0 -0
  47. package/data/craftbook-templates/ap/apply-review-findings/manifest.json +23 -0
  48. package/data/craftbook-templates/ap/apply-review-findings/versions/1.0.0/craftbook.json +436 -0
  49. package/data/craftbook-templates/ap/apply-review-findings/versions/1.0.0/test.json +291 -0
  50. package/data/craftbook-templates/br/browser-qa-audit/manifest.json +5 -1
  51. package/data/craftbook-templates/br/browser-qa-audit/versions/2.0.5/craftbook.json +438 -0
  52. package/data/craftbook-templates/br/browser-qa-audit/versions/2.0.5/test.json +379 -0
  53. package/data/craftbook-templates/bu/bug-fix-tdd/manifest.json +3 -3
  54. package/data/craftbook-templates/bu/bug-fix-tdd/versions/2.0.0/craftbook.json +545 -0
  55. package/data/craftbook-templates/bu/bug-fix-tdd/versions/2.0.0/test.json +222 -0
  56. package/data/craftbook-templates/ch/changelog-cut/manifest.json +5 -1
  57. package/data/craftbook-templates/ch/changelog-writeup/manifest.json +5 -1
  58. package/data/craftbook-templates/ci/ci-pipeline/manifest.json +5 -3
  59. package/data/craftbook-templates/ci/ci-pipeline/versions/2.0.0/craftbook.json +423 -0
  60. package/data/craftbook-templates/ci/ci-pipeline/versions/2.0.0/test.json +228 -0
  61. package/data/craftbook-templates/co/codemod-sweep/art.json +12 -0
  62. package/data/craftbook-templates/co/codemod-sweep/logo.webp +0 -0
  63. package/data/craftbook-templates/co/codemod-sweep/manifest.json +23 -0
  64. package/data/craftbook-templates/co/codemod-sweep/versions/1.0.0/craftbook.json +441 -0
  65. package/data/craftbook-templates/co/codemod-sweep/versions/1.0.0/test.json +253 -0
  66. package/data/craftbook-templates/de/dependency-upgrade/art.json +12 -0
  67. package/data/craftbook-templates/de/dependency-upgrade/logo.webp +0 -0
  68. package/data/craftbook-templates/de/dependency-upgrade/manifest.json +23 -0
  69. package/data/craftbook-templates/de/dependency-upgrade/versions/1.0.0/craftbook.json +459 -0
  70. package/data/craftbook-templates/de/dependency-upgrade/versions/1.0.0/test.json +236 -0
  71. package/data/craftbook-templates/fe/feature-flag-release/manifest.json +5 -1
  72. package/data/craftbook-templates/fe/feature-flag-rollout/manifest.json +4 -1
  73. package/data/craftbook-templates/fe/feature-flag-rollout/versions/1.1.0/craftbook.json +203 -0
  74. package/data/craftbook-templates/fe/feature-flag-rollout/versions/1.1.0/test.json +165 -0
  75. package/data/craftbook-templates/fl/flaky-test-fix/art.json +12 -0
  76. package/data/craftbook-templates/fl/flaky-test-fix/logo.webp +0 -0
  77. package/data/craftbook-templates/fl/flaky-test-fix/manifest.json +24 -0
  78. package/data/craftbook-templates/fl/flaky-test-fix/versions/1.0.0/craftbook.json +534 -0
  79. package/data/craftbook-templates/fl/flaky-test-fix/versions/1.0.0/test.json +240 -0
  80. package/data/craftbook-templates/ho/hotfix-flow/manifest.json +5 -3
  81. package/data/craftbook-templates/ho/hotfix-flow/versions/2.0.0/craftbook.json +442 -0
  82. package/data/craftbook-templates/ho/hotfix-flow/versions/2.0.0/test.json +221 -0
  83. package/data/craftbook-templates/in/investigate/manifest.json +4 -1
  84. package/data/craftbook-templates/in/investigate-root-cause/manifest.json +5 -1
  85. package/data/craftbook-templates/index.json +1 -1
  86. package/data/craftbook-templates/li/live-browser-qa/manifest.json +5 -1
  87. package/data/craftbook-templates/ni/nightly-fix-sweep/art.json +12 -0
  88. package/data/craftbook-templates/ni/nightly-fix-sweep/logo.webp +0 -0
  89. package/data/craftbook-templates/ni/nightly-fix-sweep/manifest.json +23 -0
  90. package/data/craftbook-templates/ni/nightly-fix-sweep/versions/1.0.0/craftbook.json +145 -0
  91. package/data/craftbook-templates/ni/nightly-fix-sweep/versions/1.0.0/test.json +121 -0
  92. package/data/craftbook-templates/pe/perf-audit/versions/1.1.0/craftbook.json +195 -0
  93. package/data/craftbook-templates/pe/perf-audit/versions/1.1.0/test.json +165 -0
  94. package/data/craftbook-templates/pe/perf-optimization/manifest.json +3 -3
  95. package/data/craftbook-templates/pe/perf-optimization/versions/2.0.0/craftbook.json +511 -0
  96. package/data/craftbook-templates/pe/perf-optimization/versions/2.0.0/test.json +236 -0
  97. package/data/craftbook-templates/qa/qa/manifest.json +3 -1
  98. package/data/craftbook-templates/re/refactor-module/manifest.json +2 -2
  99. package/data/craftbook-templates/re/refactor-module/versions/1.0.4/craftbook.json +150 -0
  100. package/data/craftbook-templates/re/refactor-module/versions/1.0.4/test.json +95 -0
  101. package/data/craftbook-templates/re/refactor-module/versions/2.0.0/craftbook.json +509 -0
  102. package/data/craftbook-templates/re/refactor-module/versions/2.0.0/test.json +242 -0
  103. package/data/craftbook-templates/re/release-notes/manifest.json +5 -1
  104. package/data/craftbook-templates/re/release-notes/versions/1.0.3/craftbook.json +220 -0
  105. package/data/craftbook-templates/re/release-notes/versions/1.0.3/test.json +114 -0
  106. package/data/craftbook-templates/re/release-pipeline-ci/manifest.json +5 -1
  107. package/data/craftbook-templates/re/release-readiness-review/versions/1.1.0/craftbook.json +192 -0
  108. package/data/craftbook-templates/re/release-readiness-review/versions/1.1.0/test.json +113 -0
  109. package/data/craftbook-templates/ro/root-cause-investigation/manifest.json +7 -1
  110. package/data/craftbook-templates/ro/root-cause-investigation/versions/2.0.5/craftbook.json +433 -0
  111. package/data/craftbook-templates/ro/root-cause-investigation/versions/2.0.5/test.json +157 -0
  112. package/data/craftbook-templates/sc/schema-migration/manifest.json +4 -4
  113. package/data/craftbook-templates/sc/schema-migration/versions/2.0.0/craftbook.json +459 -0
  114. package/data/craftbook-templates/sc/schema-migration/versions/2.0.0/test.json +226 -0
  115. package/data/craftbook-templates/te/test-coverage-review/versions/1.2.0/craftbook.json +195 -0
  116. package/data/craftbook-templates/te/test-coverage-review/versions/1.2.0/test.json +116 -0
  117. package/data/craftbook-templates/te/test-suite-backfill/manifest.json +1 -2
  118. package/data/craftbook-templates/te/test-suite-backfill/versions/2.0.0/craftbook.json +428 -0
  119. package/data/craftbook-templates/te/test-suite-backfill/versions/2.0.0/test.json +198 -0
  120. package/data/craftbook-templates/ty/type-safety-pass/manifest.json +3 -3
  121. package/data/craftbook-templates/ty/type-safety-pass/versions/2.0.0/craftbook.json +428 -0
  122. package/data/craftbook-templates/ty/type-safety-pass/versions/2.0.0/test.json +222 -0
  123. package/data/craftbook-templates/ux/ux-update/art.json +12 -0
  124. package/data/craftbook-templates/ux/ux-update/logo.webp +0 -0
  125. package/data/craftbook-templates/ux/ux-update/manifest.json +22 -0
  126. package/data/craftbook-templates/ux/ux-update/versions/1.0.0/craftbook.json +439 -0
  127. package/data/craftbook-templates/ux/ux-update/versions/1.0.0/test.json +207 -0
  128. package/data/craftbook-templates/ve/version-bump/versions/1.1.0/craftbook.json +206 -0
  129. package/data/craftbook-templates/ve/version-bump/versions/1.1.0/test.json +95 -0
  130. package/data/gezel-templates/bo/boekwachter/versions/1.1.0/about.md +29 -0
  131. package/data/gezel-templates/bo/boekwachter/versions/1.1.0/manifest.json +16 -0
  132. package/data/gezel-templates/bu/builder/versions/1.5.0/about.md +34 -0
  133. package/data/gezel-templates/bu/builder/versions/1.5.0/manifest.json +16 -0
  134. package/data/gezel-templates/de/developer/versions/1.5.0/about.md +34 -0
  135. package/data/gezel-templates/de/developer/versions/1.5.0/manifest.json +21 -0
  136. package/data/gezel-templates/index.json +1 -1
  137. package/data/gezel-templates/re/reviewer/versions/1.4.0/about.md +49 -0
  138. package/data/gezel-templates/re/reviewer/versions/1.4.0/manifest.json +21 -0
  139. package/data/project-types/index.json +1 -1
  140. package/data/project-types/so/software-project/manifest.json +20 -0
  141. package/data/project-types/so/software-project/versions/1.0.0/about.md +3 -0
  142. package/data/project-types/so/software-project/versions/1.0.0/manifest.json +41 -0
  143. package/data/project-types/so/software-project/versions/1.0.0/mission.md +4 -0
  144. package/package.json +1 -1
  145. package/schemas/craftbook-doc.schema.json +248 -0
  146. package/schemas/craftbook-template-version.schema.json +248 -0
  147. package/schemas/craftbook-test.schema.json +200 -0
@@ -0,0 +1,226 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "title": "Expand/contract data migration with no record stranded",
4
+ "objective": "The craftbook drives an expand/contract migration of a JSON user store from a flat name field to a nested profile shape: a plan grounded in the real files, accessors changed at their real sites with the suite green between stages, the data transformed with every value surviving exactly, and the old shape fully retired - verified mechanically, including a pure-nested-record probe proving the dual-read did not linger.",
5
+ "tags": [
6
+ "code",
7
+ "schema-migration",
8
+ "expand-contract",
9
+ "tactical-fleet"
10
+ ],
11
+ "prompt": "Use the Schema / Type Migration craftbook for this: migrate our user records from the flat name field to the nested profile shape described in source/migration-brief.md. No record may be lost, the accessors in src/users.js must keep working at every stage, and when it is done nothing may read the flat field any more.",
12
+ "setup": {
13
+ "projectName": "Crew Roster",
14
+ "about": "A tiny user-roster module backed by a JSON data file. Tests run with `npm run test` (node --test).",
15
+ "files": [
16
+ {
17
+ "path": "package.json",
18
+ "content": "{\n \"name\": \"crew-roster\",\n \"private\": true,\n \"version\": \"1.0.0\",\n \"type\": \"module\",\n \"scripts\": {\n \"test\": \"node --test\"\n }\n}\n"
19
+ },
20
+ {
21
+ "path": "data/users.json",
22
+ "content": "[\n { \"id\": 1, \"name\": \"Ada Lovelace\", \"email\": \"ada@example.com\" },\n { \"id\": 2, \"name\": \"Grace Hopper\", \"email\": \"grace@example.com\" },\n { \"id\": 3, \"name\": \"Annie Easley\", \"email\": \"annie@example.com\" }\n]\n"
23
+ },
24
+ {
25
+ "path": "src/users.js",
26
+ "content": "import { readFileSync } from 'node:fs';\n\nconst DB_URL = new URL('../data/users.json', import.meta.url);\n\nexport function loadUsers() {\n return JSON.parse(readFileSync(DB_URL, 'utf8'));\n}\n\nexport function fullName(user) {\n return user.name;\n}\n\nexport function byFullName(users, wanted) {\n return users.find((user) => user.name === wanted);\n}\n"
27
+ },
28
+ {
29
+ "path": "tests/users.test.mjs",
30
+ "content": "import assert from 'node:assert/strict';\nimport { test } from 'node:test';\nimport { byFullName, fullName, loadUsers } from '../src/users.js';\n\ntest('loads every user record', () => {\n assert.equal(loadUsers().length, 3);\n});\n\ntest('fullName renders the display name', () => {\n assert.deepEqual(loadUsers().map(fullName), [\n 'Ada Lovelace',\n 'Grace Hopper',\n 'Annie Easley',\n ]);\n});\n\ntest('byFullName finds a user by display name', () => {\n assert.equal(byFullName(loadUsers(), 'Grace Hopper').email, 'grace@example.com');\n});\n"
31
+ },
32
+ {
33
+ "path": "source/migration-brief.md",
34
+ "content": "# Migration brief: nested profile shape\n\nWe sort and filter by last name now, so the flat `name` field has to go.\n\nCurrent record shape in `data/users.json`:\n\n { \"id\": 1, \"name\": \"Ada Lovelace\", \"email\": \"ada@example.com\" }\n\nTarget record shape:\n\n { \"id\": 1, \"profile\": { \"first\": \"Ada\", \"last\": \"Lovelace\" }, \"email\": \"ada@example.com\" }\n\nRules:\n\n- Every existing record must survive the migration exactly - same people, same\n emails, names split on the single space between first and last name.\n- The accessors in `src/users.js` must keep working for their callers at every\n stage: `fullName` and `byFullName` keep returning the same display names as\n today.\n- When the migration is done, nothing reads the flat `name` field any more.\n"
35
+ },
36
+ {
37
+ "path": "tests/verify-migration.mjs",
38
+ "content": "import assert from 'node:assert/strict';\nimport { execFileSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nconst root = process.cwd();\n\n// 1) The data moved to the target shape with no record stranded.\nconst records = JSON.parse(readFileSync(join(root, 'data/users.json'), 'utf8'));\nassert.ok(Array.isArray(records), 'data/users.json must stay a JSON array');\nassert.equal(records.length, 3, 'all three records must survive the migration');\nconst expected = new Map([\n ['ada@example.com', ['Ada', 'Lovelace']],\n ['grace@example.com', ['Grace', 'Hopper']],\n ['annie@example.com', ['Annie', 'Easley']],\n]);\nfor (const record of records) {\n assert.ok(record && typeof record === 'object', 'each record must stay an object');\n assert.ok(!('name' in record), `record ${record.id} still carries the flat name field`);\n const want = expected.get(record.email);\n assert.ok(want, `record ${record.id} lost or changed its email`);\n assert.equal(record.profile?.first, want[0], `record ${record.id} must keep its first name exactly`);\n assert.equal(record.profile?.last, want[1], `record ${record.id} must keep its last name exactly`);\n}\nconsole.log('SCHEMAMIG_ORACLE data intact');\n\n// 2) The accessors read the new shape - a pure nested record, no flat fallback.\nconst users = await import(pathToFileURL(join(root, 'src/users.js')).href);\nassert.equal(\n users.fullName({ profile: { first: 'Test', last: 'User' } }),\n 'Test User',\n 'fullName must read profile.first and profile.last',\n);\nassert.equal(\n users.byFullName([{ profile: { first: 'Grace', last: 'Hopper' }, email: 'x' }], 'Grace Hopper')?.email,\n 'x',\n 'byFullName must match display names on the new shape',\n);\nconsole.log('SCHEMAMIG_ORACLE accessors migrated');\n\n// 3) Contract landed: no flat-shape read remains in the accessor module.\nconst accessorSource = readFileSync(join(root, 'src/users.js'), 'utf8');\nassert.ok(\n !/\\.name\\b|\\[[\"']name[\"']\\]/.test(accessorSource),\n 'src/users.js still reads the flat name field',\n);\nconsole.log('SCHEMAMIG_ORACLE contract complete');\n\n// 4) The suite is green on the migrated tree, and the seeded test file survives.\nreadFileSync(join(root, 'tests/users.test.mjs'));\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}\nassert.equal(runSuite(root), 0, 'the suite must be green after the migration');\nconsole.log('SCHEMAMIG_ORACLE suite green');\nconsole.log('SCHEMAMIG_ORACLE done');\n",
39
+ "surface": "harness"
40
+ }
41
+ ],
42
+ "craftbookParams": {
43
+ "workPath": "tasks/eval",
44
+ "scope": "Migrate data/users.json and src/users.js from the flat name field to profile.first/profile.last per source/migration-brief.md, with no record loss and reads working at every stage."
45
+ }
46
+ },
47
+ "mocks": [],
48
+ "success": {
49
+ "summary": "Every record reaches the nested profile shape with its values intact, the accessors read the new shape with the dual-read retired, the flat field is gone from data and code, the suite is green, and every fleet artifact exists with honest receipts.",
50
+ "deliverables": [
51
+ {
52
+ "path": "tasks/eval/migration-plan.md",
53
+ "kind": "markdown-notes",
54
+ "artifact": true,
55
+ "minBytes": 700,
56
+ "checks": [
57
+ {
58
+ "kind": "contains",
59
+ "file": "tasks/eval/migration-plan.md",
60
+ "pattern": "^##\\s+Current shape[\\s\\S]*^##\\s+Target shape[\\s\\S]*^##\\s+Stages[\\s\\S]*^##\\s+Data safety[\\s\\S]*^##\\s+Rollback per stage",
61
+ "flags": "im",
62
+ "label": "plan sections in order"
63
+ },
64
+ {
65
+ "kind": "contains",
66
+ "file": "tasks/eval/migration-plan.md",
67
+ "pattern": "data/users\\.json",
68
+ "label": "names the real data file"
69
+ },
70
+ {
71
+ "kind": "citationsResolve",
72
+ "file": "tasks/eval/migration-plan.md",
73
+ "minCitations": 2,
74
+ "artifact": true
75
+ }
76
+ ]
77
+ },
78
+ {
79
+ "path": "tasks/eval/change-notes.md",
80
+ "kind": "markdown-notes",
81
+ "artifact": true,
82
+ "minBytes": 700,
83
+ "checks": [
84
+ {
85
+ "kind": "contains",
86
+ "file": "tasks/eval/change-notes.md",
87
+ "pattern": "^##\\s+Stages executed[\\s\\S]*^##\\s+Files touched[\\s\\S]*^##\\s+Data transformed[\\s\\S]*^##\\s+Deviations",
88
+ "flags": "im",
89
+ "label": "change-notes sections in order"
90
+ },
91
+ {
92
+ "kind": "citationsResolve",
93
+ "file": "tasks/eval/change-notes.md",
94
+ "minCitations": 2,
95
+ "artifact": true
96
+ }
97
+ ]
98
+ },
99
+ {
100
+ "path": "tasks/eval/verification.md",
101
+ "kind": "markdown-notes",
102
+ "artifact": true,
103
+ "minBytes": 500,
104
+ "checks": [
105
+ {
106
+ "kind": "contains",
107
+ "file": "tasks/eval/verification.md",
108
+ "pattern": "^##\\s+Old shape check[\\s\\S]*^##\\s+Data integrity[\\s\\S]*^##\\s+Suite[\\s\\S]*^##\\s+Result",
109
+ "flags": "im",
110
+ "label": "verification sections in order"
111
+ }
112
+ ]
113
+ },
114
+ {
115
+ "path": "tasks/eval/review.md",
116
+ "kind": "markdown-report",
117
+ "artifact": true,
118
+ "minBytes": 400,
119
+ "checks": [
120
+ {
121
+ "kind": "contains",
122
+ "file": "tasks/eval/review.md",
123
+ "pattern": "Verdict:\\s*(?:PASS|REVISE)",
124
+ "flags": "i",
125
+ "label": "explicit reviewer verdict"
126
+ }
127
+ ]
128
+ }
129
+ ],
130
+ "checks": [
131
+ {
132
+ "kind": "notContains",
133
+ "file": "data/users.json",
134
+ "pattern": "\"name\"\\s*:",
135
+ "label": "the flat name field is gone from the data"
136
+ },
137
+ {
138
+ "kind": "notContains",
139
+ "file": "src/users.js",
140
+ "pattern": "\\.name\\b|\\[[\"']name[\"']\\]",
141
+ "label": "no flat-shape read remains in the accessors"
142
+ },
143
+ {
144
+ "kind": "sourceParses",
145
+ "file": "src/users.js"
146
+ },
147
+ {
148
+ "kind": "sniff",
149
+ "file": "data/users.json",
150
+ "sniff": "json-valid"
151
+ },
152
+ {
153
+ "kind": "nodeRuns",
154
+ "file": "tests/users.test.mjs"
155
+ },
156
+ {
157
+ "kind": "nodeScriptPasses",
158
+ "script": "tests/verify-migration.mjs",
159
+ "timeoutMs": 60000,
160
+ "requiredOutput": [
161
+ {
162
+ "pattern": "SCHEMAMIG_ORACLE data intact",
163
+ "label": "every record migrated with values intact"
164
+ },
165
+ {
166
+ "pattern": "SCHEMAMIG_ORACLE accessors migrated",
167
+ "label": "accessors read the new shape"
168
+ },
169
+ {
170
+ "pattern": "SCHEMAMIG_ORACLE contract complete",
171
+ "label": "the dual-read retired with the old shape"
172
+ },
173
+ {
174
+ "pattern": "SCHEMAMIG_ORACLE suite green",
175
+ "label": "suite green on the migrated tree"
176
+ }
177
+ ]
178
+ }
179
+ ],
180
+ "taskNotes": {
181
+ "minBytes": 120,
182
+ "checks": [
183
+ {
184
+ "kind": "contains",
185
+ "file": "task-notes.md",
186
+ "pattern": "\\bDONE\\b[\\s\\S]*(npm\\s+run\\s+test|node\\s+--test)",
187
+ "flags": "i",
188
+ "label": "DONE note names the real test command"
189
+ }
190
+ ]
191
+ },
192
+ "taskGraph": {
193
+ "requireCraftbookTask": true,
194
+ "requireTerminalStep": true
195
+ },
196
+ "unchangedFixtures": [
197
+ "source/migration-brief.md",
198
+ "package.json"
199
+ ]
200
+ },
201
+ "rubric": {
202
+ "artifact": {
203
+ "path": "tasks/eval/change-notes.md",
204
+ "kind": "markdown"
205
+ },
206
+ "axes": [
207
+ {
208
+ "name": "Expand/contract discipline",
209
+ "description": "The stages genuinely followed expand, migrate, contract in order - readers accepted both shapes while the data moved, and the old shape was dropped only after the transform completed with a green suite."
210
+ },
211
+ {
212
+ "name": "Data preservation",
213
+ "description": "The transform is real and lossless: every record reached the target shape with names and emails surviving exactly, proven by counts and spot-checks rather than asserted."
214
+ },
215
+ {
216
+ "name": "Honest verification",
217
+ "description": "Verification searched for leftover old-shape reads, quoted what it found, ran the real suite, and labeled anything unrun as unverified instead of claiming it."
218
+ }
219
+ ]
220
+ },
221
+ "qualityFocus": [
222
+ "expand/contract data safety",
223
+ "no record stranded",
224
+ "real-site accessor changes"
225
+ ]
226
+ }
@@ -0,0 +1,195 @@
1
+ {
2
+ "id": "test-coverage-review",
3
+ "name": "Test Coverage Review",
4
+ "description": "Review a codebase or module's test suite for real coverage and quality, then produce a gap report and a prioritized backlog of tests to add. First scopes the units under review and locks a coverage standard distinguishing line coverage from behavioral coverage (critical paths, branches, edge cases, error handling, and regression protection), then audits the existing tests for what they actually assert and which behaviors and branches are untested or weakly tested, then writes a report ranking the highest-value missing or low-quality tests with a concrete description of each. Use this for a test coverage review, finding test gaps, auditing test quality, deciding what to test next, or assessing whether a module is well-tested — it distinguishes meaningful behavioral coverage from a green coverage number and returns a prioritized testing backlog rather than 'add more tests'.\n\nA gallery craftbook generated from an archetype spec. It runs\n`phase → (per-phase gate) → … → evaluate → (loop) → finish`. Each build\nphase that produces a checkable artifact is followed by a **runtime\ngate-checkpoint** — the runtime verifies the artifact and routes with no\nmodel turn, looping back to redo the phase on a miss. The final `evaluate`\nstep holds a static deliverable gate plus a reviewer QA pass. What it adds\nover the generic `build-loop`: a specialist role per phase, a\ndomain-correct ordering, and a concrete per-phase quality bar.\n\nDeliverables marked \"artifact\" land in the project's artifacts drawer (`write_artifact` / `read_artifact`), not the shipped workspace — review output is not product source.\n\nPhases:\n\n1. Scope the coverage standard (reviewer) — lock units in scope + a behavioral coverage bar → gated on artifact `{{workPath}}/scope.md` (markdown-notes)\n2. Audit the test suite (reviewer) — find untested behavior + weak assertions → gated on artifact `{{workPath}}/audit.md` (markdown-notes)\n3. Write the coverage report (reviewer) — prioritized test backlog + quality findings → gated on artifact `{{workPath}}/coverage-review.md` (markdown-report)\n\nThe gates never advance with an unmet criterion, and loop back to the\nowning phase to fix named gaps.\n",
5
+ "entryStepId": "scope",
6
+ "triggers": [
7
+ "test coverage review",
8
+ "where are the test gaps",
9
+ "is this well tested",
10
+ "what should I test next",
11
+ "audit the test suite",
12
+ "test quality review"
13
+ ],
14
+ "steps": [
15
+ {
16
+ "id": "scope",
17
+ "name": "Scope the coverage standard",
18
+ "description": "lock units in scope + a behavioral coverage bar",
19
+ "prompt": "Step 1: Identify the modules/units under review and their behavioral surface — the public functions, the critical paths, the branches, and the failure modes that matter. Step 2: Run the coverage tool if available (`vitest --coverage`, `pytest --cov`, etc.) to get the line/branch numbers as a starting signal — but treat it as a floor, not the goal. Step 3: Write a coverage acceptance-criteria checklist that distinguishes LINE coverage from BEHAVIORAL coverage: 'every critical path has a test that asserts its outcome', 'each conditional branch is exercised', 'edge cases (empty/null/boundary/large) are tested', 'error and exception paths are tested', 'tests assert behavior, not just that code runs without throwing', 'a regression in core logic would fail at least one test'. Step 4: State the target for THIS code (e.g. 'core domain logic ~90% branch + behavioral; glue code lighter'). Write the units + the coverage bar to `write_task_note` AND `{{workPath}}/scope.md`. No audit yet.\n\nThe deliverable `{{workPath}}/scope.md` lands in the project's artifacts drawer — write it with `write_artifact` and read it back with `read_artifact`; the shipped workspace stays untouched.",
20
+ "suggestedRole": "reviewer",
21
+ "advanceWhen": {
22
+ "file": "{{workPath}}/scope.md",
23
+ "minBytes": 1,
24
+ "sniff": "nonempty",
25
+ "artifact": true
26
+ },
27
+ "gate": {
28
+ "at": "completion",
29
+ "checks": [
30
+ {
31
+ "kind": "minBytes",
32
+ "file": "{{workPath}}/scope.md",
33
+ "bytes": 120,
34
+ "artifact": true
35
+ },
36
+ {
37
+ "kind": "sniff",
38
+ "file": "{{workPath}}/scope.md",
39
+ "sniff": "nonempty",
40
+ "artifact": true
41
+ }
42
+ ],
43
+ "onReject": "scope",
44
+ "maxAttempts": 3
45
+ },
46
+ "next": "audit"
47
+ },
48
+ {
49
+ "id": "audit",
50
+ "name": "Audit the test suite",
51
+ "description": "find untested behavior + weak assertions",
52
+ "prompt": "Step 1: Map the existing tests to the behavioral surface — for each unit, what is tested and what does each test actually ASSERT. Step 2: Flag the gaps: untested public functions, untested branches, missing edge cases (empty/null/boundary/error), and missing regression protection on core logic. Step 3: Flag WEAK tests — tests that only check 'it runs' without asserting outcomes, over-mocked tests that would pass even if the real logic broke, snapshot-only tests of meaningful logic, and tests coupled to implementation rather than behavior. Step 4: Cross-check the coverage numbers: where lines are 'covered' but no assertion verifies the result, call it out (covered ≠ tested). Step 5: For each gap, draft the test to add: the unit, the scenario/input, and the expected assertion. Step 6: Rank by value — core/critical logic and error paths first. Good looks like: 'parseAmount() has no test for negative or non-numeric input → add a test asserting it throws/returns Err', not 'add more tests'. Stage the gap list to `write_task_note`. Do not write the report yet.\n\nThe deliverable `{{workPath}}/audit.md` lands in the project's artifacts drawer — write it with `write_artifact` and read it back with `read_artifact`; the shipped workspace stays untouched.",
53
+ "suggestedRole": "reviewer",
54
+ "advanceWhen": {
55
+ "file": "{{workPath}}/audit.md",
56
+ "minBytes": 1,
57
+ "sniff": "nonempty",
58
+ "artifact": true
59
+ },
60
+ "gate": {
61
+ "at": "completion",
62
+ "checks": [
63
+ {
64
+ "kind": "minBytes",
65
+ "file": "{{workPath}}/audit.md",
66
+ "bytes": 120,
67
+ "artifact": true
68
+ },
69
+ {
70
+ "kind": "sniff",
71
+ "file": "{{workPath}}/audit.md",
72
+ "sniff": "nonempty",
73
+ "artifact": true
74
+ }
75
+ ],
76
+ "onReject": "audit",
77
+ "maxAttempts": 3
78
+ },
79
+ "next": "report"
80
+ },
81
+ {
82
+ "id": "report",
83
+ "name": "Write the coverage report",
84
+ "description": "prioritized test backlog + quality findings",
85
+ "prompt": "Step 1: Open `{{workPath}}/coverage-review.md` and write a '## Summary': the coverage numbers, an honest behavioral-coverage assessment, and the biggest gap. Step 2: Add a '## Missing tests' backlog ranked by value; each entry: the unit, the untested scenario, and the assertion the new test should make. Step 3: Add a '## Weak tests' section listing low-value/misleading tests with how to strengthen them. Step 4: Add a '## Well-covered' section noting what is solidly tested (so effort goes where it's needed). Step 5: Add a '## Quick wins' callout for high-value, easy tests to add first. Every recommendation must name a concrete test and its assertion — no 'increase coverage'. On a loop-back, fix only the named gaps. `write_task_note` the report path and the count of missing high-value tests.\n\nThe deliverable `{{workPath}}/coverage-review.md` lands in the project's artifacts drawer — write it with `write_artifact` and read it back with `read_artifact`; the shipped workspace stays untouched.",
86
+ "suggestedRole": "reviewer",
87
+ "advanceWhen": {
88
+ "file": "{{workPath}}/coverage-review.md",
89
+ "minBytes": 1,
90
+ "sniff": "nonempty",
91
+ "artifact": true,
92
+ "requireChange": true
93
+ },
94
+ "gate": {
95
+ "at": "completion",
96
+ "checks": [
97
+ {
98
+ "kind": "minBytes",
99
+ "file": "{{workPath}}/coverage-review.md",
100
+ "bytes": 1500,
101
+ "artifact": true
102
+ },
103
+ {
104
+ "kind": "contains",
105
+ "file": "{{workPath}}/coverage-review.md",
106
+ "pattern": "(?:^|\\n)#{1,3}\\s+\\S",
107
+ "flags": "i",
108
+ "label": "at least one markdown heading",
109
+ "artifact": true
110
+ },
111
+ {
112
+ "kind": "citationsResolve",
113
+ "file": "{{workPath}}/coverage-review.md",
114
+ "minCitations": 2,
115
+ "artifact": true
116
+ }
117
+ ],
118
+ "onReject": "report",
119
+ "maxAttempts": 4
120
+ },
121
+ "next": "evaluate"
122
+ },
123
+ {
124
+ "id": "evaluate",
125
+ "name": "Evaluate",
126
+ "description": "Grade the deliverable against every acceptance criterion. All pass → finish; any fail → loop back and fix the gap.",
127
+ "prompt": "Open `{{workPath}}/coverage-review.md` with `read_artifact` first, then review it against the original scope: every claim cites a real path, the severities and priorities are defensible, and nothing important in scope was skipped. Open the underlying files for at least the top findings; do not grade from the report's own summary. If a finding cannot be verified, say so explicitly.\n\nWrite your review to the artifact `{{workPath}}/review.md` with one `write_artifact` call: what you checked, what held, what did not (as a findings table with columns `| Severity | File | Line | Problem | Fix |` when anything needs fixing), ending with exactly `Verdict: PASS` or `Verdict: REVISE`. The gate enforces the verdict: a well-formed REVISE is routed back to the `report` step automatically with your findings. On PASS, `advance_task_step` to `finish`.",
128
+ "suggestedRole": "reviewer",
129
+ "consumes": [
130
+ {
131
+ "file": "{{workPath}}/coverage-review.md",
132
+ "artifact": true
133
+ }
134
+ ],
135
+ "next": "finish",
136
+ "gate": {
137
+ "at": "completion",
138
+ "checks": [
139
+ {
140
+ "kind": "minBytes",
141
+ "file": "{{workPath}}/review.md",
142
+ "bytes": 300,
143
+ "artifact": true
144
+ },
145
+ {
146
+ "kind": "contains",
147
+ "file": "{{workPath}}/review.md",
148
+ "pattern": "Verdict:\\s*(?:PASS|REVISE)",
149
+ "flags": "i",
150
+ "label": "explicit PASS or REVISE verdict",
151
+ "artifact": true
152
+ }
153
+ ],
154
+ "scripts": [
155
+ {
156
+ "name": "checkFixReview",
157
+ "scope": "standard",
158
+ "inputs": {
159
+ "taskRef": "{{task.ref}}",
160
+ "reviewPath": "{{workPath}}/review.md",
161
+ "fixStepId": "report"
162
+ }
163
+ }
164
+ ],
165
+ "onReject": "evaluate",
166
+ "maxAttempts": 4
167
+ }
168
+ },
169
+ {
170
+ "id": "finish",
171
+ "name": "Finish",
172
+ "description": "All acceptance criteria met. Stamp a short summary and report DONE.",
173
+ "prompt": "Every acceptance criterion passed. Write a one-paragraph DONE summary to task notes via `write_task_note`: what was built, the deliverable path(s), and a one-line confirmation that each criterion is met. Then report DONE.",
174
+ "suggestedRole": "developer",
175
+ "terminal": true
176
+ }
177
+ ],
178
+ "version": "1.2.0",
179
+ "releasedAt": "2026-08-24T00:00:00.000Z",
180
+ "paramSchema": {
181
+ "type": "object",
182
+ "properties": {
183
+ "workPath": {
184
+ "type": "string",
185
+ "title": "Working folder",
186
+ "description": "Per-task working folder in the artifacts drawer. Defaults to this task's own folder so runs never collide; override with a stable name when you deliberately want runs to share files.",
187
+ "default": "{{task.dir}}"
188
+ }
189
+ }
190
+ },
191
+ "minGezelVersion": "1.26236",
192
+ "runModes": {
193
+ "nightShift": "supported"
194
+ }
195
+ }
@@ -0,0 +1,116 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "title": "Test Coverage Review behavioral eval",
4
+ "objective": "Measure whether the review distinguishes executed lines from meaningful assertions and proposes concrete high-value tests.",
5
+ "tags": [
6
+ "corpus"
7
+ ],
8
+ "prompt": "Use the Test Coverage Review craftbook for a whole-codebase test-health pass. Review src/price.ts and test/price.test.ts, then write tasks/eval/coverage-review.md. Do not add or change tests.",
9
+ "setup": {
10
+ "projectName": "Test Health Maintenance Eval",
11
+ "about": "A small pricing module with branches and error behavior but one weak happy-path test.",
12
+ "missionObjectives": "Find the missing boundary/error behaviors and weak assertion; leave a prioritized backlog with exact assertions.",
13
+ "files": [
14
+ {
15
+ "path": "src/price.ts",
16
+ "content": "export function finalPrice(cents: number, coupon?: string): number {\n if (!Number.isInteger(cents) || cents < 0) throw new Error('invalid cents');\n if (coupon === 'HALF') return Math.round(cents / 2);\n if (coupon && coupon !== 'SAVE10') throw new Error('unknown coupon');\n return coupon === 'SAVE10' ? Math.round(cents * 0.9) : cents;\n}\n"
17
+ },
18
+ {
19
+ "path": "test/price.test.ts",
20
+ "content": "import { test, expect } from 'vitest';\nimport { finalPrice } from '../src/price';\ntest('returns a price', () => {\n expect(finalPrice(1000)).toBeDefined();\n});\n"
21
+ },
22
+ {
23
+ "path": "coverage-summary.txt",
24
+ "content": "src/price.ts: lines 100%, branches 25%, functions 100%\n"
25
+ }
26
+ ],
27
+ "worker": {
28
+ "name": "Rae",
29
+ "role": "Reviewer"
30
+ },
31
+ "craftbookParams": {
32
+ "workPath": "tasks/eval"
33
+ }
34
+ },
35
+ "mocks": [],
36
+ "success": {
37
+ "summary": "tasks/eval/coverage-review.md exposes the misleading line coverage and specifies exact branch, boundary, and error assertions.",
38
+ "deliverables": [
39
+ {
40
+ "path": "tasks/eval/coverage-review.md",
41
+ "kind": "markdown-report",
42
+ "minBytes": 1300,
43
+ "checks": [
44
+ {
45
+ "kind": "contains",
46
+ "file": "tasks/eval/coverage-review.md",
47
+ "pattern": "src/price\\.ts|test/price\\.test\\.ts",
48
+ "flags": "i"
49
+ },
50
+ {
51
+ "kind": "contains",
52
+ "file": "tasks/eval/coverage-review.md",
53
+ "pattern": "100%[\\s\\S]{0,120}25%|line coverage[\\s\\S]{0,120}branch",
54
+ "flags": "i",
55
+ "label": "coverage is not behavior"
56
+ },
57
+ {
58
+ "kind": "contains",
59
+ "file": "tasks/eval/coverage-review.md",
60
+ "pattern": "toBeDefined|weak assertion|assert.*exact",
61
+ "flags": "i"
62
+ },
63
+ {
64
+ "kind": "contains",
65
+ "file": "tasks/eval/coverage-review.md",
66
+ "pattern": "negative|invalid cents",
67
+ "flags": "i"
68
+ },
69
+ {
70
+ "kind": "contains",
71
+ "file": "tasks/eval/coverage-review.md",
72
+ "pattern": "HALF|SAVE10",
73
+ "flags": "i"
74
+ },
75
+ {
76
+ "kind": "contains",
77
+ "file": "tasks/eval/coverage-review.md",
78
+ "pattern": "unknown coupon|toThrow",
79
+ "flags": "i"
80
+ },
81
+ {
82
+ "kind": "contains",
83
+ "file": "tasks/eval/coverage-review.md",
84
+ "pattern": "Quick wins|priority|high",
85
+ "flags": "i"
86
+ }
87
+ ]
88
+ }
89
+ ]
90
+ },
91
+ "rubric": {
92
+ "artifact": {
93
+ "path": "tasks/eval/coverage-review.md",
94
+ "kind": "markdown"
95
+ },
96
+ "axes": [
97
+ {
98
+ "name": "behavioral analysis",
99
+ "description": "The review distinguishes line execution from asserted behavior."
100
+ },
101
+ {
102
+ "name": "gap coverage",
103
+ "description": "Critical branches, boundaries, and error paths are mapped to missing tests."
104
+ },
105
+ {
106
+ "name": "backlog quality",
107
+ "description": "Each proposed test states its input, behavior, and exact assertion."
108
+ }
109
+ ]
110
+ },
111
+ "qualityFocus": [
112
+ "behavioral coverage",
113
+ "weak assertion detection",
114
+ "concrete test backlog"
115
+ ]
116
+ }
@@ -5,9 +5,8 @@
5
5
  "role": "maintenance-review",
6
6
  "category": "code-quality",
7
7
  "name": "Test Suite Backfill",
8
- "description": "Add a meaningful test suite to existing untested (or under-tested) code, prioritizing the highest-risk behavior and edge cases over vanity coverage. Scopes coverage FIRST the public surface, the critical paths, the edge/error cases, and the target the tests must hit — then writes characterization and edge-case tests that pin real behavior and would catch real regressions. Covers test prioritization, characterization tests, edge/error-case coverage, arrange-act-assert structure, and coverage-that-matters over line-count chasing.",
8
+ "description": "Add tests that actually bite to untested code: rank the untested behavior by breakage cost, write tests in the project's real layout that a wrong implementation would fail, and prove the suite green with real run receipts under an enforced independent review.",
9
9
  "tags": [
10
- "gallery",
11
10
  "tests",
12
11
  "coverage",
13
12
  "testing",