ProcureOps Procurement Control — Solver Skill (task_group_006)
Reusable workflow rules for solving Procurement Supplier & Receiving Control tasks against the shared ProcureOps API. Recipe-oriented experience; not candidate answers. Applies to all four task families: A Sourcing nomination, B Receiving-control closeout, C AP close / vendor-balance, D Change-control amendment, plus the cross-family Receiving/AP release file.
0. Environment & API mechanics
- Remote API (system of record):
<remote-env-url>. Prompts that say http://127.0.0.1:8006 mean THIS SAME remote service — always call the remote URL.
- Collections (GET list ->
{"count":N,"results":[...]}; GET /<coll>/<id> -> the record object): programs, suppliers, items, contracts, purchase_requisitions (aliases /purchase-requests, /purchase-requisitions), purchase_orders (alias /purchase-orders), receipts, ap_invoices (alias /ap/invoices), payments (alias /ap/payments), approval_events (alias /approvals), budget_snapshots (alias /budgets), vendor_risk_events (alias /vendor-risks).
- Query filters match substring/case-insensitive (incl. nested list values); blank values ignored.
start/end filter the collection's date field inclusively. There is NO pagination/_limit param — unknown params become field filters returning 0. Fetch by id from the memo/template; do not dump whole collections.
GET /manifest gives record counts + anchor ids (no task ids / answer keys). GET /health confirms liveness.
- Reconciliation chain: Program -> contracts/requisitions/POs/budget_snapshots/invoices(via po.program_id). PO -> receipts(same po_id, multiples allowed) -> invoices(invoice.po_id / invoice.receipt_id) -> payments(payment.invoice_id). Contract(contract_id) <-> PO(po.contract_id) <-> PO line unit_price <-> invoice line unit_price (contract.unit_price is the price-match anchor).
- Units: USD amounts in records are DOLLARS. Read each answer_template's per-field unit/precision (some want cents, most want 2-decimal USD; qty 2 decimals; pct 1 decimal; ratios 4 decimals). Sort every ID list ascending; list fields marked "set" are compared as sets.
Universal solver workflow
- Read the prompt + the task-local memo/packet +
answer_template.json. Extract: program_id, as-of/review date, target ids (POs/receipts/invoices/requisition/contract/supplier/sku), and any business-control rules (tax rate, approval good-actions, ceiling/budget exposure definitions, cancel-exclusion, supplier-watch policy).
- Fetch each target id directly by id; fetch related records via filter (
?po_id=, ?supplier_id=, ?contract_id=, ?sku=, ?object_id=, ?program_id=, ?invoice_id=). Fetch ALL POs on a contract (?contract_id=) and ALL receipts on a PO (?po_id=) — there can be multiple, including cancelled POs and duplicate/later receipts.
- Apply the as-of date filter to every time-sensitive set: receipts (receipt_date <= as_of), invoices (invoice_date <= as_of), vendor_risk_events (event_date <= as_of AND status in {open, monitoring}), budget_snapshots (snapshot_date <= as_of, pick the latest), payments (scheduled_date <= cutoff given in memo, e.g. "through 2026-06-30").
- Derive the fields per the family recipes below, using the enum/option sets EXACTLY as allowed. Round to the template's precision. Sort all lists.
- Emit only the JSON object matching the template. No prose.
Family A — Sourcing nomination readiness (scope + as-of, budget, per-SKU supplier decision, evidence/blockers, committee action)
Template shape: task_id ("task_group_006_train_001" / "task_group_006_test_003" pattern — use the exact required_value), program_id, as_of_date (memo date), package_line_skus (sorted), program_summary {owner, budget_headroom_usd, overall_readiness}, nomination_lines[] (matched by sku), committee_action.
Recipes:
as_of_date = the memo date.
program_summary.owner = programs.owner. budget_headroom_usd = budget_cap - committed_amount (programs row). overall_readiness = WORST-CASE across the package lines — if ANY anchor line is not_ready, overall = not_ready. Do NOT soften a not_ready line into an overall at_risk (confirmed: softening dropped the score).
- Per line (one per package anchor SKU):
selected_supplier_id = the PO's supplier_id (or item.preferred_supplier_id when no PO).
primary_requisition_id = the memo-named requisition (== po.requisition_id).
commercial_basis_id = the contract_id linked to the PO (po.contract_id); null when the PO has no contract.
package_po_ids = POs for this SKU/line (sorted).
receipt_evidence_ids = receipts for the PO with receipt_date <= as_of (sorted). Exclude later receipts.
invoice_exception_ids = invoices for the PO that are in AP-hold state as of as_of (sorted). Key on AP-hold status (see blocker note below).
risk_event_ids = vendor_risk_events for the supplier with status in {open, monitoring} AND event_date <= as_of (sorted). Supplier-level — include any open event for the supplier regardless of related_object_id.
blocker_codes (sorted) from this set: missing_contract (po.contract_id is null), supplier_watch (supplier.risk_rating == "watch"), open_supplier_risk (>=1 open/monitoring risk event as of as_of), ap_hold (an invoice for the PO has status == "on_hold"), pending_receipt (PO not fully received — no receipt OR received < ordered), late_due_date (po.due_date or requisition.need_by < as_of), none.
nomination_decision: nominate (no blockers; contract+receipt present) / conditional_nomination (commercial basis contract exists + receipt evidence present, but clearable exceptions like AP hold / partial receipt) / hold (hard blocker: missing_contract or no receipt).
readiness_status: ready (no blockers) / at_risk (clearable blockers, contract+receipt present) / not_ready (hard blocker).
committee_action: nominate_now_supplier_ids (lines with nominate), conditional_supplier_ids (conditional_nomination), hold_supplier_ids (hold), all sorted. next_owner in {buyer, finance_ops, quality_ops, program_owner, ap_team}. send_to_committee in {yes, no}.
- CRITICAL blocker flag rule (confirmed across families):
ap_hold keys on invoice status == on_hold. An invoice with status pending_receipt / hold_code NO_RECEIPT is a RECEIVING issue -> use the pending_receipt blocker, NOT ap_hold. Do not double-flag.
Pitfalls: overall_readiness must be worst-case (not a blend). missing_contract is a hard blocker -> hold/not_ready. A requisition may be converted while the approval_events show only submitted (see Family D) — for nomination, rely on the PO/contract/receipt evidence, not approval status. Watch-rated supplier with only a medium open risk still gets supplier_watch + open_supplier_risk blockers but is not a hard hold.
Family B — Receiving-control closeout (batch identity, receipt scope, ordered/received/billed reconciliation, price match, AP hold/release, financials, supplier-risk overlay, chargeback)
Template shape: task_id, batch_id, inspection_summary, line_reconciliation[] (sort by po_line_id), invoice_review, financials, decision, supplier_risk_context, evidence.
Recipes:
batch_id = the receipt under review (from the memo).
- The invoice in scope = the
ap_invoice whose receipt_id == batch_id (fetch ?po_id= for the batch's PO, pick the invoice tied to this receipt). Other invoices on the same PO tie to OTHER receipts -> out of scope for this batch.
inspection_summary: po_id, supplier_id, warehouse_id, receipt_date, packing_slip, receiver from the BATCH receipt; program_id from the PO; supplier_name from the supplier.
line_reconciliation per po_line_id present in the BATCH receipt:
ordered_qty = PO line quantity.
received_qty = the BATCH's receipt line quantity_received (NOT cumulative across all PO receipts; only this batch, and only receipts with receipt_date <= review).
rejected_qty = batch receipt line quantity_rejected.
billed_qty = the in-scope invoice line quantity_billed.
short_qty_vs_po = ordered - received. unreceived_billed_qty = billed - received.
receipt_completion_ratio = received / ordered (4 decimals).
po_unit_price (PO line) / contract_unit_price (contract.unit_price for po.contract_id) / invoice_unit_price (invoice line). contract_price_match = (contract_unit_price == po_unit_price).
invoice_review: invoice_id, invoice_status, hold_code (string or null), receipt_status (the BATCH receipt.status), po_status (PO.status), exception_codes (set; evaluator sorts).
exception_codes (allowed: INVOICE_QTY_EXCEEDS_RECEIPT, PARTIAL_RECEIPT, SUPPLIER_WATCH_RISK, PRICE_MISMATCH, DAMAGE_REJECTION, NO_EXCEPTION) — include EVERY true condition:
- INVOICE_QTY_EXCEEDS_RECEIPT: billed > received.
- PARTIAL_RECEIPT: received < ordered.
- SUPPLIER_WATCH_RISK: supplier.risk_rating == watch (and/or an open risk event). INCLUDE this code even though supplier_risk_context separately reports risk (confirmed: dropping it lowered the score).
- PRICE_MISMATCH: contract/PO/invoice unit prices differ.
- DAMAGE_REJECTION: quantity_rejected > 0 or inspection failure.
- NO_EXCEPTION: only when none of the above apply.
financials (USD, 2 decimals): received_goods_value = received_qty × po_unit_price; unreceived_goods_value = (ordered - received) × po_unit_price (equivalently (billed - received) × price when billed=ordered); invoice_subtotal/invoice_freight/invoice_tax/invoice_total from the in-scope invoice record.
decision:
batch_disposition (accept_partial_hold_variance / release_full_invoice / reject_batch / manual_recount_required): partial receipt accepted with an invoice qty-variance hold -> accept_partial_hold_variance.
ap_action (keep_invoice_on_hold / release_invoice / void_invoice): qty-variance hold -> keep_invoice_on_hold.
receiving_action (record_shortage_follow_up / no_receiving_action / reject_all_units): shortage (received < ordered) -> record_shortage_follow_up.
supplier_action (request_credit_or_remaining_delivery / no_supplier_action / supplier_debit_for_damage): underage (billed but unreceived) -> request_credit_or_remaining_delivery; damage -> supplier_debit_for_damage.
supplier_risk_context: supplier_risk_rating, has_open_supplier_risk (>=1 open/monitoring event as of review), open_supplier_risk_event_ids (sorted).
evidence.endpoint_record_ids: include the core records used (PO, receipt, invoice, contract, supplier, program, risk event). This field is subset-checked (extras tolerated; missing required ones hurt). task_payloads_reviewed: the memo filename(s).
Pitfalls: received_qty is the BATCH's only — do not sum later/duplicate receipts. Only the invoice with receipt_id == batch_id is in scope. exception_codes is a comprehensive flag set; include SUPPLIER_WATCH_RISK for watch suppliers. For an accepted partial receipt with billed>received (underage): accept_partial_hold_variance / keep_invoice_on_hold / record_shortage_follow_up / request_credit_or_remaining_delivery (this matches an approved "Underage Quantity" chargeback).
Family C — AP close / vendor-balance + hold/release (invoice hold/release, qty-variance %, totals & scheduled payments & net balance, vendor balance rows, program close totals, payment queues)
Template shape: task_id, close_date, invoice_decisions[] (invoice_id ascending), vendor_balances[] (supplier_id ascending), program_summary[] (program_id ascending), payment_hold_queue, payment_release_queue, total_close_balance.
Recipes (slice = the named target invoices only):
close_date = memo date. Opening AP balance for target suppliers in this slice = 0.00 (per memo). Scheduled payments through the memo cutoff (e.g. 2026-06-30) reduce the close balance.
invoice_decisions per target invoice:
hold_decision: invoice.status approved -> RELEASE; on_hold -> HOLD; pending_receipt -> HOLD.
hold_code: from invoice (string or null).
release_to_payment: true for RELEASE, false for HOLD.
quantity_billed = invoice line quantity_billed (2 decimals).
quantity_received = the invoice's receipt line quantity_received (invoice.receipt_id -> receipt line); 0.00 when receipt_id is null / no receipt.
quantity_variance = billed - received.
quantity_variance_pct = variance / PO quantity × 100 (PO line quantity is the denominator), 1 decimal.
invoice_total = invoice.total.
scheduled_payment_amount = sum of payments for this invoice with status scheduled AND scheduled_date <= cutoff (memo "through YYYY-MM-DD").
net_balance_impact = invoice_total - scheduled_payment_amount.
reason_codes (alphabetical; allowed: APPROVED_THREE_WAY_MATCH, NO_RECEIPT, QTY_VARIANCE, SCHEDULED_PAYMENT_FOUND):
- APPROVED_THREE_WAY_MATCH: PO qty == received == billed AND all unit prices match -> RELEASE reason.
- SCHEDULED_PAYMENT_FOUND: a scheduled payment exists for this invoice (affects net balance).
- NO_RECEIPT: invoice has no receipt (receipt_id null). NO_RECEIPT SUBSUMES QTY_VARIANCE — when there is no receipt, emit
[NO_RECEIPT] ONLY; do NOT also emit QTY_VARIANCE (the variance is a consequence of no receipt). Confirmed: this was the single fix to reach a perfect score.
- QTY_VARIANCE: receipt exists but billed != received.
- 3-way match test: PO line qty == receipt qty == invoice billed qty AND PO/contract/invoice unit prices all equal.
vendor_balances per target supplier (one row each):
opening_balance = 0.00 (slice).
invoice_total = sum of this supplier's target invoice totals.
scheduled_payments = sum of this supplier's target invoices' scheduled payments (through cutoff).
held_invoice_total = sum of HOLD-decision invoice totals (includes on_hold AND pending_receipt invoices — both are blocked).
releasable_invoice_total = sum of RELEASE-decision (approved) invoice totals.
close_balance = opening_balance + invoice_total - scheduled_payments.
balance_status (OPEN_HELD / OPEN_APPROVED / FULLY_SCHEDULED): approved AND a scheduled payment fully covers it -> FULLY_SCHEDULED; approved but not yet scheduled -> OPEN_APPROVED; has any held invoice -> OPEN_HELD.
program_summary per program (group target invoices by po.program_id):
invoice_count, invoice_total (sum), held_total (HOLD invoices), released_total (RELEASE invoices), net_close_balance = sum of that program's supplier close_balances (= invoice_total - scheduled_payments for the program).
payment_hold_queue = HOLD-decision invoice_ids (ascending). payment_release_queue = RELEASE-decision invoice_ids (ascending).
total_close_balance = sum of all vendor close_balances.
Pitfalls: variance_pct denominator is PO quantity (not received/billed). received=0 when no receipt. NO_RECEIPT subsumes QTY_VARIANCE. held_invoice_total includes pending_receipt invoices. FULLY_SCHEDULED requires the scheduled payment to cover the approved invoice. A "converted" requisition is irrelevant here — use the invoice/receipt/payment records.
Family D — Change-control contract amendment (contract status/price/qty, usage & headroom/ceiling, program-budget incremental exposure, requisition approval state, supplier risk, hold actions, final decision)
Template shape: change_request_id, program_id, contract_id, sku, supplier_id, variant_code, decision, contract_check, program_budget_check, approval_check, supplier_risk_check, supporting_ids, required_actions, summary.
Recipes:
change_request_id = memo memo_id.
contract_check:
contract_status, price_type, unit_price, ceiling_amount from the contract.
noncancelled_subtotal = sum of line subtotals (qty × unit_price) of NON-CANCELLED POs on the contract (fetch ?contract_id=; exclude status == cancelled). This is the "contract ceiling exposure = line subtotal before tax and freight" per memo business_controls.
requested_quantity = memo requested_incremental_quantity.
requested_subtotal = requested_quantity × contract unit_price (no price change unless the memo states one).
headroom_before_change = ceiling_amount - noncancelled_subtotal.
headroom_after_change = ceiling_amount - (noncancelled_subtotal + requested_subtotal).
ceiling_ok = headroom_after_change >= 0.
program_budget_check:
snapshot_id = budget_snapshot for the program with snapshot_date <= memo_date (latest). budget_cap, committed_amount from that snapshot.
remaining_budget = budget_cap - committed_amount.
requested_tax = requested_subtotal × tax_rate_percent (memo business_controls.tax_rate_percent, e.g. 7.25 -> 0.0725).
requested_total = requested_subtotal + requested_tax (+ freight ONLY if the memo provides freight).
budget_after_change = remaining_budget - requested_total.
budget_ok = budget_after_change >= 0.
max_quantity_with_current_budget = floor(remaining_budget / (unit_price × (1 + tax_rate_percent))) — per-unit cost includes tax.
approval_check:
source_requisition_id = memo source requisition.
- Fetch
approval_events?object_id=<requisition_id>. latest_event_id/latest_action/latest_actor/latest_event_date = the latest event.
approval_ok = latest_action is in memo business_controls.approval_good_actions (e.g. ["approved"]). Use approval_events, NOT the requisition status — a requisition may be converted while its latest approval event is only submitted -> approval_ok = false (confirmed).
supplier_risk_check:
supplier_status, supplier_risk_rating from supplier.
open_event_ids = vendor_risk_events for the supplier with status in {open, monitoring} AND event_date <= memo_date (sorted).
severe_open_event_ids = open events with severity high or critical (medium/low are NOT severe) (sorted).
supplier_risk_ok = (severe_open_event_ids is empty). Per memo: a watch rating is context only unless an OPEN SEVERE event exists — so a watch supplier with only a medium open event is still supplier_risk_ok = true.
supporting_ids: included_po_ids (non-cancelled POs on the contract, sorted), excluded_cancelled_po_ids (cancelled POs on the contract, sorted), approval_event_ids (for the requisition, sorted).
decision (release_amendment / hold_for_budget / hold_for_approval / hold_for_supplier_risk / hold_for_budget_and_approval / reject_contract_mismatch):
ceiling_ok false -> reject_contract_mismatch.
- else combine failing checks: budget + approval both fail ->
hold_for_budget_and_approval; budget only -> hold_for_budget; approval only -> hold_for_approval; supplier risk only -> hold_for_supplier_risk; all ok -> release_amendment.
required_actions (sorted; allowed: obtain_final_requisition_approval, raise_budget_exception_or_reduce_quantity, resolve_supplier_risk_hold, none): add one per failing check (approval -> obtain_final_requisition_approval; budget -> raise_budget_exception_or_reduce_quantity; risk -> resolve_supplier_risk_hold); none only when all ok.
summary: blocker_count = number of failing checks (ceiling/budget/approval/supplier_risk — but ceiling_ok false is reject_contract_mismatch, counted as a blocker too); currency = USD; ready_to_release = (blocker_count == 0).
Pitfalls: noncancelled_subtotal excludes cancelled POs (a contract can have several POs, some cancelled). approval_ok is event-based, not status-based. supplier_risk_ok needs an OPEN SEVERE event; medium doesn't block. requested_total includes estimated tax at the memo's tax_rate; include freight only if the memo provides it. max_quantity divides remaining budget by the tax-inclusive per-unit cost.
Cross-family — Receiving/AP release file (per-invoice release decision net of chargebacks, receiving exceptions, chargeback netting, source classification, followups)
Template shape: task_id, review_as_of, target_ids (sorted), release_decisions[], receiving_exceptions[], summary.
This family combines a LOCAL chargeback register excerpt (in the packet) with ProcureOps PO/receipt/AP records. Map each chargeback row to its invoice + receipt + PO.
Recipes:
release_decisions per target invoice (sorted by invoice_id):
decision: release_net_after_approved_chargeback (chargeback status approved -> release invoice net of the approved chargeback) / hold_missing_receipt (no receipt on the PO, no chargeback) / hold_pending_quality_chargeback (chargeback status pending_quality_review and/or receipt status inspection_hold).
primary_reason: approved_qty_chargeback (chargeback reason "Underage Quantity", approved) / approved_ap_quantity_variance (chargeback reason "AP Quantity Variance", approved) / no_receipt_on_po (no receipt) / inspection_hold_pending_chargeback (pending quality / inspection hold).
approved_chargeback_amount = basis_quantity × unit_cost for the invoice's chargeback with status approved.
pending_chargeback_amount = basis_quantity × unit_cost for the invoice's chargeback with status pending_quality_review.
net_release_amount = 0.00 for HELD invoices (hold_missing_receipt / hold_pending_quality_chargeback); = invoice_total - approved_chargeback_amount for RELEASED invoices. Confirmed: using the computed net for held invoices lowered the score — held releases nothing.
receipt_ids_in_scope = the target receipt(s) tied to this invoice (via the invoice's receipt_id OR the chargeback's receipt_id), sorted.
excluded_same_po_receipt_ids = other receipts on the same PO that are NOT in the packet's target receipt set (e.g. a duplicate receipt for a separate invoice), sorted.
receiving_exceptions per target receipt (sorted by receipt_id):
exception_codes (zero or more of: Underage Quantity, Severe Unmatched Quantity, Inspection Hold, AP Quantity Variance): map from the chargeback reason + receipt status. "Underage Quantity" -> Underage Quantity (received < ordered). "AP Quantity Variance" -> AP Quantity Variance (billed > received with received == ordered). Receipt status inspection_hold -> add Inspection Hold. Sort alphabetically within the list.
chargeback_status (approved / pending_quality_review / not_applicable) = the chargeback's status for this receipt's invoice.
resolution_status (net_release_ready / hold_for_quality_review / accepted_no_receiving_exception / missing_receipt): approved chargeback -> net_release_ready; pending_quality_review / inspection_hold -> hold_for_quality_review; no exception -> accepted_no_receiving_exception; no receipt on the PO -> missing_receipt.
summary:
release_invoice_ids (RELEASE decisions, sorted), hold_invoice_ids (HOLD decisions, sorted).
approved_chargeback_total = sum of approved_chargeback_amount across all invoices.
pending_chargeback_total = sum of pending_chargeback_amount across all invoices.
net_release_total = sum of net_release_amount for RELEASED invoices only (= released nets; held contribute 0).
authoritative_sources (one or more of: procureops_po_records, procureops_receipt_records, procureops_ap_records, local_chargeback_register): include the ProcureOps record sources AND local_chargeback_register (the chargeback register drives the netting — it is authoritative, not supporting).
supporting_only_sources (one or more of: ap_release_request_note, stale_po73xx_alias_note): requester comment notes and stale alias notes are supporting/context only.
followup_actions (one or more of: ask_receiving_for_vantix_receipt, hold_luma_duplicate_receipt_for_separate_invoice, route_po00031_quality_review, post_approved_chargeback_netting): include each applicable action — ask receiving for a missing receipt; hold/segregate a duplicate same-PO receipt for its separate invoice; route an inspection-hold receipt to quality review; post the approved-chargeback netting for released invoices. Sort ascending.
Pitfalls: net_release_amount is 0 for held invoices (not invoice - chargeback). net_release_total sums only released. A receipt can be accepted but still have an Underage Quantity chargeback (received < ordered) -> net_release_ready. received == ordered but billed > received -> AP Quantity Variance (not Underage). A receipt on inspection_hold adds Inspection Hold to exception_codes. The local chargeback register is authoritative for chargeback amounts. When a PO-73xx-style receipt is mentioned but no id exists, treat as no receipt (hold_missing_receipt) and ask receiving for the receipt.
Quick decision-logic reference (confirmed by judge feedback)
- AP-hold judgment keys on invoice status
on_hold; pending_receipt/NO_RECEIPT is a receiving (pending_receipt) issue, not an AP hold.
- exception_codes (receiving) is comprehensive — include SUPPLIER_WATCH_RISK for watch suppliers even though supplier_risk_context reports risk separately.
- reason_codes (AP close): NO_RECEIPT subsumes QTY_VARIANCE — never emit both for one invoice.
- overall nomination readiness = worst line readiness (no softening).
- approval_ok uses approval_events latest action (submitted != approved), regardless of requisition status.
- supplier_risk_ok requires an OPEN SEVERE (high/critical) event; watch rating + medium event does NOT block.
- noncancelled_subtotal excludes cancelled POs.
- net_release_amount is 0 for held release-file invoices.
- received_qty in a batch closeout is the batch's own receipt qty (date-filtered), not cumulative.
1---2name: reflect-3-attempt-02-133description: ProcureOps Procurement Control — Solver Skill (task_group_006)4---5# ProcureOps Procurement Control — Solver Skill (task_group_006)67Reusable workflow rules for solving Procurement Supplier & Receiving Control tasks against the shared ProcureOps API. Recipe-oriented experience; not candidate answers. Applies to all four task families: A Sourcing nomination, B Receiving-control closeout, C AP close / vendor-balance, D Change-control amendment, plus the cross-family Receiving/AP release file.89## 0. Environment & API mechanics1011- Remote API (system of record): `<remote-env-url>`. Prompts that say `http://127.0.0.1:8006` mean THIS SAME remote service — always call the remote URL.12- Collections (GET list -> `{"count":N,"results":[...]}`; GET `/<coll>/<id>` -> the record object): `programs`, `suppliers`, `items`, `contracts`, `purchase_requisitions` (aliases `/purchase-requests`, `/purchase-requisitions`), `purchase_orders` (alias `/purchase-orders`), `receipts`, `ap_invoices` (alias `/ap/invoices`), `payments` (alias `/ap/payments`), `approval_events` (alias `/approvals`), `budget_snapshots` (alias `/budgets`), `vendor_risk_events` (alias `/vendor-risks`).13- Query filters match substring/case-insensitive (incl. nested list values); blank values ignored. `start`/`end` filter the collection's date field inclusively. There is NO pagination/`_limit` param — unknown params become field filters returning 0. Fetch by id from the memo/template; do not dump whole collections.14- `GET /manifest` gives record counts + anchor ids (no task ids / answer keys). `GET /health` confirms liveness.15- Reconciliation chain: Program -> contracts/requisitions/POs/budget_snapshots/invoices(via po.program_id). PO -> receipts(same po_id, multiples allowed) -> invoices(invoice.po_id / invoice.receipt_id) -> payments(payment.invoice_id). Contract(contract_id) <-> PO(po.contract_id) <-> PO line unit_price <-> invoice line unit_price (contract.unit_price is the price-match anchor).16- Units: USD amounts in records are DOLLARS. Read each answer_template's per-field unit/precision (some want cents, most want 2-decimal USD; qty 2 decimals; pct 1 decimal; ratios 4 decimals). Sort every ID list ascending; list fields marked "set" are compared as sets.1718## Universal solver workflow191. Read the prompt + the task-local memo/packet + `answer_template.json`. Extract: program_id, as-of/review date, target ids (POs/receipts/invoices/requisition/contract/supplier/sku), and any business-control rules (tax rate, approval good-actions, ceiling/budget exposure definitions, cancel-exclusion, supplier-watch policy).202. Fetch each target id directly by id; fetch related records via filter (`?po_id=`, `?supplier_id=`, `?contract_id=`, `?sku=`, `?object_id=`, `?program_id=`, `?invoice_id=`). Fetch ALL POs on a contract (`?contract_id=`) and ALL receipts on a PO (`?po_id=`) — there can be multiple, including cancelled POs and duplicate/later receipts.213. Apply the as-of date filter to every time-sensitive set: receipts (receipt_date <= as_of), invoices (invoice_date <= as_of), vendor_risk_events (event_date <= as_of AND status in {open, monitoring}), budget_snapshots (snapshot_date <= as_of, pick the latest), payments (scheduled_date <= cutoff given in memo, e.g. "through 2026-06-30").224. Derive the fields per the family recipes below, using the enum/option sets EXACTLY as allowed. Round to the template's precision. Sort all lists.235. Emit only the JSON object matching the template. No prose.2425---2627## Family A — Sourcing nomination readiness (scope + as-of, budget, per-SKU supplier decision, evidence/blockers, committee action)2829Template shape: `task_id` ("task_group_006_train_001" / "task_group_006_test_003" pattern — use the exact required_value), `program_id`, `as_of_date` (memo date), `package_line_skus` (sorted), `program_summary` {owner, budget_headroom_usd, overall_readiness}, `nomination_lines[]` (matched by sku), `committee_action`.3031Recipes:32- `as_of_date` = the memo date.33- `program_summary.owner` = programs.owner. `budget_headroom_usd` = `budget_cap - committed_amount` (programs row). `overall_readiness` = **WORST-CASE across the package lines** — if ANY anchor line is `not_ready`, overall = `not_ready`. Do NOT soften a not_ready line into an overall `at_risk` (confirmed: softening dropped the score).34- Per line (one per package anchor SKU):35 - `selected_supplier_id` = the PO's supplier_id (or item.preferred_supplier_id when no PO).36 - `primary_requisition_id` = the memo-named requisition (== po.requisition_id).37 - `commercial_basis_id` = the contract_id linked to the PO (`po.contract_id`); `null` when the PO has no contract.38 - `package_po_ids` = POs for this SKU/line (sorted).39 - `receipt_evidence_ids` = receipts for the PO with `receipt_date <= as_of` (sorted). Exclude later receipts.40 - `invoice_exception_ids` = invoices for the PO that are in AP-hold state as of as_of (sorted). Key on AP-hold status (see blocker note below).41 - `risk_event_ids` = vendor_risk_events for the supplier with status in {open, monitoring} AND event_date <= as_of (sorted). Supplier-level — include any open event for the supplier regardless of related_object_id.42 - `blocker_codes` (sorted) from this set: `missing_contract` (po.contract_id is null), `supplier_watch` (supplier.risk_rating == "watch"), `open_supplier_risk` (>=1 open/monitoring risk event as of as_of), `ap_hold` (an invoice for the PO has status == "on_hold"), `pending_receipt` (PO not fully received — no receipt OR received < ordered), `late_due_date` (po.due_date or requisition.need_by < as_of), `none`.43 - `nomination_decision`: `nominate` (no blockers; contract+receipt present) / `conditional_nomination` (commercial basis contract exists + receipt evidence present, but clearable exceptions like AP hold / partial receipt) / `hold` (hard blocker: missing_contract or no receipt).44 - `readiness_status`: `ready` (no blockers) / `at_risk` (clearable blockers, contract+receipt present) / `not_ready` (hard blocker).45- `committee_action`: `nominate_now_supplier_ids` (lines with nominate), `conditional_supplier_ids` (conditional_nomination), `hold_supplier_ids` (hold), all sorted. `next_owner` in {buyer, finance_ops, quality_ops, program_owner, ap_team}. `send_to_committee` in {yes, no}.46- CRITICAL blocker flag rule (confirmed across families): `ap_hold` keys on invoice status == `on_hold`. An invoice with status `pending_receipt` / hold_code `NO_RECEIPT` is a RECEIVING issue -> use the `pending_receipt` blocker, NOT `ap_hold`. Do not double-flag.4748Pitfalls: overall_readiness must be worst-case (not a blend). missing_contract is a hard blocker -> hold/not_ready. A requisition may be `converted` while the approval_events show only `submitted` (see Family D) — for nomination, rely on the PO/contract/receipt evidence, not approval status. Watch-rated supplier with only a `medium` open risk still gets `supplier_watch` + `open_supplier_risk` blockers but is not a hard hold.4950---5152## Family B — Receiving-control closeout (batch identity, receipt scope, ordered/received/billed reconciliation, price match, AP hold/release, financials, supplier-risk overlay, chargeback)5354Template shape: `task_id`, `batch_id`, `inspection_summary`, `line_reconciliation[]` (sort by po_line_id), `invoice_review`, `financials`, `decision`, `supplier_risk_context`, `evidence`.5556Recipes:57- `batch_id` = the receipt under review (from the memo).58- The invoice in scope = the `ap_invoice` whose `receipt_id == batch_id` (fetch `?po_id=` for the batch's PO, pick the invoice tied to this receipt). Other invoices on the same PO tie to OTHER receipts -> out of scope for this batch.59- `inspection_summary`: po_id, supplier_id, warehouse_id, receipt_date, packing_slip, receiver from the BATCH receipt; program_id from the PO; supplier_name from the supplier.60- `line_reconciliation` per po_line_id present in the BATCH receipt:61 - `ordered_qty` = PO line quantity.62 - `received_qty` = **the BATCH's receipt line `quantity_received`** (NOT cumulative across all PO receipts; only this batch, and only receipts with receipt_date <= review).63 - `rejected_qty` = batch receipt line `quantity_rejected`.64 - `billed_qty` = the in-scope invoice line `quantity_billed`.65 - `short_qty_vs_po` = ordered - received. `unreceived_billed_qty` = billed - received.66 - `receipt_completion_ratio` = received / ordered (4 decimals).67 - `po_unit_price` (PO line) / `contract_unit_price` (contract.unit_price for po.contract_id) / `invoice_unit_price` (invoice line). `contract_price_match` = (contract_unit_price == po_unit_price).68- `invoice_review`: invoice_id, invoice_status, hold_code (string or null), receipt_status (the BATCH receipt.status), po_status (PO.status), `exception_codes` (set; evaluator sorts).69- `exception_codes` (allowed: INVOICE_QTY_EXCEEDS_RECEIPT, PARTIAL_RECEIPT, SUPPLIER_WATCH_RISK, PRICE_MISMATCH, DAMAGE_REJECTION, NO_EXCEPTION) — include EVERY true condition:70 - INVOICE_QTY_EXCEEDS_RECEIPT: billed > received.71 - PARTIAL_RECEIPT: received < ordered.72 - SUPPLIER_WATCH_RISK: supplier.risk_rating == watch (and/or an open risk event). **INCLUDE this code even though supplier_risk_context separately reports risk** (confirmed: dropping it lowered the score).73 - PRICE_MISMATCH: contract/PO/invoice unit prices differ.74 - DAMAGE_REJECTION: quantity_rejected > 0 or inspection failure.75 - NO_EXCEPTION: only when none of the above apply.76- `financials` (USD, 2 decimals): `received_goods_value` = received_qty × po_unit_price; `unreceived_goods_value` = (ordered - received) × po_unit_price (equivalently (billed - received) × price when billed=ordered); `invoice_subtotal`/`invoice_freight`/`invoice_tax`/`invoice_total` from the in-scope invoice record.77- `decision`:78 - `batch_disposition` (accept_partial_hold_variance / release_full_invoice / reject_batch / manual_recount_required): partial receipt accepted with an invoice qty-variance hold -> `accept_partial_hold_variance`.79 - `ap_action` (keep_invoice_on_hold / release_invoice / void_invoice): qty-variance hold -> `keep_invoice_on_hold`.80 - `receiving_action` (record_shortage_follow_up / no_receiving_action / reject_all_units): shortage (received < ordered) -> `record_shortage_follow_up`.81 - `supplier_action` (request_credit_or_remaining_delivery / no_supplier_action / supplier_debit_for_damage): underage (billed but unreceived) -> `request_credit_or_remaining_delivery`; damage -> `supplier_debit_for_damage`.82- `supplier_risk_context`: `supplier_risk_rating`, `has_open_supplier_risk` (>=1 open/monitoring event as of review), `open_supplier_risk_event_ids` (sorted).83- `evidence.endpoint_record_ids`: include the core records used (PO, receipt, invoice, contract, supplier, program, risk event). This field is subset-checked (extras tolerated; missing required ones hurt). `task_payloads_reviewed`: the memo filename(s).8485Pitfalls: received_qty is the BATCH's only — do not sum later/duplicate receipts. Only the invoice with receipt_id == batch_id is in scope. exception_codes is a comprehensive flag set; include SUPPLIER_WATCH_RISK for watch suppliers. For an accepted partial receipt with billed>received (underage): accept_partial_hold_variance / keep_invoice_on_hold / record_shortage_follow_up / request_credit_or_remaining_delivery (this matches an approved "Underage Quantity" chargeback).8687---8889## Family C — AP close / vendor-balance + hold/release (invoice hold/release, qty-variance %, totals & scheduled payments & net balance, vendor balance rows, program close totals, payment queues)9091Template shape: `task_id`, `close_date`, `invoice_decisions[]` (invoice_id ascending), `vendor_balances[]` (supplier_id ascending), `program_summary[]` (program_id ascending), `payment_hold_queue`, `payment_release_queue`, `total_close_balance`.9293Recipes (slice = the named target invoices only):94- `close_date` = memo date. Opening AP balance for target suppliers in this slice = `0.00` (per memo). Scheduled payments through the memo cutoff (e.g. 2026-06-30) reduce the close balance.95- `invoice_decisions` per target invoice:96 - `hold_decision`: invoice.status `approved` -> `RELEASE`; `on_hold` -> `HOLD`; `pending_receipt` -> `HOLD`.97 - `hold_code`: from invoice (string or null).98 - `release_to_payment`: true for RELEASE, false for HOLD.99 - `quantity_billed` = invoice line quantity_billed (2 decimals).100 - `quantity_received` = the invoice's receipt line quantity_received (invoice.receipt_id -> receipt line); **`0.00` when receipt_id is null / no receipt**.101 - `quantity_variance` = billed - received.102 - `quantity_variance_pct` = variance / **PO quantity** × 100 (PO line quantity is the denominator), 1 decimal.103 - `invoice_total` = invoice.total.104 - `scheduled_payment_amount` = sum of payments for this invoice with status `scheduled` AND scheduled_date <= cutoff (memo "through YYYY-MM-DD").105 - `net_balance_impact` = invoice_total - scheduled_payment_amount.106 - `reason_codes` (alphabetical; allowed: APPROVED_THREE_WAY_MATCH, NO_RECEIPT, QTY_VARIANCE, SCHEDULED_PAYMENT_FOUND):107 - APPROVED_THREE_WAY_MATCH: PO qty == received == billed AND all unit prices match -> RELEASE reason.108 - SCHEDULED_PAYMENT_FOUND: a scheduled payment exists for this invoice (affects net balance).109 - NO_RECEIPT: invoice has no receipt (receipt_id null). **NO_RECEIPT SUBSUMES QTY_VARIANCE — when there is no receipt, emit `[NO_RECEIPT]` ONLY; do NOT also emit QTY_VARIANCE** (the variance is a consequence of no receipt). Confirmed: this was the single fix to reach a perfect score.110 - QTY_VARIANCE: receipt exists but billed != received.111 - 3-way match test: PO line qty == receipt qty == invoice billed qty AND PO/contract/invoice unit prices all equal.112- `vendor_balances` per target supplier (one row each):113 - `opening_balance` = 0.00 (slice).114 - `invoice_total` = sum of this supplier's target invoice totals.115 - `scheduled_payments` = sum of this supplier's target invoices' scheduled payments (through cutoff).116 - `held_invoice_total` = sum of HOLD-decision invoice totals (includes on_hold AND pending_receipt invoices — both are blocked).117 - `releasable_invoice_total` = sum of RELEASE-decision (approved) invoice totals.118 - `close_balance` = opening_balance + invoice_total - scheduled_payments.119 - `balance_status` (OPEN_HELD / OPEN_APPROVED / FULLY_SCHEDULED): approved AND a scheduled payment fully covers it -> `FULLY_SCHEDULED`; approved but not yet scheduled -> `OPEN_APPROVED`; has any held invoice -> `OPEN_HELD`.120- `program_summary` per program (group target invoices by po.program_id):121 - `invoice_count`, `invoice_total` (sum), `held_total` (HOLD invoices), `released_total` (RELEASE invoices), `net_close_balance` = sum of that program's supplier close_balances (= invoice_total - scheduled_payments for the program).122- `payment_hold_queue` = HOLD-decision invoice_ids (ascending). `payment_release_queue` = RELEASE-decision invoice_ids (ascending).123- `total_close_balance` = sum of all vendor close_balances.124125Pitfalls: variance_pct denominator is PO quantity (not received/billed). received=0 when no receipt. NO_RECEIPT subsumes QTY_VARIANCE. held_invoice_total includes pending_receipt invoices. FULLY_SCHEDULED requires the scheduled payment to cover the approved invoice. A "converted" requisition is irrelevant here — use the invoice/receipt/payment records.126127---128129## Family D — Change-control contract amendment (contract status/price/qty, usage & headroom/ceiling, program-budget incremental exposure, requisition approval state, supplier risk, hold actions, final decision)130131Template shape: `change_request_id`, `program_id`, `contract_id`, `sku`, `supplier_id`, `variant_code`, `decision`, `contract_check`, `program_budget_check`, `approval_check`, `supplier_risk_check`, `supporting_ids`, `required_actions`, `summary`.132133Recipes:134- `change_request_id` = memo `memo_id`.135- `contract_check`:136 - `contract_status`, `price_type`, `unit_price`, `ceiling_amount` from the contract.137 - `noncancelled_subtotal` = sum of **line subtotals (qty × unit_price)** of NON-CANCELLED POs on the contract (fetch `?contract_id=`; exclude status == `cancelled`). This is the "contract ceiling exposure = line subtotal before tax and freight" per memo business_controls.138 - `requested_quantity` = memo `requested_incremental_quantity`.139 - `requested_subtotal` = requested_quantity × contract unit_price (no price change unless the memo states one).140 - `headroom_before_change` = ceiling_amount - noncancelled_subtotal.141 - `headroom_after_change` = ceiling_amount - (noncancelled_subtotal + requested_subtotal).142 - `ceiling_ok` = headroom_after_change >= 0.143- `program_budget_check`:144 - `snapshot_id` = budget_snapshot for the program with snapshot_date <= memo_date (latest). `budget_cap`, `committed_amount` from that snapshot.145 - `remaining_budget` = budget_cap - committed_amount.146 - `requested_tax` = requested_subtotal × tax_rate_percent (memo business_controls.tax_rate_percent, e.g. 7.25 -> 0.0725).147 - `requested_total` = requested_subtotal + requested_tax (+ freight ONLY if the memo provides freight).148 - `budget_after_change` = remaining_budget - requested_total.149 - `budget_ok` = budget_after_change >= 0.150 - `max_quantity_with_current_budget` = floor(remaining_budget / (unit_price × (1 + tax_rate_percent))) — per-unit cost includes tax.151- `approval_check`:152 - `source_requisition_id` = memo source requisition.153 - Fetch `approval_events?object_id=<requisition_id>`. `latest_event_id`/`latest_action`/`latest_actor`/`latest_event_date` = the latest event.154 - `approval_ok` = latest_action is in memo `business_controls.approval_good_actions` (e.g. `["approved"]`). **Use approval_events, NOT the requisition status** — a requisition may be `converted` while its latest approval event is only `submitted` -> approval_ok = false (confirmed).155- `supplier_risk_check`:156 - `supplier_status`, `supplier_risk_rating` from supplier.157 - `open_event_ids` = vendor_risk_events for the supplier with status in {open, monitoring} AND event_date <= memo_date (sorted).158 - `severe_open_event_ids` = open events with severity `high` or `critical` (medium/low are NOT severe) (sorted).159 - `supplier_risk_ok` = (severe_open_event_ids is empty). Per memo: a `watch` rating is **context only** unless an OPEN SEVERE event exists — so a watch supplier with only a `medium` open event is still `supplier_risk_ok = true`.160- `supporting_ids`: `included_po_ids` (non-cancelled POs on the contract, sorted), `excluded_cancelled_po_ids` (cancelled POs on the contract, sorted), `approval_event_ids` (for the requisition, sorted).161- `decision` (release_amendment / hold_for_budget / hold_for_approval / hold_for_supplier_risk / hold_for_budget_and_approval / reject_contract_mismatch):162 - `ceiling_ok` false -> `reject_contract_mismatch`.163 - else combine failing checks: budget + approval both fail -> `hold_for_budget_and_approval`; budget only -> `hold_for_budget`; approval only -> `hold_for_approval`; supplier risk only -> `hold_for_supplier_risk`; all ok -> `release_amendment`.164- `required_actions` (sorted; allowed: obtain_final_requisition_approval, raise_budget_exception_or_reduce_quantity, resolve_supplier_risk_hold, none): add one per failing check (approval -> obtain_final_requisition_approval; budget -> raise_budget_exception_or_reduce_quantity; risk -> resolve_supplier_risk_hold); `none` only when all ok.165- `summary`: `blocker_count` = number of failing checks (ceiling/budget/approval/supplier_risk — but ceiling_ok false is reject_contract_mismatch, counted as a blocker too); `currency` = USD; `ready_to_release` = (blocker_count == 0).166167Pitfalls: noncancelled_subtotal excludes cancelled POs (a contract can have several POs, some cancelled). approval_ok is event-based, not status-based. supplier_risk_ok needs an OPEN SEVERE event; medium doesn't block. requested_total includes estimated tax at the memo's tax_rate; include freight only if the memo provides it. max_quantity divides remaining budget by the tax-inclusive per-unit cost.168169---170171## Cross-family — Receiving/AP release file (per-invoice release decision net of chargebacks, receiving exceptions, chargeback netting, source classification, followups)172173Template shape: `task_id`, `review_as_of`, `target_ids` (sorted), `release_decisions[]`, `receiving_exceptions[]`, `summary`.174175This family combines a LOCAL chargeback register excerpt (in the packet) with ProcureOps PO/receipt/AP records. Map each chargeback row to its invoice + receipt + PO.176177Recipes:178- `release_decisions` per target invoice (sorted by invoice_id):179 - `decision`: `release_net_after_approved_chargeback` (chargeback status `approved` -> release invoice net of the approved chargeback) / `hold_missing_receipt` (no receipt on the PO, no chargeback) / `hold_pending_quality_chargeback` (chargeback status `pending_quality_review` and/or receipt status `inspection_hold`).180 - `primary_reason`: `approved_qty_chargeback` (chargeback reason "Underage Quantity", approved) / `approved_ap_quantity_variance` (chargeback reason "AP Quantity Variance", approved) / `no_receipt_on_po` (no receipt) / `inspection_hold_pending_chargeback` (pending quality / inspection hold).181 - `approved_chargeback_amount` = basis_quantity × unit_cost for the invoice's chargeback with status `approved`.182 - `pending_chargeback_amount` = basis_quantity × unit_cost for the invoice's chargeback with status `pending_quality_review`.183 - `net_release_amount` = **0.00 for HELD invoices** (hold_missing_receipt / hold_pending_quality_chargeback); = invoice_total - approved_chargeback_amount for RELEASED invoices. Confirmed: using the computed net for held invoices lowered the score — held releases nothing.184 - `receipt_ids_in_scope` = the target receipt(s) tied to this invoice (via the invoice's receipt_id OR the chargeback's receipt_id), sorted.185 - `excluded_same_po_receipt_ids` = other receipts on the same PO that are NOT in the packet's target receipt set (e.g. a duplicate receipt for a separate invoice), sorted.186- `receiving_exceptions` per target receipt (sorted by receipt_id):187 - `exception_codes` (zero or more of: Underage Quantity, Severe Unmatched Quantity, Inspection Hold, AP Quantity Variance): map from the chargeback reason + receipt status. "Underage Quantity" -> Underage Quantity (received < ordered). "AP Quantity Variance" -> AP Quantity Variance (billed > received with received == ordered). Receipt status `inspection_hold` -> add Inspection Hold. Sort alphabetically within the list.188 - `chargeback_status` (approved / pending_quality_review / not_applicable) = the chargeback's status for this receipt's invoice.189 - `resolution_status` (net_release_ready / hold_for_quality_review / accepted_no_receiving_exception / missing_receipt): approved chargeback -> `net_release_ready`; pending_quality_review / inspection_hold -> `hold_for_quality_review`; no exception -> `accepted_no_receiving_exception`; no receipt on the PO -> `missing_receipt`.190- `summary`:191 - `release_invoice_ids` (RELEASE decisions, sorted), `hold_invoice_ids` (HOLD decisions, sorted).192 - `approved_chargeback_total` = sum of approved_chargeback_amount across all invoices.193 - `pending_chargeback_total` = sum of pending_chargeback_amount across all invoices.194 - `net_release_total` = sum of net_release_amount **for RELEASED invoices only** (= released nets; held contribute 0).195 - `authoritative_sources` (one or more of: procureops_po_records, procureops_receipt_records, procureops_ap_records, local_chargeback_register): include the ProcureOps record sources AND `local_chargeback_register` (the chargeback register drives the netting — it is authoritative, not supporting).196 - `supporting_only_sources` (one or more of: ap_release_request_note, stale_po73xx_alias_note): requester comment notes and stale alias notes are supporting/context only.197 - `followup_actions` (one or more of: ask_receiving_for_vantix_receipt, hold_luma_duplicate_receipt_for_separate_invoice, route_po00031_quality_review, post_approved_chargeback_netting): include each applicable action — ask receiving for a missing receipt; hold/segregate a duplicate same-PO receipt for its separate invoice; route an inspection-hold receipt to quality review; post the approved-chargeback netting for released invoices. Sort ascending.198199Pitfalls: net_release_amount is 0 for held invoices (not invoice - chargeback). net_release_total sums only released. A receipt can be `accepted` but still have an Underage Quantity chargeback (received < ordered) -> net_release_ready. received == ordered but billed > received -> AP Quantity Variance (not Underage). A receipt on `inspection_hold` adds Inspection Hold to exception_codes. The local chargeback register is authoritative for chargeback amounts. When a PO-73xx-style receipt is mentioned but no id exists, treat as no receipt (hold_missing_receipt) and ask receiving for the receipt.200201---202203## Quick decision-logic reference (confirmed by judge feedback)204- AP-hold judgment keys on invoice status `on_hold`; `pending_receipt`/`NO_RECEIPT` is a receiving (pending_receipt) issue, not an AP hold.205- exception_codes (receiving) is comprehensive — include SUPPLIER_WATCH_RISK for watch suppliers even though supplier_risk_context reports risk separately.206- reason_codes (AP close): NO_RECEIPT subsumes QTY_VARIANCE — never emit both for one invoice.207- overall nomination readiness = worst line readiness (no softening).208- approval_ok uses approval_events latest action (submitted != approved), regardless of requisition status.209- supplier_risk_ok requires an OPEN SEVERE (high/critical) event; watch rating + medium event does NOT block.210- noncancelled_subtotal excludes cancelled POs.211- net_release_amount is 0 for held release-file invoices.212- received_qty in a batch closeout is the batch's own receipt qty (date-filtered), not cumulative.