skilldrop-cli 0.16.18 → 0.16.20

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 (371) hide show
  1. package/agents/devils-advocate.md +34 -22
  2. package/bin/skilldrop.js +18 -4
  3. package/catalogue.json +2 -1
  4. package/model-routing.json +219 -215
  5. package/package.json +1 -1
  6. package/packs/ai-engineering/skills/agent-adoption-stage/evals/evals.json +28 -0
  7. package/packs/ai-engineering/skills/agent-adoption-stage/evals/files/2/agent-telemetry.csv +7 -0
  8. package/packs/ai-engineering/skills/agent-adoption-stage/evals/files/2/cto-offsite-memo.md +9 -0
  9. package/packs/ai-engineering/skills/agent-adoption-stage/evals/files/2/dev-survey-summary.md +9 -0
  10. package/packs/ai-engineering/skills/agent-adoption-stage/evals/files/2/engineering-policy.md +15 -0
  11. package/packs/ai-engineering/skills/agent-budget/evals/evals.json +27 -0
  12. package/packs/ai-engineering/skills/agent-budget/evals/files/3/finance-note.md +10 -0
  13. package/packs/ai-engineering/skills/agent-budget/evals/files/3/pipeline.md +18 -0
  14. package/packs/ai-engineering/skills/agent-budget/evals/files/3/price-sheet.md +9 -0
  15. package/packs/ai-engineering/skills/agent-budget/evals/files/3/september-usage.csv +7 -0
  16. package/packs/ai-engineering/skills/agent-loop-design/evals/evals.json +28 -0
  17. package/packs/ai-engineering/skills/agent-loop-design/evals/files/3/design-guide-extract.md +13 -0
  18. package/packs/ai-engineering/skills/agent-loop-design/evals/files/3/legal-advice.md +9 -0
  19. package/packs/ai-engineering/skills/agent-loop-design/evals/files/3/request-from-head-of-planning.md +11 -0
  20. package/packs/ai-engineering/skills/agent-loop-design/evals/files/3/trial-notes.md +13 -0
  21. package/packs/ai-engineering/skills/agent-threat-model/evals/evals.json +27 -0
  22. package/packs/ai-engineering/skills/agent-threat-model/evals/files/4/agent-config.yaml +19 -0
  23. package/packs/ai-engineering/skills/agent-threat-model/evals/files/4/agent-spec.md +17 -0
  24. package/packs/ai-engineering/skills/agent-threat-model/evals/files/4/previous-review.md +10 -0
  25. package/packs/ai-engineering/skills/agent-threat-model/evals/files/4/vendor-security-note.md +4 -0
  26. package/packs/ai-engineering/skills/ai-adoption-rollout/evals/evals.json +28 -0
  27. package/packs/ai-engineering/skills/ai-adoption-rollout/evals/files/2/cno-brief.md +17 -0
  28. package/packs/ai-engineering/skills/ai-adoption-rollout/evals/files/2/education-capacity.md +5 -0
  29. package/packs/ai-engineering/skills/ai-adoption-rollout/evals/files/2/pilot-report.md +14 -0
  30. package/packs/ai-engineering/skills/ai-adoption-rollout/evals/files/2/survey-summary.md +7 -0
  31. package/packs/ai-engineering/skills/ai-adoption-rollout/evals/files/2/union-letter.md +8 -0
  32. package/packs/ai-engineering/skills/ai-readiness-assessment/evals/evals.json +28 -0
  33. package/packs/ai-engineering/skills/ai-readiness-assessment/evals/files/2/ceo-note.md +5 -0
  34. package/packs/ai-engineering/skills/ai-readiness-assessment/evals/files/2/governance-status.md +6 -0
  35. package/packs/ai-engineering/skills/ai-readiness-assessment/evals/files/2/interview-notes.md +18 -0
  36. package/packs/ai-engineering/skills/ai-readiness-assessment/evals/files/2/it-inventory.md +12 -0
  37. package/packs/ai-engineering/skills/ai-usage-report/evals/evals.json +27 -0
  38. package/packs/ai-engineering/skills/ai-usage-report/evals/files/2/draftwell-events.csv +249 -0
  39. package/packs/ai-engineering/skills/ai-usage-report/evals/files/2/export-note.md +9 -0
  40. package/packs/ai-engineering/skills/ai-usage-report/evals/files/2/published-assets.csv +44 -0
  41. package/packs/ai-engineering/skills/ai-usage-report/evals/files/2/team-roster.md +10 -0
  42. package/packs/ai-engineering/skills/ai-use-case-triage/evals/evals.json +27 -0
  43. package/packs/ai-engineering/skills/ai-use-case-triage/evals/files/2/data-team.md +5 -0
  44. package/packs/ai-engineering/skills/ai-use-case-triage/evals/files/2/finance-notes.md +7 -0
  45. package/packs/ai-engineering/skills/ai-use-case-triage/evals/files/2/ideas.csv +10 -0
  46. package/packs/ai-engineering/skills/ai-use-case-triage/evals/files/2/legal-note.md +7 -0
  47. package/packs/ai-engineering/skills/llm-eval-harness/evals/evals.json +28 -0
  48. package/packs/ai-engineering/skills/llm-eval-harness/evals/files/2/current-tests.md +6 -0
  49. package/packs/ai-engineering/skills/llm-eval-harness/evals/files/2/feature-brief.md +14 -0
  50. package/packs/ai-engineering/skills/llm-eval-harness/evals/files/2/incident-log.md +8 -0
  51. package/packs/ai-engineering/skills/llm-eval-harness/evals/files/2/pm-request.md +10 -0
  52. package/packs/ai-engineering/skills/subagent-design/evals/evals.json +27 -0
  53. package/packs/ai-engineering/skills/subagent-design/evals/files/3/current-process.md +11 -0
  54. package/packs/ai-engineering/skills/subagent-design/evals/files/3/director-proposal.md +6 -0
  55. package/packs/ai-engineering/skills/subagent-design/evals/files/3/scoring-rubric.md +9 -0
  56. package/packs/ai-engineering/skills/subagent-design/evals/files/3/trial-and-round-notes.md +11 -0
  57. package/packs/api-builder/skills/eval-harness-generator/evals/evals.json +27 -0
  58. package/packs/api-builder/skills/eval-harness-generator/evals/files/2/SKILL.md +35 -0
  59. package/packs/api-builder/skills/prompt-caching-advisor/evals/evals.json +25 -0
  60. package/packs/api-builder/skills/prompt-caching-advisor/evals/files/2/build_request.py +40 -0
  61. package/packs/api-builder/skills/prompt-caching-advisor/evals/files/2/notes.md +10 -0
  62. package/packs/api-builder/skills/token-budget-estimator/evals/evals.json +27 -0
  63. package/packs/api-builder/skills/token-budget-estimator/evals/files/2/pilot-usage.csv +17 -0
  64. package/packs/api-builder/skills/token-budget-estimator/evals/files/2/workflow.md +42 -0
  65. package/packs/career/pack.json +1 -1
  66. package/packs/career/skills/job-fit-analysis/SKILL.md +2 -1
  67. package/packs/career/skills/job-fit-analysis/manifest.json +3 -2
  68. package/packs/career/skills/role-shortlist/SKILL.md +107 -0
  69. package/packs/career/skills/role-shortlist/evals/eval_queries.json +34 -0
  70. package/packs/career/skills/role-shortlist/evals/evals.json +75 -0
  71. package/packs/career/skills/role-shortlist/evals/files/1/careers-index.html +22 -0
  72. package/packs/career/skills/role-shortlist/evals/files/1/cv.md +44 -0
  73. package/packs/career/skills/role-shortlist/evals/files/1/postings/clinical-coding-officer-bramwick.md +23 -0
  74. package/packs/career/skills/role-shortlist/evals/files/1/postings/data-and-performance-analyst.html +28 -0
  75. package/packs/career/skills/role-shortlist/evals/files/1/postings/estates-maintenance-electrician-bramwick.md +20 -0
  76. package/packs/career/skills/role-shortlist/evals/files/1/postings/healthcare-support-worker-nights-corrin-bay.md +20 -0
  77. package/packs/career/skills/role-shortlist/evals/files/1/postings/medical-secretary-cardiology-elsford.html +30 -0
  78. package/packs/career/skills/role-shortlist/evals/files/1/postings/outpatient-booking-team-leader-bramwick.md +23 -0
  79. package/packs/career/skills/role-shortlist/evals/files/1/postings/patient-pathway-coordinator-bramwick.md +30 -0
  80. package/packs/career/skills/role-shortlist/evals/files/1/postings/patient-pathway-coordinator-elsford.md +30 -0
  81. package/packs/career/skills/role-shortlist/evals/files/1/postings/reception-and-admin-assistant-corrin-bay.md +21 -0
  82. package/packs/career/skills/role-shortlist/evals/files/1/postings/senior-care-coordinator.md +25 -0
  83. package/packs/career/skills/role-shortlist/evals/files/2/cv.md +33 -0
  84. package/packs/career/skills/role-shortlist/evals/files/2/job-board-export.csv +11 -0
  85. package/packs/career/skills/role-shortlist/evals/files/2/postings/FJ-10422.md +26 -0
  86. package/packs/career/skills/role-shortlist/evals/files/2/postings/FJ-10431.md +25 -0
  87. package/packs/career/skills/role-shortlist/evals/files/2/postings/FJ-10455.md +27 -0
  88. package/packs/career/skills/role-shortlist/evals/files/2/postings/FJ-10468.md +25 -0
  89. package/packs/career/skills/role-shortlist/evals/files/2/postings/FJ-10476.md +25 -0
  90. package/packs/career/skills/role-shortlist/evals/files/2/postings/FJ-10490.md +24 -0
  91. package/packs/career/skills/role-shortlist/evals/files/2/postings/FJ-10587.md +26 -0
  92. package/packs/career/skills/role-shortlist/evals/files/4/brackwater-careers.html +118 -0
  93. package/packs/career/skills/role-shortlist/evals/files/4/mere-castell-cv.md +44 -0
  94. package/packs/career/skills/role-shortlist/evals/files/4/tradesboard-export.csv +6 -0
  95. package/packs/career/skills/role-shortlist/manifest.json +38 -0
  96. package/packs/converters/skills/file-to-markdown/evals/evals.json +27 -0
  97. package/packs/converters/skills/file-to-markdown/evals/files/3/harbourline-shift-policy.docx +0 -0
  98. package/packs/converters/skills/file-to-markdown/evals/files/4/seed-swap-2026.csv +10 -0
  99. package/packs/converters/skills/md-to-docx/evals/evals.json +28 -0
  100. package/packs/converters/skills/md-to-docx/evals/files/3/brand.json +12 -0
  101. package/packs/converters/skills/md-to-docx/evals/files/3/img/team-photo.png +0 -0
  102. package/packs/converters/skills/md-to-docx/evals/files/3/tender-response.md +51 -0
  103. package/packs/converters/skills/md-to-html/evals/evals.json +26 -0
  104. package/packs/converters/skills/md-to-html/evals/files/2/brand.json +13 -0
  105. package/packs/converters/skills/md-to-html/evals/files/2/img/kick-net.png +0 -0
  106. package/packs/converters/skills/md-to-html/evals/files/2/river-survey-guide.md +53 -0
  107. package/packs/converters/skills/md-to-html/evals/files/3/nanas-lentil-soup.md +21 -0
  108. package/packs/converters/skills/md-to-html/evals/files/3/pot.png +0 -0
  109. package/packs/converters/skills/md-to-xlsx/evals/evals.json +26 -0
  110. package/packs/converters/skills/md-to-xlsx/evals/files/3/depot-costs-q3.md +20 -0
  111. package/packs/converters/skills/md-to-xlsx/evals/files/4/hollowmere-5k-results.json +7 -0
  112. package/packs/converters/skills/mermaid-render/evals/evals.json +26 -0
  113. package/packs/converters/skills/mermaid-render/evals/files/2/dispensing-diagrams.md +39 -0
  114. package/packs/core/skills/brief-intake/evals/evals.json +27 -0
  115. package/packs/core/skills/brief-intake/evals/files/2/ops-meeting-notes.md +18 -0
  116. package/packs/core/skills/brief-intake/evals/files/2/thread.txt +40 -0
  117. package/packs/core/skills/council-review/evals/evals.json +28 -0
  118. package/packs/core/skills/council-review/evals/files/2/compliance-note.md +11 -0
  119. package/packs/core/skills/council-review/evals/files/2/link-outages-q3.csv +11 -0
  120. package/packs/core/skills/council-review/evals/files/2/proposal.md +39 -0
  121. package/packs/core/skills/council-review/evals/files/2/vendor-letter.txt +12 -0
  122. package/packs/core/skills/doc-critique/evals/evals.json +27 -0
  123. package/packs/core/skills/doc-critique/evals/files/2/exec-summary.md +43 -0
  124. package/packs/core/skills/output-hygiene/evals/evals.json +27 -0
  125. package/packs/core/skills/output-hygiene/evals/files/3/newsletter.md +17 -0
  126. package/packs/data-analytics/skills/dashboard-spec/evals/evals.json +27 -0
  127. package/packs/data-analytics/skills/dashboard-spec/evals/files/2/data-inventory.md +16 -0
  128. package/packs/data-analytics/skills/dashboard-spec/evals/files/2/request-email.md +28 -0
  129. package/packs/data-analytics/skills/sql-review/evals/evals.json +27 -0
  130. package/packs/data-analytics/skills/sql-review/evals/files/2/context.md +10 -0
  131. package/packs/data-analytics/skills/sql-review/evals/files/2/monthly_donor_revenue.sql +16 -0
  132. package/packs/data-analytics/skills/sql-review/evals/files/2/schema.md +20 -0
  133. package/packs/design/skills/brand-kit/evals/evals.json +26 -0
  134. package/packs/design/skills/brand-kit/evals/files/2/brand-guidelines.md +32 -0
  135. package/packs/design/skills/brand-kit/evals/files/2/contact-sheet.txt +6 -0
  136. package/packs/design/skills/brand-kit/evals/files/2/logo.svg +5 -0
  137. package/packs/design/skills/brand-kit/evals/files/2/website-colours.css +9 -0
  138. package/packs/design/skills/brand-kit/evals/files/3/muddy-paws-logo.png +0 -0
  139. package/packs/design/skills/deck-builder/evals/evals.json +27 -0
  140. package/packs/design/skills/deck-builder/evals/files/4/ashby-vale-board-notes.md +36 -0
  141. package/packs/design/skills/marketing-flyer/evals/evals.json +27 -0
  142. package/packs/design/skills/marketing-flyer/evals/files/2/brand.json +14 -0
  143. package/packs/design/skills/marketing-flyer/evals/files/2/larchfield-logo.svg +4 -0
  144. package/packs/design/skills/marketing-flyer/evals/files/2/manager-email.txt +6 -0
  145. package/packs/design/skills/marketing-flyer/evals/files/2/open-day-brief.md +15 -0
  146. package/packs/design/skills/slide-outliner/evals/evals.json +26 -0
  147. package/packs/design/skills/slide-outliner/evals/files/2/uv-dosing-design-notes.md +38 -0
  148. package/packs/dev-team/skills/accessibility-audit/evals/evals.json +27 -0
  149. package/packs/dev-team/skills/accessibility-audit/evals/files/2/booking.html +79 -0
  150. package/packs/dev-team/skills/accessibility-audit/evals/files/2/scan-report.txt +23 -0
  151. package/packs/dev-team/skills/accessibility-audit/evals/files/2/styles.css +56 -0
  152. package/packs/dev-team/skills/agents-md-generator/evals/evals.json +27 -0
  153. package/packs/dev-team/skills/agents-md-generator/evals/files/5/.github/workflows/ci.yml +12 -0
  154. package/packs/dev-team/skills/agents-md-generator/evals/files/5/CONTRIBUTING.md +20 -0
  155. package/packs/dev-team/skills/agents-md-generator/evals/files/5/README.md +15 -0
  156. package/packs/dev-team/skills/agents-md-generator/evals/files/5/data/raw/README.md +7 -0
  157. package/packs/dev-team/skills/agents-md-generator/evals/files/5/pyproject.toml +23 -0
  158. package/packs/dev-team/skills/agents-md-generator/evals/files/5/scripts/deploy.sh +6 -0
  159. package/packs/dev-team/skills/agents-md-generator/evals/files/5/src/sensor_ingest/__init__.py +1 -0
  160. package/packs/dev-team/skills/agents-md-generator/evals/files/5/src/sensor_ingest/parse.py +20 -0
  161. package/packs/dev-team/skills/agents-md-generator/evals/files/5/tests/test_gateway.py +10 -0
  162. package/packs/dev-team/skills/agents-md-generator/evals/files/5/tests/test_parse.py +7 -0
  163. package/packs/dev-team/skills/agents-md-generator/evals/files/6/clean_marks.R +5 -0
  164. package/packs/dev-team/skills/agents-md-generator/evals/files/6/grades_final.csv +6 -0
  165. package/packs/dev-team/skills/agents-md-generator/evals/files/6/make_report.R +7 -0
  166. package/packs/dev-team/skills/agents-md-generator/evals/files/6/notes.txt +8 -0
  167. package/packs/dev-team/skills/agents-md-generator/evals/files/6/raw_marks.csv +6 -0
  168. package/packs/dev-team/skills/bug-triage/evals/evals.json +27 -0
  169. package/packs/dev-team/skills/bug-triage/evals/files/2/payments-log.csv +15 -0
  170. package/packs/dev-team/skills/bug-triage/evals/files/2/slack-thread.txt +16 -0
  171. package/packs/dev-team/skills/bug-triage/evals/files/2/ticket.txt +10 -0
  172. package/packs/dev-team/skills/devils-advocate/SKILL.md +65 -124
  173. package/packs/dev-team/skills/devils-advocate/evals/evals.json +27 -0
  174. package/packs/dev-team/skills/devils-advocate/evals/files/6/PR_DESCRIPTION.md +20 -0
  175. package/packs/dev-team/skills/devils-advocate/evals/files/6/redeem.py +102 -0
  176. package/packs/dev-team/skills/devils-advocate/evals/files/6/test_redeem.py +54 -0
  177. package/packs/dev-team/skills/devils-advocate/examples/rate-limiter-review.md +36 -16
  178. package/packs/dev-team/skills/devils-advocate/manifest.json +3 -3
  179. package/packs/dev-team/skills/feature-implement-loop/evals/evals.json +27 -0
  180. package/packs/dev-team/skills/feature-implement-loop/evals/files/2/TICKET.md +20 -0
  181. package/packs/dev-team/skills/feature-implement-loop/evals/files/2/closures.csv +5 -0
  182. package/packs/dev-team/skills/feature-implement-loop/evals/files/2/desk.py +11 -0
  183. package/packs/dev-team/skills/feature-implement-loop/evals/files/2/fees.py +14 -0
  184. package/packs/dev-team/skills/feature-implement-loop/evals/files/2/tests/test_fees.py +26 -0
  185. package/packs/dev-team/skills/feature-implement-loop/evals/files/3/away.txt +5 -0
  186. package/packs/dev-team/skills/feature-implement-loop/evals/files/3/members.txt +8 -0
  187. package/packs/dev-team/skills/feature-implement-loop/evals/files/3/rota.py +12 -0
  188. package/packs/dev-team/skills/launch-readiness/evals/evals.json +27 -0
  189. package/packs/dev-team/skills/launch-readiness/evals/files/2/launch-brief.md +32 -0
  190. package/packs/dev-team/skills/launch-readiness/evals/files/2/load-test-summary.txt +11 -0
  191. package/packs/dev-team/skills/launch-readiness/evals/files/2/privacy-signoff.txt +9 -0
  192. package/packs/dev-team/skills/launch-readiness/evals/files/2/sms-template.txt +2 -0
  193. package/packs/dev-team/skills/migration-plan/evals/evals.json +27 -0
  194. package/packs/dev-team/skills/migration-plan/evals/files/2/context.md +27 -0
  195. package/packs/dev-team/skills/migration-plan/evals/files/2/deferral-codes.csv +8 -0
  196. package/packs/dev-team/skills/migration-plan/evals/files/2/field-mapping.csv +11 -0
  197. package/packs/dev-team/skills/migration-plan/evals/files/2/trial-import-summary.txt +9 -0
  198. package/packs/dev-team/skills/pr-description-writer/evals/evals.json +27 -0
  199. package/packs/dev-team/skills/pr-description-writer/evals/files/4/changes.diff +64 -0
  200. package/packs/dev-team/skills/pr-description-writer/evals/files/4/commits.txt +2 -0
  201. package/packs/dev-team/skills/pre-merge-review/evals/evals.json +28 -0
  202. package/packs/dev-team/skills/pre-merge-review/evals/files/3/CHANGE.md +12 -0
  203. package/packs/dev-team/skills/pre-merge-review/evals/files/3/CONTRIBUTING.md +5 -0
  204. package/packs/dev-team/skills/pre-merge-review/evals/files/3/change.diff +53 -0
  205. package/packs/dev-team/skills/pre-merge-review/evals/files/3/clinic_dosing/__init__.py +1 -0
  206. package/packs/dev-team/skills/pre-merge-review/evals/files/3/clinic_dosing/dosing.py +30 -0
  207. package/packs/dev-team/skills/pre-merge-review/evals/files/3/clinic_dosing/drugs.py +6 -0
  208. package/packs/dev-team/skills/pre-merge-review/evals/files/3/tests/__init__.py +0 -0
  209. package/packs/dev-team/skills/pre-merge-review/evals/files/3/tests/test_dosing.py +29 -0
  210. package/packs/dev-team/skills/sonar-onboard/evals/evals.json +27 -0
  211. package/packs/dev-team/skills/sonar-onboard/evals/files/2/.github/workflows/ci.yml +10 -0
  212. package/packs/dev-team/skills/sonar-onboard/evals/files/2/.gitlab-ci.yml +32 -0
  213. package/packs/dev-team/skills/sonar-onboard/evals/files/2/README.md +11 -0
  214. package/packs/dev-team/skills/sonar-onboard/evals/files/2/pyproject.toml +16 -0
  215. package/packs/dev-team/skills/sonar-onboard/evals/files/2/src/wayline/__init__.py +1 -0
  216. package/packs/dev-team/skills/sonar-onboard/evals/files/2/src/wayline/_generated/__init__.py +0 -0
  217. package/packs/dev-team/skills/sonar-onboard/evals/files/2/src/wayline/_generated/stops_pb2.py +4 -0
  218. package/packs/dev-team/skills/sonar-onboard/evals/files/2/src/wayline/timetable.py +12 -0
  219. package/packs/dev-team/skills/sonar-onboard/evals/files/2/src/wayline/vendor/__init__.py +0 -0
  220. package/packs/dev-team/skills/sonar-onboard/evals/files/2/src/wayline/vendor/gtfs_lite/__init__.py +3 -0
  221. package/packs/dev-team/skills/sonar-onboard/evals/files/2/tests/test_timetable.py +14 -0
  222. package/packs/dev-team/skills/sonar-onboard/evals/files/2/web/package.json +20 -0
  223. package/packs/dev-team/skills/sonar-onboard/evals/files/2/web/src/board.test.ts +9 -0
  224. package/packs/dev-team/skills/sonar-onboard/evals/files/2/web/src/board.ts +8 -0
  225. package/packs/dev-team/skills/sonar-review/evals/evals.json +27 -0
  226. package/packs/dev-team/skills/sonar-review/evals/files/2/changed-files.txt +5 -0
  227. package/packs/dev-team/skills/sonar-review/evals/files/2/hotspots.json +7 -0
  228. package/packs/dev-team/skills/sonar-review/evals/files/2/issues.json +26 -0
  229. package/packs/dev-team/skills/sonar-review/evals/files/2/quality-gate.json +19 -0
  230. package/packs/dev-team/skills/tech-debt-register/evals/evals.json +28 -0
  231. package/packs/dev-team/skills/tech-debt-register/evals/files/4/incidents.csv +7 -0
  232. package/packs/dev-team/skills/tech-debt-register/evals/files/4/retro-notes.md +21 -0
  233. package/packs/dev-team/skills/test-plan-generator/evals/evals.json +27 -0
  234. package/packs/dev-team/skills/test-plan-generator/evals/files/2/permit-renewal-spec.md +40 -0
  235. package/packs/dev-team/skills/user-story-splitter/evals/evals.json +27 -0
  236. package/packs/dev-team/skills/user-story-splitter/evals/files/2/prd-shift-swap.md +38 -0
  237. package/packs/experience-design/skills/content-design/evals/evals.json +27 -0
  238. package/packs/experience-design/skills/content-design/evals/files/2/contact-centre-notes.md +18 -0
  239. package/packs/experience-design/skills/content-design/evals/files/2/current-page.md +17 -0
  240. package/packs/experience-design/skills/content-design/evals/files/2/policy-extract.md +17 -0
  241. package/packs/experience-design/skills/design-system-spec/evals/evals.json +27 -0
  242. package/packs/experience-design/skills/design-system-spec/evals/files/2/designer-notes.md +23 -0
  243. package/packs/experience-design/skills/design-system-spec/evals/files/2/eng-thread.md +11 -0
  244. package/packs/experience-design/skills/design-system-spec/evals/files/2/tokens.json +27 -0
  245. package/packs/experience-design/skills/information-architecture/evals/evals.json +27 -0
  246. package/packs/experience-design/skills/information-architecture/evals/files/2/page-inventory.csv +28 -0
  247. package/packs/experience-design/skills/information-architecture/evals/files/2/search-log.csv +16 -0
  248. package/packs/experience-design/skills/information-architecture/evals/files/2/stakeholder-notes.md +13 -0
  249. package/packs/experience-design/skills/service-blueprint/evals/evals.json +27 -0
  250. package/packs/experience-design/skills/service-blueprint/evals/files/2/complaints-summary.md +14 -0
  251. package/packs/experience-design/skills/service-blueprint/evals/files/2/process-notes.md +15 -0
  252. package/packs/experience-design/skills/service-blueprint/evals/files/2/timings.csv +5 -0
  253. package/packs/experience-design/skills/ux-writing/evals/evals.json +27 -0
  254. package/packs/experience-design/skills/ux-writing/evals/files/2/brand-notes.md +8 -0
  255. package/packs/experience-design/skills/ux-writing/evals/files/2/error-codes.csv +6 -0
  256. package/packs/experience-design/skills/ux-writing/evals/files/2/screens.md +26 -0
  257. package/packs/grc/skills/dpia/evals/evals.json +27 -0
  258. package/packs/grc/skills/dpia/evals/files/2/legal-notes.md +6 -0
  259. package/packs/grc/skills/dpia/evals/files/2/project-brief.md +17 -0
  260. package/packs/grc/skills/dpia/evals/files/2/vendor-factsheet.md +8 -0
  261. package/packs/grc/skills/risk-register/evals/evals.json +27 -0
  262. package/packs/grc/skills/risk-register/evals/files/2/committee-notes.md +8 -0
  263. package/packs/grc/skills/risk-register/evals/files/2/risks-draft.csv +9 -0
  264. package/packs/grc/skills/risk-register/evals/files/2/scoring-scale.md +12 -0
  265. package/packs/grc/skills/security-questionnaire-response/evals/evals.json +27 -0
  266. package/packs/grc/skills/security-questionnaire-response/evals/files/4/evidence/business-continuity-plan.md +7 -0
  267. package/packs/grc/skills/security-questionnaire-response/evals/files/4/evidence/information-security-policy.md +10 -0
  268. package/packs/grc/skills/security-questionnaire-response/evals/files/4/evidence/pentest-summary-2026.md +10 -0
  269. package/packs/grc/skills/security-questionnaire-response/evals/files/4/evidence/staff-handbook-extract.md +3 -0
  270. package/packs/grc/skills/security-questionnaire-response/evals/files/4/instructions.md +10 -0
  271. package/packs/grc/skills/security-questionnaire-response/evals/files/4/questionnaire.csv +11 -0
  272. package/packs/grc/skills/soc2-evidence-map/evals/evals.json +27 -0
  273. package/packs/grc/skills/soc2-evidence-map/evals/files/2/audit-scope.md +10 -0
  274. package/packs/grc/skills/soc2-evidence-map/evals/files/2/controls.csv +13 -0
  275. package/packs/grc/skills/soc2-evidence-map/evals/files/2/tooling-notes.md +8 -0
  276. package/packs/infra-as-code/skills/terraform-module/evals/evals.json +27 -0
  277. package/packs/infra-as-code/skills/terraform-module/evals/files/3/requirements.md +23 -0
  278. package/packs/infra-as-code/skills/terraform-plan-review/evals/evals.json +27 -0
  279. package/packs/infra-as-code/skills/terraform-plan-review/evals/files/3/plan.txt +87 -0
  280. package/packs/product-manager/skills/business-case/evals/evals.json +27 -0
  281. package/packs/product-manager/skills/business-case/evals/files/2/hollin_vale_inputs.md +46 -0
  282. package/packs/product-manager/skills/okr-cascade/evals/evals.json +27 -0
  283. package/packs/product-manager/skills/okr-cascade/evals/files/3/quillfield_2027.md +45 -0
  284. package/packs/product-manager/skills/prd-draft/evals/evals.json +27 -0
  285. package/packs/product-manager/skills/prd-draft/evals/files/2/brief.md +7 -0
  286. package/packs/product-manager/skills/prd-draft/evals/files/2/call_center_notes.md +7 -0
  287. package/packs/product-manager/skills/prd-draft/evals/files/2/meter_facts.md +6 -0
  288. package/packs/product-manager/skills/prfaq/evals/evals.json +26 -0
  289. package/packs/product-manager/skills/prfaq/evals/files/3/drone_notes.md +25 -0
  290. package/packs/product-manager/skills/requirements-interview/evals/evals.json +27 -0
  291. package/packs/product-manager/skills/requirements-interview/evals/files/2/project_brief.md +29 -0
  292. package/packs/product-manager/skills/strategy-analysis/evals/evals.json +27 -0
  293. package/packs/product-manager/skills/strategy-analysis/evals/files/4/market_notes.md +21 -0
  294. package/packs/product-manager/skills/success-metrics/evals/evals.json +28 -0
  295. package/packs/product-manager/skills/success-metrics/evals/files/3/brief.md +21 -0
  296. package/packs/product-manager/skills/user-journey-map/evals/evals.json +26 -0
  297. package/packs/product-manager/skills/user-journey-map/evals/files/3/research_notes.md +30 -0
  298. package/packs/research/skills/hypothesis-comparison/evals/evals.json +27 -0
  299. package/packs/research/skills/hypothesis-comparison/evals/files/2/season_notes.md +29 -0
  300. package/packs/research/skills/research-plan/evals/evals.json +28 -0
  301. package/packs/research/skills/research-plan/evals/files/3/request.md +19 -0
  302. package/packs/skill-engineering/skills/skill-author/evals/evals.json +27 -0
  303. package/packs/skill-engineering/skills/skill-author/evals/files/2/constraints.md +7 -0
  304. package/packs/skill-engineering/skills/skill-author/evals/files/2/example-discharge.md +22 -0
  305. package/packs/skill-engineering/skills/skill-author/evals/files/2/process.md +15 -0
  306. package/packs/skill-engineering/skills/skill-review/evals/evals.json +27 -0
  307. package/packs/skill-engineering/skills/skill-review/evals/files/2/invoice-chaser/SKILL.md +20 -0
  308. package/packs/skill-engineering/skills/skill-review/evals/files/2/invoice-chaser/evals/evals.json +12 -0
  309. package/packs/skill-engineering/skills/skill-review/evals/files/2/invoice-chaser/scripts/send_reminders.py +46 -0
  310. package/packs/solution-architect/skills/adr-generator/evals/evals.json +27 -0
  311. package/packs/solution-architect/skills/adr-generator/evals/files/2/integration-notes.md +23 -0
  312. package/packs/solution-architect/skills/adr-generator/evals/files/2/larchway-quote.txt +10 -0
  313. package/packs/solution-architect/skills/api-contract-draft/evals/evals.json +27 -0
  314. package/packs/solution-architect/skills/api-contract-draft/evals/files/2/booking-brief.md +18 -0
  315. package/packs/solution-architect/skills/api-contract-draft/evals/files/2/facilities-policy-excerpt.md +7 -0
  316. package/packs/solution-architect/skills/architecture-diagrams/evals/evals.json +27 -0
  317. package/packs/solution-architect/skills/architecture-diagrams/evals/files/2/telemetry-overview.md +23 -0
  318. package/packs/solution-architect/skills/data-contract/evals/evals.json +27 -0
  319. package/packs/solution-architect/skills/data-contract/evals/files/2/grain_deliveries.sql +15 -0
  320. package/packs/solution-architect/skills/data-contract/evals/files/2/publisher-notes.md +14 -0
  321. package/packs/solution-architect/skills/data-contract/evals/files/2/sample_rows.csv +6 -0
  322. package/packs/solution-architect/skills/figma-diagrams/evals/evals.json +26 -0
  323. package/packs/solution-architect/skills/figma-diagrams/evals/files/2/signage-file.json +373 -0
  324. package/packs/solution-architect/skills/nfr-spec/evals/evals.json +27 -0
  325. package/packs/solution-architect/skills/nfr-spec/evals/files/2/vehicle-booking-brief.md +21 -0
  326. package/packs/solution-architect/skills/reverse-architecture/evals/evals.json +28 -0
  327. package/packs/solution-architect/skills/reverse-architecture/evals/files/2/README.md +11 -0
  328. package/packs/solution-architect/skills/reverse-architecture/evals/files/2/docker-compose.yml +42 -0
  329. package/packs/solution-architect/skills/reverse-architecture/evals/files/2/env.example +3 -0
  330. package/packs/solution-architect/skills/reverse-architecture/evals/files/2/nginx.conf +15 -0
  331. package/packs/solution-architect/skills/reverse-architecture/evals/files/2/worker-requirements.txt +4 -0
  332. package/packs/solution-architect/skills/threat-model/evals/evals.json +28 -0
  333. package/packs/solution-architect/skills/threat-model/evals/files/2/permits-design.md +23 -0
  334. package/packs/sre-oncall/skills/capacity-cost-model/evals/evals.json +28 -0
  335. package/packs/sre-oncall/skills/capacity-cost-model/evals/files/2/brief.md +22 -0
  336. package/packs/sre-oncall/skills/capacity-cost-model/evals/files/2/price-sheet.md +13 -0
  337. package/packs/sre-oncall/skills/capacity-cost-model/evals/files/2/rollout-plan.md +27 -0
  338. package/packs/sre-oncall/skills/cloud-cost-review/evals/evals.json +28 -0
  339. package/packs/sre-oncall/skills/cloud-cost-review/evals/files/3/cost-export-2026-09.csv +25 -0
  340. package/packs/sre-oncall/skills/cloud-cost-review/evals/files/3/notes.md +11 -0
  341. package/packs/sre-oncall/skills/cloud-cost-review/evals/files/3/utilisation-2026-09.csv +12 -0
  342. package/packs/sre-oncall/skills/delivery-metrics-report/evals/evals.json +27 -0
  343. package/packs/sre-oncall/skills/delivery-metrics-report/evals/files/3/deploys.csv +68 -0
  344. package/packs/sre-oncall/skills/delivery-metrics-report/evals/files/3/incidents.csv +7 -0
  345. package/packs/sre-oncall/skills/delivery-metrics-report/evals/files/3/prs.csv +46 -0
  346. package/packs/sre-oncall/skills/incident-comms/evals/evals.json +27 -0
  347. package/packs/sre-oncall/skills/incident-comms/evals/files/2/comms-rules.md +6 -0
  348. package/packs/sre-oncall/skills/incident-comms/evals/files/2/incident-channel.txt +17 -0
  349. package/packs/sre-oncall/skills/incident-comms/evals/files/2/last-status-update.md +5 -0
  350. package/packs/sre-oncall/skills/observability-plan/evals/evals.json +27 -0
  351. package/packs/sre-oncall/skills/observability-plan/evals/files/2/constraints.md +9 -0
  352. package/packs/sre-oncall/skills/observability-plan/evals/files/2/current-alerts.csv +10 -0
  353. package/packs/sre-oncall/skills/observability-plan/evals/files/2/service-overview.md +27 -0
  354. package/packs/sre-oncall/skills/runbook-generator/evals/evals.json +27 -0
  355. package/packs/sre-oncall/skills/runbook-generator/evals/files/2/deploy.sh +14 -0
  356. package/packs/sre-oncall/skills/runbook-generator/evals/files/2/handover-chat.txt +8 -0
  357. package/packs/sre-oncall/skills/runbook-generator/evals/files/2/service-notes.md +26 -0
  358. package/packs/sre-oncall/skills/runbook-generator/evals/files/2/standing-order.md +3 -0
  359. package/packs/stakeholder-comms/skills/audience-profile/evals/evals.json +26 -0
  360. package/packs/stakeholder-comms/skills/decision-log/evals/evals.json +26 -0
  361. package/packs/stakeholder-comms/skills/decision-log/evals/files/2/committee-meeting-2026-09-03.txt +23 -0
  362. package/packs/stakeholder-comms/skills/decision-log/evals/files/2/followup-thread.txt +6 -0
  363. package/packs/stakeholder-comms/skills/exec-summary/evals/evals.json +26 -0
  364. package/packs/stakeholder-comms/skills/exec-summary/evals/files/2/library-branches-options-paper.md +67 -0
  365. package/packs/trackers/skills/backlog-triage/evals/evals.json +27 -0
  366. package/packs/trackers/skills/backlog-triage/evals/files/3/parks-backlog.csv +19 -0
  367. package/packs/trackers/skills/team-status-report/evals/evals.json +28 -0
  368. package/packs/trackers/skills/team-status-report/evals/files/3/larkspur-week-42.csv +15 -0
  369. package/packs/trackers/skills/tracker-brief-sync/evals/evals.json +28 -0
  370. package/packs/trackers/skills/tracker-brief-sync/evals/files/3/brief-home-delivery.md +44 -0
  371. package/packs/dev-team/skills/devils-advocate/templates/challenge.md +0 -118
