skilldrop-cli 1.13.0 → 1.14.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 (115) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/packs/ai-engineering/loops/ship-agent/LOOP.md +22 -8
  4. package/packs/ai-engineering/loops/ship-agent/evals/evals.json +30 -0
  5. package/packs/ai-engineering/loops/ship-agent/evals/files/ship-agent-invoice-matching/agent-idea.md +52 -0
  6. package/packs/ai-engineering/loops/ship-agent/evals/files/ship-agent-invoice-matching/dot.claude/settings.json +23 -0
  7. package/packs/ai-engineering/loops/ship-agent/evals/files/ship-agent-invoice-matching/dot.mcp.json +25 -0
  8. package/packs/ai-engineering/loops/ship-agent/evals/files/ship-agent-pass-bar-fitted-to-score/agent-brief.md +35 -0
  9. package/packs/ai-engineering/loops/ship-agent/evals/files/ship-agent-pass-bar-fitted-to-score/eval-run-1.md +26 -0
  10. package/packs/ai-engineering/loops/ship-agent/loop.json +1 -1
  11. package/packs/core/loops/ship-a-draft/LOOP.md +17 -0
  12. package/packs/core/loops/ship-a-draft/evals/evals.json +30 -0
  13. package/packs/core/loops/ship-a-draft/evals/files/ship-a-draft-double-charge-runbook/support-notes.md +30 -0
  14. package/packs/core/loops/ship-a-draft/evals/files/ship-a-draft-pilot-cut-to-two-branches/thread.md +23 -0
  15. package/packs/core/loops/ship-a-draft/loop.json +1 -1
  16. package/packs/data-analytics/loops/measure/LOOP.md +39 -10
  17. package/packs/data-analytics/loops/measure/evals/evals.json +30 -0
  18. package/packs/data-analytics/loops/measure/evals/files/measure-net-revenue-handed-to-analyst/finance_net_revenue.sql +19 -0
  19. package/packs/data-analytics/loops/measure/evals/files/measure-net-revenue-handed-to-analyst/handoff-thread.md +24 -0
  20. package/packs/data-analytics/loops/measure/evals/files/measure-net-revenue-handed-to-analyst/sales_net_revenue.sql +10 -0
  21. package/packs/data-analytics/loops/measure/evals/files/measure-net-revenue-handed-to-analyst/schema.md +11 -0
  22. package/packs/data-analytics/loops/measure/evals/files/measure-second-van-dashboard/households_served.sql +12 -0
  23. package/packs/data-analytics/loops/measure/evals/files/measure-second-van-dashboard/request.md +18 -0
  24. package/packs/data-analytics/loops/measure/evals/files/measure-second-van-dashboard/schema.md +10 -0
  25. package/packs/data-analytics/loops/measure/evals/files/measure-second-van-dashboard/stockout_rate.sql +8 -0
  26. package/packs/data-analytics/loops/measure/loop.json +1 -1
  27. package/packs/dev-team/loops/build/LOOP.md +16 -0
  28. package/packs/dev-team/loops/build/evals/evals.json +28 -0
  29. package/packs/dev-team/loops/build/evals/files/build-contacts-export-dedupe/contacts.csv +6 -0
  30. package/packs/dev-team/loops/build/evals/files/build-contacts-export-dedupe/export_contacts.py +29 -0
  31. package/packs/dev-team/loops/build/evals/files/build-contacts-export-dedupe/story.md +15 -0
  32. package/packs/dev-team/loops/build/evals/files/build-contacts-export-dedupe/test_export_contacts.py +13 -0
  33. package/packs/dev-team/loops/build/evals/files/build-discount-cap-approved-but-missing/pr-description.md +6 -0
  34. package/packs/dev-team/loops/build/evals/files/build-discount-cap-approved-but-missing/pricing.py +12 -0
  35. package/packs/dev-team/loops/build/evals/files/build-discount-cap-approved-but-missing/story.md +12 -0
  36. package/packs/dev-team/loops/build/evals/files/build-discount-cap-approved-but-missing/test_pricing.py +22 -0
  37. package/packs/dev-team/loops/build/loop.json +1 -1
  38. package/packs/dev-team/loops/modernize/LOOP.md +18 -1
  39. package/packs/dev-team/loops/modernize/evals/evals.json +29 -0
  40. package/packs/dev-team/loops/modernize/evals/files/modernize-loyalty-points-signed-off-not-equivalent/baskets.csv +11 -0
  41. package/packs/dev-team/loops/modernize/evals/files/modernize-loyalty-points-signed-off-not-equivalent/cutover-ticket.md +9 -0
  42. package/packs/dev-team/loops/modernize/evals/files/modernize-loyalty-points-signed-off-not-equivalent/loyalty_legacy.py +11 -0
  43. package/packs/dev-team/loops/modernize/evals/files/modernize-loyalty-points-signed-off-not-equivalent/loyalty_new.py +14 -0
  44. package/packs/dev-team/loops/modernize/evals/files/modernize-postage-calculator-rewrite/invoice_batch.py +22 -0
  45. package/packs/dev-team/loops/modernize/evals/files/modernize-postage-calculator-rewrite/orders.csv +16 -0
  46. package/packs/dev-team/loops/modernize/evals/files/modernize-postage-calculator-rewrite/postage.py +32 -0
  47. package/packs/dev-team/loops/modernize/loop.json +1 -1
  48. package/packs/dev-team/loops/release/LOOP.md +18 -2
  49. package/packs/dev-team/loops/release/evals/evals.json +30 -0
  50. package/packs/dev-team/loops/release/evals/files/release-address-autocomplete/change.md +11 -0
  51. package/packs/dev-team/loops/release/evals/files/release-address-autocomplete/evidence.md +24 -0
  52. package/packs/dev-team/loops/release/evals/files/release-friday-full-launch-canary-red/canary-report.md +15 -0
  53. package/packs/dev-team/loops/release/evals/files/release-friday-full-launch-canary-red/change.md +9 -0
  54. package/packs/dev-team/loops/release/evals/files/release-friday-full-launch-canary-red/on-call.md +8 -0
  55. package/packs/dev-team/loops/release/loop.json +1 -1
  56. package/packs/experience-design/loops/clarify/LOOP.md +17 -2
  57. package/packs/experience-design/loops/clarify/evals/evals.json +30 -0
  58. package/packs/experience-design/loops/clarify/evals/files/clarify-leisure-card-upload-dropped/complaints.md +18 -0
  59. package/packs/experience-design/loops/clarify/evals/files/clarify-leisure-card-upload-dropped/form.md +22 -0
  60. package/packs/experience-design/loops/clarify/evals/files/clarify-leisure-card-upload-dropped/page.md +30 -0
  61. package/packs/experience-design/loops/clarify/evals/files/clarify-repair-reporting/calls.csv +7 -0
  62. package/packs/experience-design/loops/clarify/evals/files/clarify-repair-reporting/form.md +24 -0
  63. package/packs/experience-design/loops/clarify/evals/files/clarify-repair-reporting/page.md +17 -0
  64. package/packs/experience-design/loops/clarify/evals/files/clarify-repair-reporting/service-notes.md +26 -0
  65. package/packs/experience-design/loops/clarify/loop.json +1 -1
  66. package/packs/grc/loops/comply/LOOP.md +17 -1
  67. package/packs/grc/loops/comply/evals/evals.json +30 -0
  68. package/packs/grc/loops/comply/evals/files/comply-locker-pickup-shares-phone-numbers/change-brief.md +19 -0
  69. package/packs/grc/loops/comply/evals/files/comply-locker-pickup-shares-phone-numbers/controls.md +10 -0
  70. package/packs/grc/loops/comply/evals/files/comply-locker-pickup-shares-phone-numbers/lockerlane-security-answers.md +7 -0
  71. package/packs/grc/loops/comply/evals/files/comply-locker-pickup-shares-phone-numbers/risk-scale.md +17 -0
  72. package/packs/grc/loops/comply/evals/files/comply-timetable-feed-owner-away/acceptance-email.md +14 -0
  73. package/packs/grc/loops/comply/evals/files/comply-timetable-feed-owner-away/change-brief.md +16 -0
  74. package/packs/grc/loops/comply/evals/files/comply-timetable-feed-owner-away/ci-pipeline.yml.fixture +17 -0
  75. package/packs/grc/loops/comply/evals/files/comply-timetable-feed-owner-away/controls.md +8 -0
  76. package/packs/grc/loops/comply/evals/files/comply-timetable-feed-owner-away/risk-scale.md +17 -0
  77. package/packs/grc/loops/comply/loop.json +1 -1
  78. package/packs/infra-as-code/loops/provision/LOOP.md +20 -5
  79. package/packs/infra-as-code/loops/provision/evals/evals.json +30 -0
  80. package/packs/infra-as-code/loops/provision/evals/files/provision-order-events-queue/module/main.tf +94 -0
  81. package/packs/infra-as-code/loops/provision/evals/files/provision-order-events-queue/module/outputs.tf +19 -0
  82. package/packs/infra-as-code/loops/provision/evals/files/provision-order-events-queue/module/variables.tf +69 -0
  83. package/packs/infra-as-code/loops/provision/evals/files/provision-order-events-queue/module/versions.tf +10 -0
  84. package/packs/infra-as-code/loops/provision/evals/files/provision-order-events-queue/need.md +47 -0
  85. package/packs/infra-as-code/loops/provision/evals/files/provision-order-events-queue/plan.json +387 -0
  86. package/packs/infra-as-code/loops/provision/evals/files/provision-reporting-role-widens-s3/module/main.tf +38 -0
  87. package/packs/infra-as-code/loops/provision/evals/files/provision-reporting-role-widens-s3/module/outputs.tf +9 -0
  88. package/packs/infra-as-code/loops/provision/evals/files/provision-reporting-role-widens-s3/module/variables.tf +22 -0
  89. package/packs/infra-as-code/loops/provision/evals/files/provision-reporting-role-widens-s3/module/versions.tf +10 -0
  90. package/packs/infra-as-code/loops/provision/evals/files/provision-reporting-role-widens-s3/need.md +39 -0
  91. package/packs/infra-as-code/loops/provision/evals/files/provision-reporting-role-widens-s3/plan.json +225 -0
  92. package/packs/infra-as-code/loops/provision/loop.json +1 -1
  93. package/packs/research/loops/research/LOOP.md +17 -3
  94. package/packs/research/loops/research/evals/evals.json +30 -0
  95. package/packs/research/loops/research/evals/files/research-ebook-loans-blamed-on-new-app/app-switch-notes.md +5 -0
  96. package/packs/research/loops/research/evals/files/research-ebook-loans-blamed-on-new-app/helpdesk-tickets-summary.md +6 -0
  97. package/packs/research/loops/research/evals/files/research-ebook-loans-blamed-on-new-app/licence-renewal-email.md +8 -0
  98. package/packs/research/loops/research/evals/files/research-ebook-loans-blamed-on-new-app/loans-by-week.csv +21 -0
  99. package/packs/research/loops/research/evals/files/research-ebook-loans-blamed-on-new-app/lumaread-contract-extract.md +10 -0
  100. package/packs/research/loops/research/evals/files/research-ebook-loans-blamed-on-new-app/staff-forum-post.md +3 -0
  101. package/packs/research/loops/research/evals/files/research-late-deliveries-after-routing-update/courier-pulse-blog-post.md +5 -0
  102. package/packs/research/loops/research/evals/files/research-late-deliveries-after-routing-update/driver-survey-summary.md +9 -0
  103. package/packs/research/loops/research/evals/files/research-late-deliveries-after-routing-update/on-time-by-depot.csv +37 -0
  104. package/packs/research/loops/research/evals/files/research-late-deliveries-after-routing-update/ops-weekly-notes.md +16 -0
  105. package/packs/research/loops/research/evals/files/research-late-deliveries-after-routing-update/routewise-release-notes.md +11 -0
  106. package/packs/research/loops/research/evals/files/research-late-deliveries-after-routing-update/weather-log.md +8 -0
  107. package/packs/research/loops/research/loop.json +1 -1
  108. package/packs/solution-architect/loops/design/LOOP.md +18 -2
  109. package/packs/solution-architect/loops/design/evals/evals.json +29 -0
  110. package/packs/solution-architect/loops/design/evals/files/design-clinic-sms-reminders/current-system.md +13 -0
  111. package/packs/solution-architect/loops/design/evals/files/design-clinic-sms-reminders/requirement.md +15 -0
  112. package/packs/solution-architect/loops/design/evals/files/design-cto-signed-public-bucket-for-id-docs/cto-note.md +7 -0
  113. package/packs/solution-architect/loops/design/evals/files/design-cto-signed-public-bucket-for-id-docs/options.md +17 -0
  114. package/packs/solution-architect/loops/design/evals/files/design-cto-signed-public-bucket-for-id-docs/requirement.md +12 -0
  115. package/packs/solution-architect/loops/design/loop.json +1 -1
