skilldrop-cli 0.16.7 → 0.16.9

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 (103) hide show
  1. package/README.md +1 -1
  2. package/catalogue.json +3 -2
  3. package/model-routing.json +4 -0
  4. package/package.json +1 -1
  5. package/packs/ai-engineering/skills/ai-usage-policy/evals/evals.json +30 -0
  6. package/packs/ai-engineering/skills/ai-usage-policy/evals/files/4/ciso-brief.md +15 -0
  7. package/packs/ai-engineering/skills/ai-usage-policy/evals/files/4/incident-summary.md +22 -0
  8. package/packs/ai-engineering/skills/ai-usage-policy/evals/files/4/legal-notes.md +14 -0
  9. package/packs/ai-engineering/skills/ai-usage-policy/evals/files/4/tool-inventory.csv +5 -0
  10. package/packs/api-builder/skills/tool-use-schema-writer/evals/evals.json +30 -0
  11. package/packs/api-builder/skills/tool-use-schema-writer/evals/files/4/refunds.openapi.yaml +63 -0
  12. package/packs/career/loops/apply/LOOP.md +19 -10
  13. package/packs/career/loops/apply/loop.json +9 -3
  14. package/packs/career/pack.json +27 -7
  15. package/packs/career/skills/application-form-answers/SKILL.md +146 -0
  16. package/packs/career/skills/application-form-answers/evals/eval_queries.json +34 -0
  17. package/packs/career/skills/application-form-answers/evals/evals.json +103 -0
  18. package/packs/career/skills/application-form-answers/evals/files/1/form.md +17 -0
  19. package/packs/career/skills/application-form-answers/evals/files/1/posting.md +20 -0
  20. package/packs/career/skills/application-form-answers/evals/files/1/resume.md +32 -0
  21. package/packs/career/skills/application-form-answers/evals/files/2/form.md +15 -0
  22. package/packs/career/skills/application-form-answers/evals/files/2/posting.md +21 -0
  23. package/packs/career/skills/application-form-answers/evals/files/2/resume.md +32 -0
  24. package/packs/career/skills/application-form-answers/evals/files/4/form.md +14 -0
  25. package/packs/career/skills/application-form-answers/evals/files/4/posting.md +25 -0
  26. package/packs/career/skills/application-form-answers/evals/files/4/resume.md +29 -0
  27. package/packs/career/skills/application-form-answers/evals/files/5/form.md +15 -0
  28. package/packs/career/skills/application-form-answers/evals/files/5/posting.md +18 -0
  29. package/packs/career/skills/application-form-answers/evals/files/5/resume.md +23 -0
  30. package/packs/career/skills/application-form-answers/evals/files/6/form.md +11 -0
  31. package/packs/career/skills/application-form-answers/evals/files/6/posting.md +28 -0
  32. package/packs/career/skills/application-form-answers/evals/files/6/resume.md +35 -0
  33. package/packs/career/skills/application-form-answers/evals/files/7/form.md +11 -0
  34. package/packs/career/skills/application-form-answers/evals/files/7/posting.md +19 -0
  35. package/packs/career/skills/application-form-answers/evals/files/7/resume.md +26 -0
  36. package/packs/career/skills/application-form-answers/manifest.json +31 -0
  37. package/packs/career/skills/cover-letter/scripts/claim_check.py +7 -4
  38. package/packs/career/skills/job-fit-analysis/SKILL.md +46 -16
  39. package/packs/career/skills/job-fit-analysis/evals/evals.json +26 -0
  40. package/packs/career/skills/job-fit-analysis/evals/files/6/linkedin-about.txt +5 -0
  41. package/packs/career/skills/job-fit-analysis/evals/files/6/posting.md +25 -0
  42. package/packs/career/skills/job-fit-analysis/evals/files/6/resume.md +35 -0
  43. package/packs/career/skills/job-fit-analysis/evals/files/7/resume.md +32 -0
  44. package/packs/career/skills/job-fit-analysis/manifest.json +1 -1
  45. package/packs/career/skills/resume-tailor/SKILL.md +37 -9
  46. package/packs/career/skills/resume-tailor/evals/evals.json +28 -0
  47. package/packs/career/skills/resume-tailor/evals/files/8/posting.md +25 -0
  48. package/packs/career/skills/resume-tailor/evals/files/8/resume.typ +31 -0
  49. package/packs/career/skills/resume-tailor/evals/files/9/linkedin-about.txt +5 -0
  50. package/packs/career/skills/resume-tailor/evals/files/9/posting.md +25 -0
  51. package/packs/career/skills/resume-tailor/evals/files/9/resume.md +35 -0
  52. package/packs/career/skills/resume-tailor/manifest.json +1 -1
  53. package/packs/career/skills/resume-tailor/scripts/claim_check.py +7 -4
  54. package/packs/data-analytics/skills/metric-definition/evals/evals.json +30 -0
  55. package/packs/data-analytics/skills/metric-definition/evals/files/4/tables.md +32 -0
  56. package/packs/data-analytics/skills/metric-definition/evals/files/4/thread.md +31 -0
  57. package/packs/dev-team/skills/contribution-wizard/evals/evals.json +30 -0
  58. package/packs/dev-team/skills/contribution-wizard/evals/files/4/CONTRIBUTING.md +63 -0
  59. package/packs/dev-team/skills/contribution-wizard/evals/files/4/registry.json +15 -0
  60. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/PROMPT.md +10 -0
  61. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/examples/01-expected.md +2 -0
  62. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/examples/01-input.md +3 -0
  63. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/examples/02-expected.md +1 -0
  64. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/examples/02-input.md +2 -0
  65. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/examples/03-expected.md +1 -0
  66. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/examples/03-input.md +2 -0
  67. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/flag-overdue-holds/meta.json +7 -0
  68. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/PROMPT.md +11 -0
  69. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/examples/01-expected.md +4 -0
  70. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/examples/01-input.md +4 -0
  71. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/examples/02-expected.md +6 -0
  72. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/examples/02-input.md +2 -0
  73. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/examples/03-expected.md +1 -0
  74. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/examples/03-input.md +1 -0
  75. package/packs/dev-team/skills/contribution-wizard/evals/files/4/skills/summarise-reading-list/skill.toml +6 -0
  76. package/packs/dev-team/skills/devils-advocate/evals/evals.json +29 -0
  77. package/packs/dev-team/skills/devils-advocate/evals/files/4/lateFees.test.ts +46 -0
  78. package/packs/dev-team/skills/devils-advocate/evals/files/4/lateFees.ts +46 -0
  79. package/packs/dev-team/skills/release-notes/evals/evals.json +29 -0
  80. package/packs/dev-team/skills/release-notes/evals/files/4/git-log.txt +26 -0
  81. package/packs/research/skills/source-synthesis/evals/evals.json +30 -0
  82. package/packs/research/skills/source-synthesis/evals/files/4/behaviour-logs.md +31 -0
  83. package/packs/research/skills/source-synthesis/evals/files/4/parent-survey.md +25 -0
  84. package/packs/research/skills/source-synthesis/evals/files/4/pilot-report.md +27 -0
  85. package/packs/research/skills/source-synthesis/evals/files/4/teacher-focus-group.md +19 -0
  86. package/packs/research/skills/source-synthesis/evals/files/4/vendor-brochure.md +18 -0
  87. package/packs/solution-architect/skills/db-schema-design/evals/evals.json +30 -0
  88. package/packs/solution-architect/skills/db-schema-design/evals/files/4/finance-email.md +18 -0
  89. package/packs/solution-architect/skills/db-schema-design/evals/files/4/members_sample.csv +5 -0
  90. package/packs/solution-architect/skills/db-schema-design/evals/files/4/points_txn_sample.csv +17 -0
  91. package/packs/solution-architect/skills/db-schema-design/evals/files/4/requirements.md +28 -0
  92. package/packs/solution-architect/skills/design-doc/evals/evals.json +29 -0
  93. package/packs/solution-architect/skills/design-doc/evals/files/4/request.md +31 -0
  94. package/packs/solution-architect/skills/design-doc/evals/files/4/systems.md +40 -0
  95. package/packs/solution-architect/skills/tech-comparison-matrix/evals/evals.json +29 -0
  96. package/packs/solution-architect/skills/tech-comparison-matrix/evals/files/4/mobile-options.md +45 -0
  97. package/packs/sre-oncall/skills/postmortem-generator/evals/evals.json +30 -0
  98. package/packs/sre-oncall/skills/postmortem-generator/evals/files/4/finance-recon.md +28 -0
  99. package/packs/sre-oncall/skills/postmortem-generator/evals/files/4/incident-channel.txt +34 -0
  100. package/packs/sre-oncall/skills/postmortem-generator/evals/files/4/scheduler-log.txt +15 -0
  101. package/packs/stakeholder-comms/skills/guide-builder/evals/evals.json +30 -0
  102. package/packs/stakeholder-comms/skills/guide-builder/evals/files/4/handover-thread.txt +39 -0
  103. package/packs/stakeholder-comms/skills/guide-builder/evals/files/4/it-notes.txt +21 -0