@@ -1,151 +1,92 @@
1
1
  ---
2
2
  name: devils-advocate
3
- description: Adversarial review of just-generated code, run *after* an agent (or human) declares a feature done. Challenges the implementation through four lenses — edge cases the first pass missed, baked-in assumptions that won't survive future requirements, what a staff engineer would push back on in code review, and test-coverage gaps for the new code paths. Produces severity-tagged findings (blocker / major / minor / nit) with file:line evidence and concrete fixes or missing test cases. Use immediately after a feature implementation or generation pass — before merging, before declaring "done", before moving to the next ticket.
3
+ description: Adversarial review of a code change before it merges — the real bugs, most consequential first, each checked against the code before it is reported, with a fix that works. A passing test or clean local run counts as evidence only once you've said whether it would have caught the bug; when it couldn't, the review says why it passed and names the test that would have failed. Sized to the ask ("top 3", "skip the nits", "just security"); invents nothing about the codebase. Use right after a feature is declared done — before merging, before declaring "done", before moving to the next ticket.
4
4
  ---
5
5
 
6
6
  # devils-advocate
7
7
 
8
- You play the role of a **senior engineer in code review who is trying to find what the implementation missed**. Code that "works on the happy path" is the default state of newly-generated code — your job is to challenge it through four lenses and surface what the first pass didn't think about.
9
-
10
- This skill is the **code counterpart to [`doc-critique`](../../../core/skills/doc-critique/SKILL.md)** — same adversarial framing, applied to code instead of artifacts.
11
-
12
- ## When this skill runs
13
-
14
- The trigger is **right after an agent (or human) has declared a feature done**. The implementation exists, the happy path likely works, tests may even pass — and that's exactly the moment the skill is most useful, because that's the moment everyone stops looking.
15
-
16
- Specifically:
17
- - ✅ After AI code generation for a feature ("here's the implementation")
18
- - ✅ Before opening a PR / before requesting human review
19
- - ✅ Before merging
20
- - ✅ When the user asks "anything I might have missed?" or "is this ready to ship?"
21
- - ❌ For a one-line fix or trivial change — overkill
22
- - ❌ For greenfield exploration / spikes — adversarial review wastes effort on code that will be thrown away
23
- - ❌ As a substitute for actual code review by a human — this is a *pre-pass*, not a replacement
8
+ **The rule: a green test is not evidence until you've said why it would have failed with the
9
+ bug.** Changes arrive with "tests pass" or "ran it locally, fine". The agent's habit is to
10
+ take that as support, or to ignore it. Both miss the most useful thing a reviewer can say:
11
+ *why* the test passed anyway. A fixture that happens to dodge the bug, a table that was empty
12
+ on the laptop, a test that runs the job once when the bug only shows on the second run, an
13
+ assertion that one bug cancels out. For each bug you find, say whether the cited tests or run
14
+ could have caught it, and if not, why it passed and the one test that would have failed:
15
+ ✅ *"`test_refill` passes because it waits 2 s against a rate of 1/s, so it never sees the
16
+ partial-token case. Assert `allow()` is false at 0.5 s."*
17
+
18
+ A second rule: **report only what survives checking.** Before a finding goes in, trace it
19
+ through the code. Does an earlier guard already handle the case? Is the query actually
20
+ parameterised? Does the stated business rule make this behaviour correct? Does your own fix
21
+ do what you say it does? A false finding costs the reader more than a missed nit.
24
22
 
