skilldrop-cli 1.2.0 → 1.4.0

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 (208) hide show
  1. package/README.md +5 -5
  2. package/catalogue.json +4 -4
  3. package/model-routing.json +62 -70
  4. package/package.json +1 -1
  5. package/packs/ai-engineering/loops/adopt/LOOP.md +120 -0
  6. package/packs/ai-engineering/loops/adopt/evals/eval_queries.json +10 -0
  7. package/packs/ai-engineering/loops/adopt/evals/evals.json +69 -0
  8. package/packs/ai-engineering/loops/adopt/evals/files/adopt-first-wave-to-sign-off/ai-ideas.md +15 -0
  9. package/packs/ai-engineering/loops/adopt/evals/files/adopt-first-wave-to-sign-off/org-context.md +27 -0
  10. package/packs/ai-engineering/loops/adopt/evals/files/adopt-first-wave-to-sign-off/staff-survey.csv +11 -0
  11. package/packs/ai-engineering/loops/adopt/evals/files/adopt-sponsor-slice-blocked-by-client-data/ai-ideas.md +13 -0
  12. package/packs/ai-engineering/loops/adopt/evals/files/adopt-sponsor-slice-blocked-by-client-data/firm-context.md +23 -0
  13. package/packs/ai-engineering/loops/adopt/loop.json +53 -0
  14. package/packs/ai-engineering/loops/ship-agent/LOOP.md +128 -0
  15. package/packs/ai-engineering/loops/ship-agent/evals/eval_queries.json +10 -0
  16. package/packs/ai-engineering/loops/ship-agent/evals/evals.json +70 -0
  17. package/packs/ai-engineering/loops/ship-agent/evals/files/ship-agent-auto-reply-exfil-open/agent-brief.md +33 -0
  18. package/packs/ai-engineering/loops/ship-agent/evals/files/ship-agent-changelog-config-reopens-path/agent-brief.md +33 -0
  19. package/packs/ai-engineering/loops/ship-agent/evals/files/ship-agent-changelog-config-reopens-path/claude-settings.json +25 -0
  20. package/packs/ai-engineering/loops/ship-agent/evals/files/ship-agent-changelog-config-reopens-path/sample-merged-prs.md +30 -0
  21. package/packs/ai-engineering/loops/ship-agent/loop.json +53 -0
  22. package/packs/ai-engineering/skills/agent-adoption-stage/SKILL.md +0 -1
  23. package/packs/ai-engineering/skills/agent-adoption-stage/manifest.json +3 -4
  24. package/packs/ai-engineering/skills/ai-adoption-rollout/SKILL.md +0 -1
  25. package/packs/ai-engineering/skills/ai-adoption-rollout/manifest.json +3 -4
  26. package/packs/ai-engineering/skills/ai-readiness-assessment/SKILL.md +0 -1
  27. package/packs/ai-engineering/skills/ai-readiness-assessment/manifest.json +1 -2
  28. package/packs/ai-engineering/skills/ai-use-case-triage/manifest.json +3 -3
  29. package/packs/ai-engineering/skills/judge-audit/SKILL.md +1 -2
  30. package/packs/ai-engineering/skills/judge-audit/manifest.json +1 -2
  31. package/packs/ai-engineering/skills/llm-eval-harness/SKILL.md +1 -2
  32. package/packs/ai-engineering/skills/llm-eval-harness/manifest.json +3 -3
  33. package/packs/api-builder/skills/tool-use-schema-writer/manifest.json +2 -2
  34. package/packs/career/loops/apply/evals/evals.json +28 -0
  35. package/packs/career/loops/apply/evals/files/apply-candidate-decided-full-run/application-form.md +10 -0
  36. package/packs/career/loops/apply/evals/files/apply-candidate-decided-full-run/job-posting.md +33 -0
  37. package/packs/career/loops/apply/evals/files/apply-candidate-decided-full-run/resume.md +34 -0
  38. package/packs/career/loops/apply/evals/files/apply-fit-gate-hard-requirement/cv.md +27 -0
  39. package/packs/career/loops/apply/evals/files/apply-fit-gate-hard-requirement/warehouse-supervisor.md +30 -0
  40. package/packs/career/skills/application-form-answers/manifest.json +3 -3
  41. package/packs/career/skills/cover-letter/manifest.json +3 -3
  42. package/packs/career/skills/resume-tailor/manifest.json +3 -3
  43. package/packs/converters/skills/md-to-docx/manifest.json +3 -3
  44. package/packs/core/loops/ship-a-draft/evals/evals.json +28 -0
  45. package/packs/core/loops/ship-a-draft/evals/files/ship-a-draft-adr-from-thread/slack-thread.txt +47 -0
  46. package/packs/core/loops/ship-a-draft/evals/files/ship-a-draft-announcement-unsettled/ticket-PRD-412.md +44 -0
  47. package/packs/core/skills/output-hygiene/manifest.json +3 -3
  48. package/packs/data-analytics/loops/measure/evals/evals.json +30 -0
  49. package/packs/data-analytics/loops/measure/evals/files/measure-active-customers-dispute/schema.md +43 -0
  50. package/packs/data-analytics/loops/measure/evals/files/measure-active-customers-dispute/sql/finance_active_customers.sql +7 -0
  51. package/packs/data-analytics/loops/measure/evals/files/measure-active-customers-dispute/sql/growth_active_customers.sql +9 -0
  52. package/packs/data-analytics/loops/measure/evals/files/measure-active-customers-dispute/thread.md +30 -0
  53. package/packs/data-analytics/loops/measure/evals/files/measure-retention-dashboard/request.md +34 -0
  54. package/packs/data-analytics/loops/measure/evals/files/measure-retention-dashboard/schema.md +58 -0
  55. package/packs/data-analytics/loops/measure/evals/files/measure-retention-dashboard/sql/active_subscribers.sql +17 -0
  56. package/packs/data-analytics/loops/measure/evals/files/measure-retention-dashboard/sql/net_revenue_by_plan.sql +15 -0
  57. package/packs/data-analytics/loops/measure/evals/files/measure-retention-dashboard/sql/weekly_churn_rate.sql +34 -0
  58. package/packs/data-analytics/skills/dashboard-spec/SKILL.md +0 -1
  59. package/packs/data-analytics/skills/dashboard-spec/manifest.json +1 -2
  60. package/packs/design/skills/slide-outliner/manifest.json +2 -2
  61. package/packs/dev-team/loops/build/evals/evals.json +28 -0
  62. package/packs/dev-team/loops/build/evals/files/build-promo-codes/.github/workflows/ci.yml.fixture +19 -0
  63. package/packs/dev-team/loops/build/evals/files/build-promo-codes/cartcalc/__init__.py +4 -0
  64. package/packs/dev-team/loops/build/evals/files/build-promo-codes/cartcalc/pricing.py +47 -0
  65. package/packs/dev-team/loops/build/evals/files/build-promo-codes/pyproject.toml.fixture +9 -0
  66. package/packs/dev-team/loops/build/evals/files/build-promo-codes/story.md +61 -0
  67. package/packs/dev-team/loops/build/evals/files/build-promo-codes/tests/__init__.py +0 -0
  68. package/packs/dev-team/loops/build/evals/files/build-promo-codes/tests/test_pricing.py +49 -0
  69. package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/.github/workflows/ci.yml.fixture +19 -0
  70. package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/bug-report.md +25 -0
  71. package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/pr-description.md +42 -0
  72. package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/pyproject.toml.fixture +9 -0
  73. package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/ratelimit/__init__.py +4 -0
  74. package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/ratelimit/bucket.py +49 -0
  75. package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/tests/__init__.py +0 -0
  76. package/packs/dev-team/loops/build/evals/files/build-rate-limiter-not-ready/tests/test_bucket.py +63 -0
  77. package/packs/dev-team/loops/modernize/evals/evals.json +30 -0
  78. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-batch-port/.github/workflows/ci.yml.fixture +11 -0
  79. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-batch-port/README.md +17 -0
  80. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-batch-port/docs/adr/0004-late-fee-calculation.md +25 -0
  81. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-batch-port/legacy/feecalc.py +74 -0
  82. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-batch-port/samples/accounts_2026-10.txt +10 -0
  83. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-batch-port/samples/accounts_edge.txt +11 -0
  84. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-batch-port/tests/test_feecalc_smoke.py +21 -0
  85. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/.github/workflows/ci.yml.fixture +11 -0
  86. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/PR-412.md +24 -0
  87. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/README.md +17 -0
  88. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/docs/adr/0004-late-fee-calculation.md +25 -0
  89. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/hartwell_fees/__init__.py +1 -0
  90. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/hartwell_fees/cli.py +33 -0
  91. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/hartwell_fees/extract.py +33 -0
  92. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/hartwell_fees/rules.py +39 -0
  93. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/legacy/feecalc.py +74 -0
  94. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/samples/accounts_2026-10.txt +10 -0
  95. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/samples/accounts_edge.txt +11 -0
  96. package/packs/dev-team/loops/modernize/evals/files/modernize-late-fee-rewrite-not-equivalent/tests/test_feecalc_smoke.py +21 -0
  97. package/packs/dev-team/loops/release/evals/eval_queries.json +10 -0
  98. package/packs/dev-team/loops/release/evals/evals.json +34 -0
  99. package/packs/dev-team/loops/release/evals/files/release-irreversible-tomorrow/0061_switch_to_haldrin_tokens.sql +22 -0
  100. package/packs/dev-team/loops/release/evals/files/release-irreversible-tomorrow/eng-notes.md +40 -0
  101. package/packs/dev-team/loops/release/evals/files/release-irreversible-tomorrow/merged-prs.md +13 -0
  102. package/packs/dev-team/loops/release/evals/files/release-saved-searches/merged-prs.md +13 -0
  103. package/packs/dev-team/loops/release/evals/files/release-saved-searches/readiness-evidence.md +27 -0
  104. package/packs/dev-team/loops/release/evals/files/release-saved-searches/traffic-baseline.md +23 -0
  105. package/packs/dev-team/skills/feature-implement-loop/manifest.json +2 -2
  106. package/packs/dev-team/skills/pr-description-writer/manifest.json +3 -3
  107. package/packs/dev-team/skills/pre-merge-review/manifest.json +2 -2
  108. package/packs/dev-team/skills/release-notes/manifest.json +2 -2
  109. package/packs/dev-team/skills/test-plan-generator/manifest.json +2 -2
  110. package/packs/experience-design/loops/clarify/LOOP.md +114 -0
  111. package/packs/experience-design/loops/clarify/evals/eval_queries.json +10 -0
  112. package/packs/experience-design/loops/clarify/evals/evals.json +68 -0
  113. package/packs/experience-design/loops/clarify/evals/files/clarify-garden-waste-no-complaint-data/form-fields.csv +12 -0
  114. package/packs/experience-design/loops/clarify/evals/files/clarify-garden-waste-no-complaint-data/garden-waste-page.md +29 -0
  115. package/packs/experience-design/loops/clarify/evals/files/clarify-parking-permit-with-call-data/backoffice-notes.md +14 -0
  116. package/packs/experience-design/loops/clarify/evals/files/clarify-parking-permit-with-call-data/calls-q3.csv +8 -0
  117. package/packs/experience-design/loops/clarify/evals/files/clarify-parking-permit-with-call-data/form-fields.csv +12 -0
  118. package/packs/experience-design/loops/clarify/evals/files/clarify-parking-permit-with-call-data/permit-page.md +27 -0
  119. package/packs/experience-design/loops/clarify/loop.json +35 -0
  120. package/packs/experience-design/skills/service-blueprint/manifest.json +3 -3
  121. package/packs/experience-design/skills/ux-writing/manifest.json +3 -3
  122. package/packs/grc/loops/comply/evals/evals.json +29 -0
  123. package/packs/grc/loops/comply/evals/files/comply-chat-vendor-launch/vendor-brief.md +72 -0
  124. package/packs/grc/loops/comply/evals/files/comply-loyalty-app-unowned-risks/launch-note.md +31 -0
  125. package/packs/grc/loops/comply/evals/files/comply-loyalty-app-unowned-risks/risk-register.csv +6 -0
  126. package/packs/infra-as-code/loops/provision/LOOP.md +128 -0
  127. package/packs/infra-as-code/loops/provision/evals/eval_queries.json +9 -0
  128. package/packs/infra-as-code/loops/provision/evals/evals.json +67 -0
  129. package/packs/infra-as-code/loops/provision/evals/files/provision-rds-no-plan-yet/.terraform.lock.hcl.fixture +24 -0
  130. package/packs/infra-as-code/loops/provision/evals/files/provision-rds-no-plan-yet/network.md +36 -0
  131. package/packs/infra-as-code/loops/provision/evals/files/provision-replica-plan-replaces-primary/main.tf +74 -0
  132. package/packs/infra-as-code/loops/provision/evals/files/provision-replica-plan-replaces-primary/plan.json +901 -0
  133. package/packs/infra-as-code/loops/provision/evals/files/provision-replica-plan-replaces-primary/variables.tf +47 -0
  134. package/packs/infra-as-code/loops/provision/loop.json +41 -0
  135. package/packs/infra-as-code/skills/terraform-module/manifest.json +3 -3
  136. package/packs/product-manager/loops/discover/evals/evals.json +28 -0
  137. package/packs/product-manager/loops/discover/evals/files/discover-no-show-signal/interview-notes.md +63 -0
  138. package/packs/product-manager/loops/discover/evals/files/discover-no-show-signal/support-tickets.csv +13 -0
  139. package/packs/product-manager/loops/discover/evals/files/discover-vp-loyalty-no-evidence/vp-message.txt +13 -0
  140. package/packs/product-manager/skills/user-journey-map/manifest.json +2 -2
  141. package/packs/research/loops/research/evals/evals.json +28 -0
  142. package/packs/research/loops/research/evals/files/research-ticket-spike-confounded/sources/t1-ticket-volume.md +15 -0
  143. package/packs/research/loops/research/evals/files/research-ticket-spike-confounded/sources/t2-release-notes-4-2.md +11 -0
  144. package/packs/research/loops/research/evals/files/research-ticket-spike-confounded/sources/t3-billing-migration.md +12 -0
  145. package/packs/research/loops/research/evals/files/research-ticket-spike-confounded/sources/t4-agent-poll.md +11 -0
  146. package/packs/research/loops/research/evals/files/research-ticket-spike-confounded/sources/t5-app-store-reviews.md +12 -0
  147. package/packs/research/loops/research/evals/files/research-trial-conversion-drop/sources/s1-analytics-export.md +29 -0
  148. package/packs/research/loops/research/evals/files/research-trial-conversion-drop/sources/s2-email-delivery-report.md +25 -0
  149. package/packs/research/loops/research/evals/files/research-trial-conversion-drop/sources/s3-pricing-changelog.md +9 -0
  150. package/packs/research/loops/research/evals/files/research-trial-conversion-drop/sources/s4-trial-interview-notes.md +21 -0
  151. package/packs/research/loops/research/evals/files/research-trial-conversion-drop/sources/s5-competitor-note.md +9 -0
  152. package/packs/research/loops/research/evals/files/research-trial-conversion-drop/sources/s6-weekly-growth-recap.md +7 -0
  153. package/packs/research/skills/research-plan/manifest.json +3 -3
  154. package/packs/research/skills/source-synthesis/manifest.json +3 -3
  155. package/packs/skill-engineering/skills/skill-author/manifest.json +3 -3
  156. package/packs/solution-architect/loops/design/evals/evals.json +28 -0
  157. package/packs/solution-architect/loops/design/evals/files/design-bulk-export/adr/0001-postgres-system-of-record.md +23 -0
  158. package/packs/solution-architect/loops/design/evals/files/design-bulk-export/adr/0002-background-work-via-job-queue.md +23 -0
  159. package/packs/solution-architect/loops/design/evals/files/design-bulk-export/adr/0003-tenant-isolation-row-level.md +25 -0
  160. package/packs/solution-architect/loops/design/evals/files/design-bulk-export/prd-bulk-export.md +50 -0
  161. package/packs/solution-architect/loops/design/evals/files/design-draft-prd-webhooks/adr/0002-background-work-via-job-queue.md +23 -0
  162. package/packs/solution-architect/loops/design/evals/files/design-draft-prd-webhooks/adr/0004-new-stateful-infra-needs-platform-signoff.md +22 -0
  163. package/packs/solution-architect/loops/design/evals/files/design-draft-prd-webhooks/prd-partner-webhooks.md +36 -0
  164. package/packs/solution-architect/skills/api-contract-draft/manifest.json +3 -3
  165. package/packs/solution-architect/skills/architecture-diagrams/manifest.json +3 -3
  166. package/packs/solution-architect/skills/design-doc/manifest.json +2 -2
  167. package/packs/solution-architect/skills/figma-diagrams/manifest.json +3 -3
  168. package/packs/sre-oncall/loops/operate/evals/evals.json +28 -0
  169. package/packs/sre-oncall/loops/operate/evals/files/operate-export-service-first-outage/alerts.log +22 -0
  170. package/packs/sre-oncall/loops/operate/evals/files/operate-export-service-first-outage/incident-chat.txt +27 -0
  171. package/packs/sre-oncall/loops/operate/evals/files/operate-export-service-first-outage/service-notes.md +46 -0
  172. package/packs/sre-oncall/loops/operate/evals/files/operate-incident-still-open/oncall-log.txt +17 -0
  173. package/packs/sre-oncall/loops/operate/evals/files/operate-incident-still-open/runbook-webhooks.md +38 -0
  174. package/packs/sre-oncall/skills/cloud-cost-review/SKILL.md +0 -1
  175. package/packs/sre-oncall/skills/cloud-cost-review/manifest.json +1 -2
  176. package/packs/sre-oncall/skills/delivery-metrics-report/SKILL.md +0 -1
  177. package/packs/sre-oncall/skills/delivery-metrics-report/manifest.json +1 -2
  178. package/packs/sre-oncall/skills/incident-comms/manifest.json +2 -2
  179. package/packs/sre-oncall/skills/postmortem-generator/manifest.json +2 -2
  180. package/packs/stakeholder-comms/skills/decision-log/manifest.json +2 -2
  181. package/packs/trackers/skills/team-status-report/manifest.json +3 -3
  182. package/packs/ai-engineering/skills/ai-usage-report/SKILL.md +0 -111
  183. package/packs/ai-engineering/skills/ai-usage-report/evals/eval_queries.json +0 -30
  184. package/packs/ai-engineering/skills/ai-usage-report/evals/evals.json +0 -46
  185. package/packs/ai-engineering/skills/ai-usage-report/evals/files/1/northwind-ai-events.csv +0 -4213
  186. package/packs/ai-engineering/skills/ai-usage-report/evals/files/2/draftwell-events.csv +0 -249
  187. package/packs/ai-engineering/skills/ai-usage-report/evals/files/2/export-note.md +0 -9
  188. package/packs/ai-engineering/skills/ai-usage-report/evals/files/2/published-assets.csv +0 -44
  189. package/packs/ai-engineering/skills/ai-usage-report/evals/files/2/team-roster.md +0 -10
  190. package/packs/ai-engineering/skills/ai-usage-report/examples/weekly-engineering-team.md +0 -133
  191. package/packs/ai-engineering/skills/ai-usage-report/manifest.json +0 -12
  192. package/packs/ai-engineering/skills/ai-usage-report/scripts/build_report.py +0 -453
  193. package/packs/ai-engineering/skills/ai-usage-report/templates/report-per-user.md +0 -42
  194. package/packs/ai-engineering/skills/ai-usage-report/templates/report-team-rollup.md +0 -49
  195. package/packs/ai-engineering/skills/ai-usage-report/templates/usage-event-schema.md +0 -76
  196. package/packs/product-manager/skills/lean-canvas/SKILL.md +0 -162
  197. package/packs/product-manager/skills/lean-canvas/evals/eval_queries.json +0 -42
  198. package/packs/product-manager/skills/lean-canvas/evals/evals.json +0 -82
  199. package/packs/product-manager/skills/lean-canvas/evals/files/1/pawpass-notes.md +0 -54
  200. package/packs/product-manager/skills/lean-canvas/evals/files/3/lunchloop-pitch.md +0 -30
  201. package/packs/product-manager/skills/lean-canvas/evals/files/4/clubkit-notes.md +0 -44
  202. package/packs/product-manager/skills/lean-canvas/evals/files/5/cost-model.csv +0 -5
  203. package/packs/product-manager/skills/lean-canvas/evals/files/5/proposal.md +0 -40
  204. package/packs/product-manager/skills/lean-canvas/evals/files/5/stakeholder-emails.txt +0 -18
  205. package/packs/product-manager/skills/lean-canvas/examples/bike-repair.md +0 -72
  206. package/packs/product-manager/skills/lean-canvas/manifest.json +0 -34
  207. package/packs/product-manager/skills/lean-canvas/reference.md +0 -102
  208. package/packs/product-manager/skills/lean-canvas/scripts/unit_economics.py +0 -211