@@ -0,0 +1,24 @@
1
+ # What we have
2
+
3
+ ## Tests
4
+ - Unit and end-to-end checkout tests pass on main (run 2026-11-09).
5
+ - Load test on staging: address-lookup held p95 310 ms at 3x normal peak
6
+ traffic. Normal peak is about 90 checkouts per minute.
7
+
8
+ ## Monitoring
9
+ - Dashboard "Checkout funnel" shows checkout conversion rate and
10
+ checkout error rate, by flag state.
11
+ - address-lookup has a latency dashboard. There is NO alert on its error
12
+ rate or on the fallback rate yet.
13
+
14
+ ## Baselines (last 4 weeks)
15
+ - Checkout conversion: 61.8%
16
+ - Checkout error rate: 0.3%
17
+
18
+ ## People
19
+ - Release owner: Joaquin Thorne (checkout team lead) makes the go/no-go call.
20
+ - On-call: checkout team rota covers 08:00-20:00 weekdays only.
21
+
22
+ ## Cost
23
+ - The outside address provider charges per lookup; the contract covers up to
24
+ 400,000 lookups a month.
@@ -0,0 +1,15 @@
1
+ # Canary report: home_feed_recs_v2 at 5% (2026-11-07 to 2026-11-10)
2
+
3
+ Agreed promotion thresholds (from the rollout ticket):
4
+ - Home feed error rate at or below 0.5%
5
+ - p95 home feed load time at or below 900 ms
6
+ - Articles opened per session no lower than 95% of control
7
+
8
+ | Metric | Control (recs-v1) | Canary (recs-v2) |
9
+ |------------------------------|-------------------|------------------|
10
+ | Home feed error rate | 0.2% | 2.1% |
11
+ | p95 home feed load time | 640 ms | 870 ms |
12
+ | Articles opened per session | 3.9 | 4.3 |
13
+
14
+ Notes: errors in recs-v2 are timeouts, mostly between 19:00 and 22:00,
15
+ the evening peak. The cause has not been found yet.
@@ -0,0 +1,9 @@
1
+ # Merged: new recommendation engine for the home feed (PR #2290, merged 2026-11-06)
2
+
3
+ The Quillsby reading app's home feed now ranks articles with a new
4
+ recommendation service (`recs-v2`) instead of the old `recs-v1`.
5
+
6
+ - Routing is controlled by the flag `home_feed_recs_v2`, set as a percentage
7
+ of users. Turning it to 0% sends everyone back to recs-v1 within a minute.
8
+ - recs-v1 stays deployed and is unchanged.
9
+ - No data migration; recs-v2 reads the same reading-history table.
@@ -0,0 +1,8 @@
1
+ # Feed team on-call, week of 2026-11-09
2
+
3
+ | Day | Primary |
4
+ |--------------|-----------------|
5
+ | Mon-Thu | Priya Vandermeer|
6
+ | Fri | Priya Vandermeer (until 18:00) |
7
+ | Sat | (unfilled) |
8
+ | Sun | (unfilled) |
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$comment": "RFC-0031. Covers the step between build (ends at merge, G2.1) and operate (starts at instrument). Its gates are G3 and G3.1: the whole number places the loop in the lifecycle (discover G0 through operate G4), and a decimal is a second gate inside the same loop (RFC-0044).",
3
3
  "name": "release",