25
23
  ## How to respond
26
24
 
27
- **Four rules come before the steps and outrank them:**
28
-
29
- - **Answer what was asked, first.** Open with the answer, the decision or the artifact, in plain words. Scores, matrices, frameworks and tags come after it, and anything that doesn't change the answer is cut.
30
- - **Use only what you were given.** Don't add facts, names, numbers, incidents, history, steps or sections the input doesn't contain. What you need and don't have is left out of the artifact and listed once at the end under "To confirm".
31
- - **Deliver from what you have.** When the request gives you something to work on, state your assumptions in a line and produce the result. When it gives you nothing to work on, ask for it in one or two plain sentences and say what you will do once you have it.
32
- - **Write for someone who has never heard of this skill.** No skill names, no paths or scripts from this folder, no internal terms, and nothing about how the run was set up. A next step is one plain sentence at the end that describes the work.
33
- - **For this skill:** With no code or document to review, ask for it in one sentence and name the three or four things you will check in it, taken from what the user said it does.
34
-
35
- 1. **Identify the change under review.** In order of preference:
36
- - The agent / user has just shown you a diff — review that diff.
37
- - Git working tree has unstaged changes — `git diff` is the scope.
38
- - User points to specific files / a PR / a recent commit — that's the scope.
39
- - User says "the feature I just built" with no diff — ask which files, or run `git diff HEAD~1` if a commit was just made.
40
-
41
- **Don't review the whole repo.** The scope is the *just-generated* code. Touched files only.
42
-
43
- 2. **Classify the code shape.** What you challenge depends on what was built. Map to one or more:
44
-
45
- | Shape | Lens emphasis |
46
- |---|---|
47
- | HTTP / RPC endpoint, API handler | edge-cases (input validation, auth), adversarial (rate limit, error mapping) |
48
- | Async handler / queue consumer | edge-cases (retries, idempotency, poison messages), future-proofing (ordering) |
49
- | DB migration / schema change | future-proofing (rollback, online-safe), adversarial (locking, big-table risk) |
50
- | State machine / workflow | edge-cases (impossible transitions, concurrent updates) |
51
- | Parser / data transformation | edge-cases (malformed, encoding, huge inputs) |
52
- | CLI tool / script | edge-cases (missing flags, env, partial runs) |
53
- | UI component | edge-cases (loading/empty/error states, a11y) |
54
- | Background job / cron | edge-cases (overlap, missed runs, partial completion) |
55
- | Library / pure function | edge-cases (boundary inputs), future-proofing (API stability) |
56
- | Config / infra change | adversarial (blast radius), future-proofing (drift) |
57
-
58
- Multiple shapes is common — a PR can be "endpoint + migration + UI." Apply each lens to the right slice.
59
-
60
- 3. **Sweep the four lenses in order.** Each lens has its own checklist — read it, apply it, write findings. Don't merge lenses; each surfaces a different category of risk.
61
-
62
- | Lens | File | Asks |
63
- |---|---|---|
64
- | 1. Edge cases | [`lenses/edge-cases.md`](lenses/edge-cases.md) | What inputs / states / timings break this? |
65
- | 2. Future-proofing | [`lenses/future-proofing.md`](lenses/future-proofing.md) | What assumptions won't survive the next 6 months? |
66
- | 3. Adversarial review | [`lenses/adversarial-review.md`](lenses/adversarial-review.md) | What would a staff engineer push back on in review? |
67
- | 4. Test coverage | [`lenses/test-coverage.md`](lenses/test-coverage.md) | Which new code paths have no test, and which scenarios are missing tests? |
68
-
69
- 4. **Categorize every finding by severity:**
70
-
71
- | Severity | Meaning |
72
- |---|---|
73
- | 🟥 **Blocker** | This will ship a bug or a security issue. Examples: SQL injection, unhandled `null`, race condition on shared state, migration that locks a 10M-row table, missing auth check, infinite retry loop. |
74
- | 🟧 **Major** | This will hurt within months. Examples: hard-coded limits that 2× growth will hit, no idempotency on a retryable operation, error swallowed silently, no observability for a load-bearing path, magic constants. |
75
- | 🟨 **Minor** | Good craft. Examples: missing edge-case test, suboptimal log level, naming that won't age well, a comment that explains *what* instead of *why*. |
76
- | ⚪ **Nit** | Style, formatting, micro-preference. Optional. |
77
-
78
- When in doubt between two severities, **downgrade**. Inflated severity makes the report unreadable. If your output has more blockers than major findings, you're inflating.
79
-
80
- 5. **For every finding, write four parts:**
81
-
82
- - **Where:** `file:line` (e.g. `src/api/checkout.ts:47`) — and quote 5–15 chars of the offending line.
83
- - **What's wrong:** one sentence — which lens fired and why.
84
- - **Concrete scenario:** ✅ "When `discount=null` reaches line 47, `applyDiscount` throws `TypeError`." — ❌ "Doesn't handle null." A scenario the first pass can reproduce.
85
- - **Fix:** ✅ "Add `if (discount == null) return 0;` at the top of `applyDiscount` — or thread the null through to skip the line item entirely (preferred — see how `applyTax` handles it at line 102)." — ❌ "Add null handling."
86
-
87
- 6. **Open with a verdict, not the findings.** First thing the user sees:
88
-
89
- ```
90
- Verdict: SHIP WITH FIXES — 2 blockers, 5 major, 4 minor, 3 nits.
91
-
92
- The endpoint validates auth and the happy path but doesn't bound the request body (blocker — DoS via 1GB payload), and the new migration adds a NOT NULL column without a default on a table the migration script doesn't backfill (blocker — will fail on first deploy). Of the 5 major findings, 3 are around idempotency on the retry path. Test coverage misses the new error branches at api/checkout.ts:71–88 entirely.
93
- ```
25
+ 1. **Answer the question first.** Open with a plain answer to what they asked, usually
26
+ whether it's safe to merge, and the worst problem in one sentence.
94
27
 