@@ -0,0 +1,10 @@
1
+ 10000101A Okafor 48210 30S
2
+ 10000102B Marchetti 1290 3S
3
+ 10000103C Duval 233400 45S
4
+ 10000104D Nakamura 87500 21P
5
+ 10000105E Brennan 412000 120S
6
+ 10000106F Osei 310000 60P
7
+ 10000107G Halvorsen 15000 15S
8
+ 10000108H Iqbal 0 40S
9
+ 10000109I Moreau 66600 14S
10
+ 10000110J Kowalczyk 125075 95P
@@ -0,0 +1,11 @@
1
+ # edge cases collected by ops, Oct 2026
2
+ 20000201Credit Balance Ltd -2000 30S
3
+ 20000202Half Pence S 33500 30S
4
+ 20000203Half Pence P 60050 30P
5
+ 20000204Exactly Grace 99999 14S
6
+ 20000205Unknown Tier 50000 30X
7
+ 20000206Cap Then Double 300000 91P
8
+ 20000207lower case name 40000 30S
9
+ 20000208Short Line 123
10
+ 20000209Bad Balance 12a4567 30S
11
+ 20000210Exactly Ninety 400000 90S
@@ -0,0 +1,21 @@
1
+ import subprocess
2
+ import sys
3
+ import unittest
4
+ from pathlib import Path
5
+
6
+ ROOT = Path(__file__).resolve().parent.parent
7
+
8
+
9
+ class SmokeTest(unittest.TestCase):
10
+ def test_runs_and_writes_trailer(self):
11
+ out = subprocess.run(
12
+ [sys.executable, str(ROOT / "legacy" / "feecalc.py"),
13
+ str(ROOT / "samples" / "accounts_2026-10.txt"), "20261031"],
14
+ capture_output=True, text=True, check=True,
15
+ ).stdout
16
+ self.assertTrue(out.startswith("# FEERUN 20261031"))
17
+ self.assertIn("# TOTAL", out.splitlines()[-1])
18
+
19
+
20
+ if __name__ == "__main__":
21
+ unittest.main()
@@ -0,0 +1,10 @@
1
+ [
2
+ {"query": "we merged saved searches, how do we roll it out and are we ready to launch?", "should_trigger": true},
3
+ {"query": "run the release loop on this merged change", "should_trigger": true},
4
+ {"query": "plan the rollout and rollback for this migration, check readiness, then give me the go/no-go", "should_trigger": true},
5
+ {"query": "is this change ready to go live tomorrow?", "should_trigger": true},
6
+ {"query": "write release notes for v2.3 from these merged PRs", "should_trigger": false},
7
+ {"query": "plan the canary stages for this flag rollout", "should_trigger": false},
8
+ {"query": "is this PR safe to merge?", "should_trigger": false},
9
+ {"query": "we're in an incident, help me write the status update", "should_trigger": false}
10
+ ]
@@ -0,0 +1,34 @@
1
+ {
2
+ "loop_name": "release",
3
+ "evals": [
4
+ {
5
+ "id": "release-saved-searches",
6
+ "held_out": "2026-11-04",
7
+ "prompt": "Saved searches v2 is merged and deployed with the flag off. PRs are in merged-prs.md, our search traffic numbers are in traffic-baseline.md, and what we've got for readiness is in readiness-evidence.md. Can you plan how we roll it out, tell me if we're ready, draft the customer changelog entry, and set Joanna up for the go/no-go on Thursday?",
8
+ "assertions": [
9
+ "Works in loop order: the rollout plan comes first, readiness is judged against that plan, the changelog entry is drafted after the readiness verdict, and the go/no-go material comes last",
10
+ "The exposure ladder uses the cohorts the flag tool supports (140 internal staff, then the 9 design-partner workspaces, then percentages of workspaces, not of users), and each step has guardrails measured against the stated baseline (search p95 420 ms, 5xx 0.3%) with a promote, hold or roll-back rule set in advance",
11
+ "Notes that the weekly digest only runs on Mondays at 06:00 UTC, so any step meant to prove the digest must last through at least one Monday run",
12
+ "Says what turning the flag off does not undo: digest emails already sent stay sent and rows in saved_searches remain; and treats migration 0057 as additive, needing no rollback of its own",
13
+ "The readiness report has one row per check with its owner, its evidence link taken from the input and a status; it marks the digest job's missing alert and missing runbook as not met, and its verdict is PROCEED WITH CONDITIONS or REVISE, not an unconditional PROCEED",
14
+ "The changelog entry covers saved searches, the opt-in weekly digest and the page-2 pagination fix, and leaves out the internal refactor (#823) and the CI bump (#824)",
15
+ "Leaves the go/no-go to Joanna: it sets out a recommendation and what she needs to decide, and does not declare the feature live or approved",
16
+ "Does not invent metrics, owners, links or dates that are not in the input, such as a digest job baseline or an alert threshold for the digest"
17
+ ]
18
+ },
19
+ {
20
+ "id": "release-irreversible-tomorrow",
21
+ "held_out": "2026-11-04",
22
+ "prompt": "Billing provider switch is merged. merged-prs.md has the PRs, the migration is 0061_switch_to_haldrin_tokens.sql, and the team's notes are in eng-notes.md. Marketing already told customers it's live at 9am tomorrow. Write the release notes and confirm we're good to go, I just need a yes.",
23
+ "assertions": [
24
+ "Plans and judges readiness before writing release notes, instead of going straight to the notes as asked",
25
+ "Finds that migration 0061 drops legacy_card_token and card_token_map in the same deploy as the switch, names that as a point of no return, and recommends splitting it so the contract step comes after the new provider is proven",
26
+ "Explains that 'revert the deploy' is not a rollback: the reverted code needs legacy_card_token and CorvaneClient, the column and the map are gone after 0061, and the 412 unmatched cards lose their only token",
27
+ "Marks rollback, runbook, load test, Haldrin webhook alerting and on-call cover after 12:00 as not met, citing the notes, and gives a readiness verdict of REVISE or BLOCKED rather than PROCEED, despite the marketing email",
28
+ "Does not give the yes: the go/no-go is left to a person, and the agent's own recommendation is not to go as things stand",
29
+ "Any release notes drafted are marked as held until readiness passes, tell the 412 affected customers they will need to re-enter their card, and leave out the internal SDK bump (#850)",
30
+ "Does not invent facts that are not in the input: no rollback procedure presented as if it already exists, no load-test results, no owners or dates the notes don't give, and no repeat of marketing's 'faster checkout' claim, which no PR supports"
31
+ ]
32
+ }
33
+ ]
34
+ }
@@ -0,0 +1,22 @@
1
+ -- Migration 0061: switch payment_methods to Haldrin Pay tokens
2
+ -- PR #845. Runs inside the 5 Nov deploy, before the new app pods start.
3
+
4
+ BEGIN;
5
+
6
+ ALTER TABLE payment_methods ADD COLUMN provider_token text;
7
+
8
+ UPDATE payment_methods pm
9
+ SET provider_token = m.provider_token
10
+ FROM card_token_map m
11
+ WHERE m.legacy_card_token = pm.legacy_card_token;
12
+
13
+ -- Cards with no Haldrin match are marked so the app asks the customer to re-enter them.
14
+ UPDATE payment_methods
15
+ SET status = 'needs_reentry'
16
+ WHERE provider_token IS NULL;
17
+
18
+ ALTER TABLE payment_methods DROP COLUMN legacy_card_token;
19
+
20
+ DROP TABLE card_token_map;
21
+
22
+ COMMIT;
@@ -0,0 +1,40 @@
1
+ # #billing-switch — notes copied from the channel, 4 Nov 2026
2
+
3
+ **Bea Lindgren** 10:12
4
+ Token import done. 31,640 cards in payment_methods, 31,228 matched in Haldrin's file. 412 didn't match, Haldrin says they'll look into it but probably expired or Corvane didn't export them.
5
+
6
+ **Sami Haddad** 10:20
7
+ those 412 get flagged needs_reentry by 0061 so the app will prompt them
8
+
9
+ **Priya Natarajan (Eng Manager)** 11:03
10
+ what's the rollback if Haldrin charges start failing?
11
+
12
+ **Bea Lindgren** 11:05
13
+ revert the deploy I guess
14
+
15
+ **Sami Haddad** 11:06
16
+ CorvaneClient is deleted in #846 but we can revert that too
17
+
18
+ **Priya Natarajan** 11:30
19
+ runbook?
20
+
21
+ **Bea Lindgren** 11:31
22
+ TODO, will write tonight
23
+
24
+ **Sami Haddad** 13:45
25
+ haven't load-tested the Haldrin client. sandbox was fine for the ~50 test charges I ran
26
+
27
+ **Priya Natarajan** 14:02
28
+ alerts?
29
+
30
+ **Bea Lindgren** 14:04
31
+ we have the existing "charge failure rate > 5%" alert, it's provider-agnostic so should just work. nothing for Haldrin webhooks yet
32
+
33
+ **Leo Marchetti (Marketing)** 15:40
34
+ heads up, the "new faster checkout" email to all customers went out at 15:00, says live from 9am tomorrow. blog post scheduled for 09:00.
35
+
36
+ **Priya Natarajan** 15:52
37
+ ok. who's on call tomorrow morning for billing?
38
+
39
+ **Sami Haddad** 15:53
40
+ me until 12, then nobody until Bea's back on Thursday
@@ -0,0 +1,13 @@
1
+ # Tallyhall — billing provider switch (Corvane Payments -> Haldrin Pay)
2
+
3
+ Merged to main 2–4 Nov 2026. Not deployed yet. Planned deploy: 5 Nov, 07:00 UTC.
4
+
5
+ | PR | Title | Author | Notes |
6
+ |---|---|---|---|
7
+ | #840 | Haldrin Pay client and webhook handler | Bea Lindgren | Replaces `CorvaneClient` in `billing/charge.py`. No flag; the switch happens on deploy. |
8
+ | #842 | Token import: load Haldrin token map | Bea Lindgren | Loads Haldrin's import file into `card_token_map (legacy_card_token, provider_token)`. Ran against production on 3 Nov. |
9
+ | #845 | Migration 0061: switch payment_methods to Haldrin tokens | Bea Lindgren | See `0061_switch_to_haldrin_tokens.sql`. Runs as part of the 5 Nov deploy. |
10
+ | #846 | Remove `CorvaneClient` and Corvane webhook route | Sami Haddad | Deletes the old client code. |
11
+ | #848 | Billing settings: show "Powered by Haldrin Pay" and new card form | Sami Haddad | User-visible. New card form uses Haldrin's hosted fields. |
12
+ | #849 | Fix: invoice PDF showed card brand in lowercase | Sami Haddad | User-visible, small. |
13
+ | #850 | Bump `haldrin-sdk` to 3.2.0 | deps bot | Internal. |
@@ -0,0 +1,13 @@
1
+ # Tallyhall — merged to main for "saved searches v2" (release train 2026.45)
2
+
3
+ All merged between 26 Oct and 3 Nov 2026. Deployed to production on 3 Nov with flag `saved_searches_v2` OFF for everyone.
4
+
5
+ | PR | Title | Author | Notes |
6
+ |---|---|---|---|
7
+ | #812 | Add `saved_searches` table (migration 0057) | Rui Tanaka | New table only: `id, workspace_id, user_id, name, query_json, notify_weekly, created_at, updated_at`. No changes to existing tables. Ran in production on 3 Nov, 0.4s. |
8
+ | #815 | Saved searches API: `POST/GET/DELETE /api/v2/saved-searches` | Rui Tanaka | Behind `saved_searches_v2`. Max 50 saved searches per user (returns 422 above that). |
9
+ | #819 | Saved searches in the sidebar | Elif Demir | Behind `saved_searches_v2`. Save the current search from the search bar; rename; delete. |
10
+ | #821 | Weekly email digest of new matches for a saved search | Elif Demir | Behind `saved_searches_v2`. Opt-in per saved search (`notify_weekly`). New job `saved-search-digest` runs Mondays 06:00 UTC. |
11
+ | #823 | Refactor: extract `QueryBuilder` from `SearchController` | Rui Tanaka | Internal. No behaviour change. |
12
+ | #824 | CI: bump Node to 22 in build image | Platform bot | Internal. |
13
+ | #826 | Fix: search results skipped the 51st result when moving to page 2 | Kofi Mensah | Not flagged. Live since the 3 Nov deploy. |
@@ -0,0 +1,27 @@
1
+ # Saved searches v2 — what we have for readiness
2
+
3
+ Collected by Elif Demir (tech lead), 4 Nov 2026. Go/no-go meeting Thursday 6 Nov; decider is Joanna Price (Director of Engineering).
4
+
5
+ ## Rollback
6
+ - Turning `saved_searches_v2` off hides the sidebar, returns 404 from the API and stops the digest job from sending. Tested in staging on 31 Oct. Owner: Elif. Evidence: https://wiki.example/eng/saved-searches/flag-off-test
7
+ - Migration 0057 only adds a table. Nothing reads it with the flag off.
8
+
9
+ ## Monitoring and alerts
10
+ - Dashboard: https://grafana.example/d/saved-searches (API latency, error rate, saves per hour).
11
+ - Alert: saved-searches API 5xx > 1% for 10 min pages the Search on-call. https://alerts.example/rules/saved-search-5xx
12
+ - Digest job `saved-search-digest`: no alert yet. If it fails, nobody would know until users say they didn't get the email. Elif: "on my list".
13
+
14
+ ## Runbooks
15
+ - API: https://wiki.example/runbooks/saved-searches-api (owner: Rui).
16
+ - Digest job: none yet.
17
+
18
+ ## Performance
19
+ - Load test 30 Oct: `POST /api/v2/saved-searches` p95 180 ms at 3x expected peak; `GET` p95 95 ms. https://wiki.example/eng/saved-searches/loadtest-2026-10-30
20
+ - Digest job not load-tested. In staging it took 4 min for 2,000 saved searches.
21
+
22
+ ## Privacy
23
+ - Saved query text can include customer names and email addresses. Privacy review PRIV-88 approved 30 Oct 2026 by Marta Varga (DPO), on condition that saved searches are deleted when the user is deleted. Deletion hook merged in #815. https://wiki.example/privacy/PRIV-88
24
+
25
+ ## Support and comms
26
+ - Support macro drafted and reviewed by Support lead (Owen Fitzgerald). https://wiki.example/support/macros/saved-searches
27
+ - Customer changelog entry: not written yet.
@@ -0,0 +1,23 @@
1
+ # Search traffic baseline (last 28 days, to 2 Nov 2026)
2
+
3
+ Source: https://grafana.example/d/search-overview (pulled by Kofi, 3 Nov)
4
+
5
+ | Metric | Value |
6
+ |---|---|
7
+ | Weekly active users (all of Tallyhall) | ~18,000 |
8
+ | Daily users who run at least one search | ~2,600 (weekdays); ~400 (weekends) |
9
+ | Searches per day | ~31,000 (weekdays) |
10
+ | Search API p95 latency | 420 ms |
11
+ | Search API p99 latency | 1.1 s |
12
+ | Search API 5xx rate | 0.3% |
13
+ | Searches repeated by the same user within 7 days (same query text) | 38% |
14
+
15
+ ## Cohorts available for flag targeting
16
+
17
+ | Cohort | Size |
18
+ |---|---|
19
+ | Internal staff (Tallyhall workspace) | 140 users |
20
+ | Design partners (opted in to early access) | 9 workspaces, ~600 users |
21
+ | Everyone else | percentage rollout by workspace ID |
22
+
23
+ Flag tool supports targeting by cohort and by percentage of workspaces. It does not support percentage of users within a workspace.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feature-implement-loop",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Implement a feature or story so it ends up *verified*, not just generated. Takes a description + acceptance criteria, writes code and tests, then runs an adversarial review pass that hunts for gaps (broken edge cases, baked-in assumptions, uncovered acceptance criteria), and re-generates to close them — looping until the review is clean or a 3-round cap is hit. Use when handed a ticket / story / feature spec with acceptance criteria and the goal is shippable, self-checked code — not a first draft.",
5
5
  "entrypoint": "SKILL.md",
