Fix the Placemint redeployment sync
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.
Fix the Placemint redeployment sync
From: Integrations / Delivery Ops Vendor: Placemint Surface: polling, writeback Category: fix · Tier: 2
Context
Meridian Talent Group’s ATS records a redeployment — a candidate coming off one
assignment and onto another — as one card movement with two ends. The nightly
export in input/redeployments.csv has a row per movement: the placement the
candidate left and the status it should end up on, the placement they joined
with its status and fee, when it happened, and the reason the consultant typed.
This connector pushes those into Placemint, which is what Finance reads.
It has run every night for two years. Finance’s quarter-end reconciliation has just come back and Yannick has escalated:
“The reconciliation will not balance. I have placements sitting closed with nobody opened against them, and candidates whose old assignment has been reopened and closed again by this thing weeks after the desk had already finished with it. The log says most of these rows were refused, so I do not understand how anything got written at all — and where it did write, half the time there is no note, so nobody can tell me why any of it moved.”
Delivery Ops keep their own runbook for this job at
docs/meridian-redeployment-runbook.md. Full vendor documentation is in
docs/ — start at docs/index.md.
The rules Delivery Ops settled on
These are ours, not Placemint’s.
- A redeployment lands in full or not at all. In full means: the leaver
carries the row’s
from_status, the joiner carries the row’sto_statusandto_fee_amount, and exactly one note holding the row’sreasonverbatim is filed on the joiner, authoredredeployments@meridian.test. - A row naming a placement Placemint does not hold is
unknown: logged, nothing written. - A row whose leaver has already closed — Placemint has it at
placedorfell_through— is one the desk has already dealt with. It isrejected: nothing written, on either end. - A row carrying a status that is not one of Placemint’s placement stages is
rejected: nothing written, on either end. - One entry in the log per row of the export, in file order, and a redeployment is never applied twice.
What we need
The harness runs your code exactly as follows — this command is the contract:
python -m placemint_movement_sync apply-movements
# -> writes the output artifact listed below
- Work out how a row the log calls refused is still changing Placemint.
- Fix it, keeping the rules above.
- Re-run; running twice over the same export must leave Placemint exactly as the first run left it.
Output artifacts
output/movement_log.json—row_count,applied_count,rejected_count,unknown_count, andmovements: one entry per row of the export, in file order, each with itsmovement_ref,from_placement_id,to_placement_id,outcome(applied,rejectedorunknown), thefrom_stage,to_stageandto_fee_amountwritten, thenote_idPlacemint gave the note, and thesource_lineit came from.
Environment
| Variable | Meaning |
|---|---|
VENDOR_BASE_URL | Vendor sandbox base URL (e.g. http://vendor:8000) |
PM_CLIENT_ID | Vendor credential injected by the test harness |
PM_CLIENT_SECRET | Vendor credential injected by the test harness |
REDEPLOYMENTS_FILE | Path to the ATS’s nightly redeployment export |
OUTPUT_DIR | Directory where output artifacts land (defaults to ./output) |
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
The entry command exits 0, every redeployment the rules allow has landed on both its placements with the note the export asks for, nothing the rules exclude carries anything this run put there, the log accounts for each row exactly once, and a second run changes nothing.
Graded checks (306)
Names of every assertion the grader runs for this task. Per-attempt pass/fail and details are on each trajectory page.
- redeployment_run_completed
- movement_log_accounts_for_every_row_once
- redeployment_RD-2026-0001_logged_rejected
- redeployment_RD-2026-0002_logged_rejected
- redeployment_RD-2026-0003_logged_unknown
- redeployment_RD-2026-0004_logged_rejected
- redeployment_RD-2026-0005_logged_rejected
- redeployment_RD-2026-0006_logged_unknown
- redeployment_RD-2026-0007_logged_rejected
- redeployment_RD-2026-0008_logged_rejected
- redeployment_RD-2026-0009_logged_unknown
- redeployment_RD-2026-0010_logged_unknown
- redeployment_RD-2026-0011_logged_unknown
- redeployment_RD-2026-0012_logged_rejected
- redeployment_RD-2026-0013_logged_rejected
- redeployment_RD-2026-0014_logged_rejected
- redeployment_RD-2026-0015_logged_rejected
- redeployment_RD-2026-0016_logged_rejected
- redeployment_RD-2026-0017_logged_rejected
- redeployment_RD-2026-0018_logged_rejected
- redeployment_RD-2026-0019_logged_applied
- redeployment_RD-2026-0020_logged_applied
- redeployment_RD-2026-0021_logged_applied
- redeployment_RD-2026-0022_logged_applied
- redeployment_RD-2026-0023_logged_rejected
- redeployment_RD-2026-0024_logged_applied
- redeployment_RD-2026-0025_logged_applied
- redeployment_RD-2026-0026_logged_unknown
- redeployment_RD-2026-0027_logged_rejected
- redeployment_RD-2026-0028_logged_unknown
- redeployment_RD-2026-0029_logged_rejected
- redeployment_RD-2026-0030_logged_rejected
- redeployment_RD-2026-0031_logged_rejected
- redeployment_RD-2026-0032_logged_unknown
- redeployment_RD-2026-0033_logged_applied
- redeployment_RD-2026-0034_logged_rejected
- redeployment_RD-2026-0035_logged_rejected
- redeployment_RD-2026-0036_logged_rejected
- redeployment_RD-2026-0037_logged_applied
- redeployment_RD-2026-0038_logged_rejected
- redeployment_RD-2026-0039_logged_rejected
- redeployment_RD-2026-0040_logged_rejected
- redeployment_RD-2026-0041_logged_rejected
- redeployment_RD-2026-0042_logged_rejected
- redeployment_RD-2026-0043_logged_applied
- redeployment_RD-2026-0044_logged_rejected
- redeployment_RD-2026-0045_logged_rejected
- redeployment_RD-2026-0046_logged_rejected
- redeployment_RD-2026-0047_logged_applied
- redeployment_RD-2026-0048_logged_rejected
- redeployment_RD-2026-0049_logged_rejected
- redeployment_RD-2026-0050_logged_unknown
- redeployment_RD-2026-0051_logged_applied
- redeployment_RD-2026-0052_logged_applied
- redeployment_RD-2026-0053_logged_rejected
- redeployment_RD-2026-0054_logged_rejected
- redeployment_RD-2026-0055_logged_rejected
- redeployment_RD-2026-0056_logged_unknown
- redeployment_RD-2026-0057_logged_applied
- redeployment_RD-2026-0058_logged_rejected
- and 246 more