Why the register and the floor disagree by March, and how to build intake that keeps them in step

ยท Asset Foresight

"The spreadsheet says 42 robots, but the shop floor has 37." Founders running hardware fleets often find this gap in March, when someone finally counts. It is rarely one big mistake. Two units shipped to a customer site in November and the packing slip stayed with operations. Two were stripped for parts in December and the incident reports went to engineering. A demo unit went to a trade show in October and never came back.

Four ordinary events cause most of the drift: a unit moves, a unit leaves for a customer, a unit is retired, or a unit gets new parts. The last one changes cost, not headcount, and a person has to decide whether a rebuild is a repair or something bigger. None of it is neglect. It happens outside finance's view, so the register keeps reporting what was true six months ago.

The count date can carry a tax bill. In California, for example, business property is assessed as it exists at 12:01 a.m. on January 1, the lien date, so a robot that left in August but still sits on the register can be reported and taxed. Other places set other rules and dates; the engineering problem is the same everywhere: evidence of each event exists on the day it happens, and the register should change that day, not in March.

That is an intake problem, and it is where a multi-agent system earns its place. It is also where a careless design does damage, because the tempting build (one large agent with a prompt and write access to the register) turns a confident misreading into a booked fact. Here is a design that holds up, piece by piece.

Evidence in, structured out. The input is whatever the floor produces: a phone photo of a unit's metal plate, a purchase order, a repair bill, a damage report, a technician's voice note. A multimodal model reads each one into a typed structure: serial number, model, vendor, amount, dates. The model's job is reading. Nothing it returns is trusted yet.

A fixed graph, not a free-roaming agent. The extracted document then runs through a graph workflow: a fixed set of nodes and edges where each node is either an agent or plain code. Google's Agent Development Kit describes this as combining "AI-powered agent reasoning with deterministic tools and code." In a working version of this pattern, four checks fan out in parallel: is the vendor known, is the amount within the normal range for this kind of document, is the date valid, is this invoice number a duplicate of one already received. They join, and only then does a model node look at the results. The checks are independent I/O, so running them side by side is faster than letting a model call them one at a time. Each check passes only on its own success result; a field the model could not extract is recorded as skipped, never as clean, so a blank never reads as a pass.

One narrow slot for the model. The triage node is the only judgment call in the graph. It returns structured output with exactly three allowed values (auto-approve, send to a person, reject) plus its reasons. The thresholds that separate them are policy, stated once in the triage node and enforced again in code. If the model returns anything outside the three values, a routing node in code turns it into "send to a person" instead of trusting it. ADK's graph routes also offer a catch-all branch for a value no other edge matched.

Code can only make the answer stricter. After the model decides, a code check re-reads the parallel results and the account's policy. It can downgrade an auto-approve to human review; it can never promote a review or a rejection upward. This one-way ratchet is the most important line in the design. A model that is wrong in the cautious direction costs a minute of someone's time. A model that is wrong in the permissive direction costs a wrong register, and the ratchet makes that direction unreachable from the model alone.

Matching is ordered rules, and a person picks. A document that names a machine has to be tied to the right row. Finding candidates is lookup, not inference: first by asset code, then by serial number (trimmed and case-insensitive, since serials are unique that way), and only when neither matches, by brand and model together, never a bare brand that would return half the fleet. Each step is deterministic and testable. But a photo that names a serial is never enough to attach evidence to a machine by itself, however confident the match: the candidates go to a reviewer, and only the reviewer's pick links the document to the row. A wrong link puts a fault or a cost on the wrong machine, and that error is quiet; a question costs a click.

A person saves the record. Even an approved document creates nothing on its own: a person clicks to create the machine or record the repair. Repairs are recorded as expenses; whether a chassis rebuild should instead add to the machine's cost is the accountant's call, made by a person. Retiring a unit names one of five fates (sold, disposed, lost, stolen, donated) and a date. A unit nobody can find is the case to be most careful with, so writing it off waits for the account owner, who types the amount again to confirm it.

Every change is logged, and the log cannot be edited. Each change records who or what made it and links to the document it came from. The audit tables are append-only, enforced by the database itself, which rejects deletes and any rewrite of a logged row, so the history cannot be quietly rewritten by any later code path, including an agent's.

Now run December's two stripped units through it. A technician photographs each unit's plate and records a voice note: "frame cracked, pulling the drives for spares." The model reads the serial from the photo and the fault from the note. The candidate finder matches both serials on the second rule, and the reviewer confirms each link. From that point the fault report goes on each unit's record straight away, because a report of what happened is evidence, not a decision. What to do about it is the decision: the reviewer retires both units with the fate "disposed" and the December date, and the record keeps the photo, the note, the link and who confirmed it. The October demo unit has no paper at all, so the same week someone reports it Not found, and the write-off waits for the owner to retype the amount. By January 1 the register is a confirmation, not a rescue, and every line on it traces back to a photo, a document or a person's decision.

What changes is timing. The register moves when the evidence is created, and the expensive judgment (is this a repair, is this unit gone) still belongs to a person, with the paper attached.

What to do on Monday. Draw your own intake path, from a photo or a PDF to a row in the register. Mark every place a model's output reaches a write. For each one, write down the code check that sits between them, and what happens when the model returns something you did not expect. Where the answer is "nothing" or "it would go through", that is your first change. Then pick ten register rows at random and trace each back to its source document. The rows you cannot trace show you which of the four events your intake is missing.

General information, not tax advice. Your accountant knows your situation.

Sources:

San Mateo County Assessor, "Business Property Statement Form 571-L FAQs"

Agent Development Kit, "Graph-based agent workflows"