6
6
  "deps": { "npm": [], "pip": [] },
@@ -10,5 +10,5 @@
10
10
  { "to": "pre-merge-review", "when": "the code exists and the question is whether it can merge", "purpose": "Judge the diff that now exists against a mechanical gate.", "fallback": "If pre-merge-review is absent, run the repo's own lint and tests and honour the exit code; do not self-certify." }
11
11
  ],
12
12
  "tags": ["dev-workflow", "implementation", "tdd", "acceptance-criteria", "adversarial", "self-correcting", "code-generation"],
13
- "model": { "tier": "standard", "rationale": "Code + test generation against acceptance criteria. The adversarial pass delegates to devils-advocate (heavy) where available; the loop itself is generation." }
13
+ "model": { "tier": "light", "rationale": "Measured (RFC-0073): on its held-out evals the light tier met 85% and 85% of checks in two tier trials, against standard's 85% and heavy's 76% and 85%, within 5 points of the best both times." }
14
14
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pr-description-writer",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Write the pull request title and description for one change, from the actual diff and commits: what changed and why, how it was tested with only the checks that were really run, what a reviewer should look at first, and the risk and rollback. It also reports what the diff contains that the commits don't mention, such as a dependency bump, a deleted test or a schema change. Use when the user asks to write a PR description, a pull request summary, a merge request body, or says \"describe this change for review\", \"write up this branch\".",
5
5
  "entrypoint": "SKILL.md",
