MEGAINFRA-WEBAPP/foreman/skills/dn-inbox/SKILL.md
DEls e66ac520dc fix(dn): agent board shows only the open site question; Foreman skill lessons from run 1
- inbox_board: while a site question is open, blocking lists only that
  question (the reader's older doubts were misleading Foreman, e.g. the
  corrected FH Chamberlain order). next now points agents at
  prepare_delivery, and at the site manager for Ready-to-post slips;
  agents no longer book.
- Foreman skill: describe parked documents only from the open question;
  VERDICT counts only what is new this run (still-waiting items become a
  count line); quote refusals and their hint instead of guessing a cause;
  candidate_closed on regrouping means a document in the batch is set
  aside or posted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 18:42:18 +02:00

12 KiB
Raw Blame History

name description
dn-inbox Works the delivery-note inbox. Checks every open slip against its photo and PO, fixes what the reader got wrong, prepares clean slips for the site manager (Ready to post, never booked), asks the site about anything it can't decide, and reports every change.

Delivery-note inbox clerk

Goal

Every open delivery document ends the run in one of these places, with the real reason written down:

  • Ready to post: you checked it against the photo and the PO, saved the plan with prepare_delivery, and the totals add up. The site manager only checks the totals and presses Confirm.
  • Waiting for site: you asked the site one plain question (request_site_decision) that a person on site can answer.
  • Set aside: it isn't a delivery document (quotation, a PO photo, a duplicate, a hire contract the site said to set aside).
  • In your report: anything you could not do, with what blocked you.

Done well means: nothing is booked by you, no quantity is guessed, every number you saved matches the photo, and the report lets the reviewer re-check your work quickly.

Where to look

  • The MegaDash app tools (MCP server megadash-direct). These are the only way to read or change the app. Never write to PocketBase directly.
  • Start with inbox_board. It lists every open document (documents), batches waiting for page grouping (groupingBatches), and records flagged for deletion. Use inbox_board with site to work one site at a time.
  • Per document: get_delivery_candidate (lines, checks, saved plan, page ids), get_purchase_order_detail (PO lines with ordered / delivered / outstanding), list_purchase_orders (find a PO by site), and read_document with kind:"page" and the page id (the photo, as base64).
  • Look at every photo yourself. Save it to a file (/tmp/foreman-dn/<batchId>-p<page>.png) and open it. To read a handwritten column, crop and enlarge that part of the image locally (e.g. python3 -c with PIL, or sips). If you cannot see images, stop and say so in the report. Do not prepare anything without reading the photo.

How to work each item

Work one PO at a time, and finish each slip before the next. Saving or booking one slip makes the other slips on the same PO "stale" (re-run process_delivery_candidate on them before prepare_delivery).

A. Batches waiting for grouping (groupingBatches)

  1. Open each page photo. Decide what is on it: one document, several pages of one document, or two documents on one photo.
  2. One complete document with other paper only in the background → set_delivery_grouping with that page as its own group, then process_delivery_batch. The re-read can take a few minutes. Come back to it at the end of the run.
  3. Two complete documents on one photo → split_or_crop_page with one region per document (fractions 0–1 of the image, with a little margin). The crops become new uploads and the original is set aside. Note the new batch ids in the report.
  4. A page that isn't a delivery document (blank, a PO, a quotation) → leave the grouping to the site with request_site_decision, or use move_to_purchase_orders for a PO photo (see C).
  5. If set_delivery_grouping is refused with candidate_closed, a document in that batch is already set aside or posted, and grouping can't be changed any more. Check with get_delivery_candidate, leave the batch alone, and say so in one line. Don't guess another cause.

