@bendyline/gilde 0.1.49 → 0.1.51

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 (244) hide show
  1. package/data/craftbook-templates/ac/accessibility-retrofit/versions/2.0.0/test.json +14 -17
  2. package/data/craftbook-templates/ad/ad-variations/versions/1.0.2/test.json +0 -3
  3. package/data/craftbook-templates/al/album-curate/versions/1.0.2/test.json +0 -3
  4. package/data/craftbook-templates/al/alert-rules/versions/1.0.2/test.json +0 -3
  5. package/data/craftbook-templates/an/anniversary-cut/versions/1.0.4/test.json +0 -3
  6. package/data/craftbook-templates/an/annotated-bibliography/versions/1.0.2/test.json +0 -3
  7. package/data/craftbook-templates/ap/api-contract-review/versions/1.1.2/test.json +82 -8
  8. package/data/craftbook-templates/ap/apply-review-findings/versions/1.0.0/test.json +21 -22
  9. package/data/craftbook-templates/au/audio-ad-spot/versions/1.0.2/test.json +0 -3
  10. package/data/craftbook-templates/au/audio-highlight-reel/versions/1.0.2/test.json +0 -3
  11. package/data/craftbook-templates/au/audiobook-master-pack/versions/1.0.4/test.json +0 -3
  12. package/data/craftbook-templates/au/automation-recipe/versions/1.0.2/test.json +0 -3
  13. package/data/craftbook-templates/ba/backup-routine/versions/1.0.2/test.json +0 -3
  14. package/data/craftbook-templates/bl/blog-post/versions/1.0.2/test.json +0 -3
  15. package/data/craftbook-templates/bo/board-deck/versions/1.0.2/test.json +0 -3
  16. package/data/craftbook-templates/bo/board-game-web/versions/1.0.2/test.json +0 -3
  17. package/data/craftbook-templates/bo/booking-automation/versions/1.0.2/test.json +0 -3
  18. package/data/craftbook-templates/br/broadcast-announcement/versions/1.0.2/test.json +0 -3
  19. package/data/craftbook-templates/br/browser-qa-audit/versions/2.0.5/test.json +1 -4
  20. package/data/craftbook-templates/bu/bug-fix-tdd/versions/2.0.0/test.json +14 -15
  21. package/data/craftbook-templates/ca/calendar-brief/versions/1.0.2/test.json +0 -3
  22. package/data/craftbook-templates/ca/canvas-generative-art/versions/1.0.2/test.json +0 -3
  23. package/data/craftbook-templates/ca/case-study/versions/1.0.2/test.json +0 -3
  24. package/data/craftbook-templates/ca/case-study-writeup/versions/1.0.2/test.json +0 -3
  25. package/data/craftbook-templates/ch/chapter-narration-run/versions/1.0.3/test.json +0 -3
  26. package/data/craftbook-templates/ch/chapter-weave/versions/1.0.2/test.json +0 -3
  27. package/data/craftbook-templates/ch/character-sheet/versions/1.0.2/test.json +0 -3
  28. package/data/craftbook-templates/ch/character-turnaround/versions/1.0.2/test.json +0 -3
  29. package/data/craftbook-templates/ch/chart-pack/versions/1.0.2/test.json +0 -3
  30. package/data/craftbook-templates/ch/chrome-extension/versions/1.0.2/test.json +0 -3
  31. package/data/craftbook-templates/ci/ci-pipeline/versions/2.0.0/test.json +14 -17
  32. package/data/craftbook-templates/cl/cli-tool/versions/1.1.2/test.json +0 -3
  33. package/data/craftbook-templates/co/code-review/versions/1.0.0/test.json +175 -53
  34. package/data/craftbook-templates/co/codemod-sweep/versions/1.0.0/test.json +12 -13
  35. package/data/craftbook-templates/co/company-research-brief/versions/1.0.2/test.json +0 -3
  36. package/data/craftbook-templates/co/comparison-matrix/versions/1.0.2/test.json +0 -3
  37. package/data/craftbook-templates/co/config-scaffold/versions/1.0.2/test.json +0 -3
  38. package/data/craftbook-templates/co/content-deck/versions/1.2.2/craftbook.json +217 -0
  39. package/data/craftbook-templates/co/content-deck/versions/1.2.2/test.json +169 -0
  40. package/data/craftbook-templates/co/contract-template/versions/1.0.2/test.json +0 -3
  41. package/data/craftbook-templates/co/cookbook-layout/versions/1.0.2/test.json +0 -3
  42. package/data/craftbook-templates/co/corpus-email-digest/versions/1.2.2/craftbook.json +221 -0
  43. package/data/craftbook-templates/co/corpus-email-digest/versions/1.2.2/test.json +187 -0
  44. package/data/craftbook-templates/co/cover-letter/versions/1.0.2/test.json +0 -3
  45. package/data/craftbook-templates/cr/crm-update-batch/versions/1.0.2/test.json +0 -3
  46. package/data/craftbook-templates/cr/cron-job/versions/1.0.2/test.json +0 -3
  47. package/data/craftbook-templates/cs/csv-transformer/versions/1.2.3/test.json +0 -3
  48. package/data/craftbook-templates/da/dashboard-spec/versions/1.0.2/test.json +0 -3
  49. package/data/craftbook-templates/da/data-dictionary/versions/1.0.2/test.json +0 -3
  50. package/data/craftbook-templates/da/data-export-migrate/versions/1.0.2/test.json +0 -3
  51. package/data/craftbook-templates/da/data-join-merge/versions/1.0.2/test.json +0 -3
  52. package/data/craftbook-templates/da/data-pipeline-etl/versions/1.0.3/test.json +0 -3
  53. package/data/craftbook-templates/da/data-viz-page/versions/1.0.2/test.json +0 -3
  54. package/data/craftbook-templates/da/dataset-clean/versions/1.2.3/test.json +0 -3
  55. package/data/craftbook-templates/db/db-index-tuning/versions/1.0.2/test.json +0 -3
  56. package/data/craftbook-templates/de/deep-security-review/versions/1.1.2/test.json +28 -4
  57. package/data/craftbook-templates/de/dependency-upgrade/versions/1.0.0/test.json +12 -13
  58. package/data/craftbook-templates/de/deploy-checklist/versions/1.0.2/test.json +0 -3
  59. package/data/craftbook-templates/de/design-system-consultation/versions/2.0.4/test.json +1 -4
  60. package/data/craftbook-templates/di/diagram-from-text/versions/1.0.2/test.json +0 -3
  61. package/data/craftbook-templates/di/digest-from-feeds/versions/1.0.2/test.json +0 -3
  62. package/data/craftbook-templates/do/doc-intake-pipeline/versions/1.0.2/test.json +0 -3
  63. package/data/craftbook-templates/do/doc-rewrite/versions/1.0.2/test.json +0 -3
  64. package/data/craftbook-templates/do/dockerize-app/versions/1.0.2/test.json +0 -3
  65. package/data/craftbook-templates/do/docs-site/versions/1.0.2/test.json +0 -3
  66. package/data/craftbook-templates/dr/drive-wrap-up/versions/1.0.2/test.json +0 -3
  67. package/data/craftbook-templates/du/due-diligence-brief/versions/1.0.2/test.json +0 -3
  68. package/data/craftbook-templates/eb/ebook-compile/versions/1.0.2/test.json +0 -3
  69. package/data/craftbook-templates/ed/edit-notes/versions/1.0.2/test.json +0 -3
  70. package/data/craftbook-templates/em/email-sequence/versions/1.0.2/test.json +0 -3
  71. package/data/craftbook-templates/em/email-template/versions/1.0.2/test.json +0 -3
  72. package/data/craftbook-templates/en/engineering-retrospective/versions/2.0.4/test.json +1 -4
  73. package/data/craftbook-templates/es/escalation-playbook/versions/1.0.2/test.json +0 -3
  74. package/data/craftbook-templates/ev/evidence-brief/versions/1.0.2/test.json +0 -3
  75. package/data/craftbook-templates/ex/expense-categorize/versions/1.0.2/test.json +0 -3
  76. package/data/craftbook-templates/fa/fact-check/versions/1.0.2/test.json +0 -3
  77. package/data/craftbook-templates/fa/faq-from-docs/versions/1.0.2/test.json +0 -3
  78. package/data/craftbook-templates/fa/favicon-set/versions/1.0.2/test.json +0 -3
  79. package/data/craftbook-templates/fe/feature-flag-rollout/versions/1.1.0/test.json +0 -3
  80. package/data/craftbook-templates/fe/feedback-widget/versions/1.0.2/test.json +0 -3
  81. package/data/craftbook-templates/fl/flaky-test-fix/versions/1.0.0/test.json +15 -16
  82. package/data/craftbook-templates/fo/folder-to-audio/versions/1.0.2/test.json +0 -3
  83. package/data/craftbook-templates/fo/forecast-model/versions/1.0.2/test.json +0 -3
  84. package/data/craftbook-templates/fo/form-fill-batch/versions/1.0.2/test.json +0 -3
  85. package/data/craftbook-templates/fo/form-wizard/versions/1.0.2/test.json +0 -3
  86. package/data/craftbook-templates/ga/game-with-screens/versions/1.0.2/test.json +0 -3
  87. package/data/craftbook-templates/gl/glossary-build/versions/1.0.2/test.json +0 -3
  88. package/data/craftbook-templates/gr/graphql-api/versions/1.0.3/test.json +0 -3
  89. package/data/craftbook-templates/gr/grpc-service/versions/1.0.2/test.json +0 -3
  90. package/data/craftbook-templates/ha/handbook-section/versions/1.0.2/test.json +0 -3
  91. package/data/craftbook-templates/he/hero-image/versions/1.0.2/test.json +0 -3
  92. package/data/craftbook-templates/ho/holiday-card-run/versions/1.0.2/test.json +0 -3
  93. package/data/craftbook-templates/ho/hotfix-flow/versions/2.0.0/test.json +12 -13
  94. package/data/craftbook-templates/ht/html-puzzle-game/versions/1.0.2/test.json +0 -3
  95. package/data/craftbook-templates/ic/icon-pack/versions/1.0.2/test.json +0 -3
  96. package/data/craftbook-templates/id/idea-office-hours/versions/2.0.4/test.json +1 -4
  97. package/data/craftbook-templates/id/idle-clicker-game/versions/1.0.2/test.json +0 -3
  98. package/data/craftbook-templates/im/image-batch-edit/versions/1.0.2/test.json +0 -3
  99. package/data/craftbook-templates/im/image-dedup-cluster/versions/1.0.2/test.json +0 -3
  100. package/data/craftbook-templates/im/image-palette-extract/versions/1.0.2/test.json +0 -3
  101. package/data/craftbook-templates/im/image-seo-rename/versions/1.0.2/test.json +0 -3
  102. package/data/craftbook-templates/in/inbox-triage/versions/1.0.2/test.json +0 -3
  103. package/data/craftbook-templates/in/incident-comms-templates/versions/1.0.2/test.json +0 -3
  104. package/data/craftbook-templates/in/incident-postmortem/versions/1.0.2/test.json +0 -3
  105. package/data/craftbook-templates/in/insurance-inventory/versions/1.0.2/test.json +0 -3
  106. package/data/craftbook-templates/in/interactive-quiz/versions/1.0.2/test.json +0 -3
  107. package/data/craftbook-templates/in/invitation-design/versions/1.0.2/test.json +0 -3
  108. package/data/craftbook-templates/in/invoice-generator/versions/1.0.2/test.json +0 -3
  109. package/data/craftbook-templates/in/invoice-run/versions/1.1.2/test.json +0 -3
  110. package/data/craftbook-templates/index.json +1 -1
  111. package/data/craftbook-templates/it/item-intake/versions/1.0.2/test.json +0 -3
  112. package/data/craftbook-templates/ju/juice-pass/versions/1.0.2/test.json +0 -3
  113. package/data/craftbook-templates/kn/knowledge-base-article/versions/1.0.2/test.json +0 -3
  114. package/data/craftbook-templates/kp/kpi-scorecard/versions/1.0.2/test.json +0 -3
  115. package/data/craftbook-templates/la/landing-copy/versions/1.0.2/test.json +0 -3
  116. package/data/craftbook-templates/la/landing-page/versions/1.0.2/test.json +0 -3
  117. package/data/craftbook-templates/le/lead-enrichment/versions/1.0.2/test.json +0 -3
  118. package/data/craftbook-templates/li/library-package/versions/1.0.2/test.json +0 -3
  119. package/data/craftbook-templates/li/literature-review/versions/1.0.2/test.json +0 -3
  120. package/data/craftbook-templates/lo/localize-content/versions/1.0.2/test.json +0 -3
  121. package/data/craftbook-templates/lo/logo-set/versions/1.0.2/test.json +0 -3
  122. package/data/craftbook-templates/me/meeting-minutes/versions/1.0.2/test.json +0 -3
  123. package/data/craftbook-templates/me/meeting-notes-to-actions/versions/1.0.2/test.json +0 -3
  124. package/data/craftbook-templates/me/meeting-summary-audio/versions/1.0.2/test.json +0 -3
  125. package/data/craftbook-templates/me/memory-prompt-session/versions/1.0.2/test.json +0 -3
  126. package/data/craftbook-templates/me/message-queue-consumer/versions/1.0.2/test.json +0 -3
  127. package/data/craftbook-templates/mi/micro-game-jam/versions/1.0.2/test.json +0 -3
  128. package/data/craftbook-templates/mo/mock-interview/versions/1.0.2/test.json +0 -3
  129. package/data/craftbook-templates/mo/monitor-and-alert/versions/1.0.2/test.json +0 -3
  130. package/data/craftbook-templates/mo/month-close/versions/1.0.2/test.json +0 -3
  131. package/data/craftbook-templates/mo/moodboard/versions/1.0.2/test.json +0 -3
  132. package/data/craftbook-templates/mo/morning-brief/versions/1.0.2/test.json +0 -3
  133. package/data/craftbook-templates/mo/morning-report/versions/1.0.2/test.json +0 -3
  134. package/data/craftbook-templates/mu/music-metadata-tag/versions/1.0.2/test.json +0 -3
  135. package/data/craftbook-templates/na/narrated-slideshow/versions/1.1.2/test.json +0 -3
  136. package/data/craftbook-templates/ne/newsletter-issue/versions/1.0.2/test.json +0 -3
  137. package/data/craftbook-templates/ni/nightly-fix-sweep/versions/1.0.0/test.json +3 -4
  138. package/data/craftbook-templates/no/notification-router/versions/1.0.2/test.json +0 -3
  139. package/data/craftbook-templates/oc/ocr-extract/versions/1.0.2/test.json +0 -3
  140. package/data/craftbook-templates/of/offer-compare/versions/1.0.2/test.json +0 -3
  141. package/data/craftbook-templates/on/onboarding-checklist/versions/1.0.2/test.json +0 -3
  142. package/data/craftbook-templates/on/onboarding-flow/versions/1.0.2/test.json +0 -3
  143. package/data/craftbook-templates/on/oncall-handoff/versions/1.0.2/test.json +0 -3
  144. package/data/craftbook-templates/on/one-pager/versions/1.0.2/test.json +0 -3
  145. package/data/craftbook-templates/op/ops-runbook/versions/1.0.2/test.json +0 -3
  146. package/data/craftbook-templates/pa/page-spread/versions/1.0.2/test.json +0 -3
  147. package/data/craftbook-templates/pa/parser-grammar/versions/1.0.2/test.json +0 -3
  148. package/data/craftbook-templates/pe/perf-audit/versions/1.1.0/test.json +0 -3
  149. package/data/craftbook-templates/pe/perf-optimization/versions/2.0.0/test.json +16 -17
  150. package/data/craftbook-templates/pe/pest-diagnosis/versions/1.0.2/test.json +0 -3
  151. package/data/craftbook-templates/ph/photo-cull/versions/1.0.2/test.json +0 -3
  152. package/data/craftbook-templates/ph/physics-toy/versions/1.0.2/test.json +0 -3
  153. package/data/craftbook-templates/pi/pitch-deck/versions/1.0.2/test.json +0 -3
  154. package/data/craftbook-templates/pl/playtest-report/versions/1.0.2/test.json +0 -3
  155. package/data/craftbook-templates/po/podcast-chaptering/versions/1.0.2/test.json +0 -3
  156. package/data/craftbook-templates/po/portfolio-site/versions/1.0.2/test.json +0 -3
  157. package/data/craftbook-templates/po/powerpoint-deck/versions/1.7.8/craftbook.json +404 -0
  158. package/data/craftbook-templates/po/powerpoint-deck/versions/1.7.8/test.json +240 -0
  159. package/data/craftbook-templates/pr/pr-security-review/versions/1.0.2/test.json +0 -3
  160. package/data/craftbook-templates/pr/practice-exam/versions/1.0.2/test.json +0 -3
  161. package/data/craftbook-templates/pr/practice-session/versions/1.0.2/test.json +0 -3
  162. package/data/craftbook-templates/pr/pre-departure-countdown/versions/1.0.2/test.json +0 -3
  163. package/data/craftbook-templates/pr/press-release/versions/1.0.2/test.json +0 -3
  164. package/data/craftbook-templates/pr/price-tracker/versions/1.0.2/test.json +0 -3
  165. package/data/craftbook-templates/pr/pricing-page/versions/1.0.2/test.json +0 -3
  166. package/data/craftbook-templates/pr/product-descriptions/versions/1.0.2/test.json +0 -3
  167. package/data/craftbook-templates/pr/proposal-sow/versions/1.0.2/test.json +0 -3
  168. package/data/craftbook-templates/pu/pull-request-review/versions/1.9.0/test.json +0 -3
  169. package/data/craftbook-templates/pu/puzzle-pack-layout/versions/1.0.2/test.json +0 -3
  170. package/data/craftbook-templates/pw/pwa-offline/versions/1.0.2/test.json +0 -3
  171. package/data/craftbook-templates/re/reading-list/versions/1.0.2/test.json +0 -3
  172. package/data/craftbook-templates/re/receipt-intake/versions/1.0.2/test.json +0 -3
  173. package/data/craftbook-templates/re/receipt-ocr-ledger/versions/1.0.2/test.json +0 -3
  174. package/data/craftbook-templates/re/reception-report/versions/1.0.1/test.json +8 -9
  175. package/data/craftbook-templates/re/recipe-capture/versions/1.0.2/test.json +0 -3
  176. package/data/craftbook-templates/re/record-a-relative/versions/1.0.2/test.json +0 -3
  177. package/data/craftbook-templates/re/recurring-invoice-run/versions/1.0.2/test.json +0 -3
  178. package/data/craftbook-templates/re/refactor-module/versions/2.0.0/test.json +15 -16
  179. package/data/craftbook-templates/re/regex-builder/versions/1.0.2/test.json +0 -3
  180. package/data/craftbook-templates/re/release-announcement/versions/1.0.2/test.json +0 -3
  181. package/data/craftbook-templates/re/release-artifact-sanity-check/versions/1.0.2/test.json +0 -3
  182. package/data/craftbook-templates/re/release-notes/versions/1.0.3/test.json +0 -3
  183. package/data/craftbook-templates/re/release-readiness-review/versions/1.1.0/test.json +0 -3
  184. package/data/craftbook-templates/re/report-pdf/versions/1.1.2/test.json +0 -3
  185. package/data/craftbook-templates/re/rest-api/versions/1.0.3/test.json +0 -3
  186. package/data/craftbook-templates/re/resume-cv/versions/1.0.2/test.json +0 -3
  187. package/data/craftbook-templates/ro/rollback-plan/versions/1.0.2/test.json +0 -3
  188. package/data/craftbook-templates/ro/rough-cut-assembly/versions/1.0.3/test.json +0 -3
  189. package/data/craftbook-templates/ru/runbook/versions/1.0.2/test.json +0 -3
  190. package/data/craftbook-templates/sc/schema-migration/versions/2.0.0/test.json +12 -13
  191. package/data/craftbook-templates/sc/scrape-to-structured/versions/1.0.3/test.json +0 -3
  192. package/data/craftbook-templates/sc/script-automation/versions/1.0.2/test.json +0 -3
  193. package/data/craftbook-templates/sd/sdk-wrapper/versions/1.0.3/test.json +0 -3
  194. package/data/craftbook-templates/se/seasonal-maintenance-sweep/versions/1.0.2/test.json +0 -3
  195. package/data/craftbook-templates/se/seo-meta-pack/versions/1.0.2/test.json +0 -3
  196. package/data/craftbook-templates/so/social-digest/versions/1.0.1/test.json +7 -8
  197. package/data/craftbook-templates/so/social-thread/versions/1.0.2/test.json +0 -3
  198. package/data/craftbook-templates/so/source-quality-audit/versions/1.0.2/test.json +0 -3
  199. package/data/craftbook-templates/sp/spa-dashboard/versions/1.0.2/test.json +0 -3
  200. package/data/craftbook-templates/sp/spec-authoring/versions/2.0.4/test.json +1 -4
  201. package/data/craftbook-templates/sp/spec-doc/versions/1.0.2/test.json +0 -3
  202. package/data/craftbook-templates/sp/spreadsheet-model/versions/1.0.2/test.json +0 -3
  203. package/data/craftbook-templates/sp/sprite-sheet/versions/1.0.2/test.json +0 -3
  204. package/data/craftbook-templates/sq/sql-analysis/versions/1.0.2/test.json +0 -3
  205. package/data/craftbook-templates/st/standup-summary/versions/1.0.2/test.json +0 -3
  206. package/data/craftbook-templates/st/state-machine/versions/1.0.2/test.json +0 -3
  207. package/data/craftbook-templates/st/status-report/versions/1.0.2/test.json +0 -3
  208. package/data/craftbook-templates/su/subscription-audit/versions/1.0.2/test.json +0 -3
  209. package/data/craftbook-templates/su/subtitle-generator/versions/1.0.2/test.json +0 -3
  210. package/data/craftbook-templates/su/summarize-long/versions/1.0.2/test.json +0 -3
  211. package/data/craftbook-templates/su/survey-analysis/versions/1.0.2/test.json +0 -3
  212. package/data/craftbook-templates/sv/svg-animation/versions/1.0.2/test.json +0 -3
  213. package/data/craftbook-templates/ta/tailor-resume/versions/1.0.2/test.json +0 -3
  214. package/data/craftbook-templates/te/technical-documentation/versions/2.0.4/test.json +1 -4
  215. package/data/craftbook-templates/te/test-suite-backfill/versions/2.0.0/test.json +13 -16
  216. package/data/craftbook-templates/th/thank-you-sweep/versions/1.0.2/test.json +0 -3
  217. package/data/craftbook-templates/th/threat-model/versions/1.0.2/test.json +0 -3
  218. package/data/craftbook-templates/th/thumbnail-generator/versions/1.0.2/test.json +0 -3
  219. package/data/craftbook-templates/ti/tileset-batch/versions/1.0.2/test.json +0 -3
  220. package/data/craftbook-templates/to/tone-rewrite/versions/1.0.2/test.json +0 -3
  221. package/data/craftbook-templates/to/topic-explainer/versions/1.0.2/test.json +0 -3
  222. package/data/craftbook-templates/tr/transcribe-audio/versions/1.0.2/test.json +0 -3
  223. package/data/craftbook-templates/tr/translate-content/versions/1.1.1/craftbook.json +90 -0
  224. package/data/craftbook-templates/tr/translate-content/versions/1.1.1/test.json +141 -0
  225. package/data/craftbook-templates/ty/type-safety-pass/versions/2.0.0/test.json +13 -14
  226. package/data/craftbook-templates/ux/ux-update/versions/1.0.0/test.json +12 -13
  227. package/data/craftbook-templates/ve/version-bump/versions/1.1.0/test.json +0 -3
  228. package/data/craftbook-templates/vi/video-storyboard/versions/1.0.2/test.json +0 -3
  229. package/data/craftbook-templates/vi/visit-prep/versions/1.0.2/test.json +0 -3
  230. package/data/craftbook-templates/vo/voiceover-script/versions/1.0.2/test.json +0 -3
  231. package/data/craftbook-templates/we/weak-spot-drill/versions/1.0.2/test.json +0 -3
  232. package/data/craftbook-templates/we/web-app-crud/versions/1.0.2/test.json +0 -3
  233. package/data/craftbook-templates/we/web-component/versions/1.0.2/test.json +0 -3
  234. package/data/craftbook-templates/we/webhook-handler/versions/1.0.2/test.json +0 -3
  235. package/data/craftbook-templates/we/weekly-menu-plan/versions/1.0.2/test.json +0 -3
  236. package/data/craftbook-templates/we/weekly-pipeline-review/versions/1.0.2/test.json +0 -3
  237. package/data/craftbook-templates/we/weekly-review/versions/1.0.2/test.json +0 -3
  238. package/data/craftbook-templates/we/weekly-walkthrough/versions/1.0.2/test.json +0 -3
  239. package/data/craftbook-templates/ye/year-in-review/versions/1.0.2/test.json +0 -3
  240. package/data/craftbook-templates/yo/youtube-chapters-seo/versions/1.0.2/test.json +0 -3
  241. package/package.json +1 -1
  242. package/schemas/craftbook-doc.schema.json +12 -0
  243. package/schemas/craftbook-template-version.schema.json +12 -0
  244. package/schemas/craftbook-test.schema.json +12 -0