@@ -0,0 +1,32 @@
1
+ # Tables (Snowflake, database TARNVALLEY)
2
+
3
+ ## FIELD.JOBS — one row per visit
4
+ | column | type | notes |
5
+ |---|---|---|
6
+ | job_id | NUMBER | primary key |
7
+ | address_id | NUMBER | always filled |
8
+ | appliance_id | NUMBER | NULL for every job before 2026-03-03 |
9
+ | job_type | VARCHAR | 'repair', 'recall', 'annual_service', 'install' |
10
+ | status | VARCHAR | 'completed', 'cancelled', 'no_access' |
11
+ | follow_up_required | BOOLEAN | ticked by the engineer on closing the job |
12
+ | engineer_id | NUMBER | |
13
+ | created_at | TIMESTAMP_NTZ | UK local time, when the job was booked |
14
+ | completed_at | TIMESTAMP_NTZ | UK local time, NULL unless status = 'completed' |
15
+
16
+ There is no column that links a recall, or any later visit, to the job it follows.
17
+
18
+ ## FIELD.APPLIANCES
19
+ | column | type | notes |
20
+ |---|---|---|
21
+ | appliance_id | NUMBER | primary key |
22
+ | address_id | NUMBER | |
23
+ | make | VARCHAR | |
24
+ | model | VARCHAR | |
25
+ | installed_on | DATE | often NULL |
26
+
27
+ ## FIELD.ENGINEERS
28
+ | column | type | notes |
29
+ |---|---|---|
30
+ | engineer_id | NUMBER | primary key |
31
+ | region | VARCHAR | 'north', 'central', 'coast' |
32
+ | employment_type | VARCHAR | 'employed', 'subcontractor' |
@@ -0,0 +1,31 @@
1
+ # #ops-reporting — export, 1–2 October 2026
2
+
3
+ **Gethin Aldous (Regional Ops Manager), 1 Oct 09:12**
4
+ September first-time fix is in. 3,912 of 4,830 completed repairs closed with no follow-up flag. That's 84%. Best month this year.
5
+
6
+ **Roisin Fairweather (Customer Care Lead), 1 Oct 09:40**
7
+ We get 68%. 3,282 of 4,830. We only count a repair as fixed if nobody had to go back within 30 days.
8
+
9
+ **Gethin Aldous, 1 Oct 09:44**
10
+ The engineer ticks follow_up_required when the job needs another visit. That is the record. If they didn't tick it, it was fixed.
11
+
12
+ **Roisin Fairweather, 1 Oct 09:58**
13
+ They don't tick it when they think it's fixed and it isn't. 630 of your 3,912 had someone back out within 30 days. Those customers rang us, not you.
14
+ And you can't just count recalls either. The contact centre logs about half of the go-backs as a brand new repair instead of a recall, because that's the default in the booking screen.
15
+
16
+ **Gethin Aldous, 1 Oct 10:03**
17
+ For what it's worth 4,830 already leaves out cancelled and no-access visits. We agree on that at least.
18
+
19
+ **Nkechi Brandt (BI Analyst), 1 Oct 10:20**
20
+ I pulled both sets of numbers this morning. Two things from the data side:
21
+ - appliance_id has only been filled in since 3 March 2026 when the new engineer app went live. Before that it's NULL and all you have is address_id.
22
+ - Some addresses have more than one appliance (HMOs, small commercial units). So "same address" and "same appliance" are not the same test.
23
+
24
+ **Owen Prys (Finance Director), 2 Oct 08:15**
25
+ The board pack needs one number, ready on the 1st of each month, with last September next to it for comparison. Subcontractors in or out, I don't mind, just tell me which. And who owns this going forward?
26
+
27
+ **Gethin Aldous, 2 Oct 08:31**
28
+ It was Marguerite's before she left in August. Nobody has picked it up.
29
+
30
+ **Roisin Fairweather, 2 Oct 08:40**
31
+ Installs and annual services shouldn't be anywhere near this, by the way. It's a repair measure.
@@ -43,6 +43,36 @@
43
43
  "It does not invent the director's name, the team's name, team members other than Priya, or a specific repo folder stated as fact",