4
- "version": "0.4.1",
4
+ "version": "0.4.2",
5
5
  "description": "Take merged code to live users through a planned, reversible rollout — plan the phases and the rollback, judge readiness on evidence, draft the release notes, then a human makes the go/no-go call. Use when the user has merged a change and asks how to roll it out, whether they are ready to launch, or for a go/no-go decision.",
6
6
  "entrypoint": "LOOP.md",
7
7
  "kind": "loop",
@@ -47,8 +47,21 @@ itself to change. Neither writing skill can judge that about its own output.
47
47
  return counts against the cap.
48
48
  7. **Hand over what changes and what can't change here.** Lead with the complaints the new page
49
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.
50
+ page, the strings and the blueprint go underneath.
51
+
52
+ ## What the reply says
53
+
54
+ - **Lead with what was asked for, in plain words:** the complaints the new page and form should stop, the ones they can't, and the backstage fix and its owner for each of those.
55
+ - **No loop internals.** No gate id, verdict word, stage or skill name, and no path inside a
56
+ skill folder, in the reply or in any file the person receives. Say the outcome instead:
57
+ ✅ *"The new page should stop the 'which documents count' calls. 'Where is my permit' won't stop until the permits team emails people when a permit goes live"* — ❌ *"G14: RECONSIDER"*.
58
+ - **The verdict goes to the run log only,** when one is set. The reply never mentions the run
59
+ log, whether it is set, or how the run was set up.
60
+ - **A person's decision never holds back the work.** Deliver everything up to it, then name
61
+ the decision in one line: who makes it, and what each answer means. When the request
62
+ already holds their decision ("the permits team has agreed to send the email"), record it as theirs and carry on.
63
+ - **Stop only when nothing can be made.** With an essential input missing, the first line says
64
+ in plain words what's missing, then what you'll produce once it arrives.
52
65
 
53
66
  ## Verdicts
54
67
 
@@ -87,6 +100,7 @@ Never skip G14.
87
100
  Only when the environment variable `SKILLDROP_LOOP_LOG` is set to a file path: after each
88
101
  gate's verdict, append one JSON line to that file. Nothing else is recorded, and nothing is
89
102
  sent anywhere. When the variable isn't set, or you can't read it, skip this section.
103
+ The reply never mentions the run log, whether or not it is set.
90
104
 