@@ -42,31 +42,28 @@
42
42
  "content": "import assert from 'node:assert/strict';\nimport { readFileSync } from 'node:fs';\n\nconst html = readFileSync('index.html', 'utf8');\n\nfunction imgTag(src) {\n const tags = [...html.matchAll(/<img\\b[^>]*>/gi)].map((m) => m[0]);\n const tag = tags.find((t) => t.includes(src));\n assert.ok(tag, `an img referencing ${src} still exists`);\n return tag;\n}\nfunction altOf(tag, src) {\n const alt = tag.match(/\\balt\\s*=\\s*(\"([^\"]*)\"|'([^']*)')/i);\n assert.ok(alt, `image ${src} carries an alt attribute`);\n return alt[2] ?? alt[3] ?? '';\n}\n\n// 1) Meaningful images: specific, non-empty alt text.\nfor (const src of ['harvest-crew', 'seed-chart']) {\n const alt = altOf(imgTag(src), src).trim();\n assert.ok(alt.length >= 10, `alt for ${src} must be specific, got \"${alt}\"`);\n assert.ok(!/^(image|photo|picture|graphic|img)$/i.test(alt), `alt for ${src} must not be filler`);\n assert.ok(!/^(an? )?(image|photo|picture) of/i.test(alt), `alt for ${src} must not open with \"image of\"`);\n}\nconsole.log('A11YRETRO_ORACLE alts ok');\n\n// 2) The decorative divider keeps an EMPTY alt - no sprayed description.\nassert.equal(altOf(imgTag('divider'), 'divider').trim(), '', 'decorative divider keeps alt=\"\"');\nconsole.log('A11YRETRO_ORACLE decorative ok');\n\n// 3) The email input is labeled by a real label whose for resolves to its id.\nconst labels = [...html.matchAll(/<label\\b[^>]*\\bfor\\s*=\\s*[\"']([^\"']+)[\"'][^>]*>/gi)];\nassert.ok(labels.length >= 1, 'a label element with a for attribute exists');\nconst paired = labels.filter((m) => new RegExp(`<input\\\\b[^>]*\\\\bid\\\\s*=\\\\s*[\"']${m[1]}[\"']`, 'i').test(html));\nassert.ok(paired.length >= 1, \"a label's for attribute resolves to a real input id\");\nconsole.log('A11YRETRO_ORACLE label ok');\n\n// 4) The join control is a real button, or carries complete ARIA button semantics.\nconst join = html.match(/<([a-z0-9]+)\\b([^>]*)>\\s*Join the list/i);\nassert.ok(join, 'the \"Join the list\" control still exists');\nconst [, joinTag, joinAttrs] = join;\nif (joinTag.toLowerCase() !== 'button') {\n assert.ok(/\\brole\\s*=\\s*[\"']button[\"']/i.test(joinAttrs), 'non-button control carries role=\"button\"');\n assert.ok(/\\btabindex\\s*=\\s*[\"']0[\"']/i.test(joinAttrs), 'non-button control is focusable via tabindex=\"0\"');\n const keyWired = /\\bonkey(?:down|up|press)\\s*=/i.test(joinAttrs) || /addEventListener\\s*\\(\\s*[\"']key(?:down|up|press)[\"']/i.test(html);\n assert.ok(keyWired, 'non-button control has keyboard activation wired');\n}\nconsole.log('A11YRETRO_ORACLE control ok');\n\n// 5) Heading order is monotonic from a single h1.\nconst levels = [...html.matchAll(/<h([1-6])\\b[^>]*>/gi)].map((m) => Number(m[1]));\nassert.ok(levels.length >= 3, 'the page keeps its headings');\nassert.equal(levels[0], 1, 'the page starts at h1');\nfor (let i = 1; i < levels.length; i++) {\n assert.ok(levels[i] <= levels[i - 1] + 1, `heading level jumps from h${levels[i - 1]} to h${levels[i]}`);\n}\nconsole.log('A11YRETRO_ORACLE headings ok');\n\n// 6) The join behavior target survives the retrofit.\nassert.ok(/joined-note/.test(html), 'the joined-note behavior target survives');\nconsole.log('A11YRETRO_ORACLE done');\n",