44
44
  "The test cases use realistic pasted standup notes as input, and at least one covers thin or missing notes"
45
45
  ]
46
+ },
47
+ {
48
+ "id": 4,
49
+ "held_out": "2026-10-06",
50
+ "prompt": "Our library systems team keeps a small skills repo, it's this folder (CONTRIBUTING.md, registry.json, a couple of existing skills under skills/). I want to add one called ILL_Request_Triage. Staff paste in an interlibrary loan request from the request form export (patron name, card number, the title, author, year published, list price, and whether the catalogue check found a copy on our shelves) and it says which of our four routes the request goes down, with a one-line reason:\n\n- fill from our own stock, if the catalogue check says we hold a copy that's on the shelf\n- borrow through the Northmere Consortium, if we don't hold it and it was published more than 2 years ago\n- buy it, if we don't hold it, it was published in the last 2 years and the list price is under £60\n\nCategory is resource-sharing, maintainer is resource-sharing@harrowgate.example. Can you write up everything I need for the pull request?",
51
+ "assertions": [
52
+ "The skill's metadata is delivered as a skill.toml file alongside PROMPT.md and an examples folder, and no meta.json is created for the new skill",
53
+ "The skill is given a lowercase hyphenated name that starts with a verb and spells out interlibrary loan (for example triage-interlibrary-loan-requests), not ILL_Request_Triage or a name containing the abbreviation ill, and the reply tells the author the name was changed to fit the naming rules",
54
+ "handles_patron_data is set to true, and the skill's instructions tell the assistant not to repeat the library card number in its output",
55
+ "The reply tells the author that four routes were mentioned but only three were described, and does not write a rule for a fourth route as though the author had given one",
56
+ "It points out at least one request the stated rules do not cover, such as a title published in the last 2 years with a list price of £60 or more, or a copy we hold that is out on loan",
57
+ "The skill's instructions carry the 2-year and £60 thresholds exactly as given and introduce no other price or age threshold",
58
+ "There are at least three example input/expected pairs, and at least one is an awkward case such as a request with a field missing",
59
+ "A registry.json entry for the new skill is provided with category resource-sharing and maintainer resource-sharing@harrowgate.example"
60
+ ]
61
+ },
62
+ {
63
+ "id": 5,
64
+ "held_out": "2026-10-06",
65
+ "prompt": "my cofounder keeps saying we should have a 'skill' so our coding agent writes the release notes instead of me doing it every other friday. input is the list of merged PR titles since the last release, output is the notes we post for customers (they're shop owners, not devs). some PRs shouldn't show up publicly, security fixes mostly, so handle that somehow. we're 4 people and don't have a skills setup yet, i think it'd go in .claude/skills in the main repo but not sure that's right. keep it small, one file if possible, plus a couple of examples i can try it on",
66
+ "assertions": [
67
+ "It delivers a drafted instruction file for the release-notes skill and at least two example inputs to try it on, and does not stop at a list of questions",
68
+ "The skill itself is one instruction file, with no separate manifest, metadata file or multi-file package presented as required",
69
+ "It says where the skill should live is unconfirmed, treating .claude/skills as the author's guess to check, not as an established fact about their repo",
70
+ "The skill's instructions tell it to write only from the PR titles it is given and not to add features, fixes or details the titles do not contain",
71
+ "The skill's instructions tell it to write for shop owners in plain language, not to copy developer-facing PR titles through as they are",
72
+ "The skill's instructions keep security-fix PRs out of the public notes or set them aside for a person to decide, and the reply says the exact rule for what stays private is the author's to confirm",
73
+ "At least one of the examples includes a security-fix PR title",
74
+ "It does not invent a product name, a company name, a version number scheme, PR label names or a command for fetching the PR titles and state it as fact"
75
+ ]
46
76
  }
47
77
  ]
48
78
  }