95
- Verdicts: `SHIP IT` · `SHIP WITH FIXES` · `DO NOT MERGE` · `RECONSIDER APPROACH`. The last is for when the implementation works but solved the wrong problem (e.g. building a custom retry queue when the framework already has one).
28
+ 2. **Review the change, not the repo.** The diff, the files they named, or `git diff` of the
29
+ working tree. Read the tests that came with it.
96
30
 
97
- 7. **Output structure** — use [`templates/challenge.md`](templates/challenge.md):
31
+ 3. **Find what would bite, most consequential first.** Wrong results, data loss, security
32
+ holes, failures on real data that the dev setup hides, retries and concurrency, then
33
+ fragility. For a large or unfamiliar change, the checklists in
34
+ [`lenses/edge-cases.md`](lenses/edge-cases.md),
35
+ [`lenses/future-proofing.md`](lenses/future-proofing.md),
36
+ [`lenses/adversarial-review.md`](lenses/adversarial-review.md) and
37
+ [`lenses/test-coverage.md`](lenses/test-coverage.md) are a sweep to run privately; they are
38
+ not sections of the reply.
98
39
 
99
- ```markdown
100
- # Devil's advocate: {feature name / PR title}
101
- _Scope: {N files, M lines changed} · Reviewed: {YYYY-MM-DD}_
40
+ 4. **Each finding:** where (`file:line`), what goes wrong in one concrete scenario ("when
41
+ `tz` is `None`, line 47 raises `TypeError`"), and the fix. When the fix is small,
42
+ give it as code they can paste. When the change is a script or migration, give the
43
+ corrected version.
102
44
 
103
- ## Verdict
104
- {one-liner} — {N} blocker · {N} major · {N} minor · {N} nit
105
- {3-sentence summary, lead with the worst}
45
+ 5. **Say what the tests prove.** Apply the rule to every test or run the user cites, and name
46
+ the missing tests as scenarios: ✅ *"No test runs the job twice; add one asserting the reminder
47
+ email is sent once."*
106
48
 
107
- ## Findings by lens
49
+ 6. **Size to the ask.** "Top 3" gets three. "Skip the nits" gets none. "Just security" gets
50
+ security. Without a limit, report what would actually bite; leave style out unless asked.
51
+ No severity counts, verdict labels or praise sections unless they asked.
108
52
 
109
- ### 1. Edge cases
110
- ### 2. Future-proofing
111
- ### 3. Adversarial review
112
- ### 4. Test coverage
53
+ 7. **Invent nothing about the codebase.** No row counts, traffic, run times, callers,
54
+ column contents or config you weren't shown. Where a finding depends on one, say what to
55
+ check: "if `orders` already has rows in production, this migration fails".
113
56
 
114
- ## What's solid
115
- - {2–4 things the implementation got right — not flattery, real patterns to preserve}
57
+ 8. **Deliver from what you have.** With code to review, review it. With nothing, ask for the
58
+ diff in one sentence and name the three or four things you'll check in it.
116
59
 
117
- ## Suggested order to address
118
- 1. Fix blockers
119
- 2. Add the missing tests in §4 (they double as regression catches)
120
- 3. Major findings in priority order
121
- ```
60
+ ## Useful references in this skill
122
61
 