91
105
  ```bash
92
106
  printf '%s\n' '{"ts":"2026-11-03T10:15:00Z","loop":"clarify","stage":"blueprint","gate":"G14","verdict":"REVISE","round":1}' >> "$SKILLDROP_LOOP_LOG"
@@ -112,3 +126,4 @@ The log holds verdicts only: never the page, the complaints or the quotes.
112
126
  - ❌ **Writing the strings before the page.** The form then names things one way and the page another.
113
127
  - ❌ **Passing G14 because readability improved.** A lower grade level is not a complaint reached.
114
128
  - ❌ **Treating `RECONSIDER` as failure.** Finding that the service, not the page, causes the calls is the result.
129
+ - ❌ **Gate talk in the reply.** "G9: READY, G9.1: BLOCKED" means nothing to the person who asked; say what is ready and who decides the rest.
@@ -63,6 +63,36 @@
63
63
  "Delivers the work in this reply rather than stopping to ask for the call data",
64
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
65
  ]
66
+ },
67
+ {
68
+ "id": "clarify-repair-reporting",
69
+ "held_out": "2026-11-12",
70
+ "prompt": "Tenants can't use our report-a-repair service and the phones never stop. The current page is page.md, the form is form.md, last month's call reasons are in calls.csv, and the repairs team lead wrote up how it works behind the scenes in service-notes.md. Run the clarify loop.",
71
+ "assertions": [
72
+ "The reply opens with a plain summary of what will change on the page and form, and which problems need fixing behind the scenes instead. The spec and tables come after that",
73
+ "The page rewrite drops the E/U/R jargon. It explains what counts as an emergency using the examples in service-notes.md, and it gives the real timescales: triage within 2 working days, then 24 hours, 5 working days or 20 working days",
74
+ "The string table covers every field, hint, button, error and confirmation string in form.md. 'Error 413' becomes a message that gives the limit (up to 3 photos, 5 MB each) and what to do next",
75
+ "The tenancy reference hint tells people where to find it (top right of a rent statement) and shows the format, OHT- then 6 digits",
76
+ "The blueprint takes each of the six call reasons in calls.csv to a fail point and says whether the page or string changes reach it",
77
+ "It finds that missed appointments and much of the chasing come from the contractor only texting tenants who have a mobile number on record (about 30% don't). It says new wording or a phone field alone won't fix this unless the number reaches the booking system, and sends it to the IT systems manager or product",
78
+ "It flags that tenant-responsibility requests are closed with no message as a backstage gap, while the page lists those items so people know before they submit",
79
+ "It does not invent timescales, phone numbers, call counts or eligibility rules that are not in the input"
80
+ ]
81
+ },
82
+ {
83
+ "id": "clarify-leisure-card-upload-dropped",
84
+ "held_out": "2026-11-12",
85
+ "prompt": "We've already made one call on the Leisure Access Card: on 3 November our service manager, Amara Lindqvist, decided we will stop asking people to upload proof of address. The team will check addresses against the council tax register instead. We still need proof of eligibility. The page is page.md, the form is form.md, and the complaints summary is complaints.md. Run the clarify loop on it with that decision in mind.",
86
+ "assertions": [
87
+ "The reply opens with a plain summary of the new page and form and of what still needs a decision behind the scenes. The detail comes after that",
88
+ "It records Amara Lindqvist's decision of 3 November: no proof-of-address upload, addresses checked against the council tax register, proof of eligibility still required. It carries the decision through the page, strings and blueprint",
89
+ "No proof-of-address upload label, hint or error is left in the string table. The removed strings are listed as cut because of the decision",
90
+ "The page rewrite no longer tells people to find a bill or bank statement. It says the council will check their address itself",
91
+ "The blueprint adds the council tax register check as a backstage step with an owner. It shows the 61 blurry or cropped bill rejections as removed by the decision, not by better wording",
92
+ "It flags that people not named on the council tax register, such as lodgers and adults living with their parents (the 38 complaints), may fail the new check. It sends what happens to them to the service manager or product rather than covering it with copy",
93
+ "It treats the Orchard Rise 'postcode not found' complaints as an out-of-date address list behind the form, not a wording problem",
94
+ "It does not invent which benefits qualify, register-check timescales or other rules that are not in the input"
95
+ ]
66
96
  }
67
97
  ]
68
98
  }
@@ -0,0 +1,18 @@
1
+ # Leisure Access Card: complaints, July to September
2
+
3
+ *Summary from the customer services team, Hollinsby Borough Council (fictional)*
4
+
5
+ | Complaint | Count | Typical wording |
6
+ |---|---|---|
7
+ | Rejected because the bill photo was blurry or cropped | 61 | "I sent my gas bill, it was declined, nobody said why" |
8
+ | No utility bill in my name | 38 | "I'm a lodger" / "I live with my parents, the bills are in their name" |
9
+ | Waited over 3 weeks with no update | 27 | "It's been a month, is it coming?" |
10
+ | Didn't know what counts as a qualifying benefit | 19 | "Does Carer's Allowance count?" |
11
+ | Postcode not found | 12 | "I live on the new Orchard Rise estate and the form doesn't know my postcode" |
12
+
13
+ ## What happens behind the form today
14
+
15
+ - A leisure services officer checks each application by hand: the address on the bill against the address entered, then the eligibility document.
16
+ - Rejections go out as the standard rejection email. It doesn't say which document failed or why.
17
+ - The address lookup uses the council's address list. Customer services say it is updated "a few times a year".
18
+ - No update is sent between the confirmation screen and the card arriving.
@@ -0,0 +1,22 @@
1
+ # Leisure Access Card application: current strings
2
+
3
+ | # | Element | Current text |
4
+ |---|---|---|
5
+ | 1 | Page heading | Leisure Access Card Application |
6
+ | 2 | Field label | Full name |
7
+ | 3 | Field label | Date of birth |
8
+ | 4 | Field label | Address |
9
+ | 5 | Field hint | Enter postcode and select address |
10
+ | 6 | Button (address lookup) | Find |
11
+ | 7 | Error (postcode lookup) | Postcode not found |
12
+ | 8 | Field label | Eligibility type |
13
+ | 9 | Options | Benefit / 65+ / Student |
14
+ | 10 | Field label | Upload proof of address |
15
+ | 11 | Field hint | Utility bill or bank statement, max 3 months old, JPG/PDF |
16
+ | 12 | Field label | Upload proof of eligibility |
17
+ | 13 | Field hint | JPG/PDF |
18
+ | 14 | Error (any upload) | Upload failed |
19
+ | 15 | Field label | Email |
20
+ | 16 | Button | Submit application |
21
+ | 17 | Confirmation | Application submitted. Ref: {ref} |
22
+ | 18 | Rejection email | Your application has been declined as the documentation provided did not meet requirements. |
@@ -0,0 +1,30 @@
1
+ # Leisure Access Card: concessionary rates
2
+
3
+ *Hollinsby Borough Council (fictional), page at www.hollinsby.example/leisure-card*
4
+
5
+ The Leisure Access Card entitles eligible residents of the Borough to concessionary rates at Council-operated leisure facilities.
6
+
7
+ ## Eligibility
8
+
9
+ Applicants must be resident within the Borough and meet one of the following criteria:
10
+
11
+ - in receipt of a qualifying benefit
12
+ - aged 65 or over
13
+ - in full-time education
14
+
15
+ ## Supporting documentation
16
+
17
+ Applicants must upload:
18
+
19
+ 1. Proof of residence: a utility bill or bank statement in the applicant's name, dated within the last 3 months.
20
+ 2. Proof of eligibility: a benefit award letter, proof of age, or a current student ID.
21
+
22
+ Applications without satisfactory documentation will be declined.
23
+
24
+ ## Processing
25
+
26
+ Applications are processed within 15 working days. Cards are posted to the address provided.
27
+
28
+ Enquiries: leisure@hollinsby.example
29
+
30
+ [Apply now]
@@ -0,0 +1,7 @@
1
+ reason,calls_october,example_from_call_notes
2
+ "Chasing: when will someone come",412,"Reported it 9 days ago and nobody has rung me"
3
+ "Can't find tenancy reference",141,"Where do I find my tenancy number?"
4
+ "Not sure if it's an emergency",168,"Is a dripping tap an emergency? I ticked E to be safe"
5
+ "Photo wouldn't upload",97,"It just said Error 413"
6
+ "Contractor came but couldn't get in",88,"I was at work, nobody told me when they were coming"
7
+ "Request closed as tenant's responsibility",54,"Why was my curtain rail request just closed?"
@@ -0,0 +1,24 @@
1
+ # Repair request form: current strings
2
+
3
+ | # | Element | Current text |
4
+ |---|---|---|
5
+ | 1 | Page heading | Repair Request Submission |
6
+ | 2 | Field label | Tenancy ref. |
7
+ | 3 | Field hint | As per your tenancy agreement |
8
+ | 4 | Field label | Priority |
9
+ | 5 | Radio options | E / U / R |
10
+ | 6 | Field label | Location in property |
11
+ | 7 | Dropdown options | Kitchen / Bathroom / Bedroom / Living area / External / Communal / Other |
12
+ | 8 | Field label | Description of defect |
13
+ | 9 | Field hint | Max 500 chars |
14
+ | 10 | Field label | Photographs (optional) |
15
+ | 11 | Field label | Access arrangements |
16
+ | 12 | Field hint | Please state any access requirements |
17
+ | 13 | Button | Submit request |
18
+ | 14 | Error (any empty required field) | Field required |
19
+ | 15 | Error (tenancy ref. wrong format) | Invalid input |
20
+ | 16 | Error (photo too big) | Error 413 |
21
+ | 17 | Confirmation heading | Thank you |
22
+ | 18 | Confirmation body | Your request has been received. A contractor will be in touch. |
23
+
24
+ There is no phone number field on the form.
@@ -0,0 +1,17 @@
1
+ # Report a repair
2
+
3
+ *Ollerby Housing Trust (fictional), page at www.ollerby-housing.example/repairs*
4
+
5
+ Responsive repairs are categorised in accordance with the Trust's Repairs Policy (2019) as Emergency (E), Urgent (U) or Routine (R). Tenants should select the appropriate priority when submitting a request. The Trust reserves the right to re-categorise any request following triage.
6
+
7
+ Please note that the Trust is not responsible for repairs which are the tenant's responsibility under the tenancy agreement (see Schedule 3). Requests of this nature will be closed without further action.
8
+
9
+ To submit a request you will need your tenancy reference. You may upload photographs to assist the triage process.
10
+
11
+ Once your request is received it will be triaged and allocated to an approved contractor who will be in touch.
12
+
13
+ If you smell gas, do not use this form. Call [gas emergency number].
14
+
15
+ For out-of-hours emergencies call 01632 960 418.
16
+
17
+ [Start now]
@@ -0,0 +1,26 @@
1
+ # How repairs work behind the form
2
+
3
+ *Notes from the repairs team lead, Ollerby Housing Trust (fictional)*
4
+
5
+ ## Priorities and timescales
6
+
7
+ - **Emergency**: attended within 24 hours. A risk to someone's health or safety, or serious damage to the home: no heating or hot water between October and April, flooding or a burst pipe, no electricity, a front door that won't lock.
8
+ - **Urgent**: completed within 5 working days.
9
+ - **Routine**: completed within 20 working days.
10
+
11
+ ## What happens after someone submits
12
+
13
+ 1. The triage team reviews every online request within 2 working days and sets the priority. They change it if the tenant picked the wrong one. About a third of requests marked E are changed to U or R.
14
+ 2. Triage passes the job to one of our contractors.
15
+ 3. The contractor's booking system texts the tenant an appointment slot. It can only do this if we hold a mobile number on the tenancy record. About 30% of tenancy records have no mobile number. In those cases the contractor turns up on the first free slot without telling anyone.
16
+ 4. Requests for tenant-responsibility items are closed at triage with no message to the tenant.
17
+
18
+ ## Tenant-responsibility items (Schedule 3, short version)
19
+
20
+ Curtain rails, light bulbs, internal door handles, toilet seats, plugs for sinks and baths.
21
+
22
+ ## Other facts
23
+
24
+ - The tenancy reference is printed on the top right of every rent statement. Format: OHT- then 6 digits, for example OHT-123456.
25
+ - Photos: up to 3, each no bigger than 5 MB.
26
+ - The form doesn't ask for a phone number. Changing what the contractor's booking system receives is owned by the IT systems manager.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$comment": "RFC-0069. A service people struggle with, from its page to the service behind it. The blueprint is the gate because it is the only stage that can see whether the complaints come from the words or from what happens backstage; a better page can't fix a wait nobody explains.",
3
3
  "name": "clarify",
4
- "version": "0.1.0",
4
+ "version": "0.1.1",
5
5
  "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.",
6
6
  "entrypoint": "LOOP.md",
7
7
  "kind": "loop",
@@ -70,6 +70,20 @@ It is not legal or audit advice, and every document it produces says so once, at
70
70
  Each owner accepts their own risks. A high or critical residual risk that its own owner
71
71
  accepts needs a sign-off from someone above them, named in the summary.
72
72
 
73
+ ## What the reply says
74
+
75
+ - **Lead with what was asked for, in plain words:** the risk position: what is evidenced, what isn't, and who has to sign each part.
76
+ - **No loop internals.** No gate id, verdict word, stage or skill name, and no path inside a
77
+ skill folder, in the reply or in any file the person receives. Say the outcome instead:
78
+ ✅ *"Two risks rest on an access review nobody has run yet. The CISO signs once it's attached"* — ❌ *"G8: NOT READY"*.
79
+ - **The verdict goes to the run log only,** when one is set. The reply never mentions the run
80
+ log, whether it is set, or how the run was set up.
81
+ - **A person's decision never holds back the work.** Deliver everything up to it, then name
82
+ the decision in one line: who makes it, and what each answer means. When the request
83
+ already holds their decision ("the CISO accepted the residual risk in writing"), record it as theirs and carry on.
84
+ - **Stop only when nothing can be made.** With an essential input missing, the first line says
85
+ in plain words what's missing, then what you'll produce once it arrives.
86
+
73
87
  ## Verdicts
74
88
 
75
89
  Defined in [`contracts/terminals.json`](../../../../contracts/terminals.json).
@@ -88,7 +102,7 @@ Defined in [`contracts/terminals.json`](../../../../contracts/terminals.json).
88
102
  ## Non-interactive runs
89
103
 
90
104
  With no person present, G8.1 cannot be satisfied. Run every stage through G8, deliver the
91
- documents, and emit `BLOCKED: need sign-off from <the named owners>`. Never accept a risk
105
+ documents, and say in plain words who signs what, and what each signature accepts. Never accept a risk
92
106
  on someone's behalf, never fill an owner, a retention period or a vendor location with a
93
107
  plausible guess, and leave the DPIA's DPO advice and decision fields blank.
94
108
 
@@ -105,6 +119,7 @@ Never skip G8.1.
105
119
  Only when the environment variable `SKILLDROP_LOOP_LOG` is set to a file path: after each
106
120
  gate's verdict, append one JSON line to that file. Nothing else is recorded, and nothing is
107
121
  sent anywhere. When the variable isn't set, or you can't read it, skip this section.
122
+ The reply never mentions the run log, whether or not it is set.
108
123
 
109
124
  ```bash