@@ -0,0 +1,63 @@
1
+ # Contributing a skill
2
+
3
+ Harrowgate University Library, Systems & Discovery team. Last revised 12 March 2026.
4
+
5
+ Skills are short instruction files our staff assistant loads when a member of staff
6
+ asks for a particular job. Six of us maintain them. Keep them small.
7
+
8
+ ## Layout
9
+
10
+ Each skill is one folder under `skills/`:
11
+
12
+ ```
13
+ skills/<name>/
14
+ skill.toml metadata
15
+ PROMPT.md the instructions the assistant follows
16
+ examples/
17
+ 01-input.md what a member of staff would paste
18
+ 01-expected.md what a good answer looks like
19
+ 02-input.md
20
+ ...
21
+ ```
22
+
23
+ At least three input/expected pairs. One of them must be an awkward case (missing
24
+ field, contradictory request, nothing to do).
25
+
26
+ Since March 2026 metadata lives in `skill.toml`. A few older skills still carry a
27
+ `meta.json` until someone migrates them. New skills must not add one.
28
+
29
+ ## skill.toml
30
+
31
+ ```toml
32
+ name = "summarise-reading-list" # same as the folder name
33
+ summary = "One sentence, 120 characters at most."
34
+ category = "cataloguing" # one of the categories in registry.json
35
+ maintainer = "alias@harrowgate.example"
36
+ handles_patron_data = false
37
+ version = "0.1.0" # new skills start at 0.1.0
38
+ ```
39
+
40
+ ## Naming
41
+
42
+ - lowercase, words joined with hyphens
43
+ - starts with a verb (`summarise-`, `flag-`, `draft-`)
44
+ - no abbreviations a new member of staff would not know. Write `interlibrary-loan`,
45
+ not `ill`; write `reading-list`, not `rl`.
46
+ - 40 characters at most
47
+
48
+ ## Patron data
49
+
50
+ If the input a skill receives can contain patron names, library card numbers or
51
+ contact details, set `handles_patron_data = true`, and PROMPT.md must tell the
52
+ assistant never to repeat a library card number in its output (refer to the patron
53
+ by name or by request number instead).
54
+
55
+ ## Registry
56
+
57
+ Add one entry for the skill to the `skills` list in `registry.json` (name, category,
58
+ maintainer). Keep the list in alphabetical order by name.
59
+
60
+ ## Before you open a pull request
61
+
62
+ Run `python3 tools/lint_skills.py` from the repo root. It checks the layout, the
63
+ naming rules and that every skill is in the registry.
@@ -0,0 +1,15 @@
1
+ {
2
+ "categories": ["acquisitions", "cataloguing", "circulation", "resource-sharing"],
3
+ "skills": [
4
+ {
5
+ "name": "flag-overdue-holds",
6
+ "category": "circulation",
7
+ "maintainer": "circdesk@harrowgate.example"
8
+ },
9
+ {
10
+ "name": "summarise-reading-list",
11
+ "category": "cataloguing",
12
+ "maintainer": "metadata@harrowgate.example"
13
+ }
14
+ ]
15
+ }
@@ -0,0 +1,10 @@
1
+ # flag-overdue-holds
2
+
3
+ You are given the hold-shelf report: one line per item with request number, title,
4
+ patron name, card number and the date the item was shelved.
5
+
6
+ 1. List every item shelved more than 7 days before the report date, oldest first.
7
+ 2. For each, give the request number, the title and the patron's name.
8
+ 3. Never repeat a library card number. Refer to the patron by name.
9
+
10
+ If nothing is over 7 days, say so.
@@ -0,0 +1,2 @@
1
+ 1 item over 7 days:
2
+ - R-88121, Silent Spring, Amara Okoye (shelved 2026-02-09)
@@ -0,0 +1,3 @@
1
+ Report date 2026-02-20
2
+ R-88121 | Silent Spring | Amara Okoye | 2100457781 | 2026-02-09
3
+ R-88160 | The Peregrine | Jonas Lind | 2100331290 | 2026-02-17
@@ -0,0 +1,2 @@
1
+ Report date 2026-02-20
2
+ R-88160 | The Peregrine | Jonas Lind | 2100331290 | 2026-02-17
@@ -0,0 +1 @@
1
+ Nothing can be flagged: R-88171 (Waterlog, Petra Havel) has no shelved date.
@@ -0,0 +1,2 @@
1
+ Report date 2026-02-20
2
+ R-88171 | Waterlog | Petra Havel | 2100778123 |
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "flag-overdue-holds",
3
+ "summary": "Lists hold-shelf items uncollected for more than 7 days so the desk can release them.",
4
+ "category": "circulation",
5
+ "maintainer": "circdesk@harrowgate.example",
6
+ "version": "1.2.0"
7
+ }
@@ -0,0 +1,11 @@
1
+ # summarise-reading-list
2
+
3
+ You are given a module reading list pasted from the reading list system: one item
4
+ per line, with title, author, year, format and a `held` column (yes/no).
5
+
6
+ 1. Count the items by format (book, e-book, article, other).
7
+ 2. List every item where `held` is `no`, with title, author and year.
8
+ 3. If a line has no `held` value, list it separately under "Holding not stated".
9
+ Do not guess.
10
+
11
+ Never add items that are not in the pasted list. If the list is empty, say so and stop.
@@ -0,0 +1,4 @@
1
+ Books: 2, e-books: 1.
2
+
3
+ Not held:
4
+ - Landscape and Memory, Schama, 1995
@@ -0,0 +1,4 @@
1
+ Module HIS2041
2
+ The Making of the English Landscape | Hoskins | 1955 | book | yes
3
+ Landscape and Memory | Schama | 1995 | book | no
4
+ Fields of Vision | Daniels | 1993 | e-book | yes
@@ -0,0 +1,6 @@
1
+ Books: 1.
2
+
3
+ Not held: none.
4
+
5
+ Holding not stated:
6
+ - An Atlas of Rural Settlement, Roberts, 2000
@@ -0,0 +1,2 @@
1
+ Module GEO1010
2
+ An Atlas of Rural Settlement | Roberts | 2000 | book |
@@ -0,0 +1,6 @@
1
+ name = "summarise-reading-list"
2
+ summary = "Turns a module reading list into a count of items by format and a list of titles we do not hold."
3
+ category = "cataloguing"
4
+ maintainer = "metadata@harrowgate.example"
5
+ handles_patron_data = false
6
+ version = "0.3.0"
@@ -43,6 +43,35 @@
43
43
  "It gives a concrete fix, such as reading with the csv module and normalising the email with strip and lower",
44
44
  "It does not state as fact what the other columns hold or what the real file contains beyond what was given"
45
45
  ]