123
- 8. **End with "what's solid"**, not more criticism. The user (or the next agent) often needs to know what to *keep* and what *patterns to reuse* elsewhere in the change.
62
+ - [`examples/rate-limiter-review.md`](examples/rate-limiter-review.md) — a change with "tests pass", and a review that says why they passed
124
63
 
125
64
  ## Quality bar
126
65
 
127
- - **Every finding has a reproducible scenario.** A senior engineer reading the finding should be able to reproduce the bug or violation in their head. "Doesn't handle null" is not a finding; "When `discount=null` reaches line 47, …" is.
128
- - **Severity is calibrated.** More blockers than major ⇒ inflating ⇒ demote.
129
- - **Findings cite `file:line`.** Reviewers must be able to jump to the spot. Section names aren't enough for code.
130
- - **Fixes are concrete and paste-able where possible.** When you can suggest a one-line patch, do; when you can't, suggest the *approach* in one sentence — not "improve error handling."
131
- - **Don't redesign.** This isn't your chance to push a different architecture. Stay in the lane of "given this approach, what's missing." If the approach itself is wrong, that's a single `RECONSIDER APPROACH` verdict, not a wholesale rewrite suggestion.
132
- - **Test-coverage findings reference scenarios, not files.** ❌ "No test for `applyDiscount`." ✅ "No test covers `applyDiscount(null)` — add a case that asserts the function returns 0 (or skips) without throwing."
66
+ - **Every cited test or run is judged:** could it have caught each bug, and if not, why did it
67
+ pass and what test would fail.
68
+ - **Every finding survives a trace through the code and the stated rules.** No false
69
+ positives.
70
+ - **The answer to "can this merge?" comes first;** findings are ordered by consequence.
71
+ - **Fixes work,** and are code when the change is small.
72
+ - **The scope asked for is respected.**
73
+ - **Nothing about the codebase is invented.**
133
74
 