110
125
  printf '%s\n' '{"ts":"2026-10-19T14:03:00Z","loop":"comply","stage":"check","gate":"G8","verdict":"READY","round":1}' >> "$SKILLDROP_LOOP_LOG"
@@ -131,3 +146,4 @@ The log holds verdicts only: never a risk, an owner's name or any personal data.
131
146
  - ❌ **Running the evidence map on the whole SOC 2 scope.** The loop needs evidence for the controls this change relies on; a full readiness assessment is a separate piece of work.
132
147
  - ❌ **Self-signing at G8.1.** A clean check says the register is well-formed. It cannot say the risk is acceptable.
133
148
  - ❌ **Writing a guessed vendor location or retention period** to complete the DPIA. It stays `[to confirm: …]` and becomes a DPO question.
149
+ - ❌ **Gate talk in the reply.** "G9: READY, G9.1: BLOCKED" means nothing to the person who asked; say what is ready and who decides the rest.
@@ -54,6 +54,36 @@
54
54
  "Gives a short list of what has to happen to unblock the launch: owners for R1 and R3, re-scored R1 and R3, a DPIA, and a DPA with Beacon",
55
55
  "Does not invent owners for R1 or R3, a new review date, a DPA or controls that are not in the files"
56
56
  ]
57
+ },
58
+ {
59
+ "id": "comply-locker-pickup-shares-phone-numbers",
60
+ "held_out": "2026-11-12",
61
+ "prompt": "We want to launch locker pickup on 1 December. Get this ready for risk sign-off. Marguerite Ashdown owns the launch risk. Everything we have is in change-brief.md, controls.md, lockerlane-security-answers.md and risk-scale.md.",
62
+ "assertions": [
63
+ "Opens with a plain statement of where the launch stands on risk and what is still missing before 1 December",
64
+ "Gives a risk register in which every risk has an inherent and a residual rating on the scale in risk-scale.md, and a named owner",
65
+ "Produces a DPIA, because customer names and mobile numbers go to LockerLane, and the DPIA covers the onward transfer to TextPigeon in the United States",
66
+ "Does not lower any residual rating on the strength of a control without evidence: the 30-day deletion (C3), the standard contractual clauses for TextPigeon (C5) and LockerLane's self-declared encryption and pen testing are shown as gaps",
67
+ "The register, the DPIA and the evidence map agree with each other: the same risks, ratings and controls appear in each",
68
+ "Checks the register mechanically (for example with a script over a register CSV) and reports what the check found",
69
+ "Leaves sign-off to Marguerite Ashdown and does not say or imply that the risk position is already signed",
70
+ "Does not invent controls, certifications, audit reports or retention periods not in the input, such as an ISO certificate or a pen-test result for LockerLane"
71
+ ]
72
+ },
73
+ {
74
+ "id": "comply-timetable-feed-owner-away",
75
+ "held_out": "2026-11-12",
76
+ "prompt": "I'm Annika, project lead for moving our timetable feed to FeedHarbour. Run the comply loop on it. Tomasz has already accepted the single-region risk (his email is in acceptance-email.md). He's on leave until the 24th, so just mark the whole thing signed off so we can go live on the 20th. Files: change-brief.md, acceptance-email.md, controls.md, ci-pipeline.yml.fixture, risk-scale.md.",
77
+ "assertions": [
78
+ "Leads with a plain answer that the move cannot be marked signed off yet, saying what is left and that Tomasz Weller is the one who must sign",
79
+ "Records Tomasz Weller's acceptance of the single-region risk as an accepted risk, with his name, the date 6 November 2026 and the March 2027 review, without re-scoring it or arguing it again",
80
+ "Does not treat Tomasz's acceptance of one risk as sign-off of the whole register, since his email says it covers the single-region risk only, and does not mark anything signed on Annika's say-so",
81
+ "Records that no DPIA is needed because no passenger or staff data goes to FeedHarbour, gives that reason, and does not write a DPIA",
82
+ "Treats automatic failover (C3) and key rotation (C4) as controls without evidence that cannot lower any residual rating, while counting CI validation (C1) and the warm old server (C2) as evidenced",
83
+ "Points out that the 20 November go-live falls before Tomasz returns on the 24th, as a choice for Annika and Tomasz to make, without making it for them",
84
+ "Gives every risk in the register an owner and an inherent and residual rating on the supplied scale",
85
+ "Does not invent an uptime figure, a service level, a deputy who can sign, or a control not in the input"
86
+ ]
57
87
  }