43
43
  "surface": "harness"
44
44
  }
45
- ],
46
- "craftbookParams": {
47
- "workPath": "tasks/eval"
48
- }
45
+ ]
49
46
  },
50
47
  "mocks": [],
51
48
  "success": {
52
49
  "summary": "All five seeded violations are repaired at their real sites in index.html — specific alts on the meaningful images, an empty alt preserved on the decorative divider, a paired label, a keyboard-operable join control, monotonic headings — and every fleet artifact exists with honest citations.",
53
50
  "deliverables": [
54
51
  {
55
- "path": "tasks/eval/audit.md",
52
+ "path": "{{task.dir}}/audit.md",
56
53
  "kind": "markdown-notes",
57
54
  "artifact": true,
58
55
  "minBytes": 600,
59
56
  "checks": [
60
57
  {
61
58
  "kind": "contains",
62
- "file": "tasks/eval/audit.md",
59
+ "file": "{{task.dir}}/audit.md",
63
60
  "pattern": "^##\\s+Scope[\\s\\S]*^##\\s+Violations[\\s\\S]*^##\\s+Priorities",
64
61
  "flags": "im",
65
62
  "label": "audit sections in order"
66
63
  },
67
64
  {
68
65
  "kind": "tableShape",
69
- "file": "tasks/eval/audit.md",
66
+ "file": "{{task.dir}}/audit.md",
70
67
  "requiredColumns": [
71
68
  "File",
72
69
  "Issue",
@@ -77,48 +74,48 @@
77
74
  },
78
75
  {
79
76
  "kind": "citationsResolve",
80
- "file": "tasks/eval/audit.md",
77
+ "file": "{{task.dir}}/audit.md",
81
78
  "minCitations": 2,
82
79
  "artifact": true
83
80
  },
84
81
  {
85
82
  "kind": "contains",
86
- "file": "tasks/eval/audit.md",
83
+ "file": "{{task.dir}}/audit.md",
87
84
  "pattern": "index\\.html",
88
85
  "label": "the audit names the real page"
89
86
  }
90
87
  ]
91
88
  },
92
89
  {
93
- "path": "tasks/eval/fix-notes.md",
90
+ "path": "{{task.dir}}/fix-notes.md",
94
91
  "kind": "markdown-notes",
95
92
  "artifact": true,
96
93
  "minBytes": 700,
97
94
  "checks": [
98
95
  {
99
96
  "kind": "contains",
100
- "file": "tasks/eval/fix-notes.md",
97
+ "file": "{{task.dir}}/fix-notes.md",
101
98
  "pattern": "^##\\s+Problem[\\s\\S]*^##\\s+Change[\\s\\S]*^##\\s+Files touched[\\s\\S]*^##\\s+Per-violation disposition[\\s\\S]*^##\\s+Risk[\\s\\S]*^##\\s+How to verify",
102
99
  "flags": "im",
103
100
  "label": "fix-notes sections in order"
104
101
  },
105
102
  {
106
103
  "kind": "citationsResolve",
107
- "file": "tasks/eval/fix-notes.md",
104
+ "file": "{{task.dir}}/fix-notes.md",
108
105
  "minCitations": 2,
109
106
  "artifact": true
110
107
  }
111
108
  ]
112
109
  },
113
110
  {
114
- "path": "tasks/eval/validation.md",
111
+ "path": "{{task.dir}}/validation.md",
115
112
  "kind": "markdown-notes",
116
113
  "artifact": true,
117
114
  "minBytes": 500,
118
115
  "checks": [
119
116
  {
120
117
  "kind": "contains",
121
- "file": "tasks/eval/validation.md",
118
+ "file": "{{task.dir}}/validation.md",
122
119
  "pattern": "^##\\s+Per-item verification[\\s\\S]*^##\\s+Keyboard walk[\\s\\S]*^##\\s+Result",
123
120
  "flags": "im",
124
121
  "label": "validation sections in order"
@@ -126,14 +123,14 @@
126
123
  ]
127
124
  },
128
125
  {
129
- "path": "tasks/eval/review.md",
126
+ "path": "{{task.dir}}/review.md",
130
127
  "kind": "markdown-report",
131
128
  "artifact": true,
132
129
  "minBytes": 400,
133
130
  "checks": [
134
131
  {
135
132
  "kind": "contains",
136
- "file": "tasks/eval/review.md",
133
+ "file": "{{task.dir}}/review.md",
137
134
  "pattern": "Verdict:\\s*(?:PASS|REVISE)",
138
135
  "flags": "i",
139
136
  "label": "explicit reviewer verdict"
@@ -205,7 +202,7 @@
205
202
  },
206
203
  "rubric": {
207
204
  "artifact": {
208
- "path": "tasks/eval/fix-notes.md",
205
+ "path": "{{task.dir}}/fix-notes.md",
209
206
  "kind": "markdown"
210
207
  },
211
208
  "axes": [
@@ -14,9 +14,6 @@
14
14
  "worker": {
15
15
  "name": "Janne",
16
16
  "role": "Copywriter"
17
- },
18
- "craftbookParams": {
19
- "workPath": "tasks/eval"
20
17
  }
21
18
  },
22
19
  "mocks": [],
@@ -51,9 +51,6 @@
51
51
  "worker": {
52
52
  "name": "Loes",
53
53
  "role": "Curator"
54
- },
55
- "craftbookParams": {
56
- "workPath": "tasks/eval"
57
54
  }
58
55
  },
59
56
  "mocks": [],
@@ -19,9 +19,6 @@
19
19
  "worker": {
20
20
  "name": "Aafke",
21
21
  "role": "SRE"
22
- },
23
- "craftbookParams": {
24
- "workPath": "tasks/eval"
25
22
  }
26
23
  },
27
24
  "mocks": [],
@@ -23,9 +23,6 @@
23
23
  "worker": {
24
24
  "name": "Noor",
25
25
  "role": "Curator"
26
- },
27
- "craftbookParams": {
28
- "workPath": "tasks/eval"
29
26
  }
30
27
  },
31
28
  "mocks": [
@@ -19,9 +19,6 @@
19
19
  "worker": {
20
20
  "name": "Bente",
21
21
  "role": "Researcher"
22
- },
23
- "craftbookParams": {
24
- "workPath": "tasks/eval"
25
22
  }
26
23
  },
27
24
  "mocks": [],
@@ -1,23 +1,37 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "title": "API Contract Review codebase eval",
4
- "objective": "Measure whether the review reconciles an OpenAPI contract with its handler and catches consistency, semantics, auth, and pagination defects.",
4
+ "objective": "Measure whether the review reconciles an OpenAPI contract with the implemented route inventory and catches consistency, semantics, auth, pagination, and drift defects without inventing drift.",
5
5
  "tags": [
6
6
  "corpus"
7
7
  ],
8
- "prompt": "Use the API Contract Review craftbook for a codebase-wide API design pass. Compare openapi.yaml with src/routes.ts and write tasks/eval/api-review.md with corrected snippets. Do not edit the contract or handler.",
8
+ "prompt": "Use the API Contract Review craftbook for a codebase-wide API design pass. Reconcile openapi.yaml against the implemented routes and write tasks/eval/api-review.md with corrected snippets, plus a machine-readable list of the contract/implementation drifts you found at tasks/eval/drift.json (one record per drift, each with its path, method, issue, and fix). Do not edit the contract or the handlers.",
9
9
  "setup": {
10
10
  "projectName": "API Design Maintenance Eval",
11
- "about": "A small REST API whose contract and implementation contain deliberate design and drift defects.",
12
- "missionObjectives": "Produce an evidence-backed API design report covering every seeded operation and its implementation.",
11
+ "about": "A small REST API whose OpenAPI contract and route files contain deliberate design defects and contract/implementation drift.",
12
+ "missionObjectives": "Produce an evidence-backed API design report covering every documented operation and every implemented route, plus a structured drift list.",
13
13
  "files": [
14
14
  {
15
15
  "path": "openapi.yaml",
16
- "content": "openapi: 3.0.3\ninfo: { title: Widget API, version: 1.0.0 }\npaths:\n /getWidgets:\n get:\n responses:\n '200':\n description: widgets\n content:\n application/json:\n schema: { type: array, items: { $ref: '#/components/schemas/Widget' } }\n /widgets:\n post:\n requestBody:\n required: true\n content:\n application/json:\n schema: { $ref: '#/components/schemas/Widget' }\n responses:\n '200': { description: created }\ncomponents:\n schemas:\n Widget:\n type: object\n properties:\n id: { type: string }\n display_name: { type: string }\n"
16
+ "content": "openapi: 3.0.3\ninfo: { title: Widget API, version: 1.0.0 }\npaths:\n /getWidgets:\n get:\n summary: List widgets\n responses:\n '200':\n description: widgets\n content:\n application/json:\n schema: { type: array, items: { $ref: '#/components/schemas/Widget' } }\n /widgets:\n post:\n requestBody:\n required: true\n content:\n application/json:\n schema: { $ref: '#/components/schemas/Widget' }\n responses:\n '200': { description: created }\n /widgets/{widgetId}/history:\n get:\n summary: Revision history for one widget\n parameters:\n - { name: widgetId, in: path, required: true, schema: { type: string } }\n responses:\n '200':\n description: revisions\n content:\n application/json:\n schema: { type: array, items: { $ref: '#/components/schemas/Revision' } }\n /widgets/{widgetId}/status:\n get:\n summary: Processing status for one widget\n parameters:\n - { name: widgetId, in: path, required: true, schema: { type: string } }\n responses:\n '200':\n description: status\n content:\n application/json:\n schema:\n type: object\n required: [state, retryCount]\n properties:\n state: { type: string, enum: [queued, running, done] }\n retryCount: { type: string }\n /widgets/{widgetId}/owner:\n get:\n summary: Owner of one widget\n parameters:\n - { name: widgetId, in: path, required: true, schema: { type: string } }\n responses:\n '200':\n description: owner\n content:\n application/json:\n schema:\n type: object\n required: [id]\n properties:\n id: { type: string }\n email: { type: string, nullable: true }\n /users/{userId}:\n get:\n summary: One user\n parameters:\n - { name: userId, in: path, required: true, schema: { type: string } }\n responses:\n '200':\n description: user\n content:\n application/json:\n schema: { $ref: '#/components/schemas/User' }\n /users/{userId}/sessions:\n get:\n summary: Sessions for one user\n parameters:\n - { name: userId, in: path, required: true, schema: { type: string } }\n responses:\n '200':\n description: sessions\n content:\n application/json:\n schema: { type: array, items: { $ref: '#/components/schemas/Session' } }\ncomponents:\n schemas:\n Widget:\n type: object\n properties:\n id: { type: string }\n display_name: { type: string }\n Revision:\n type: object\n properties:\n id: { type: string }\n changedAt: { type: string, format: date-time }\n User:\n type: object\n properties:\n id: { type: string }\n email: { type: string }\n Session:\n type: object\n properties:\n id: { type: string }\n startedAt: { type: string, format: date-time }\n"
17
17
  },
18
18
  {
19
19
  "path": "src/routes.ts",
20
- "content": "app.get('/widgets', async (_req, res) => res.json(await db.widgets.all()));\napp.post('/widgets', async (req, res) => {\n const widget = await db.widgets.create(req.body);\n res.status(200).json(widget);\n});\napp.get('/widgets/:id', async (req, res) => {\n const item = await db.widgets.get(req.params.id);\n if (!item) return res.status(404).json({ message: 'missing' });\n res.json(item);\n});\n"
20
+ "content": "import { registerSessionRoutes } from './session-routes';\n\nexport function registerRoutes(app, db) {\n app.get('/getWidgets', async (_req, res) => {\n res.json(await db.widgets.all());\n });\n\n app.post('/widgets', async (req, res) => {\n const widget = await db.widgets.create(req.body);\n res.status(200).json(widget);\n });\n\n app.get('/widgets/:id', async (req, res) => {\n const item = await db.widgets.get(req.params.id);\n if (!item) return res.status(404).json({ message: 'missing' });\n res.json(item);\n });\n\n app.get('/widgets/:widgetId/status', async (req, res) => {\n const row = await db.widgets.status(req.params.widgetId);\n res.json({ state: row.state, retryCount: row.attempts.length });\n });\n\n app.get('/widgets/:widgetId/owner', async (req, res) => {\n const owner = await db.widgets.owner(req.params.widgetId);\n const body = { id: owner.id };\n if (owner.email !== null && owner.email !== undefined) body.email = owner.email;\n res.json(body);\n });\n\n app.get('/users/:userId', async (req, res) => {\n res.json(await db.users.get(req.params.userId));\n });\n\n registerSessionRoutes(app, db);\n}\n"
21
+ },
22
+ {
23
+ "path": "src/session-routes.ts",
24
+ "content": "export function registerSessionRoutes(app, db) {\n app.get('/users/:userId/sessions', async (req, res) => {\n res.json(await db.sessions.forUser(req.params.userId));\n });\n}\n"
25
+ },
26
+ {
27
+ "path": "docs/api-contract.md",
28
+ "content": "# Contract conventions\n\n`openapi.yaml` is the contract. The route inventory is `src/routes.ts` **and**\n`src/session-routes.ts` together: `registerRoutes` imports and calls\n`registerSessionRoutes`, so an operation is implemented when a handler for it exists in\neither file.\n\n## Path parameters\n\nPath templating differs by convention and is never drift on its own. The contract writes a\npath parameter as `{name}`; the router writes the same parameter as `:name`. `GET\n/users/{userId}` and `app.get('/users/:userId', ...)` are the same operation.\n\n## Response bodies\n\nA response property listed under `required` must always be present with its declared type.\nA property that is NOT listed under `required` and is marked `nullable: true` may be\nomitted or sent as null: a handler that leaves it out when it has no value is correct as\nwritten, not a contract violation.\n"
29
+ },
30
+ {
31
+ "path": "tests/api-contract-oracle.mjs",
32
+ "content": "// Precision/recall oracle for the API contract review.\n//\n// Run by the harness with the reviewed workspace as cwd. It grades the two\n// halves of a real reconciliation separately, because recall alone is passed\n// by a report that flags every operation it could not instantly match:\n//\n// RECALL - each of the three REAL drifts between openapi.yaml and the\n// route inventory is reported, matched by path AND class.\n// PRECISION - none of the three SAFE operations is CLAIMED to drift. Each\n// is a deliberate look-alike of a real drift, and each is\n// documented as correct in docs/api-contract.md.\n//\n// Classes are matched by their ordinary names - documented but not\n// implemented, implemented but not documented, response schema mismatch - and\n// never by wording this fixture invented, so the bar is \"a real contract\n// reconciliation\" rather than this scenario's vocabulary.\n//\n// Three rules keep the precision half off correct work, because a gate that\n// punishes a good review is worse than no gate at all:\n//\n// 1. A record is judged by what it is ABOUT - its path/endpoint field - not\n// by every string it contains. Citing a neighbouring operation as the\n// model for a fix (\"add a path item like /widgets/{widgetId}/owner\") is\n// normal review prose, not a claim against that neighbour.\n// 2. Precision fires only on a reconciliation CLAIM: missing handler,\n// undocumented operation, schema or parameter disagreement. Saying a\n// safe operation has no pagination, no security scheme or no documented\n// 404 is TRUE of this fixture and is fair review - those design smells\n// are graded by the api-review.md checks, never punished here. HARD\n// claims name the operation itself and always count; SOFT claims leave\n// the subject implicit (\"missing from the spec\") and are read as design\n// remarks when they sit in a clause about a design feature.\n// 3. A \"this one is fine\" verdict is a non-claim only when it asserts no\n// drift class. That keeps ordinary remediation wording - \"change the\n// type so the schema matches the handler\" - from erasing a real finding,\n// and stops a false positive from being excused by appending \"no drift\".\n//\n// The recall classes are built from the same families as the precision\n// claims, so a record that satisfies recall can never be discarded as a\n// verdict, and the two halves cannot drift apart as the vocabulary grows.\nimport { readFileSync } from 'node:fs';\n\n/**\n * Fail with the message ALONE on stderr.\n *\n * A thrown Error would work, but the harness feeds this script's stderr\n * into the model's repair nudge verbatim, and an uncaught throw pads that\n * nudge with a Node stack trace and a version banner. The actionable\n * sentence is what the next attempt needs; the stack is noise that pushes\n * it out of view on a small model.\n */\nfunction fail(message) {\n console.error(message);\n process.exit(1);\n}\n\n\nconst DRIFT = 'tasks/eval/drift.json';\n\nlet raw;\ntry {\n raw = readFileSync(DRIFT, 'utf8');\n} catch {\n fail(DRIFT + ' does not exist - the machine-readable drift list is required');\n}\n\nlet records;\ntry {\n records = JSON.parse(raw.replace(/^\\uFEFF/, ''));\n} catch (err) {\n fail(DRIFT + ' is not valid JSON: ' + err.message);\n}\nif (!Array.isArray(records)) {\n const arrays =\n records && typeof records === 'object' ? Object.values(records).filter(Array.isArray) : [];\n if (arrays.length === 0) fail(DRIFT + ' must be an array of drift records');\n records = arrays.flat();\n}\n\nfunction strings(value, out) {\n if (typeof value === 'string') out.push(value);\n else if (Array.isArray(value)) for (const entry of value) strings(entry, out);\n else if (value && typeof value === 'object')\n for (const entry of Object.values(value)) strings(entry, out);\n return out;\n}\n\nconst union = (...parts) => new RegExp(parts.map((part) => part.source).join('|'));\n\n// `{widgetId}` and `:widgetId` are the same parameter; the contract and the\n// router spell it differently and a review may quote either form.\nconst normalize = (text) =>\n text\n .toLowerCase()\n .replace(/\\{\\s*([a-z0-9_]+)\\s*\\}/g, ':$1')\n // Mark sentence ends with `;` so the clause-scoped spans below cannot\n // borrow words from the next sentence - but leave the dot inside\n // `src/routes.ts` and `row.attempts.length` alone, or every clause would\n // stop at the first filename a review cites as evidence.\n .replace(/\\.(?=\\s|$)/g, ' ; ');\n\nconst textOf = (record) => normalize(strings(record, []).join(' | '));\n\n// What a record is ABOUT. The drift list is one record per operation and the\n// record schema requires a `path`, so the identifying fields are the honest\n// subject; `issue` and `fix` prose routinely names other operations.\nconst SUBJECT_KEY = /^(api)?(path|endpoint|operation|operationid|route|url|uri|resource)s?$/;\nfunction subjectOf(record) {\n const parts = [];\n for (const [key, value] of Object.entries(record)) {\n if (SUBJECT_KEY.test(key.toLowerCase().replace(/[^a-z]/g, ''))) strings(value, parts);\n }\n return parts.length > 0 ? normalize(parts.join(' | ')) : null;\n}\n\n// ---------------------------------------------------------------------------\n// The ordinary vocabulary for \"the contract and the code disagree\". Prose is\n// joined with ` | ` and clause spans never cross `;` or `|`, so one sentence\n// cannot borrow words from the next.\n// ---------------------------------------------------------------------------\n\n// HARD: the operation itself is named as the thing that is wrong.\nconst NO_HANDLER = union(\n /no (matching |registered |corresponding )?(route|handler|endpoint)\\b/,\n /missing (route|handler|endpoint)\\b/,\n /(handler|route|endpoint)[^;|]{0,40}(is |are )?(missing|absent|not found|not registered|does not exist|doesn'?t exist)/,\n /(missing|absent) from (the )?(route|router|code|src|handler)/,\n /not (present|found|registered|defined) in (the )?(route|router|code|src)/,\n /not (registered|implemented|defined|handled) (by|in) (either|any|both)/,\n /neither[^;|]{0,80}(register|implement|defin|handl)/,\n /(none of|not one of)[^;|]{0,60}(route|file|handler)[^;|]{0,40}(register|implement|defin|handl)/,\n /does not appear in (either|any|both|the) ?(of the )?(route|router|code|file)/,\n /(nothing|no code|no file|nowhere)[^;|]{0,30}implement/,\n /(code|implementation|router?|server|service|app)[^;|]{0,30}(does not|doesn'?t) implement/,\n /(could not|couldn'?t|cannot|can'?t|unable to) (find|locate|see)[^;|]{0,40}(handler|route|endpoint|implementation)/,\n /lacks (a |an )?(handler|route|implementation)\\b/,\n /ghost (route|endpoint|operation|path)/,\n /orphan(ed)? (spec|contract|path|operation|entry)/,\n /spec[- ]only/,\n /dead (spec|contract) entry/,\n);\n\nconst NO_PATH_ITEM = union(\n /undocumented (operation|endpoint|route|path|handler)/,\n /(operation|endpoint|route|path|handler)[^;|]{0,40}(is |are )?(not documented|undocumented)/,\n /no path item/,\n /no (matching |corresponding )?(spec|contract|openapi(\\.yaml)?) (entry|path item)/,\n /shadow (route|endpoint)/,\n /(spec|contract|openapi(\\.yaml)?)[^;|]{0,50}(does not|doesn'?t|fails to) (document|include|list|cover|mention)[^;|]{0,15}\\b(it|this|that|the (operation|endpoint|route|path))\\b/,\n /(spec|contract|openapi(\\.yaml)?)[^;|]{0,40}(omits|lacks|has no|says nothing about)[^;|]{0,15}\\b(it|this|that|entry|path item|the (operation|endpoint|route|path))\\b/,\n);\n\nconst SCHEMA_DISAGREEMENT = union(\n /schema mismatch|response mismatch|type mismatch/,\n /type (conflict|disagreement|drift)/,\n /wrong type|incorrect type/,\n /(does not|doesn'?t) match the (schema|contract|spec|declared)/,\n /(violates|contradicts) the (schema|contract|spec)/,\n /(declar\\w+|documented)[^;|]{0,40}\\b(string|number|integer|boolean|array|object)\\b[^;|]{0,80}(returns|sends|responds|actually|but)/,\n /required (field|property|member)[^;|]{0,40}(missing|omitted|absent|not returned)/,\n /(omits|drops|does not return|doesn'?t return|never returns)[^;|]{0,40}(email|required)/,\n);\n\nconst PARAM_DISAGREEMENT = union(\n /param\\w*[^;|]{0,60}(mismatch|mismatched|differ|do(es)? not match|doesn'?t match|inconsistent|drift)/,\n /(templat|naming)\\w*[^;|]{0,60}(mismatch|differ|drift|inconsistent)/,\n);\n\n// SOFT: the subject is implicit, so these are also how a reviewer says a\n// design feature is absent. They count against precision only outside a\n// clause about such a feature.\nconst NOT_IMPLEMENTED_LOOSE = union(\n /not implemented|no implementation|missing implementation|unimplemented|never implemented/,\n /implemented nowhere/,\n /(missing|absent) from (the )?implementation/,\n);\n\nconst NOT_DOCUMENTED_LOOSE = union(\n /not documented|undocumented|documented nowhere/,\n /(missing|absent) from (the )?(spec|contract|openapi)/,\n /not in (the )?(spec|contract|openapi)/,\n);\n\nconst HARD_CLAIM = union(NO_HANDLER, NO_PATH_ITEM, SCHEMA_DISAGREEMENT, PARAM_DISAGREEMENT);\nconst SOFT_CLAIM = union(NOT_IMPLEMENTED_LOOSE, NOT_DOCUMENTED_LOOSE);\n\n// A clause whose subject is a design feature rather than the operation. Every\n// one of these is genuinely absent from this fixture, so a reviewer naming it\n// is right and must not be charged with inventing drift.\nconst DESIGN_CLAUSE =\n /[^;|]*\\b(pagination|paginat\\w+|cursor|offset|page size|security|securityschemes?|scopes?|auth\\w*|oauth|401|403|404|4xx|5xx|error responses?|status codes?|examples?|descriptions?|summar\\w+|naming|verb in (the )?path|rate[- ]limit\\w*|versioning|idempoten\\w+|cach\\w+|etag|headers?|content[- ]type)\\b[^;|]*/g;\n\nconst claimsDrift = (text) =>\n HARD_CLAIM.test(text) || SOFT_CLAIM.test(text.replace(DESIGN_CLAUSE, ' '));\n\n// Recall is deliberately more generous than precision: extra tolerance here\n// only risks passing a sloppy review, while a miss fails a correct one.\nconst TYPE_EVIDENCE =\n /(?<!\\bno )mismatch|(?<!\\bno )not match|doesn'?t match|typed as|should be (a |an )?(number|integer)|declar\\w*[\\s\\S]{0,60}\\b(string|number|integer)\\b|\\bstring\\b[\\s\\S]{0,120}\\b(number|integer)\\b|\\b(number|integer)\\b[\\s\\S]{0,120}\\bstring\\b/;\n\nconst REAL = [\n {\n label:\n 'GET /widgets/{widgetId}/history is documented in openapi.yaml but no handler implements it',\n path: /\\/widgets\\/:[a-z0-9_]+\\/history/,\n klass: union(\n NO_HANDLER,\n NOT_IMPLEMENTED_LOOSE,\n /documented but/,\n /only (exists )?in the (spec|contract|openapi)/,\n ),\n },\n {\n label:\n 'GET /widgets/{widgetId}/status returns retryCount as a number while the contract declares it a string',\n path: /\\/widgets\\/:[a-z0-9_]+\\/status/,\n klass: union(SCHEMA_DISAGREEMENT, TYPE_EVIDENCE),\n },\n {\n label: 'GET /widgets/:id is implemented in src/routes.ts but absent from openapi.yaml',\n path: /\\/widgets\\/:[a-z0-9_]+(?![a-z0-9_/])/,\n klass: union(\n NO_PATH_ITEM,\n NOT_DOCUMENTED_LOOSE,\n /add[^;|]{0,50}\\b(path item|operation|entry|endpoint|route|definition|it)\\b[^;|]{0,20}\\bto\\b[^;|]{0,15}(spec|contract|openapi)/,\n /document it/,\n ),\n },\n];\n\n// A record that states the operation conforms is a verdict, not a drift\n// claim - but only when it asserts no drift class of its own.\nconst NO_DRIFT_VERDICT =\n /no drift|not a drift|not drift|matches the (spec|contract|implementation|handler|schema)|conforms to the (spec|contract)|correct as written|as designed|verified (safe|correct|ok)|no mismatch|no issue|no violation|not a (real )?(issue|violation|finding)|false positive|(permitted|allowed) by the (spec|contract)/;\n\nconst assertsDrift = (text) => claimsDrift(text) || REAL.some((real) => real.klass.test(text));\n\nconst entries = records\n .filter((record) => record && typeof record === 'object')\n .map((record) => ({ record, text: textOf(record), subject: subjectOf(record) }));\n\nconst claims = entries.filter(\n (entry) => assertsDrift(entry.text) || !NO_DRIFT_VERDICT.test(entry.text),\n);\n\nconst missing = REAL.filter(\n (real) => !claims.some((entry) => real.path.test(entry.text) && real.klass.test(entry.text)),\n);\nif (missing.length > 0) {\n fail(\n 'RECALL FAILURE - openapi.yaml and the route inventory disagree in three places and these ' +\n 'were not reported: ' +\n missing.map((real) => real.label).join('; ') +\n '. Reported paths: ' +\n (entries\n .map((entry) => String(entry.record.path ?? entry.record.operation ?? '?'))\n .join(', ') || '(nothing)'),\n );\n}\n\nconst SAFE = [\n {\n label: 'GET /users/{userId}',\n path: /\\/users\\/:[a-z0-9_]+(?![a-z0-9_/])/,\n why: 'it is documented AND implemented in src/routes.ts - `{userId}` in the contract and `:userId` in the router are the same path parameter',\n },\n {\n label: 'GET /users/{userId}/sessions',\n path: /\\/users\\/:[a-z0-9_]+\\/sessions/,\n why: 'its handler is registered in src/session-routes.ts, which src/routes.ts imports and calls - reading only one route file is what makes it look missing',\n },\n {\n label: 'GET /widgets/{widgetId}/owner',\n path: /\\/widgets\\/:[a-z0-9_]+\\/owner/,\n why: 'the contract marks `email` nullable and leaves it out of `required`, so a handler that omits it when the owner has no address is permitted',\n },\n];\n\nconst falsePositives = [];\nfor (const safe of SAFE) {\n for (const entry of claims) {\n // Judge the record by its subject, so a fix that cites this operation as\n // the model for another one is not counted against the review.\n if (!safe.path.test(entry.subject ?? entry.text)) continue;\n // And only when it actually claims a contract/implementation\n // disagreement - a design remark about a safe operation is fair review.\n if (!claimsDrift(entry.text)) continue;\n falsePositives.push(\n safe.label +\n ' reported as \"' +\n String(entry.record.issue ?? entry.record.kind ?? entry.record.type ?? 'drift') +\n '\" - ' +\n safe.why,\n );\n }\n}\nif (falsePositives.length > 0) {\n fail(\n 'PRECISION FAILURE - these operations agree with the contract and must not be listed as ' +\n 'drift: ' +\n falsePositives.join('; ') +\n '. A reconciliation that invents drift is not usable; re-read docs/api-contract.md and ' +\n 'both route files before deciding an operation is missing.',\n );\n}\n\nconsole.log(\n 'API contract precision/recall oracle passed: all 3 real drifts reported, 0 false drifts on ' +\n 'the 3 safe operations.',\n);\n",
33
+ "surface": "workspace",
34
+ "modelInput": false
21
35
  }
22
36
  ],
23
37
  "worker": {
@@ -30,7 +44,7 @@
30
44
  },
31
45
  "mocks": [],
32
46
  "success": {
33
- "summary": "tasks/eval/api-review.md covers every seeded operation, contract/implementation drift, and corrected contract snippets.",
47
+ "summary": "tasks/eval/api-review.md covers every seeded operation with corrected contract snippets, and tasks/eval/drift.json lists every real contract/implementation drift and nothing else.",
34
48
  "deliverables": [
35
49
  {
36
50
  "path": "tasks/eval/api-review.md",
@@ -79,6 +93,13 @@
79
93
  "flags": "i",
80
94
  "label": "implementation drift"
81
95
  },
96
+ {
97
+ "kind": "contains",
98
+ "file": "tasks/eval/api-review.md",
99
+ "pattern": "retryCount|schema mismatch|type mismatch|response schema",
100
+ "flags": "i",
101
+ "label": "response schema drift"
102
+ },
82
103
  {
83
104
  "kind": "contains",
84
105
  "file": "tasks/eval/api-review.md",
@@ -87,6 +108,58 @@
87
108
  "label": "corrected snippet"
88
109
  }
89
110
  ]
111
+ },
112
+ {
113
+ "path": "tasks/eval/drift.json",
114
+ "kind": "json",
115
+ "minBytes": 200,
116
+ "checks": [
117
+ {
118
+ "kind": "sniff",
119
+ "file": "tasks/eval/drift.json",
120
+ "sniff": "json-valid"
121
+ },
122
+ {
123
+ "kind": "recordSchema",
124
+ "file": "tasks/eval/drift.json",
125
+ "format": "json",
126
+ "minRows": 3,
127
+ "fields": [
128
+ {
129
+ "name": "path",
130
+ "type": "nonempty",
131
+ "required": true
132
+ },
133
+ {
134
+ "name": "method",
135
+ "type": "nonempty",
136
+ "required": true
137
+ },
138
+ {
139
+ "name": "issue",
140
+ "type": "nonempty",
141
+ "required": true
142
+ },
143
+ {
144
+ "name": "fix",
145
+ "type": "nonempty",
146
+ "required": true
147
+ }
148
+ ],
149
+ "allowExtraFields": true
150
+ },
151
+ {
152
+ "kind": "nodeScriptPasses",
153
+ "script": "tests/api-contract-oracle.mjs",
154
+ "timeoutMs": 30000,
155
+ "requiredOutput": [
156
+ {
157
+ "pattern": "API contract precision/recall oracle passed",
158
+ "label": "every real drift reported, and no safe operation reported"
159
+ }
160
+ ]
161
+ }
162
+ ]
90
163
  }
91
164
  ]
92
165
  },
@@ -113,6 +186,7 @@
113
186
  "qualityFocus": [
114
187
  "contract-implementation reconciliation",
115
188
  "API semantics",
116
- "corrected snippets"
189
+ "corrected snippets",
190
+ "drift precision"
117
191
  ]
118
192
  }
@@ -47,7 +47,6 @@
47
47
  }
48
48
  ],
