The case-note mirror is short every morning
Results
The ticket
This is PROBLEM.md exactly as the agent received it. Vendor documentation and the starter repository ship inside the task environment and are not reproduced here.
The case-note mirror is short every morning
From: Clinical Systems / Ellerby Health Vendor: Rosterly Surface: polling Category: harden · Tier: 3
Context
Our safeguarding team works from a nightly mirror of the case notes attached to
carers in Rosterly. The job in repo/ came across from the pilot tenant and has
been running successfully in production: it exits cleanly, writes both files,
and gives the morning meeting a plausible-looking total.
The live tenant is now much larger than the pilot. During an audit, Clinical
Governance sampled notes visible in Rosterly and found that a substantial number
never reached import_report.csv. The missing notes do not fall into one date
range, author, or carer status, and the job has not raised an operational error.
We need the existing connector hardened so that a successful run means the
mirror is genuinely complete.
Ellerby’s operating note for this job is at
docs/ellerby-case-note-mirror-note.md. Full vendor documentation is in
docs/ — start at docs/index.md.
What we need
The harness runs one nightly pass exactly as follows:
python -m ellerby_note_mirror
Keep the existing package and artifact shapes. A pass must read the complete Rosterly roster and mirror every case note the tenant currently holds, exactly once. A note remains part of the mirror for as long as Rosterly returns it, including notes and carers represented as retired upstream. The job must not report a partial pass as complete.
Output artifacts
output/import_report.csv— header row plus one row per case note, sorted bynote_id:note_id,worker_id,author,body,created_utc,updated_utc,state. Both timestamps are UTC strings inYYYY-MM-DDTHH:MM:SSZform.stateisactiveorretired.output/result.json—workers_on_roster,workers_polled,note_count,active_note_count, andretired_note_countfor that same pass.
Keep transport, mirror decisions, and artifact writing separate.
Environment
| Variable | Meaning |
|---|---|
VENDOR_BASE_URL | Rosterly sandbox base URL |
RY_CLIENT_ID | OAuth client id injected by the harness |
RY_CLIENT_SECRET | OAuth client secret injected by the harness |
OUTPUT_DIR | Artifact directory (defaults to ./output) |
PAGE_LIMIT | Optional page-size override |
Engineering expectations
This ships to production, so the usual bar applies:
- Well-organized, modular code — keep transport, sync logic, and output concerns separate.
- Tests, runnable with
pytest, covering the core logic you add or change. - Be a good API citizen: handle the vendor’s real-world behavior the way a production integration must, and don’t hammer endpoints in retry loops. Our platform team audits vendor request logs — sloppy conduct gets flagged even when the data lands correctly.
Done when
python -m ellerby_note_mirror exits 0, the report contains exactly one
correct row for every case note Rosterly holds against the complete roster,
the summary counts agree with that report, retired material is represented
with the required state, and no incomplete pass is presented as a successful
mirror.
Graded checks (159)
Names of every assertion the grader runs for this task. Per-attempt pass/fail and details are on each trajectory page.
- case_note_mirror_run_completed
- case_note_mirror_headline_counts_exact
- case_note_mirror_csv_contract_exact
- case_note_note_0001_mirrored_exact
- case_note_note_0002_mirrored_exact
- case_note_note_0003_mirrored_exact
- case_note_note_0004_mirrored_exact
- case_note_note_0005_mirrored_exact
- case_note_note_0006_mirrored_exact
- case_note_note_0007_mirrored_exact
- case_note_note_0008_mirrored_exact
- case_note_note_0009_mirrored_exact
- case_note_note_0010_mirrored_exact
- case_note_note_0011_mirrored_exact
- case_note_note_0012_mirrored_exact
- case_note_note_0013_mirrored_exact
- case_note_note_0014_mirrored_exact
- case_note_note_0015_mirrored_exact
- case_note_note_0016_mirrored_exact
- case_note_note_0017_mirrored_exact
- case_note_note_0018_mirrored_exact
- case_note_note_0019_mirrored_exact
- case_note_note_0020_mirrored_exact
- case_note_note_0021_mirrored_exact
- case_note_note_0022_mirrored_exact
- case_note_note_0023_mirrored_exact
- case_note_note_0024_mirrored_exact
- case_note_note_0025_mirrored_exact
- case_note_note_0026_mirrored_exact
- case_note_note_0027_mirrored_exact
- case_note_note_0028_mirrored_exact
- case_note_note_0029_mirrored_exact
- case_note_note_0030_mirrored_exact
- case_note_note_0031_mirrored_exact
- case_note_note_0032_mirrored_exact
- case_note_note_0033_mirrored_exact
- case_note_note_0034_mirrored_exact
- case_note_note_0035_mirrored_exact
- case_note_note_0036_mirrored_exact
- case_note_note_0037_mirrored_exact
- case_note_note_0038_mirrored_exact
- case_note_note_0039_mirrored_exact
- case_note_note_0040_mirrored_exact
- case_note_note_0041_mirrored_exact
- case_note_note_0042_mirrored_exact
- case_note_note_0043_mirrored_exact
- case_note_note_0044_mirrored_exact
- case_note_note_0045_mirrored_exact
- case_note_note_0046_mirrored_exact
- case_note_note_0047_mirrored_exact
- case_note_note_0048_mirrored_exact
- case_note_note_0049_mirrored_exact
- case_note_note_0050_mirrored_exact
- case_note_note_0051_mirrored_exact
- case_note_note_0052_mirrored_exact
- case_note_note_0053_mirrored_exact
- case_note_note_0054_mirrored_exact
- case_note_note_0055_mirrored_exact
- case_note_note_0056_mirrored_exact
- case_note_note_0057_mirrored_exact
- and 99 more