6
6
  "deps": {
@@ -24,7 +24,7 @@
24
24
  "merge-request"
25
25
  ],
26
26
  "model": {
27
- "tier": "standard",
28
- "rationale": "Reads a diff and rewrites it for a reviewer. Bounded by the diff; the judgment is in picking what a reviewer needs first."
27
+ "tier": "light",
28
+ "rationale": "Measured (RFC-0073): on its held-out evals the light tier met 85% and 85% of checks in two tier trials, against standard's 85% and heavy's 77% and 85%, within 5 points of the best both times."
29
29
  }
30
30
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pre-merge-review",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Gate an existing change for merge — run one skill that fires the whole production-readiness pass. First a deterministic mechanical gate (lint + typecheck + tests, via a script whose exit code decides), then the three-reviewer panel dispatched in parallel — devils-advocate (correctness), security-reviewer (exploitability), code-quality (craft) — then a single READY / NOT READY verdict. Use before opening a PR or merging, when you want the full review fleet run on a diff you already have. Do NOT use to implement a feature from a spec (that's feature-implement-loop) or to review a document (that's doc-critique).",
5
5
  "entrypoint": "SKILL.md",
6
6
  "deps": { "npm": [], "pip": [] },
@@ -11,5 +11,5 @@
11
11
  ],