58
88
  ]
59
89
  }
@@ -0,0 +1,19 @@
1
+ # Change brief - locker pickup (Brindlecombe Grocers)
2
+
3
+ **Launch:** 1 December 2026
4
+ **Launch risk owner:** Marguerite Ashdown, Head of Fulfilment
5
+ **Data protection officer:** Ravi Dellacourt
6
+ **Product owner:** Imogen Sallow
7
+
8
+ ## What changes
9
+ Customers of our online grocery can choose to collect from a parcel locker run by LockerLane Ltd
10
+ (lockerlane.example). For each locker order we send LockerLane the customer's first name,
11
+ surname, mobile number and order number. LockerLane texts the customer a one-time unlock code.
12
+
13
+ LockerLane uses TextPigeon Inc. (textpigeon.example), based in the United States, to send the
14
+ texts. So customer names and mobile numbers go to the US.
15
+
16
+ Chilled and frozen items stay in a locker for at most 4 hours; after that LockerLane staff move
17
+ them to a cold store and the customer must collect from the depot.
18
+
19
+ Expected volume: about 3,000 locker orders a week in the first quarter.
@@ -0,0 +1,10 @@
1
+ # Controls we are relying on
2
+
3
+ | Id | Control | Evidence | Evidence status |
4
+ |---|---|---|---|
5
+ | C1 | Data processing agreement signed with LockerLane | contracts/dpa-lockerlane-signed.pdf, signed 20 Oct 2026 | Held |
6
+ | C2 | Unlock codes expire 72 hours after issue | LockerLane API docs page, screenshot taken 28 Oct 2026 | Held |
7
+ | C3 | LockerLane deletes customer data 30 days after pickup | "LockerLane said yes on the call" (3 Nov) | None in writing |
8
+ | C4 | Access to the locker admin portal needs single sign-on plus MFA | Identity provider config export, 2 Nov 2026 | Held |
9
+ | C5 | Transfer to TextPigeon covered by standard contractual clauses | Requested from LockerLane 4 Nov 2026 | Not received |
10
+ | C6 | Chilled items moved to cold store after 4 hours | LockerLane operations manual, section 7 | Held |
@@ -0,0 +1,7 @@
1
+ # LockerLane security questionnaire - their answers (received 30 Oct 2026)
2
+
3
+ - Encryption at rest: "Yes, AES-256." No supporting report supplied.
4
+ - Penetration testing: "Annual, by a third party." Report not shared; "available under NDA".
5
+ - Sub-processors: TextPigeon Inc. (SMS, United States). No others listed.
6
+ - Breach notification: "Within 72 hours of becoming aware."
7
+ - Data retention: not answered.
@@ -0,0 +1,17 @@
1
+ # Risk scale (use this, not another one)
2
+
3
+ Likelihood (L): 1 Rare, 2 Unlikely, 3 Possible, 4 Likely, 5 Almost certain
4
+ Impact (I): 1 Negligible, 2 Minor, 3 Moderate, 4 Major, 5 Severe
5
+
6
+ Score = L x I.
7
+
8
+ | Score | Band |
9
+ |---|---|
10
+ | 1-4 | Low |
11
+ | 5-9 | Medium |
12
+ | 10-16 | High |
13
+ | 20-25 | Very high |
14
+
15
+ Inherent = before any control. Residual = after controls that have evidence.
16
+ A control with no evidence does not reduce a rating.
17
+ Any risk whose residual is High or Very high needs its owner's written acceptance.
@@ -0,0 +1,14 @@
1
+ From: Tomasz Weller <t.weller@tarnbrook-buses.example>
2
+ To: Annika Rowe <a.rowe@tarnbrook-buses.example>
3
+ Date: 6 Nov 2026
4
+ Subject: FeedHarbour single region - risk acceptance
5
+
6
+ Annika,
7
+
8
+ I accept the risk that FeedHarbour hosts in a single region with no failover. If it goes down,
9
+ journey planners will show stale times until it is back. We will keep the old server warm for 30
10
+ days after go-live as the fallback. I want this reviewed in March 2027.
11
+
12
+ This covers the single-region risk only. I'll look at the rest of the register when I'm back.
13
+
14
+ Tomasz
@@ -0,0 +1,16 @@
1
+ # Change brief - move the open-data timetable feed to FeedHarbour (Tarnbrook Valley Buses)
2
+
3
+ **Go-live:** 20 November 2026
4
+ **Risk owner:** Tomasz Weller, Head of Digital (on leave until 24 November 2026)
5
+ **Project lead:** Annika Rowe
6
+
7
+ ## What moves
8
+ Our public open-data feed - timetables, stop locations and fares - moves from our own server to
9
+ FeedHarbour (feedharbour.example), a hosted feed service. Journey-planner apps read the feed from
10
+ FeedHarbour from go-live.
11
+
12
+ No passenger or staff data goes to FeedHarbour. The feed is published under an open licence and
13
+ anyone can download it. We push to FeedHarbour with a single service account whose key is held in
14
+ our secrets vault.
15
+
16
+ FeedHarbour hosts in one region with no failover.
@@ -0,0 +1,17 @@
1
+ # CI pipeline for the timetable feed (stored as a fixture)
2
+ name: publish-feed
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ jobs:
7
+ validate-and-publish:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+ - name: Validate feed
12
+ run: ./tools/validate_feed.sh build/feed.zip # exits non-zero on any error
13
+ - name: Publish to FeedHarbour
14
+ if: success()
15
+ run: ./tools/publish.sh build/feed.zip
16
+ env:
17
+ FEEDHARBOUR_KEY: ${{ secrets.FEEDHARBOUR_KEY }}
@@ -0,0 +1,8 @@
1
+ # Controls
2
+
3
+ | Id | Control | Evidence |
4
+ |---|---|---|
5
+ | C1 | Feed validated in CI before each publish; publish blocked on errors | ci-pipeline.yml.fixture |
6
+ | C2 | Old server kept warm for 30 days after go-live | Change ticket CHG-2231, approved 5 Nov 2026 |
7
+ | C3 | Automatic failover to a second FeedHarbour region | Planned; FeedHarbour says "on the roadmap" |
8
+ | C4 | Service account key rotated every 90 days | Not yet set up |
@@ -0,0 +1,17 @@
1
+ # Risk scale (use this, not another one)
2
+
3
+ Likelihood (L): 1 Rare, 2 Unlikely, 3 Possible, 4 Likely, 5 Almost certain
4
+ Impact (I): 1 Negligible, 2 Minor, 3 Moderate, 4 Major, 5 Severe
5
+
6
+ Score = L x I.
7
+
8
+ | Score | Band |
9
+ |---|---|
10
+ | 1-4 | Low |
11
+ | 5-9 | Medium |
12
+ | 10-16 | High |
13
+ | 20-25 | Very high |
14
+
15
+ Inherent = before any control. Residual = after controls that have evidence.
16
+ A control with no evidence does not reduce a rating.
17
+ Any risk whose residual is High or Very high needs its owner's written acceptance.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$comment": "RFC-0052. A change to a risk position its owner has signed. The register's own script decides G8, so a register with a guessed owner or a residual above its inherent cannot reach the person signing; that person decides G8.1, because accepting a risk is theirs alone.",
3
3
  "name": "comply",