46
+ },
47
+ {
48
+ "id": 4,
49
+ "held_out": "2026-10-06",
50
+ "prompt": "Finished the late fee feature for the tenant billing service (lateFees.ts, tests in lateFees.test.ts). Rules from finance: nothing if the invoice is 5 days or fewer past due. After that it's 1.5% of the balance for each calendar month the invoice has been overdue in, so one due 20 March and still open on 2 May has March, April and May. Capped at $75 per invoice in total. Never on paid or void invoices. A nightly job calls applyLateFees with every invoice. Tests are green. Can you go over it before I merge? Skip the style nits, I want the things that would actually bite us.",
51
+ "assertions": [
52
+ "It flags that monthsOverdue subtracts month numbers without the year, so an invoice due in November or December and still open in January gets a zero or negative count and no fee",
53
+ "It flags that the $75 cap is applied to one month's amount before multiplying by the months, so a large balance overdue for two or more months is charged more than $75 (for example $10,000 over two months gives $150)",
54
+ "It flags that applyLateFees adds the whole fee to the balance on every nightly run with nothing recording what was already charged, so the same invoice is charged again each night",
55
+ "It points out that the cap test uses a single month overdue, where a per-month cap and a total cap give the same $75, so it cannot catch the cap bug",
56
+ "It points out that the applyLateFees test only checks the balance went up after one run, and that no test runs it twice or checks the amount",
57
+ "It names a missing test for an invoice that is overdue across a year boundary",
58
+ "It does not report the grace-period check as a bug: charging nothing at 5 days late or fewer matches the stated rule",
59
+ "It says plainly that the change is not ready to merge as it stands"
60
+ ]
61
+ },
62
+ {
63
+ "id": 5,
64
+ "held_out": "2026-10-06",
65
+ "prompt": "agent wrote this migration for me. adds region onto orders so the regional dashboards don't need the join to customers. ran clean on my laptop db. postgres. the orders table in prod is big-ish, don't know the exact size. top 3 things i should worry about before i run it friday?\n\n```sql\nALTER TABLE orders ADD COLUMN region_code VARCHAR(2) NOT NULL;\n\nUPDATE orders\nSET region_code = (SELECT region FROM customers WHERE customers.id = orders.customer_id);\n\nCREATE INDEX idx_orders_region ON orders(region_code);\n```",
66
+ "assertions": [
67
+ "It flags that adding a NOT NULL column with no default fails on a table that already has rows, so the first statement will error on prod",
68
+ "It says the clean run on the laptop does not show the migration works on prod, for example because the local orders table may have been empty",
69
+ "It flags locking or long-running work on a large table, from the single full-table UPDATE or the non-concurrent index build, and gives a concrete mitigation such as batching the backfill or CREATE INDEX CONCURRENTLY",
70
+ "It flags that a customer with no region, or a region longer than 2 characters, would break the backfill, and says what customers.region holds is not known from what was given",
71
+ "It gives a corrected order of steps: add the column as nullable, backfill it, then add the NOT NULL constraint",
72
+ "It does not state the row count of orders, how long the migration will take, or what customers.region contains as fact",
73
+ "It leads with three main concerns as asked, and anything beyond the three is kept to a brief mention"
74
+ ]
46
75
  }
47
76
  ]
48
77
  }
@@ -0,0 +1,46 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { applyLateFees, computeLateFee, Invoice } from "./lateFees";
3
+
4
+ const day = (s: string) => new Date(s + "T12:00:00Z");
5
+
6
+ const invoice = (over: Partial<Invoice> = {}): Invoice => ({
7
+ id: "INV-1001",
8
+ tenantId: "T-204",
9
+ dueDate: "2026-03-01",
10
+ balance: 1000,
11
+ status: "open",
12
+ ...over,
13
+ });
14
+
15
+ describe("computeLateFee", () => {
16
+ it("charges nothing inside the grace period", () => {
17
+ expect(computeLateFee(invoice(), day("2026-03-06"))).toBe(0);
18
+ });
19
+
20
+ it("charges 1.5% once the grace period is over", () => {
21
+ expect(computeLateFee(invoice(), day("2026-03-07"))).toBe(15);
22
+ });
23
+
24
+ it("charges for each calendar month overdue", () => {
25
+ const inv = invoice({ dueDate: "2026-03-20" });
26
+ expect(computeLateFee(inv, day("2026-05-02"))).toBe(45);
27
+ });
28
+
29
+ it("caps the fee at $75", () => {
30
+ const inv = invoice({ balance: 10000 });
31
+ expect(computeLateFee(inv, day("2026-03-10"))).toBe(75);
32
+ });
33
+
34
+ it("never charges paid or void invoices", () => {
35
+ expect(computeLateFee(invoice({ status: "paid" }), day("2026-06-01"))).toBe(0);
36
+ expect(computeLateFee(invoice({ status: "void" }), day("2026-06-01"))).toBe(0);
37
+ });
38
+ });
39
+
40
+ describe("applyLateFees", () => {
41
+ it("adds the fee to open invoices", () => {
42
+ const inv = invoice();
43
+ applyLateFees([inv], day("2026-03-10"));
44
+ expect(inv.balance).toBeGreaterThan(1000);
45
+ });
46
+ });
@@ -0,0 +1,46 @@
1
+ export interface Invoice {
2
+ id: string;
3
+ tenantId: string;
4
+ dueDate: string; // ISO date, e.g. "2026-03-01"
5
+ balance: number; // dollars outstanding
6
+ status: "open" | "paid" | "void";
7
+ }
8
+
9
+ const GRACE_DAYS = 5;
10
+ const MONTHLY_RATE = 0.015;
11
+ const FEE_CAP = 75;
12
+ const MS_PER_DAY = 86_400_000;
13
+
14
+ function parseDue(inv: Invoice): Date {
15
+ return new Date(inv.dueDate + "T00:00:00Z");
16
+ }
17
+
18
+ export function daysLate(inv: Invoice, today: Date): number {
19
+ return Math.floor((today.getTime() - parseDue(inv).getTime()) / MS_PER_DAY);
20
+ }
21
+
22
+ // Number of calendar months the invoice has been overdue in, counting the
23
+ // month it fell due. Due 20 March, today 2 May -> 3.
24
+ export function monthsOverdue(inv: Invoice, today: Date): number {
25
+ return today.getUTCMonth() - parseDue(inv).getUTCMonth() + 1;
26
+ }
27
+
28
+ export function computeLateFee(inv: Invoice, today: Date): number {
29
+ if (inv.status !== "open") return 0;
30
+ if (daysLate(inv, today) <= GRACE_DAYS) return 0;
31
+
32
+ const monthly = Math.min(inv.balance * MONTHLY_RATE, FEE_CAP);
33
+ const fee = monthly * monthsOverdue(inv, today);
34
+ return Math.round(fee * 100) / 100;
35
+ }
36
+
37
+ // Called by the nightly job with every invoice for the portfolio.
38
+ export function applyLateFees(invoices: Invoice[], today: Date): Invoice[] {
39
+ for (const inv of invoices) {
40
+ const fee = computeLateFee(inv, today);
41
+ if (fee > 0) {
42
+ inv.balance += fee;
43
+ }
44
+ }
45
+ return invoices;
46
+ }
@@ -43,6 +43,35 @@
43
43
  "It does not invent dates, PR numbers, a commit count for commits it was not shown, or features not in the pasted list",