12
12
  "tags": ["dev-workflow", "code-review", "pre-merge", "quality-gate", "subagents", "production-readiness"],
13
13
  "permissions": {"network": [], "commands": ["git", "ruff", "mypy", "pytest", "*"], "files": "project", "notes": "Runs the lint, typecheck and test commands configured for the project, through a shell, by design. --install-hook writes a git pre-commit hook in the repository."},
14
- "model": { "tier": "standard", "rationale": "Coordination: runs a deterministic gate script, dispatches the (heavy) reviewer subagents, and renders a rule-based go/no-go. The adversarial reasoning is delegated to the panel, so the skill itself is orchestration, not deep judgment." }
14
+ "model": { "tier": "light", "rationale": "Measured (RFC-0073): on its held-out evals the light tier met 93% and 93% of checks in two tier trials, against standard's 86% and heavy's 93% and 93%, within 5 points of the best both times." }
15
15
  }
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "release-notes",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Write release notes from a git log, a list of merged PRs or rough notes about what changed — for the audience and in the format the user names (a customer changelog page, an email, an in-app \"what's new\", store text, a CHANGELOG.md entry). Says nothing the input doesn't, writes a vague change only as far as it was described, puts breaking changes and anything the reader must do first, and keeps internal noise and working notes out of the text. Use when the user wants release notes, a changelog entry, \"what's in this release\", a deploy announcement, or to summarise changes since the last tag.",
5
5
  "entrypoint": "SKILL.md",
6
6
  "deps": { "npm": [], "pip": [] },
7
7
  "env": { "required": [], "optional": [] },
8
8
  "related": ["devils-advocate", "exec-summary", "pr-description-writer", "sonar-review"],
9
9
  "tags": ["release-notes", "changelog", "git", "release", "deploy", "communication"],
10
- "model": { "tier": "standard", "rationale": "Reads a range for what really shipped and rewrites it for one reader. The audience translation needs judgment; escalate via large-input on very long ranges." }
10
+ "model": { "tier": "light", "rationale": "Measured (RFC-0073): on its held-out evals the light tier met 96% and 96% of checks in two tier trials, against standard's 91% and heavy's 100% and 98%, within 5 points of the best both times." }
11
11
  }
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "test-plan-generator",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Generate a risk-based test plan for a feature, PR, or release — risks ranked by likelihood × impact, test cases pushed to the lowest pyramid level that catches the failure, every acceptance criterion mapped to a test, and an explicit \"not tested\" list. Use when the user asks for a test plan, test cases, a QA strategy for a change, \"how should we test this\", or pre-release test coverage.",
5
5
  "entrypoint": "SKILL.md",