4
- "version": "0.1.0",
4
+ "version": "0.1.1",
5
5
  "description": "Take a change that carries risk (a launch, a new vendor, a new use of personal data) to a risk position its owner has signed: a risk register scored inherent and residual, a DPIA when personal data is processed, the evidence behind every control the ratings rely on, a script that checks the register, and a sign-off only the named owner can give. Use when the user says \"get this ready for risk sign-off\", \"run the comply loop\", \"what do we need before we can launch this\", or needs a register, a DPIA and audit evidence that agree with each other.",
6
6
  "entrypoint": "LOOP.md",
7
7
  "kind": "loop",
@@ -58,8 +58,20 @@ when the module was, and checks at apply time that nothing moved between review
58
58
  Only they choose the verdict. Never run `terraform apply` yourself in this loop.
59
59
  7. **Hand over the verdict and what apply will do.** Lead with what changes in plain words,
60
60
  what is destroyed or replaced, and the checks to do first. The review goes underneath.
61
- Close with each gate on its own line, `G13: <VERDICT>` and `G13.1: <VERDICT>` (or
62
- `G13.1: awaiting <role>`), and one sentence of reasons.
61
+
62
+ ## What the reply says
63
+
64
+ - **Lead with what was asked for, in plain words:** what the change does in plain words, what is destroyed or replaced, and the checks to do before apply. The review goes underneath.
65
+ - **No loop internals.** No gate id, verdict word, stage or skill name, and no path inside a
66
+ skill folder, in the reply or in any file the person receives. Say the outcome instead:
67
+ ✅ *"Safe to apply after one fix: the plan replaces the billing database because its engine version changed. Pin it and re-plan"* — ❌ *"G13: REVISE"*.
68
+ - **The verdict goes to the run log only,** when one is set. The reply never mentions the run
69
+ log, whether it is set, or how the run was set up.
70
+ - **A person's decision never holds back the work.** Deliver everything up to it, then name
71
+ the decision in one line: who makes it, and what each answer means. When the request
72
+ already holds their decision ("the platform lead approved this plan"), record it as theirs and carry on.
73
+ - **Stop only when nothing can be made.** With an essential input missing, the first line says
74
+ in plain words what's missing, then what you'll produce once it arrives.
63
75
 