134
75
  ## When NOT to use this skill
135
76
 
136
- - ❌ For greenfield prototype / spike code that's about to be thrown away.
137
- - ❌ For one-line / trivial changes — overkill, and the noise drowns out real signal.
138
- - ❌ As a substitute for human code review — it's a pre-pass, not a replacement.
139
- - ❌ For *evaluating the choice of approach* before code exists. That's a design conversation, not a code challenge. Use `design-doc` + `doc-critique` for that loop.
140
- - ❌ For generated code in a language you can't reason about line-by-line. Better to refuse than fabricate findings.
77
+ - ❌ For greenfield prototype or spike code that's about to be thrown away.
78
+ - ❌ For one-line or trivial changes.
79
+ - ❌ As a substitute for human code review — it's a pre-pass.
80
+ - ❌ For *evaluating the choice of approach* before code exists. That's a design conversation: `design-doc`, then `doc-critique`.
81
+ - ❌ For code in a language you can't reason about line by line. Refuse rather than fabricate findings.
141
82
 
142
83
  ## Anti-patterns to avoid
143
84
 
144
- - ❌ **Severity inflation.** If everything is a blocker, the report is unreadable. Most findings are major or minor.
145
- - ❌ **Vague findings.** "Handle errors better" / "Consider edge cases" — the whole point of this skill is to *name* the missed cases. If you can't name a specific scenario, drop the finding.
146
- - ❌ **Restating the lens.** ❌ "Code should be future-proof." ✅ "Hard-coded 100ms timeout on line 53 won't survive p99 growth — make it configurable."
147
- - ❌ **Lecturing on style** when there's a real bug to flag. Style notes go in the Nits section, not on top.
148
- - ❌ **Reviewing untouched code.** Out-of-scope. The skill challenges the *change*, not the codebase.
149
- - ❌ **Demanding tests for *everything* the change touches.** Only the new logic and new error paths. Don't insist on backfilling tests for previously-untested neighbouring code.
150
- - ❌ **Skipping "what's solid".** Trains the user (or downstream agent) to dread the skill. End on signal that's actionable in the other direction.
151
- - ❌ **Showing the machinery.** The reply and the artifact are for the person who asked. Don't mention this skill, its files, templates, caps or internal terms, or that the run is non-interactive. Name another skill once, at the end, as a suggested next step, never inside the artifact.
85
+ - ❌ **"Tests pass" taken at face value,** or ignored. Say what they prove.
86
+ - ❌ **The plausible false positive.** SQL injection in a parameterised query; a bug in
87
+ behaviour the business rule asks for; a CRLF issue text mode already handles.
88
+ - ❌ **Padding to fill sections.** Marginal findings are where the errors are.
89
+ - ❌ **A count that disagrees with the list.** Don't print counts.
90
+ - ❌ **Describing a fix instead of giving it** when it fits in a few lines.
91
+ - ❌ **Facts about production you weren't given.** Row counts, lock times, what a column holds.
92
+ - ❌ **Redesigning.** Stay on what's missing given this approach.
@@ -72,6 +72,33 @@
72
72
  "It does not state the row count of orders, how long the migration will take, or what customers.region contains as fact",
73
73
  "It leads with three main concerns as asked, and anything beyond the three is kept to a brief mention"
74
74
  ]
75
+ },
76
+ {
77
+ "id": 6,
78
+ "held_out": "2026-10-17",
79
+ "prompt": "I'm the reviewer on PR #412 for the Fernlocket loyalty service and it's meant to merge this afternoon. The change is in redeem.py, the tests are in test_redeem.py, and the author's description and test run are in PR_DESCRIPTION.md. Find what's wrong with it before it ships. Give me the three issues that matter most, most serious first, and skip style and naming nits entirely.",
80
+ "assertions": [
81
+ "It finds that quantity is only checked against the upper limit, so a negative quantity gives a negative cost that passes the balance check and adds points to the member's balance, and puts this among its top issues",
82
+ "It finds that the points are deducted and committed before fulfillment.ship() is called, so a failed shipment leaves the member charged with no refund, and that the \"Please try again\" message invites a second deduction for the same reward",
83
+ "It does not report the f-string query in list_redemptions as SQL injection, since the ORDER BY text can only come from the fixed SORT_COLUMNS mapping and the values are bound parameters, and it does not report the balance read-then-update as a double-spend race, since the row is locked with FOR UPDATE inside the same transaction",
84
+ "It says test_fulfillment_failure_returns_502 would pass with the bug in place, because it checks only the status and call count and never the member's balance, so the 6-passed run does not show that #398 is fixed",
85
+ "Its fixes would work: quantity must be required to be at least 1 (a tighter upper limit is not enough), and on a failed shipment the points must be rolled back or credited back, or not committed until the shipment succeeds; logging the failure or changing the status code alone does not count",
86
+ "It does not state as fact anything the files don't show: how fulfillment.ship() or the transaction helper behave beyond what the code and comments say, whether the fulfillment service rejects a negative quantity, how many members or redemptions there are, or what else calls redeem()",
87
+ "It leads with three issues, most serious first, and makes no style or naming comments; anything beyond the three is at most a brief mention"
88
+ ]
89
+ },
90
+ {
91
+ "id": 7,
92
+ "held_out": "2026-10-17",
93
+ "prompt": "hey quick one, can you check this before I push? it sends the weekly digest to all subscribers, max 8 at a time. we're on go 1.23. go test ./... is green and I ran it on staging against a handful of test subscribers, all delivered fine. just tell me if anything's actually broken, I don't care about style\n\n```go\nfunc SendAll(ctx context.Context, subs []Subscriber, d Digest) error {\n\tsem := make(chan struct{}, 8) // at most 8 pushes in flight\n\tvar wg sync.WaitGroup\n\tvar errs []error\n\n\tfor _, s := range subs {\n\t\twg.Add(1)\n\t\tsem <- struct{}{}\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tdefer func() { <-sem }()\n\t\t\tif err := push(ctx, s, d); err != nil {\n\t\t\t\terrs = append(errs, fmt.Errorf(\"subscriber %s: %w\", s.ID, err))\n\t\t\t}\n\t\t}()\n\t}\n\n\twg.Wait()\n\treturn errors.Join(errs...)\n}\n```",
94
+ "assertions": [
95
+ "It finds that the goroutines append to the shared errs slice with no lock, a data race that can lose errors or corrupt the slice when more than one push fails",
96
+ "It does not flag the closure capturing the loop variable s as a bug, since on Go 1.22 and later each loop iteration gets its own s",
97
+ "It says the green test run and the staging run don't show the code is safe: with every push succeeding the append never runs, and a plain go test without -race wouldn't report the race anyway",
98
+ "Its fix would work: a mutex around the append, or a per-subscriber slot in a slice sized to len(subs); if it suggests errgroup it says that this changes the behaviour (only the first error comes back, and with a group context the rest of the sends are cancelled)",
99
+ "It does not state as fact what push() does inside (retries, timeouts, how it uses ctx), how many subscribers there are, or that this has already failed in production",
100
+ "It keeps to what's actually broken, as asked: a short reply with no style or naming suggestions, not padded out with a long list of minor or hypothetical concerns"
101
+ ]
75
102
  }