44
44
  "It delivers usable release notes in the reply rather than only asking questions, and lists the items that need confirming before sending"
45
45
  ]
46
+ },
47
+ {
48
+ "id": 4,
49
+ "held_out": "2026-10-06",
50
+ "prompt": "Portside WMS 5.0.0 goes out to customers on Thursday. The log since 4.9.2 is in git-log.txt. Two things please: (1) upgrade notes for admins. Our customers run Portside on their own servers, so their IT people need to know what to do before they upgrade. (2) A short paragraph for the customer newsletter, three or four sentences. Sales want the newsletter to lead with batch scanning and to say the duplicate pick list problem is finally fixed. Also remind people that 4.x support ends on 31 December.",
51
+ "assertions": [
52
+ "The PostgreSQL 15+ requirement is called out as something admins must deal with before upgrading (the installer aborts on PostgreSQL 13 and 14), even though its commit is labelled chore",
53
+ "The removal of /api/v1/stock is called out as a breaking change with /api/v2/stock-levels as the replacement, and the breaking items come before the new features in the admin notes",
54
+ "Batch scanning is described as off by default (flag scan.batch.enabled, missed reads on older handhelds), not as a feature that works out of the box after upgrading",
55
+ "The duplicate pick list problem is not described as fully fixed; the output says split shipments can still produce a duplicate line (#1893) or flags that the 'finally fixed' claim is not supported by the log",
56
+ "The end of 4.x maintenance is given as 31 March 2027, or the conflict between the requested 31 December date and the log is flagged; 31 December is not repeated as fact",
57
+ "The wms.mail.host to wms.smtp.host rename is described as a deprecation where the old key still works, not as a change that breaks existing configuration on upgrade",
58
+ "The admin notes include the security fix for session tokens not being invalidated on password change (LSA-2026-04)",
59
+ "The newsletter paragraph does not mention the spring-boot bump, the StockLedger refactor or the CI test shards"
60
+ ]
61
+ },
62
+ {
63
+ "id": 5,
64
+ "held_out": "2026-10-06",
65
+ "prompt": "need the what's new text for the app stores for Tallybird 1.6 (habit tracker, it's just me and Sam). short, people don't read these. stuff that's in: dark mode, home screen widgets (iOS only i think? Sam would know), fixed the bug where streaks reset if you logged right around midnight, a few crash fixes, Sam did something with sync, and we dropped iOS 15. iOS goes out tomorrow, android build is still stuck in review",
66
+ "assertions": [
67
+ "It delivers store text that could be pasted in as it stands, not only a list of questions",
68
+ "Dark mode and the fix for streaks resetting around midnight both appear in the store text",
69
+ "The end of iOS 15 support is mentioned in the iOS text or raised explicitly as something users on iOS 15 need to be told",
70
+ "Widgets are not promised to Android users; the output flags that whether widgets are iOS-only needs confirming with Sam, or gives separate iOS and Android text with widgets only in the iOS one",
71
+ "The sync change is not described as a specific improvement (such as faster or more reliable sync); it is left out or flagged as needing detail from Sam",
72
+ "It does not invent crash counts, percentages, a release date for Android, or features that are not in the list",
73
+ "The store text itself is short: about 100 words or fewer per store"
74
+ ]
46
75
  }
47
76
  ]
48
77
  }