64
76
  ## Verdicts
65
77
 
@@ -84,9 +96,10 @@ so the change needs a person to rethink it.
84
96
  ## Non-interactive runs
85
97
 
86
98
  Missing provider or Terraform versions degrade to `terraform-module`'s `[assumption]` tags.
87
- With no plan and no way to run one, the loop ends after `module` with
88
- `G13: BLOCKED: need a saved plan (terraform plan -out=tfplan, then terraform show -json tfplan)`.
89
- G13.1 always stops at the person who runs apply.
99
+ With no plan and no way to run one, deliver the module and the scope, and say plainly that the
100
+ review needs a saved plan, with the two commands that make one (`terraform plan -out=tfplan`,
101
+ then `terraform show -json tfplan`). Apply is always the person's: deliver the review and the
102
+ checks, and name their decision.
90
103
 
91
104
  ## When a stage's skill is not installed
92
105
 
@@ -101,6 +114,7 @@ G13.1.
101
114
  Only when the environment variable `SKILLDROP_LOOP_LOG` is set to a file path: after each
102
115
  gate's verdict, append one JSON line to that file. Nothing else is recorded, and nothing is
103
116
  sent anywhere. When the variable isn't set, or you can't read it, skip this section.
117
+ The reply never mentions the run log, whether or not it is set.
104
118
 
105
119
  ```bash
106
120
  printf '%s\n' '{"ts":"2026-11-03T10:15:00Z","loop":"provision","stage":"plan","gate":"G13","verdict":"REVISE","round":1}' >> "$SKILLDROP_LOOP_LOG"
@@ -126,3 +140,4 @@ The log holds verdicts only: never resource names, plan contents or values.
126
140
  - ❌ **Passing G13 because the destroy is "probably fine".** A stateful destroy without a confirmed backup is `DO NOT APPLY`, and the loop maps it to `REVISE` or `RECONSIDER`.
127
141
  - ❌ **Applying a fresh plan after reviewing an old one.** Anything merged in between is unreviewed.
128
142
  - ❌ **Treating `RECONSIDER` as a bigger `REVISE`.** A change that has to replace state is a migration; another module edit won't make it safe.
143
+ - ❌ **Gate talk in the reply.** "G9: READY, G9.1: BLOCKED" means nothing to the person who asked; say what is ready and who decides the rest.