76
103
  ]
77
104
  }
@@ -0,0 +1,20 @@
1
+ ## Synchronous reward redemption (#412)
2
+
3
+ Members currently wait for the nightly batch to find out whether a redemption went through.
4
+ This moves redemption onto a synchronous endpoint so they get an answer straight away.
5
+
6
+ - `redeem()` backs `POST /members/{member_id}/redemptions`
7
+ - `list_redemptions()` backs the history screen, with a `sort` option
8
+ - The balance row is locked with `SELECT ... FOR UPDATE`, so a double tap on "Redeem" can't spend the same points twice
9
+ - A failed shipment returns 502 and asks the member to try again; this closes #398 and is covered by `test_fulfillment_failure_returns_502`
10
+ - Per-order cap of 10 so nobody can clear out a reward's stock in one request
11
+
12
+ ### Test run
13
+
14
+ ```
15
+ $ pytest tests/test_redeem.py -q
16
+ ...... [100%]
17
+ 6 passed in 0.41s
18
+ ```
19
+
20
+ Ready for review. I'd like to get this into Thursday's release.
@@ -0,0 +1,102 @@
1
+ """Reward redemption for the Fernlocket loyalty programme.
2
+
3
+ PR #412: move redemption off the nightly batch onto a synchronous endpoint.
4
+ """
5
+ import logging
6
+ import uuid
7
+
8
+ from .db import transaction
9
+ from .fulfillment import FulfillmentClient, FulfillmentError
10
+
11
+ log = logging.getLogger(__name__)
12
+
13
+ MAX_PER_ORDER = 10
14
+
15
+ SORT_COLUMNS = {
16
+ "newest": "created_at DESC",
17
+ "oldest": "created_at ASC",
18
+ "points": "points_spent DESC",
19
+ }
20
+
21
+
22
+ class RedemptionError(Exception):
23
+ def __init__(self, status: int, message: str):
24
+ super().__init__(message)
25
+ self.status = status
26
+ self.message = message
27
+
28
+
29
+ def redeem(conn, fulfillment: FulfillmentClient, member_id: str, payload: dict) -> dict:
30
+ """Spend a member's points on a reward and ship it.
31
+
32
+ Called by POST /members/{member_id}/redemptions with the JSON body as `payload`.
33
+ """
34
+ reward_id = payload["reward_id"]
35
+ quantity = int(payload.get("quantity", 1))
36
+ if quantity > MAX_PER_ORDER:
37
+ raise RedemptionError(400, f"at most {MAX_PER_ORDER} of a reward per order")
38
+
39
+ with transaction(conn) as cur:
40
+ cur.execute(
41
+ "SELECT points_cost, active FROM rewards WHERE id = %s",
42
+ (reward_id,),
43
+ )
44
+ row = cur.fetchone()
45
+ if row is None or not row[1]:
46
+ raise RedemptionError(404, "reward not available")
47
+ cost = row[0] * quantity
48
+
49
+ # Lock the member's balance row so two taps on "Redeem" can't both spend it.
50
+ cur.execute(
51
+ "SELECT balance FROM point_accounts WHERE member_id = %s FOR UPDATE",
52
+ (member_id,),
53
+ )
54
+ balance = cur.fetchone()[0]
55
+ if balance < cost:
56
+ raise RedemptionError(409, "not enough points")
57
+
58
+ redemption_id = str(uuid.uuid4())
59
+ cur.execute(
60
+ "UPDATE point_accounts SET balance = %s WHERE member_id = %s",
61
+ (balance - cost, member_id),
62
+ )
63
+ cur.execute(
64
+ "INSERT INTO redemptions (id, member_id, reward_id, quantity, points_spent, status)"
65
+ " VALUES (%s, %s, %s, %s, %s, 'pending')",
66
+ (redemption_id, member_id, reward_id, quantity, cost),
67
+ )
68
+ # transaction commits on leaving the block
69
+
70
+ try:
71
+ fulfillment.ship(redemption_id, reward_id, quantity)
72
+ except FulfillmentError:
73
+ log.exception("fulfillment failed for redemption %s", redemption_id)
74
+ raise RedemptionError(502, "We couldn't send your reward. Please try again.")
75
+
76
+ with transaction(conn) as cur:
77
+ cur.execute(
78
+ "UPDATE redemptions SET status = 'shipped' WHERE id = %s",
79
+ (redemption_id,),
80
+ )
81
+
82
+ return {
83
+ "redemption_id": redemption_id,
84
+ "points_spent": cost,
85
+ "balance": balance - cost,
86
+ }
87
+
88
+
89
+ def list_redemptions(conn, member_id: str, sort: str = "newest", limit: int = 20) -> list:
90
+ """Redemption history for the member's account screen."""
91
+ order_by = SORT_COLUMNS.get(sort)
92
+ if order_by is None:
93
+ raise RedemptionError(400, "unknown sort")
94
+ limit = max(1, min(int(limit), 100))
95
+
96
+ with transaction(conn) as cur:
97
+ cur.execute(
98
+ "SELECT id, reward_id, quantity, points_spent, status, created_at"
99
+ f" FROM redemptions WHERE member_id = %s ORDER BY {order_by} LIMIT %s",
100
+ (member_id, limit),
101
+ )
102
+ return cur.fetchall()
@@ -0,0 +1,54 @@
1
+ import pytest
2
+
3
+ from rewards.fulfillment import FulfillmentError
4
+ from rewards.redeem import RedemptionError, list_redemptions, redeem
5
+ from tests.fakes import FakeFulfillment, make_db
6
+
7
+
8
+ @pytest.fixture
9
+ def db():
10
+ conn = make_db()
11
+ conn.seed_member("m-100", balance=500)
12
+ conn.seed_reward("r-mug", points_cost=120, active=True)
13
+ conn.seed_reward("r-old-tote", points_cost=50, active=False)
14
+ return conn
15
+
16
+
17
+ def test_happy_path(db):
18
+ result = redeem(db, FakeFulfillment(), "m-100", {"reward_id": "r-mug", "quantity": 2})
19
+ assert result["points_spent"] == 240
20
+ assert db.balance("m-100") == 260
21
+
22
+
23
+ def test_not_enough_points(db):
24
+ with pytest.raises(RedemptionError) as err:
25
+ redeem(db, FakeFulfillment(), "m-100", {"reward_id": "r-mug", "quantity": 5})
26
+ assert err.value.status == 409
27
+ assert db.balance("m-100") == 500
28
+
29
+
30
+ def test_inactive_reward(db):
31
+ with pytest.raises(RedemptionError) as err:
32
+ redeem(db, FakeFulfillment(), "m-100", {"reward_id": "r-old-tote"})
33
+ assert err.value.status == 404
34
+
35
+
36
+ def test_quantity_limit(db):
37
+ with pytest.raises(RedemptionError) as err:
38
+ redeem(db, FakeFulfillment(), "m-100", {"reward_id": "r-mug", "quantity": 11})
39
+ assert err.value.status == 400
40
+
41
+
42
+ def test_fulfillment_failure_returns_502(db):
43
+ """Regression for #398: a failed shipment must not cost the member their points."""
44
+ fulfillment = FakeFulfillment(fail_with=FulfillmentError("carrier timeout"))
45
+ with pytest.raises(RedemptionError) as err:
46
+ redeem(db, fulfillment, "m-100", {"reward_id": "r-mug", "quantity": 1})
47
+ assert err.value.status == 502
48
+ assert fulfillment.calls == 1
49
+
50
+
51
+ def test_history_rejects_unknown_sort(db):
52
+ with pytest.raises(RedemptionError) as err:
53
+ list_redemptions(db, "m-100", sort="points; DROP TABLE redemptions")
54
+ assert err.value.status == 400
@@ -1,10 +1,9 @@
1
- # Worked example — adversarial review of a just-written rate limiter
1
+ # Worked example — review of a rate limiter that "passes its tests"
2
2
 
3
- Input → output oracle for `devils-advocate`. Shows the four-lens sweep producing
4
- severity-calibrated findings with `file:line` evidence and paste-able fixes — not a
5
- generic "looks good, consider tests" pass.
3
+ Input → output oracle for `devils-advocate`. Shows the answer first, findings that survive a
4
+ trace through the code, and the cited tests judged for what they could and could not catch.
6
5
 
7
- ## Input (the "done" implementation)
6
+ ## Input
8
7
 
9
8
  > "Implemented the per-user rate limiter, tests pass, ready for review."
10
9
 
@@ -23,24 +22,45 @@ def allow(user_id: str, rate: float, burst: float) -> bool:
23
22
  return False
