A collector can save a detailed CSV and still leave an invoice archive incomplete. It can also save a delivery document that belongs to the wrong account. A single downloaded = true flag hides both problems.
HD Supply provides a useful design example. Our published retrieval guide documents separate PDF and CSV Detail outputs, plus a DVLR route to proof-of-delivery information. Those outputs answer different questions. The architecture below turns that distinction into an application-side acceptance rule.
I work on BrowserAct content. This is a proposed receipt ledger with synthetic checks, not an HD Supply integration, a PDF parser, or a tested portal collector. The guide's underlying documentation research was recorded on November 9, 2026. An earlier publishing attempt recorded a regional access restriction at the supplier FAQ. This post retains that evidence boundary; it does not report a newly tested HD Supply account.
Define the required set before collecting files
Start with the business request. An invoice archive might require an invoice PDF and an accounting export. An exception concerning delivery might additionally require POD evidence. Do not require POD for every invoice merely because the portal offers a link.
Use (account, invoice, artifact_kind) as the expected key. Include the account because invoice numbers alone are not a safe cross-account identity. Keep invoice dates and property references as supporting metadata when needed; they do not replace the scoped identifier.
For example, the following invented request has two obligations:
{ "account": "demo-property-7", "invoice": "example-1042", "required": ["invoice_pdf", "csv_detail"], "pod_required": false } These are local application fields. They are not a claimed HD Supply export schema. A statement PDF must have a different kind from an invoice PDF, even if both share a file extension.
Make a receipt follow validation
A browser click produces an attempt. A saved file produces a candidate. Only a separate validator should produce a validated receipt.
That validator needs evidence appropriate to the artifact: file readability and invoice identity for a PDF, parsed headers and invoice associations for an export, and an explicit association with the relevant delivery for POD. A filename, HTTP success, or nonempty byte count alone does not establish those facts.
Store the immutable artifact reference and the validator's observed key alongside the requested key. Preserve the original download when deriving normalized data. If one CSV contains several invoices, retain its row-to-invoice mapping instead of pretending the file belongs exclusively to one invoice.
Reconcile receipts without parsing the portal
This small Python function checks already-produced receipts. It deliberately does not open files, authenticate, download, or infer document identity. The upstream validator owns the meaning of validated; this function cannot make an incorrect validator trustworthy.
def reconcile(expected, receipts): expected = list(expected) if not expected or len(set(expected)) != len(expected): raise ValueError("Expected keys must be nonempty and unique") wanted = set(expected) states = {} for key in expected: candidates = [r for r in receipts if r["requested"] == key] if not candidates: states[key] = "missing" continue valid = ( len(candidates) == 1 and candidates[0]["status"] == "validated" and candidates[0]["observed"] == key and bool(candidates[0]["artifact_ref"].strip()) ) states[key] = "ready" if valid else "review" unexpected = [r for r in receipts if r["requested"] not in wanted] return { "states": states, "unexpected": unexpected, "complete": not unexpected and all( state == "ready" for state in states.values() ), } Keys in this example are Python tuples. Deserialize and validate receipt types before calling the function; malformed or untrusted input needs its own schema check. Keep references to actual stored artifacts rather than credentials or expiring portal session URLs.
Two candidate receipts for one requirement go to review, even when one claims success. They may be legitimate versions, an accidental duplicate, or conflicting documents. Resolve the conflict explicitly before choosing the accepted artifact.
Give each outcome a different next action
| Receipt outcome | What it establishes | Next action |
|---|---|---|
| PDF ready, CSV missing | Archive file accepted; data obligation open | Collect the missing export |
| CSV ready, PDF missing | Data accepted; document obligation open | Retrieve the invoice document |
| Observed invoice differs | Candidate does not satisfy the requested key | Review scope and matching |
| Two candidate receipts | Acceptance is ambiguous | Resolve versions or duplicates |
| Unexpected artifact | Something arrived outside the request | Review before closing the batch |
Persist this result before deciding on a retry. A missing artifact can enter a targeted collection queue. A review outcome should keep its evidence and reason; automatically repeating the whole month does not resolve an identity mismatch.
An email notification is another candidate event. Unless the required attachment was actually received and validated, it cannot close the PDF requirement. Similarly, a POD page being reachable does not prove that an archive-ready delivery artifact was saved.
Test the ledger separately from the collector
Fifteen local synthetic checks passed using fabricated keys and receipt dictionaries. They cover a complete set, missing artifacts, notification-only and failed statuses, wrong identity or kind, blank references, duplicates, unexpected output, partial completion, and invalid expected sets. Those checks validate the reconciliation policy only. They say nothing about supplier login, download reliability, PDF contents, or actual CSV parsing.
Before scheduling a real collector, demonstrate those upstream validators with authorized samples and preserve their evidence. BrowserAct can be evaluated for the remaining browser work; the receipt contract should remain useful even when native email delivery or a different collection method supplies the files.
The useful completion question is specific: does every required artifact have one accepted, correctly scoped receipt? That answer is much easier to audit than a generic successful-run badge.