49
49
  "craftbookParams": {
50
- "workPath": "tasks/eval",
51
50
  "findingsPath": "reviews/findings.json"
52
51
  }
53
52
  },
@@ -56,131 +55,131 @@
56
55
  "summary": "All three seeded findings are genuinely closed at their real sites (validated quantity input, propagating config parse errors, an honest discount message), the neighborhood tests stay green, and the finding ids reconcile across triage, fix notes, and verification.",
57
56
  "deliverables": [
58
57
  {
59
- "path": "tasks/eval/triage.md",
58
+ "path": "{{task.dir}}/triage.md",
60
59
  "kind": "markdown-notes",
61
60
  "artifact": true,
62
61
  "minBytes": 600,
63
62
  "checks": [
64
63
  {
65
64
  "kind": "contains",
66
- "file": "tasks/eval/triage.md",
65
+ "file": "{{task.dir}}/triage.md",
67
66
  "pattern": "^##\\s+Findings read[\\s\\S]*^##\\s+Will fix[\\s\\S]*^##\\s+Deferred[\\s\\S]*^##\\s+Clusters",
68
67
  "flags": "im",
69
68
  "label": "triage sections in order"
70
69
  },
71
70
  {
72
71
  "kind": "contains",
73
- "file": "tasks/eval/triage.md",
72
+ "file": "{{task.dir}}/triage.md",
74
73
  "pattern": "\\bRV-1\\b",
75
74
  "label": "finding RV-1 triaged"
76
75
  },
77
76
  {
78
77
  "kind": "contains",
79
- "file": "tasks/eval/triage.md",
78
+ "file": "{{task.dir}}/triage.md",
80
79
  "pattern": "\\bRV-2\\b",
81
80
  "label": "finding RV-2 triaged"
82
81
  },
83
82
  {
84
83
  "kind": "contains",
85
- "file": "tasks/eval/triage.md",
84
+ "file": "{{task.dir}}/triage.md",
86
85
  "pattern": "\\bRV-3\\b",
87
86
  "label": "finding RV-3 triaged"
88
87
  },
89
88
  {
90
89
  "kind": "citationsResolve",
91
- "file": "tasks/eval/triage.md",
90
+ "file": "{{task.dir}}/triage.md",
92
91
  "minCitations": 2,
93
92
  "artifact": true
94
93
  }
95
94
  ]
96
95
  },
97
96
  {
98
- "path": "tasks/eval/fix-notes.md",
97
+ "path": "{{task.dir}}/fix-notes.md",
99
98
  "kind": "markdown-notes",
100
99
  "artifact": true,
101
100
  "minBytes": 700,
102
101
  "checks": [
103
102
  {
104
103
  "kind": "contains",
105
- "file": "tasks/eval/fix-notes.md",
104
+ "file": "{{task.dir}}/fix-notes.md",
106
105
  "pattern": "^##\\s+Problem[\\s\\S]*^##\\s+Change[\\s\\S]*^##\\s+Files touched[\\s\\S]*^##\\s+Per-finding disposition[\\s\\S]*^##\\s+Risk[\\s\\S]*^##\\s+How to verify",
107
106
  "flags": "im",
108
107
  "label": "fix-notes sections in order"
109
108
  },
110
109
  {
111
110
  "kind": "contains",
112
- "file": "tasks/eval/fix-notes.md",
111
+ "file": "{{task.dir}}/fix-notes.md",
113
112
  "pattern": "\\bRV-1\\b",
114
113
  "label": "disposition for RV-1"
115
114
  },
116
115
  {
117
116
  "kind": "contains",
118
- "file": "tasks/eval/fix-notes.md",
117
+ "file": "{{task.dir}}/fix-notes.md",
119
118
  "pattern": "\\bRV-2\\b",
120
119
  "label": "disposition for RV-2"
121
120
  },
122
121
  {
123
122
  "kind": "contains",
124
- "file": "tasks/eval/fix-notes.md",
123
+ "file": "{{task.dir}}/fix-notes.md",
125
124
  "pattern": "\\bRV-3\\b",
126
125
  "label": "disposition for RV-3"
127
126
  },
128
127
  {
129
128
  "kind": "citationsResolve",
130
- "file": "tasks/eval/fix-notes.md",
129
+ "file": "{{task.dir}}/fix-notes.md",
131
130
  "minCitations": 2,
132
131
  "artifact": true
133
132
  }
134
133
  ]
135
134
  },
136
135
  {
137
- "path": "tasks/eval/validation.md",
136
+ "path": "{{task.dir}}/validation.md",
138
137
  "kind": "markdown-notes",
139
138
  "artifact": true,
140
139
  "minBytes": 450,
141
140
  "checks": [
142
141
  {
143
142
  "kind": "contains",
144
- "file": "tasks/eval/validation.md",
143
+ "file": "{{task.dir}}/validation.md",
145
144
  "pattern": "^##\\s+Per-finding verification[\\s\\S]*^##\\s+Result",
146
145
  "flags": "im",
147
146
  "label": "validation sections in order"
148
147
  },
149
148
  {
150
149
  "kind": "contains",
151
- "file": "tasks/eval/validation.md",
150
+ "file": "{{task.dir}}/validation.md",
152
151
  "pattern": "\\bRV-1\\b",
153
152
  "label": "verification for RV-1"
154
153
  },
155
154
  {
156
155
  "kind": "contains",
157
- "file": "tasks/eval/validation.md",
156
+ "file": "{{task.dir}}/validation.md",
158
157
  "pattern": "\\bRV-2\\b",
159
158
  "label": "verification for RV-2"
160
159
  },
161
160
  {
162
161
  "kind": "contains",
163
- "file": "tasks/eval/validation.md",
162
+ "file": "{{task.dir}}/validation.md",
164
163
  "pattern": "\\bRV-3\\b",
165
164
  "label": "verification for RV-3"
166
165
  },
167
166
  {
168
167
  "kind": "citationsResolve",
169
- "file": "tasks/eval/validation.md",
168
+ "file": "{{task.dir}}/validation.md",
170
169
  "minCitations": 2,
171
170
  "artifact": true
172
171
  }
173
172
  ]
174
173
  },
175
174
  {
176
- "path": "tasks/eval/review.md",
175
+ "path": "{{task.dir}}/review.md",
177
176
  "kind": "markdown-report",
178
177
  "artifact": true,
179
178
  "minBytes": 400,
180
179
  "checks": [
181
180
  {
182
181
  "kind": "contains",
183
- "file": "tasks/eval/review.md",
182
+ "file": "{{task.dir}}/review.md",
184
183
  "pattern": "Verdict:\\s*(?:PASS|REVISE)",
185
184
  "flags": "i",
186
185
  "label": "explicit reviewer verdict"
@@ -265,7 +264,7 @@
265
264
  },
266
265
  "rubric": {
267
266
  "artifact": {
268
- "path": "tasks/eval/fix-notes.md",
267
+ "path": "{{task.dir}}/fix-notes.md",
269
268
  "kind": "markdown"
270
269
  },
271
270
  "axes": [
@@ -23,9 +23,6 @@
23
23
  "worker": {
24
24
  "name": "Jules",
25
25
  "role": "Producer"
26
- },
27
- "craftbookParams": {
28
- "workPath": "tasks/eval"
29
26
  }
30
27
  },
31
28
  "mocks": [],
@@ -23,9 +23,6 @@
23
23
  "worker": {
24
24
  "name": "Jules",
25
25
  "role": "Producer"
26
- },
27
- "craftbookParams": {
28
- "workPath": "tasks/eval"
29
26
  }
30
27
  },
31
28
  "mocks": [],
@@ -67,9 +67,6 @@
67
67
  "worker": {
68
68
  "name": "Ruben",
69
69
  "role": "Producer"
70
- },
71
- "craftbookParams": {
72
- "workPath": "tasks/eval"
73
70
  }
74
71
  },
75
72
  "mocks": [
@@ -19,9 +19,6 @@
19
19
  "worker": {
20
20
  "name": "Daan",
21
21
  "role": "Huisautomaat"
22
- },
23
- "craftbookParams": {
24
- "workPath": "tasks/eval"
25
22
  }
26
23
  },
27
24
  "mocks": [
@@ -19,9 +19,6 @@
19
19
  "worker": {
20
20
  "name": "Daan",
21
21
  "role": "Developer"
22
- },
23
- "craftbookParams": {
24
- "workPath": "tasks/eval"
25
22
  }
26
23
  },
27
24
  "mocks": [],
@@ -19,9 +19,6 @@
19
19
  "worker": {
20
20
  "name": "Nora",
21
21
  "role": "Writer"
22
- },
23
- "craftbookParams": {
24
- "workPath": "tasks/eval"
25
22
  }
26
23
  },
27
24
  "mocks": [],
@@ -19,9 +19,6 @@
19
19
  "worker": {
20
20
  "name": "Liv",
21
21
  "role": "Developer"
22
- },
23
- "craftbookParams": {
24
- "workPath": "tasks/eval"
25
22
  }
26
23
  },
27
24
  "mocks": [],
@@ -19,9 +19,6 @@
19
19
  "worker": {
20
20
  "name": "Jules",
21
21
  "role": "Developer"
22
- },
23
- "craftbookParams": {
24
- "workPath": "tasks/eval"
25
22
  }
26
23
  },
27
24
  "mocks": [],
@@ -19,9 +19,6 @@
19
19
  "worker": {
20
20
  "name": "Jules",
21
21
  "role": "Developer"
22
- },
23
- "craftbookParams": {
24
- "workPath": "tasks/eval"
25
22
  }
26
23
  },
27
24
  "mocks": [
@@ -19,9 +19,6 @@
19
19
  "worker": {
20
20
  "name": "Eline",
21
21
  "role": "Copywriter"
22
- },
23
- "craftbookParams": {
24
- "workPath": "tasks/eval"
25
22
  }
26
23
  },
27
24
  "mocks": [],