24
23
  ```
25
24
 
25
+ ```python
26
+ # test_ratelimit.py
27
+ def test_burst_then_deny():
28
+ for _ in range(3):
29
+ assert allow("u1", rate=1, burst=3)
30
+ assert not allow("u1", rate=1, burst=3)
31
+ ```
32
+
26
33
  ## Output (the review)
27
34
 
28
- **Verdict: not ready — 1 blocker, 1 major.** Four lenses swept; happy path is fine, the concurrency and growth paths are not.
35
+ **Not ready to merge.** Under concurrent requests for one user it admits more than the limit,
36
+ and the test can't see that.
37
+
38
+ 1. **Race on the shared dict** — `ratelimit.py:6-10`. Two requests for the same user both read
39
+ `tokens=1.0`, both pass, both write back `0.0`, so parallel bursts get through at up to
40
+ twice the intended rate. Fix: hold a per-user lock around the read-modify-write:
29
41
 
30
- 🟥 **Blocker — race on the shared dict (assumptions lens).** `ratelimit.py:6-11` reads then writes `_buckets[user_id]` with no lock. Two concurrent requests for the same user both read `tokens=1.0`, both pass, both write back `0.0` — the limiter leaks one token per race, so a burst of N parallel requests admits ~2× the intended rate. The "tests pass" because they're single-threaded. *Fix:* guard the read-modify-write with a per-user lock, or move to an atomic backend (Redis `INCR`+TTL). A dict-of-locks keyed by `user_id` is the minimal change.
42
+ ```python
43
+ _locks = collections.defaultdict(threading.Lock)
31
44
 
32
- 🟧 **Major — unbounded memory growth (edge-case lens).** `_buckets` never evicts (`:1`). Every distinct `user_id` ever seen stays forever; a service facing the open internet (or spoofable user ids) OOMs over time. *Fix:* cap with an LRU (`functools.lru_cache` won't fit the mutable value — use `cachetools.TTLCache(maxsize=…, ttl=…)`), evicting idle buckets.
45
+ def allow(user_id, rate, burst):
46
+ with _locks[user_id]:
47
+ ... # existing body unchanged
48
+ ```
33
49
 
34
- 🟨 **Minor — first call gets a free full burst (edge-case lens).** A never-seen `user_id` starts at `(burst, now)` (`:6`), so a brand-new user can immediately spend the whole burst. If the intent is "warm up", seed at `min(burst, rate*window)` instead — flag for product, don't silently change.
50
+ 2. **Memory grows without bound** — `ratelimit.py:2`. Nothing ever leaves `_buckets`, so every
51
+ distinct `user_id` stays for the life of the process. Fix: a `cachetools.TTLCache` in place
52
+ of the dict, with a TTL longer than `burst / rate`.
35
53
 
36
- ⚪ **Nit — `rate`/`burst` unvalidated (staff-engineer lens).** `rate<=0` freezes every user out; `burst<1` makes `allow` always false. Assert `rate>0 and burst>=1` at the boundary.
54
+ **What the test proves.** `test_burst_then_deny` runs on one thread, so it passes with the
55
+ race in place. It also never waits, so refill is untested. Tests that would fail today:
37
56
 
38
- **Test-coverage gaps (the "tests pass" were happy-path only):**
39
- - Concurrency: two threads hammering one `user_id` must not exceed `burst + rate*elapsed` admits.
40
- - Refill: after exhausting tokens, `allow` returns True again only after `1/rate` seconds.
41
- - Eviction: memory stays bounded under 10k distinct ids.
42
- - Boundary: `tokens` sitting at exactly `1.0` admits; at `0.999…` denies.
57
+ - Ten threads calling `allow("u1", rate=1, burst=3)` at once; assert at most three return
58
+ `True`.
59
+ - After draining the bucket, `allow` is false at 0.5 s and true at 1.0 s (with a patched clock).
43
60
 
44
61
  ## Why this passes the quality bar
45
62
 
46
- Severity is calibrated (one blocker, demoted the rest); every finding cites `file:line`, names the *lens* it came from, and gives a concrete fix or a specific missing test — not "add more tests."
63
+ The merge answer comes first. Each finding names the line, a concrete failure and a fix as
64
+ code. The cited test is judged for what it could catch, and the missing tests are scenarios.
65
+ The free first burst for a new user was left out: it is a product choice, not a bug in this
66
+ change.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "devils-advocate",
3
- "version": "0.1.2",
4
- "description": "Adversarial review of just-generated code, run *after* an agent (or human) declares a feature done. Challenges the implementation through four lenses — edge cases the first pass missed, baked-in assumptions that won't survive future requirements, what a staff engineer would push back on in code review, and test-coverage gaps for the new code paths. Produces severity-tagged findings (blocker / major / minor / nit) with file:line evidence and concrete fixes or missing test cases. Use immediately after a feature implementation or generation pass — before merging, before declaring \"done\", before moving to the next ticket.",
3
+ "version": "0.2.0",
4
+ "description": "Adversarial review of a code change before it merges — the real bugs, most consequential first, each checked against the code before it is reported, with a fix that works. A passing test or clean local run counts as evidence only once you've said whether it would have caught the bug; when it couldn't, the review says why it passed and names the test that would have failed. Sized to the ask (\"top 3\", \"skip the nits\", \"just security\"); invents nothing about the codebase. Use right after a feature is declared done — before merging, before declaring \"done\", before moving to the next ticket.",
5
5
  "entrypoint": "SKILL.md",
6
6
  "deps": { "npm": [], "pip": [] },
7
7
  "env": { "required": [], "optional": [] },
@@ -10,5 +10,5 @@
10
10
  { "event": "pre-commit-review", "action": "devils-advocate", "description": "adversarially review staged changes before they land" }
11
11
  ],
12
12
  "tags": ["review", "code-review", "adversarial", "edge-cases", "future-proofing", "test-coverage", "dev-workflow"],
13
- "model": { "tier": "heavy", "rationale": "Adversarial code review across four lenses. Cheaper models miss edge cases and under-call severity. Never downgrade." }
13
+ "model": { "tier": "heavy", "rationale": "Adversarial code review that must trace each finding and judge what the tests prove. Cheaper models miss edge cases and report false positives. Never downgrade." }
14
14
  }
@@ -14,6 +14,33 @@
14
14
  "Final report has a status (VERIFIED, VERIFIED WITH OPEN ITEMS, or BLOCKED), an acceptance-criteria table mapping each criterion to a test, manual-verify, or open item, an honest round log, and open items",
15
15
  "Does not add criteria the user did not give without echoing them back first"
16
16
  ]
17
+ },
18
+ {
19
+ "id": 2,
20
+ "held_out": "2026-10-18",
21
+ "prompt": "Please implement LIB-88 (TICKET.md) in this repo - the code is fees.py and desk.py, closures.csv holds the closure dates, and the tests are in tests/test_fees.py. Tests run with `python3 -m unittest discover -s tests`. When you're done, give me a short summary: what you built, what you checked, and anything I need to decide.",
22
+ "assertions": [
23
+ "Implements the fee calculation with tests, runs `python3 -m unittest discover -s tests`, and reports the real result; it does not claim tests pass without having run them",
24
+ "Flags that the ticket's worked example is wrong: 8 March is a Sunday and 9 March is a closure day, so 3 chargeable days and $0.75, not $1.25; no test expects $1.25",
25
+ "Notices that the existing MAX_FEE of $15.00 in fees.py conflicts with the ticket's $10.00 cap and says which one it applied",
26
+ "Has tests with specific expected amounts for the junior-card rule, the cap at the lower of replacement cost and $10.00, and the Sunday and closure exclusions",
27
+ "Does not invent a daily rate for magazines; a magazine is rejected or raised as a decision for the user",
28
+ "Uses only the standard library, and the existing tests and desk.checkin still work",
29
+ "The closing summary is short (a few lines plus any decisions needed)"
30
+ ]
31
+ },
32
+ {
33
+ "id": 3,
34
+ "held_out": "2026-10-18",
35
+ "prompt": "hi, I do the tea and setup rota for our community choir with rota.py (members.txt is everyone). can you make it skip people who are away? they're in away.txt, I typed it in a hurry. just make it work and tell me in a couple of lines what you changed, I'm not a programmer",
36
+ "assertions": [
37
+ "After the change, running rota.py puts nobody on a date when away.txt says they are away, even though away.txt uses different capitalisation and extra spaces",
38
+ "Handles or clearly points out that Edith Marsh is back for 5 Dec, rather than silently leaving her off every date or treating '(back for the 5 dec one)' as part of her name",
39
+ "The header line and the name that is not a member (Ruth Ng) cause no error and do not appear in the rota",
40
+ "The script is actually run and the output keeps the same 'date: name & name' format",
41
+ "The reply to the user is a couple of plain-language lines without programming jargon",
42
+ "Does not add features that were not asked for (no new options, dependencies or file formats)"
43
+ ]
17
44
  }
18
45
  ]
19
46
  }
@@ -0,0 +1,20 @@
1
+ # LIB-88: Late fees for overdue items
2
+
3
+ As a circulation desk volunteer, I want the system to work out the late fee when an item is
4
+ checked in, so every patron is charged the same way.
5
+
6
+ Constraint: the desk laptops are locked down. Python 3.10, standard library only - nothing can
7
+ be pip-installed.
8
+
9
+ ## Acceptance criteria
10
+
11
+ 1. Fee = daily rate x chargeable days late. Daily rates: book $0.25, DVD $1.00.
12
+ 2. Sundays, and the dates listed in closures.csv, are not chargeable days.
13
+ 3. An item returned on or before its due date is charged $0.00.
14
+ 4. The fee for one item is capped at its replacement cost or $10.00, whichever is lower.
15
+ 5. Patrons with a junior card (card type "junior") are never charged.
16
+
17
+ ## Worked example (from the desk)
18
+
19
+ A book due Friday 2026-03-06 and returned Wednesday 2026-03-11 is 5 days late:
20
+ 5 x $0.25 = $1.25.
@@ -0,0 +1,5 @@
1
+ date,reason
2
+ 2026-03-09,Staff training day
3
+ 2026-04-03,Public holiday
4
+ 2026-12-25,Public holiday
5
+ 2026-12-26,Public holiday