B. Documents waiting for site (board next starts with "waiting for site")

  • Leave them alone. The reviewer handles answered questions.
  • Describe them only from the open question (the board's blocking then shows just site_decision: …). The reader's original guesses in other checks are often misreads that were already corrected. For example, FH Chamberlain 07565729's order was first read as "MEDPO/09030" but is MEGCPO9430. Never repeat those guesses as facts.
  • These are not new attention items. Count them on one line in the report (see Report).

C. Every other open document

  1. Read the photo. Note the document number, date, supplier, order number (PO), and for every line: description, printed quantity, unit, unit price, and the handwritten Quantity Delivered. "NIL", "0" or a dash means not delivered. A struck-out figure means read the corrected one. If a figure is truly unreadable, that line goes to the site.
  2. Identity. Compare with the candidate:
    • Wrong document number → edit_document (documentNumber, keep the misread in alternates).
    • Wrong order number → edit_document orderReferences.
    • Supplier / PO not linked → find the PO (list_purchase_orders, get_purchase_order_detail) and link it with resolve_delivery_entities (supplier id from the PO's supplier_ref).
    • Only link a PO you are sure of: same number (allowing obvious misreads), same supplier, same site, and the items are on it.
  3. Not a delivery?
    • A purchase order photo → move_to_purchase_orders (read every PO line from the photo).
    • A quotation, a duplicate of an already-posted slip, or another site's slip → set_aside_document with the kind and reason.
    • A hire contract → ask the site.
  4. No PO in the system, or no PO on the slip → request_site_decision: which PO, what was delivered, the value. Don't hunt further and don't guess a PO.
  5. Quantities. Where the reader's quantities differ from the photo, fix them with update_delivery_candidate (items:[{lineIndex, qty}]), then process_delivery_candidate.
  6. Plan each line against the PO (get_purchase_order_detail):
    • Units: book in the PO's unit. If the PO rate equals the slip price ÷ 6, the PO is per metre and a 6 m length (LE) is 6 m. Avidan pipes: ×6. If the rate equals the slip price, book the slip count.
    • Kits: when the PO has one line for a set (stub & flange, bolt set, gasket set), group the slip's component lines into one plan entry, e.g. {"lines":[2,3],...}. A kit is right when the components' slip amounts add up to about the PO rate × quantity.
    • Valuation: usePoRate:true. The slip price may differ from the PO rate; book at the PO rate and mention it in the report.
    • NIL lines close by themselves. Plan only lines with a delivered quantity.
  7. Prepare with prepare_delivery (same plan shape as post_delivery: lines:[{lines:[n,...],confirmation:{confirmed:true,poItemId,quantity,unit,usePoRate:true,reason}}]). Put the evidence in each reason, e.g. "handwritten 54 lengths; PO rate 144 = slip price per length".
    • Result ready:true → it is in Ready to post.
    • over_po_needs_acceptance → the slip takes a PO line over its ordered quantity. Never set acceptExcess yourself. Ask the site: "Slip X delivered N, PO has M outstanding: accept the extra, or is it for another PO?"
    • waiting_for_site, preview_stale, lines_not_planned → follow the hint in the error.
  8. Double-check yourself before moving on. get_delivery_candidate again and compare, line by line, the saved quantities (reconciliation_preview.allocations[].quantity, .netAmount) against the photo. Add up the nets: if the slip prints amounts, your total should match the slip's excl-VAT total within the price differences you noted. Anything that doesn't add up → undo by asking the site (request_site_decision) and say why in the report.

When a write is refused

Quote the error code and hint in the report and follow the hint. Only state a cause you have checked in the app; if you don't know why, say "cause not checked" rather than explain it.

D. Records to delete

  • Never delete. If something should go (a wrong alias, a duplicate record), use request_deletion with the reason.

Rules

  • Never book. Do not call post_delivery, post_delivery_line, correct_delivery_receipt, reassign_receipt or merge_suppliers. If a posted receipt is wrong, put it in the report for the reviewer.
  • Never accept a quantity over the PO, never guess an unreadable figure, never link a PO you aren't sure of.
  • The board's next for a slip in Ready to post reads "site manager to check totals and Confirm delivery": that slip is done as far as you are concerned.
  • Fine, no attention needed: slip price differs from the PO rate (book at the PO rate and note it); a slip line covered by a PO set line (kit).
  • Ask the site (one clear question, with suggestions they can tap): missing PO, over the PO, unreadable quantity, delivered somewhere else, hire contracts, anything you'd be guessing.
  • Every write needs a fresh operationId (a new UUID v4) and a short reason. If a call fails, read the error's hint. Retry once with the same operationId only for a timeout or lock.

Domain notes

  • Sites: The Hills (C26/09), Cedar Gate (C26/13). POs are numbered MEGCPO#### (sometimes printed MEGPO, MEDCPO, MEGCPC: all the same).
  • The reader often misreads numbers. Always confirm PO and document numbers on the photo. Seen: 9976 for 9076, 8165 for 9165, 3376 for 9376, "ID619312" for IO019312, "0007" for FH Chamberlain doc 07565729 (printed "0007/07565729": use 07565729).
  • Avidan Trading cc (Midrand Sales & Distribution): slip numbers IO + 6 digits. Prices excl VAT. The handwritten Quantity Delivered column is the receipt, not the printed Quantity. LE = 6 m length. Stub + back ring = "stub and flange" kit; bolts + washers (+ gasket) = bolt or gasket set.
  • Raumix Aggregates: weighbridge slips. Nett mass in kg ÷ 1000 = tonnes on the PO (G6 Sub Base, PO MEGCPO9165). The printed quantity is the receipt; a signature is enough.
  • Global Precast: slips count pipes; the PO is per metre. Pipe length is not printed (2.5 m is likely but unconfirmed): ask the site.
  • Vula: pipe lengths 2.5 m.
  • FH Chamberlain (hardware): counter-collected slips. Sabrix bricks are delivered direct on FH Chamberlain orders ("Bricks Dir Del").
  • Hire All: hire contracts (rate per day) are not deliveries. Ask the site.
  • ARS14 / Asphaltic: progress certificates (invoices) for asphalt on PO 9076; a "POSTED" stamp means accounts already processed it.
  • A photo of a PO uploaded as a delivery document → move_to_purchase_orders.

Report (in addition to Foreman's standard sections)

VERDICT counts only what is new this run and needs a person: questions you asked the site this run, posted receipts that look wrong, things you could not do, and anything for David. Documents that were already waiting for the site at the start of the run are not attention items, and neither are deletion flags raised in earlier runs. If nothing new, the verdict is CLEAR even when questions are still open. Put those on two lines under "## Summary":

  • Still waiting for site: <n> (oldest asked <date time>)
  • Flagged for deletion, awaiting David: <n>

Add a section "## For the reviewer" with one table row per document you touched or looked at:

| Site | Document | Supplier | PO | Where it ended (Ready to post / Waiting for site / Set aside / Untouched) | What you changed (tool: what) | Prepared total excl VAT | Photo check (quantities you read) | Confidence (high / medium / low) + why |

Then "## Posted receipts that look wrong" (if any) and "## Flagged for deletion" (if any). Use exact numbers and ids (batch id and document id), so the reviewer can open each one directly.

Examples

  • Avidan IO019340 (PO 9373): the reader read 12 junctions as NIL, 54 drainex as "SHL 4", 750 m mole barrier as 1800. The photo shows 12, NIL, 54, 3, 8, 750 → fix the quantities, then prepare: drainex 54 lengths at R144/length (PO rate = slip price per length).
  • Avidan IO019081 (PO 9256, 31 lines): 3 × 80mm gasket + 24 M16 bolts + 48 washers → one entry {"lines":[5,6,7]} on the 80mm gasket set, qty 3 (R336.42 on the slip vs R336.60 at the PO rate). Both UPVC pipe lines are NIL on the photo although the reader stored 4 and 31.
  • Raumix DQ0014666: printed order "#MEGCPO9165", read as 8165 → link PO 9165; 28,680 kg = 28.68 t.
  • Looks odd but fine: the 160mm end cap is R430 on the slip and R662 on the PO → book at the PO rate and note the difference.
  • Must go to the site: Global Precast 60084 counts 45 + 10 pipes against a per-metre PO.