@@ -0,0 +1,26 @@
1
+ # git log v4.9.2..v5.0.0-rc2 (oldest first) -- Portside WMS
2
+ 9c1e4a7 2026-07-14 feat(picking): wave planning screen groups orders by carrier cutoff (#1802)
3
+ b3d0f52 2026-07-16 fix(receiving): ASN import rejects files that start with a BOM (#1809)
4
+ 4e7a918 2026-07-21 chore(deps): bump spring-boot 3.2.5 -> 3.3.2
5
+ a80c3de 2026-07-23 feat(scan): batch barcode scan mode for handhelds (#1777)
6
+ 17f6b0c 2026-07-28 chore(db): migrations now use MERGE; requires PostgreSQL 15+ (#1815)
7
+ Installer aborts on PostgreSQL 13 and 14. 4.x supported 13+.
8
+ d52e9a1 2026-07-30 fix(labels): ZPL label truncates SKUs longer than 20 characters (#1821)
9
+ 6fa23c8 2026-08-04 refactor(inventory): split StockLedger into reader and writer
10
+ e19b7d4 2026-08-06 feat(api): /api/v2/stock-levels endpoint with pagination (#1790)
11
+ 0b4c8f1 2026-08-11 fix(picking): dedupe pick lists on wave release (#1833)
12
+ Partial. Split shipments can still produce a duplicate line, tracked in #1893.
13
+ c7719ae 2026-08-13 perf(reports): stock valuation report at 500k SKUs: 212s -> 58s (#1840)
14
+ 83ad5e0 2026-08-18 feat(scan): put batch scan behind flag scan.batch.enabled, default false (#1848)
15
+ Field test at the pilot site showed missed reads on older handhelds.
16
+ Stays off by default until #1851 is fixed.
17
+ f2061bb 2026-08-20 security: session tokens were not invalidated on password change (LSA-2026-04) (#1852)
18
+ 5d9e3c0 2026-08-25 docs: 4.x maintenance ends 2027-03-31 (was 2026-12-31) (#1856)
19
+ a1f47e2 2026-08-27 feat(api)!: remove /api/v1/stock (deprecated since 4.6); use /api/v2/stock-levels (#1858)
20
+ 39b8d6f 2026-09-01 ci: split integration tests into 4 shards
21
+ 7c40e95 2026-09-03 fix: tweaks
22
+ e6d1a07 2026-09-08 feat(config): rename wms.mail.host to wms.smtp.host (#1866)
23
+ Old key is still read and logs a deprecation warning. Removal planned for 6.0.
24
+ 2ab95f3 2026-09-10 fix(receiving): putaway suggestion ignored the bin weight limit (#1870)
25
+ b90c7e8 2026-09-15 feat(ui): Polish translation of the handheld screens (#1874)
26
+ d07a3b6 2026-09-22 fix(installer): upgrade from 4.9.x failed when the backup directory was a symlink (#1881)
@@ -44,6 +44,36 @@
44
44
  "It says five conversations are too few to set a price or to conclude that cafe owners want it, and gives any price suggestion as tentative",
45
45
  "It does not add market figures, competitor prices or cafe-industry facts that are not in the notes"
46
46
  ]
47
+ },
48
+ {
49
+ "id": 4,
50
+ "held_out": "2026-10-06",
51
+ "prompt": "I'm the governance officer at Marlowe Vale Academy Trust (9 secondary schools). Next month the board decides whether to roll the phone-pouch scheme out from the two pilot schools to all nine. Everything we've got is in this folder: pilot-report.md, behaviour-logs.md, teacher-focus-group.md, parent-survey.md and vendor-brochure.md. Can you pull together what the evidence actually shows? Two pages max, it's going in the board pack. They'll particularly want to know what it did to behaviour and to exam results.",
52
+ "assertions": [
53
+ "It states that logged incidents at Fenwick Park rose from 280 to 291, which contradicts the pilot report's statement that incidents fell at both schools",
54
+ "It says Ashcombe's fall from 412 to 318 cannot be credited to the pouches because the logging system changed on 5 January 2026 and stopped counting low-level disruption, which was 96 of the 412 the year before",
55
+ "It traces the 40% reduction figure to the vendor brochure's footnote (a 2019 study of three New Zealand schools commissioned by the vendor) and does not count the pilot report's repetition of it as separate evidence",
56
+ "It corrects the parent survey response rate: 1,140 out of 3,050 is about 37%, not 47%",
57
+ "On exam results it says the sources contain no attainment data (the pilot report says results were not analysed and the brochure's 'improves grades' has no source), and it gives no estimated effect on results",
58
+ "It reports that phone confiscations fell at both schools (87 to 9 at Ashcombe, 64 to 22 at Fenwick Park) as the clearest measured change",
59
+ "It notes the teacher focus group was six teachers all from Ashcombe, with none from Fenwick Park, and reports the drawbacks they raised (for example ten minutes lost at form time or pupils pouching a dummy phone), not only the positive view in the pilot report",
60
+ "It does not bring in research, statistics or claims about phones in schools that are not in the five files"
61
+ ]
62
+ },
63
+ {
64
+ "id": 5,
65
+ "held_out": "2026-10-06",
66
+ "prompt": "I'm on the committee for our village hall and the boiler is on its last legs. We're arguing about whether to get a heat pump instead. This is everything I've collected, sorry it's a bit scrappy:\n\n- Quote from Fernbrook Renewables: £14,200 to fit an air source heat pump. They only do heat pumps. The chap reckoned a new gas boiler would be 'about £4,100' but that's not a quote, he doesn't fit them.\n- Spoke to the treasurer at Little Aldwick hall, they got a heat pump in 2024. She said their bills 'went down about a third'. They also had the roof insulated the same year.\n- Cut a paragraph out of a magazine a while ago, no idea which one or when: 'heat pumps are three to four times as efficient as gas boilers'.\n- I think there's a grant, up to £7,500? Read it somewhere. Not sure village halls can get it.\n- We spent about £2,300 on gas last year I think. Hall's in use maybe 4 days a week.\n\nCan you pull together what we actually know? Mainly: would a heat pump be cheaper to run?",
67
+ "assertions": [
68
+ "It delivers the write-up from the notes as given and does not stop to ask for more information first",
69
+ "It says the notes cannot answer whether a heat pump would be cheaper to run, because they contain no electricity or gas prices and no running-cost estimate for this hall, and it states no annual saving as fact",
70
+ "It says Little Aldwick's bills falling by about a third cannot be put down to the heat pump alone because the roof was insulated in the same year",
71
+ "It says the 'three to four times as efficient' line is about efficiency, not running cost, and comes from an undated cutting from an unknown magazine",
72
+ "The grant is treated as unconfirmed on both the amount and whether a village hall qualifies, and the £7,500 is not subtracted from the cost as if it were secured",
73
+ "It notes that the £4,100 boiler figure is an offhand estimate from an installer who only fits heat pumps, not a quote",
74
+ "It gives the up-front gap as about £10,100 (£14,200 against about £4,100)",
75
+ "It does not add energy prices, grant scheme rules or typical heat pump costs from outside the notes, unless clearly labelled as not coming from the notes"
76
+ ]
47
77
  }
48
78
  ]
49
79
  }
@@ -0,0 +1,31 @@
1
+ # Behaviour logs: pilot schools
2
+
3
+ Extract by the trust data team, 9 July 2026. Counts of logged behaviour incidents per term.
4
+
5
+ ## Ashcombe School (1,620 pupils)
6
+
7
+ | Year | Autumn | Spring | Summer | Total |
8
+ |---|---|---|---|---|
9
+ | 2024-25 (before pilot) | 150 | 138 | 124 | 412 |
10
+ | 2025-26 (pilot year) | 141 | 92 | 85 | 318 |
11
+
12
+ Note: on 5 January 2026 Ashcombe moved from the old paper-and-spreadsheet log to ClassLedger. Under ClassLedger, "low-level disruption" is recorded as a classroom note and is no longer logged as an incident. In 2024-25, low-level disruption accounted for 96 of Ashcombe's 412 incidents.
13
+
14
+ ## Fenwick Park School (1,430 pupils)
15
+
16
+ | Year | Autumn | Spring | Summer | Total |
17
+ |---|---|---|---|---|
18
+ | 2024-25 (before pilot) | 98 | 94 | 88 | 280 |
19
+ | 2025-26 (pilot year) | 101 | 97 | 93 | 291 |
20
+
21
+ Note: no change to the logging system at Fenwick Park in either year.
22
+
23
+ ## Phone confiscations (both years logged the same way at both schools)
24
+
25
+ | School | 2024-25 | 2025-26 |
26
+ |---|---|---|
27
+ | Ashcombe | 87 | 9 |
28
+ | Fenwick Park | 64 | 22 |
29
+
30
+ ## Not available
31
+ No behaviour extract was requested for the seven schools outside the pilot.
@@ -0,0 +1,25 @@
1
+ # Parent survey: summary
2
+
3
+ Online survey, open 1–19 June 2026. Sent to all 3,050 households with a child at Ashcombe or Fenwick Park. One response per household.
4
+
5
+ Responses received: 1,140 (Ashcombe 790, Fenwick Park 350)
6
+
7
+ ## Q1. Should the pouch scheme continue next year?
8
+ | Answer | Share of respondents |
9
+ |---|---|
10
+ | Yes | 58% |
11
+ | No | 24% |
12
+ | Not sure | 18% |
13
+
14
+ Results were not broken down by school.
15
+
16
+ ## Q2. What, if anything, worries you about the scheme? (tick all that apply)
17
+ | Concern | Share of respondents |
18
+ |---|---|
19
+ | Not being able to reach my child in an emergency | 41% |
20
+ | Cost of replacing a lost pouch | 19% |
21
+ | My child needs their phone for a medical reason | 6% |
22
+ | Nothing worries me | 37% |
23
+
24
+ ## Q3. Has your child's behaviour at home around their phone changed?
25
+ Free text, 412 comments. Not yet coded.
@@ -0,0 +1,27 @@
1
+ # Phone-pouch pilot: evaluation report
2
+
3
+ Prepared by Hollis Tran, Office of the Deputy CEO, Marlowe Vale Academy Trust
4
+ 17 July 2026
5
+
6
+ ## 1. Background
7
+ From September 2025 pupils at two of our nine secondary schools, Ashcombe School and Fenwick Park School, have locked their phones in a magnetic pouch at morning registration and unlocked them at the gate at the end of the day. The other seven schools kept the existing "off and in your bag" rule.
8
+
9
+ ## 2. Behaviour
10
+ Behaviour incidents fell at both pilot schools over the pilot year. This is in line with evidence from other schools, which shows a 40% reduction in behaviour incidents after pouches are introduced.
11
+
12
+ Phone confiscations dropped sharply at both schools.
13
+
14
+ ## 3. Staff view
15
+ A focus group of teachers was positive overall. Staff reported fewer confrontations in lessons.
16
+
17
+ ## 4. Parents
18
+ Parents are strongly supportive. 58% of respondents support continuing the scheme. The response rate was 47% (1,140 responses from 3,050 households).
19
+
20
+ ## 5. Attainment
21
+ Summer 2026 exam results had not been analysed at the time of writing.
22
+
23
+ ## 6. Cost
24
+ Year-one cost was £25.40 per pupil, including replacement of the 11% of pouches lost or damaged during the year.
25
+
26
+ ## 7. Recommendation
27
+ Roll out to all nine schools from January 2027.
@@ -0,0 +1,19 @@
1
+ # Teacher focus group: notes and quotes
2
+
3
+ Held 12 May 2026, Ashcombe School library, 50 minutes. Six teachers, all from Ashcombe. Facilitated by Hollis Tran. A session at Fenwick Park was planned for June but did not take place.
4
+
5
+ [04:10] Maths teacher: "I used to have one argument a week about a phone under the desk. I've had maybe two all year."
6
+
7
+ [09:30] Head of Year 9: "Form time is a mess now. Pouching takes ten minutes every morning. That's ten minutes of registration and notices gone."
8
+
9
+ [14:45] English teacher: "Some of them bring an old dead phone to put in the pouch and keep the real one. I don't know how many. More in Year 10 and 11."
10
+
11
+ [21:00] Science teacher: "I miss them for practicals. We used phone timers and the slow-motion camera. I've had to book the tablet trolley and there's one trolley for the department."
12
+
13
+ [27:20] PE teacher: "Lunchtime is louder. They actually talk to each other. I'd call that a good thing but the duty staff might not."
14
+
15
+ [33:05] Head of Year 9: "The gate at ten past three is the flashpoint. One unlocking station per year group, two hundred and seventy kids. We've had pushing."
16
+
17
+ [41:15] Maths teacher: "Would I go back? No. But I wouldn't say behaviour is transformed. Lessons are calmer. Corridors are the same."
18
+
19
+ [46:00] English teacher: "Nobody has asked the pupils."