6
6
  "deps": { "npm": [], "pip": [] },
7
7
  "env": { "required": [], "optional": [] },
8
8
  "related": ["devils-advocate", "feature-implement-loop", "sonar-review", "user-story-splitter"],
9
9
  "tags": ["testing", "test-plan", "qa", "risk-based", "test-cases", "quality"],
10
- "model": { "tier": "standard", "rationale": "Synthesizes a structured plan from a change description. Risk ranking needs judgment but is bounded; escalate via ambiguous-input on contested or high-stakes releases." }
10
+ "model": { "tier": "light", "rationale": "Measured (RFC-0073): on its held-out evals the light tier met 76% and 92% of checks in two tier trials, against standard's 76% and heavy's 61% and 54%, within 5 points of the best both times." }
11
11
  }
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: clarify
3
+ description: Take a service people struggle with from its page to the service behind it: a content spec and plain-language rewrite from what users need, every string on the form or flow, and a service blueprint that tests whether those fixes reach the fail points behind the complaints, with a gate that sends the work back to the page when it misses a fail point and out to product when the fix is backstage. Use when the user says "people can't use this service", "fix this page and form", "why do we keep getting these calls", "run the clarify loop", or has a confusing page, form and complaints about the service behind it.
4
+ ---
5
+
6
+ # clarify
7
+
8
+ One service, from the words people read to the work behind them. A clearer page stops the calls
9
+ that come from confusion and none of the calls that come from a wait or a lost handoff. The
10
+ content spec and the strings fix the words. Then the blueprint traces each complaint to the cell
11
+ that causes it. That shows which complaints the new words reach and which need the service
12
+ itself to change. Neither writing skill can judge that about its own output.
13
+
14
+ ## Stages
15
+
16
+ | # | Stage | Type | Skills | Gate |
17
+ |---|---|---|---|---|
18
+ | 1 | `page` | generate | [`content-design`](../../skills/content-design/SKILL.md) | — |
19
+ | 2 | `strings` | generate | [`ux-writing`](../../skills/ux-writing/SKILL.md) | — |
20
+ | 3 | `blueprint` | verify | [`service-blueprint`](../../skills/service-blueprint/SKILL.md) | **G14** review |
21
+
22
+ ## How to run this loop
23
+
24
+ 1. **List the complaints first.** From the calls, tickets, survey answers or anything else the
25
+ person brought, write `complaints.md`: each kind of complaint, how often if known, and one
26
+ quote. Every later stage reads it. Without complaints, the loop checks the words against
27
+ nothing.
28
+ 2. **Write the page.** Run `content-design` on the current page, with the complaints as
29
+ evidence of what users need to know. The questions the page must answer come from the
30
+ complaints first. Save the spec and rewrite as `page.md`, with the readability before and
31
+ after.
32
+ 3. **Write the strings.** Run `ux-writing` on the form or flow, using the terms the content spec
33
+ chose, so the page and the form call the same thing by the same name. Save the string table
34
+ as `strings.md`.
35
+ 4. **Blueprint the service.** Run `service-blueprint` on the scenario the complaints describe,
36
+ from the page through to the outcome the person is waiting for. Trace every complaint in
37
+ `complaints.md` to the cell that causes it. Then mark each complaint as reached by the page,
38
+ reached by the strings, or caused backstage. Save it as `blueprint.md`.
39
+ 5. **Judge the fixes at G14.** Ask three questions, then choose the verdict below:
40
+ - Is every complaint caused by the words reached by a specific line in `page.md` or
41
+ `strings.md`?
42
+ - Which complaints are caused backstage, and does the page at least tell people what
43
+ happens and how long it takes?
44
+ - Do the page, the strings and the blueprint use the same names for the same things?
45
+ 6. **On `REVISE`, fix the words for the missed complaint.** Return to `page` with the complaint
46
+ and the cell that causes it. Then re-run `strings` when the change touches the form. Each
47
+ return counts against the cap.
48
+ 7. **Hand over what changes and what can't change here.** Lead with the complaints the new page
49
+ and form should stop, and the ones they can't, with the backstage fix and its owner. The
50
+ page, the strings and the blueprint go underneath. Close with the gate on its own line,
51
+ `G14: <VERDICT>`, and one sentence of reasons.
52
+
53
+ ## Verdicts
54
+
55
+ Defined in [`contracts/terminals.json`](../../../../contracts/terminals.json). G14 emits:
56
+
57
+ - `PROCEED`: every complaint caused by the words is reached by a named line, the names match
58
+ across all three, and no complaint is caused backstage.
59
+ - `PROCEED WITH CONDITIONS`: the words are right, but some complaints are caused backstage.
60
+ The page says what happens and how long it takes, and each backstage fix travels with its
61
+ owner as a condition.
62
+ - `REVISE`: a complaint caused by the words is reached by no line, or the page and form name
63
+ the same thing differently. Return to `page`.
64
+ - `RECONSIDER`: most of the complaints are caused backstage, so new words won't move them. The
65
+ fix is a change to the service, so the work goes to product as a requirement, with the
66
+ blueprint's ranked fixes, and the loop ends here.
67
+ - `BLOCKED`: no service or scenario can be identified, or there is no current page or form.
68
+
69
+ On the cap-th `REVISE`, emit `PROCEED WITH CONDITIONS` with the missed complaint named as open.
70
+
71
+ ## Non-interactive runs
72
+
73
+ A missing reader or voice degrades to the skills' `[assumption]` lines. With no complaints at
74
+ all, tag the loop's output `[no complaint evidence]` and judge G14 on the blueprint's fail
75
+ points alone. With no service or scenario, `service-blueprint` emits
76
+ `BLOCKED: need the service and one customer scenario`; carry it through as the verdict.
77
+
78
+ ## When a stage's skill is not installed
79
+
80
+ Name the missing skill and skilldrop as its source, do the minimal inline version of that
81
+ stage, and record that it ran degraded. A degraded `blueprint` still traces every complaint to
82
+ a frontstage, backstage or support cause, because G14 can't be judged without that trace.
83
+ Never skip G14.
84
+
85
+ ## Run log (opt-in)
86
+
87
+ Only when the environment variable `SKILLDROP_LOOP_LOG` is set to a file path: after each
88
+ gate's verdict, append one JSON line to that file. Nothing else is recorded, and nothing is
89
+ sent anywhere. When the variable isn't set, or you can't read it, skip this section.
90
+
91
+ ```bash
92
+ printf '%s\n' '{"ts":"2026-11-03T10:15:00Z","loop":"clarify","stage":"blueprint","gate":"G14","verdict":"REVISE","round":1}' >> "$SKILLDROP_LOOP_LOG"
93
+ ```
94
+
95
+ Fields: `ts` (UTC), `loop`, `stage`, `gate` (`null` for a stage without one), `verdict` (the
96
+ gate's exact word), and `round` (1 for the first attempt, counting returns under the cap).
97
+ The log holds verdicts only: never the page, the complaints or the quotes.
98
+ `skilldrop loop-stats` summarises the file.
99
+
100
+ ## Quality bar
101
+
102
+ - **The complaints are written down before any rewrite.** Every later stage is judged against them.
103
+ - **Every complaint is traced to the cell that causes it,** and marked as reached by the page, reached by the strings, or caused backstage.
104
+ - **The page and the form use the same name for the same thing,** and the blueprint uses it too.
105
+ - **A backstage cause is named with its owner,** never written around with friendlier words.
106
+ - **The reply says which complaints the new words can't stop.**
107
+
108
+ ## Anti-patterns to avoid
109
+
110
+ - ❌ **Rewriting the page from a style guide instead of the complaints.** The page reads better and the same calls keep coming.
111
+ - ❌ **Fixing a wait with reassuring copy.** "We're working on it" doesn't shorten a five-week wait; say how long it takes, and send the wait to its owner.
112
+ - ❌ **Writing the strings before the page.** The form then names things one way and the page another.
113
+ - ❌ **Passing G14 because readability improved.** A lower grade level is not a complaint reached.
114
+ - ❌ **Treating `RECONSIDER` as failure.** Finding that the service, not the page, causes the calls is the result.
@@ -0,0 +1,10 @@
1
+ [
2
+ {"query": "people can't use our permit service: fix the page and the form and find out why they keep calling", "should_trigger": true},
3
+ {"query": "run the clarify loop on the benefits application journey", "should_trigger": true},
4
+ {"query": "we keep getting 'where is my order' calls, rewrite the help page and check whether that will even fix it", "should_trigger": true},
5
+ {"query": "fix this page and form, here are last quarter's complaints", "should_trigger": true},
6
+ {"query": "rewrite this page in plain English", "should_trigger": false},
7
+ {"query": "write the error messages for our signup form", "should_trigger": false},
8
+ {"query": "build a service blueprint of our claims process", "should_trigger": false},
9
+ {"query": "reorganise our help centre navigation", "should_trigger": false}
10
+ ]
@@ -0,0 +1,68 @@
1
+ {
2
+ "loop_name": "clarify",
3
+ "evals": [
4
+ {
5
+ "id": "words-and-backstage-split",
6
+ "prompt": "Run the clarify loop on Ashby Vale Council's parking permit service. The current page:\n\n\"Residents' Parking Permits. Eligibility for a residents' parking permit (RPP) is determined in accordance with the Traffic Management Order applicable to your zone. Applicants must furnish proof of residency (see Schedule 2) and vehicle registration documentation. Applications are processed within the statutory timeframe. Permits are issued digitally; no paper permit will be displayed.\"\n\nThe form asks for 'RPP zone', 'V5C reference' and 'Proof type (Sched. 2)'. Last quarter's calls: 412 'where is my permit', 188 'which documents count as proof', 97 'do I need to put anything in my windscreen', 60 'what zone am I in'. The team says applications sit in a shared inbox until someone checks documents, which takes 2 to 15 working days; nobody emails the applicant when the permit is live. Non-interactive: no follow-up questions.",
7
+ "assertions": [
8
+ "Writes down the four complaint types with their counts before rewriting anything",
9
+ "The content spec's questions come from the complaints: proof documents, zone, nothing in the windscreen, and how long it takes",
10
+ "The form strings use the same terms the page chose, and replace 'RPP zone', 'V5C reference' and 'Proof type (Sched. 2)' with plain words",
11
+ "The blueprint traces 'where is my permit' to the shared-inbox wait and the missing confirmation email, both backstage",
12
+ "Marks each complaint as reached by the page, reached by the strings, or caused backstage",
13
+ "Gives G14 PROCEED WITH CONDITIONS or RECONSIDER, not PROCEED, because the biggest complaint is caused backstage, and names the backstage fix with an owner role",
14
+ "The page tells applicants how long processing takes, using the 2 to 15 working days the team gave",
15
+ "Does not invent a processing time, owner name or statistic the prompt did not give"
16
+ ]
17
+ },
18
+ {
19
+ "id": "missed-complaint-sends-it-back",
20
+ "prompt": "Continuing the clarify loop. The blueprint traced 188 calls a quarter ('which documents count as proof') to the page, but the new page.md still just says 'Upload proof that you live at this address' with no list of what counts. Everything else lined up. What's the G14 verdict and what happens next?",
21
+ "assertions": [
22
+ "Gives G14 REVISE because a complaint caused by the words is reached by no line",
23
+ "Returns to page with that complaint, not to the blueprint",
24
+ "Says the strings stage re-runs if the change touches the form's proof upload field",
25
+ "Counts the next attempt as round 2 under the cap of 3",
26
+ "Does not invent the list of accepted documents; marks it for the team to supply if the input doesn't give it"
27
+ ]
28
+ },
29
+ {
30
+ "id": "blocked-without-a-service",
31
+ "prompt": "Run the clarify loop. Our users are confused. Non-interactive, no follow-up questions.",
32
+ "assertions": [
33
+ "Emits BLOCKED naming what is missing: the service, one customer scenario, and the current page or form",
34
+ "Does not invent a service, page or complaints",
35
+ "Does not produce a content spec, strings or blueprint",
36
+ "Says in plain words what it will produce once it has them"
37
+ ]
38
+ },
39
+ {
40
+ "id": "clarify-parking-permit-with-call-data",
41
+ "held_out": "2026-11-03",
42
+ "prompt": "People can't use our resident parking permit service and the phones never stop. The current page is permit-page.md, the form is form-fields.csv, last quarter's call reasons are in calls-q3.csv and I sat with the permits team and wrote up how it works behind the scenes (backoffice-notes.md). Run the clarify loop, I want to know what we can fix on the page and what we can't.",
43
+ "assertions": [
44
+ "Runs content design, then UX writing, then the service blueprint, then gate G14, and the string table reuses the content spec's terms (one name for proof of address, and 'registration number' or similar rather than 'VRM')",
45
+ "The content spec builds its user needs from the call reasons, lists the questions the page must answer in priority order, gives a plain-language rewrite of permit-page.md with a before/after readability check, and lists what to cut and why",
46
+ "The string table covers every field in form-fields.csv, and each error says what happened and what to do next, including the 4 MB limit and accepted formats on uploads and how to enter a registration number",
47
+ "The blueprint places each of the seven call reasons at a step and layer, marking as fail points with owners the Tuesday/Thursday evidence batches, Friday printing and second-class post, the 4 MB platform cap, the no-spaces registration check, and the double charge after pressing Back on a timed-out payment",
48
+ "Gate G14 sends 'Where is my permit' (batching and post) and 'Charged twice' out to product as backstage fixes, naming the Digital Services manager for the payment fault, rather than claiming the copy fixes them; the page may still set an honest expectation from the 13-working-day average",
49
+ "Any page-fixable fail point the first pass misses (such as the unlinked postcode zone lookup, the accepted and rejected proofs of address, or the 50-a-year visitor permit allowance) sends the work back to the page with a REVISE verdict, and the final mapping shows every page-fixable fail point covered",
50
+ "Does not invent call volumes, timescales, prices, rules or owners not in the inputs"
51
+ ]
52
+ },
53
+ {
54
+ "id": "clarify-garden-waste-no-complaint-data",
55
+ "held_out": "2026-11-03",
56
+ "prompt": "People can't use our garden waste subscription page and sign-up form, everyone says so. Page is garden-waste-page.md, form fields are in form-fields.csv. I don't have any call data, the contact centre won't share it until next quarter, so just fix it with what's there.",
57
+ "assertions": [
58
+ "Runs content design, then UX writing, then the service blueprint, in that order, and still produces a content spec, plain-language rewrite and string table from the page and form",
59
+ "Says plainly that no complaint or call data was supplied, and labels the user needs and fail points it draws from the page and form as assumptions to test",
60
+ "The blueprint marks its fail points as hypotheses (for example, where to find the bin serial number, how long the permit sticker takes to arrive, the full-year charge for a late start) rather than as confirmed complaint drivers",
61
+ "Gate G14 does not report a pass on evidence it lacks: the verdict is PROCEED WITH CONDITIONS or NOT READY, naming the contact centre's call reasons as what is needed to confirm the fixes reach the fail points",
62
+ "The string table covers every field in form-fields.csv, and each error says what happened and what to do next",
63
+ "Delivers the work in this reply rather than stopping to ask for the call data",
64
+ "Does not invent call volumes or complaint themes presented as fact, or service details not on the page such as sticker delivery times, bin delivery times or collection days"
65
+ ]
66
+ }
67
+ ]
68
+ }
@@ -0,0 +1,12 @@
1
+ step,field,label,hint,error_message,rules
2
+ 1,postcode,Postcode,,Invalid,Required; UK postcode format
3
+ 1,address,Address,,Please select,Required; picked from postcode lookup
4
+ 2,bins_required,Number of bins,,Invalid,Required; 1 to 3
5
+ 2,existing_bin,Do you have an existing brown bin?,,Please answer,Required; Yes or No
6
+ 2,bin_serial,Bin serial number,,Serial number not recognised,Required if existing_bin = Yes; 8 digits
7
+ 3,start_date,Start date,DD/MM/YYYY,Invalid date,Required; between 1 March and 30 November
8
+ 3,email,Email address,,Invalid,Required
9
+ 3,phone,Telephone,,Invalid,Optional
10
+ 4,terms,I accept the terms and conditions,,You must accept,Required checkbox; links to terms page
11
+ 5,pay,Pay now,,Payment failed,Card only
12
+ 6,confirmation,Thank you,Your subscription reference is {ref}.,,Shown after payment
@@ -0,0 +1,29 @@
1
+ # Garden Waste Collection Service
2
+
3
+ *Ashcombe Vale Council: ashcombevale.example/bins/garden-waste*
4
+
5
+ The Council provides a chargeable garden waste collection service to households within the district, in accordance with the Environmental Protection Act 1990 and the Council's Waste Collection Policy. Participation in the scheme is voluntary and subject to the terms and conditions set out below.
6
+
7
+ ## Subscription
8
+
9
+ Subscriptions run from 1 March to 30 November inclusive and are payable annually. The annual charge is £52 per bin. Households may subscribe for up to three bins. Subscriptions taken out part-way through the year are charged at the full annual rate. Subscriptions are non-transferable and non-refundable.
10
+
11
+ ## Collections
12
+
13
+ Collections are made fortnightly on the household's scheduled collection day. Please refer to your collection calendar. Collections are suspended from December to February.
14
+
15
+ ## Bins and permits
16
+
17
+ New subscribers will be supplied with a brown wheeled bin, subject to availability. Existing bin holders must quote the serial number of their bin when subscribing. A permit sticker will be dispatched and must be affixed to the bin before collections can commence. Bins not displaying a valid permit sticker will not be emptied.
18
+
19
+ ## Acceptable materials
20
+
21
+ Grass cuttings, hedge trimmings, leaves, flowers, weeds and small branches. Not accepted: soil, rubble, food waste, plastic bags, pet waste, Japanese knotweed.
22
+
23
+ ## Renewal
24
+
25
+ Subscribers will be invited to renew in February each year. Failure to renew by the stated date will result in the suspension of collections.
26
+
27
+ ## Terms and conditions
28
+
29
+ By subscribing, the householder agrees to the terms and conditions of the scheme, which may be varied by the Council from time to time.
@@ -0,0 +1,14 @@
1
+ # Parking Services back office: how a resident permit gets issued
2
+
3
+ Notes from a walk-through with the permits team lead, October 2026.
4
+
5
+ 1. Applications from the online form land in a shared inbox queue. Two permit officers work it.
6
+ 2. Evidence is checked by hand, in batches, on Tuesdays and Thursdays. Anything that arrives on a Friday waits until Tuesday.
7
+ 3. Proof of address we accept: current year council tax bill; tenancy agreement with at least 6 months left to run; utility bill dated within the last 3 months. We do not accept bank statements or mobile phone bills. About a third of applications send one of these and get returned by email.
8
+ 4. Approved permits are printed on Fridays and posted second class. Permits are paper and go in the windscreen.
9
+ 5. Average time from application to permit arriving: 13 working days. The council's target is 10.
10
+ 6. The form platform caps uploads at 4 MB per file; that is a platform setting the permits team can't change. Phone photos are often 5 to 8 MB.
11
+ 7. The registration field rejects spaces. Most people type their registration with a space (as it appears on the number plate) and get "Invalid input".
12
+ 8. Zones: a postcode zone lookup exists at brindlemoor.example/parking/zones but the permit page doesn't link to it.
13
+ 9. Visitor permits: each household can buy up to 50 one-day visitor permits a year, £2.50 each. This isn't written down anywhere public.
14
+ 10. Payment: if the payment page times out and the resident presses Back and pays again, they are charged twice. Finance refunds within 10 working days. A ticket with the form platform supplier has been open since May 2026. The product owner for the form platform is the Digital Services manager.
@@ -0,0 +1,8 @@
1
+ call_reason,calls_jul,calls_aug,calls_sep
2
+ Where is my permit,171,184,183
3
+ Unsure what proof of address to send,129,141,142
4
+ Upload rejected or file too large,88,97,102
5
+ Don't know which zone I live in,64,70,69
6
+ Vehicle registration not accepted,45,51,48
7
+ Visitor permits: how many can I buy,40,38,44
8
+ Charged twice,18,22,21
@@ -0,0 +1,12 @@
1
+ step,field,label,hint,error_message,rules
2
+ 1,postcode,Postcode,,Invalid input,Required; UK postcode format
3
+ 1,address,Select address,,Please select,Required; picked from postcode lookup
4
+ 2,vrm,VRM,,Invalid input,Required; letters and digits only; no spaces allowed; max 7 characters
5
+ 2,vehicle_make,Make,,Invalid input,Required
6
+ 2,keeper,Are you the registered keeper?,,Please answer,Required; Yes or No
7
+ 3,proof_of_residency,Upload satisfactory evidence of residency,,Upload failed,Required; JPG PNG or PDF; max 4 MB per file
8
+ 3,proof_of_vehicle,Upload vehicle registration document or lease agreement,,Upload failed,Required; JPG PNG or PDF; max 4 MB per file
9
+ 4,permit_start,Commencement date,DD/MM/YYYY,Invalid date,Required; today or later; no more than 30 days ahead
10
+ 4,email,Email,,Invalid input,Required; valid email address
11
+ 5,pay,Proceed,,Transaction error,Opens payment page; times out after 10 minutes
12
+ 6,confirmation,Application received,Your reference is {ref}.,,Shown after payment