Aradus Field Guide

Aradus has one Operations surface kept current by four automation layers. Then we spend a month inside an invented customer's account to see both at work.

What Aradus does

Every company that moves physical goods runs on two kinds of information. There is the record: an order was placed, an invoice was issued, a container was booked. And there is the traffic: the emails, PDFs, WhatsApp messages, phone calls and portal screens through which the record gets made and kept up to date. ERPs are good at the record. Nobody is good at the traffic. It is read by people, one message at a time, and typed into the record by hand.

Aradus exists to do the traffic. A manufacturer or a distributor keeps its ERP, or its spreadsheet if it has no ERP, and we sit in front of it reading what arrives, deciding what it means, and either doing the next thing or asking a person. The stated scope in the repo is procure-to-pay, order-to-cash and the logistics between them. Aradus can track terms, schedules, payments and collection work, but it does not post a general ledger or replace the customer's accounting system.

Seen that way, the automation in the codebase is four layers of one machine.

The first layer is the edge: how traffic gets in and out. Email through Outlook and Resend, WhatsApp through Twilio, voice calls, uploads, and portal scraping for tracking. Each of these is a door, and each door today has its own little room behind it where it keeps what came through.

The second layer is reading. This is the document pipeline. A PDF arrives and the pipeline works out what it is, splits it if it is several things stapled together, and pulls the fields out: invoice number, lines, totals, the counterparty. It is the part of the system that turns pixels into candidate facts. They are candidates because the pipeline is not allowed to be sure. Its output is a proposal with a confidence, and the design is built around keeping that honest: proposals are written down and left as written, a person or a policy decides, and only the decision becomes a fact.

The third layer is deciding and acting. This is the code-defined workflow engine, the customer rulebook and the Command Center. When the pipeline says "this looks like the second version of invoice 4471 from the same supplier," a workflow raises a version review, an operator picks the right one, and something downstream happens. When a shipment's ETA slips, a notification goes out. The workflow layer applies a tenant's own rules: who approves what, when to escalate, what counts as a duplicate. There is no editable workflow canvas in the greenfield system.

The fourth layer is memory, and it gets the least attention relative to what it is worth. What did we decide, on what evidence, and what rule came out of it. This is what Pallet calls their Enterprise Memory Layer and markets as the moat. An ERP will happily tell you what an order says. It cannot tell you that the supplier's invoices come in two flavours, that this customer signs off artwork by marking up a screenshot, or that a particular carrier's emails are trustworthy about vessels and useless about dates. Every human intervention is a rule waiting to be written down. The system that writes them down and applies them next time is the one customers cannot leave.

Around those layers is Operations: the partners, products, bills of materials, requests, quotes, orders, shipments, obligations, payments and work queues that people use to run the company. Operations is not a fifth pipeline stage. Omar can create a purchase order directly, or the four-layer loop can create one from an email; both paths use the same business rules, authority checks and audit trail. If the ERP owns the record, Operations is the local working view and the ERP is written last. If there is no ERP, Aradus holds the record itself.

Edge email, WhatsApp, voice, uploads, feeds Reading classify, extract and propose with evidence Deciding code workflows, rulebook, review queue Memory decisions, evidence, rules and versions Operations partners · products · bills of materials requests · quotes · orders shipments · obligations · payments risk · compliance · pending work direct commands and automated changes use the same rules and audit trail when authoritative ERP written last
The four automation layers turn traffic into trusted changes. Operations is where people work with the records; an ERP is written only when it owns them.

The current work, placed on the Operations surface and its automation layers.

Document intake and invoice versioning are the reading layer feeding the deciding layer, for ITCC. Supplier invoices arrive by email, get read, get compared with earlier versions, and a person resolves the difference in the Command Center. This is the most mature path in the system and the one with paying traffic.

Shipment tracking is an edge door (carrier feeds, the bill of lading, the vessel fallback for small carriers) feeding the part of the memory layer that was built properly: observations and a reducer.

Document generation, which IMP uses, is the deciding and reading layers run backwards: a loading list goes in, a packing list and a commercial invoice come out, and it is the one workflow where we produce documents rather than read them.

Freight requests, quotes and bookings are Operations records. The reading layer handles replies that arrive as files or messages, and the deciding layer compares the offers and records the selected booking.

Order confirmation, the next workflow for IMP, uses Operations and every automation layer at once. IMP is a trader. A customer orders branded cans; IMP orders printed sheets from one supplier; the goods go straight through. Nothing can be ordered from the supplier until the customer has confirmed the artwork on every line. So order confirmation is where order-to-cash hands off to procure-to-pay, and it is the step Sari spends two hours on per order and gets wrong at ten thousand dollars a time. Operations holds the customer, products and orders. The workflow needs the doors (WhatsApp for Sari, email for his customers), the reading layer (which specification is this file, what did the customer say), the deciding layer (send, remind, escalate, convert, approve the PO), and above all the memory: which exact version the customer approved, and the rule that came out of every question we had to ask him.

Why do shipments have observations and a reducer, while orders get a row that gets overwritten?

Start from what the two patterns are for. A single overwritable column is enough when one source states a fact once. It stops being enough when the fact is reported by several outside sources, over time, with different reliability, and with a gap between what is expected and what has happened. Under those conditions every new report destroys the previous one, and no rule about which source to trust can be applied, because the inputs it would compare are gone. The alternative is to keep every report and derive the current value from them with a stated rule: observations and a reducer.

A shipment has all four properties from the day it is booked: the bill of lading says one departure date, the carrier feed says another, an operator overrides it after a call, and the feed comes back a week later with what happened. Storing one ETA and letting each source overwrite the last produces exactly the failure the pattern prevents, a refresh from the BL wiping out an operator's correction, so tracking gets the append-and-reduce treatment: write every statement down, leave it as written, compute the current state with a function whose rules are versioned.

BL says 10th feed says 12th operator says 11th reducer v3 rules: feed > document, actual > expected, operator edits survive refresh current state: departed 12th
Three sources report different dates for one shipment. A versioned reducer decides the current state from ranked rules.

An order looks, at first, like the other kind of object: placed once, from one document, then done. That holds only while the order's single source is the document that created it. It stops holding the moment anyone else reports on the order: a supplier writes that the lead time has moved out a week, a customer confirms line three by phone, a buyer adds five hundred units in a reply. Each of those is an outside report about an existing object, arriving over time, from sources of differing reliability, some expected and some actual. The same is true of a specification once a forwarded artwork file can change which version is current. Once messages are an input in their own right rather than a carrier for attachments, every business object acquires the four properties, and the distinction between "objects the pipeline creates" and "objects the world reports on" collapses.

So the observation-and-reducer pattern is the general case, and the shipment was only its first instance. Any object should absorb the world's reports about it the same way: a supplier email is one observation about an order's promised date, ranked below a signed confirmation and above nothing; the reducer for that attribute says which wins; and the review gate in front of it says when a person should look. The data model of the current system, which has the pattern for shipments and an overwritable column for everything else, is a snapshot of which objects had multiple reporters at the time it was drawn, and that set has grown.

Aradus reads the traffic so the Operations record stays true, and remembers how it decided so it does not have to ask twice. Order confirmation is the first feature that uses the Operations surface and all four automation layers for one customer on one order, which is why it comes next and why it will be harder than it looks.

A month at Zaytoun Foods

Zaytoun Foods is an invented customer. Over one month its master data, orders, invoices, shipments and messages move across Operations and the automation loop. Each episode ends with the rows it left behind, so every table in the design is seen earning its place.

The company. Zaytoun Foods LLC, Dubai. Twelve employees. Two things going on under one roof.

They make date syrup and tahini. Some of it sells under their own label. Most of it sells as private label: a supermarket chain in Riyadh wants the same tahini in a jar that says "Al-Tamimi Select," so Zaytoun prints the chain's artwork on the label and ships it. Private label is where the money is, and where the mistakes are, because the jar displays someone else's brand.

To make anything they buy glass jars and lids from one supplier, Camlica Cam in Izmir, Turkey. Jars arrive by sea in containers, roughly one a month.

They sell finished goods two ways: to the Gulf chains by truck, and to distributors in Kenya and Tanzania by sea, in their own containers.

They have a small ERP for stock and invoices, and a shared mailbox, ops@zaytoun.ae, that three people read. Their customers and suppliers talk to them by email, WhatsApp and phone, in about that order of volume. Before Aradus, the three people spent most of their day copying things from those channels into the ERP and chasing people who had not replied.

Over the month Aradus sits in front of the ERP while Layla runs operations, Omar does purchasing, and Hana prepares export documents.

W1 W2 W3 W4 BOM says 40,000 jars, PO to Camlica (ERP) freight request, 3 quotes, comparison, booking forecast: reorder point 30,000, lead time p50 7.5 weeks invoice CC-8812 v1 auto-approved v2 +$210, version review rule saved freight invoice vs quote: demurrage line flagged vessel: BL vs feed, carrier email, port change + ETA Al-Tamimi photo order, confirm quantities, order confirmation loop 400 broken jars: credit note, adjustment, payment day 30 loading list, packing list + commercial invoice Doha tender, 30 lines matched, request, quote, acceptance voice note: 1L to 300 cartons, audio kept, span as evidence any week: Oman inquiry, auto-reply
Four weeks at Zaytoun Foods, each column showing that week's episodes, with one message that can arrive any week.

standing data Day 0: what Aradus already knows. Before the month starts there is a standing picture. Zaytoun is a row in organizations, the account that logs in. Everyone they deal with is an objects row of kind partner scoped to Zaytoun, roles carried in its snapshot: Camlica supplier, Al-Tamimi and the Kenyan distributor customer, MSC carrier, and Zaytoun itself a partner object so that it can be the seller on its own invoices. Each partner has people in contacts, and each person has addresses in contact_channels: Omar's counterpart at Camlica has an email, Al-Tamimi's buyer has an email and a WhatsApp number that is verified and opted in, and their buyer role there is an object_links row of kind contact_of scoped to the Al-Tamimi partner. Products are objects of kind product: the tahini SKUs, the syrup SKUs, and the J-370 jar and its lid as purchased components. The recipe that says a jar of tahini is one J-370 jar, one lid, one label and 350 grams of sesame paste is a bills_of_materials header for the tahini product with bom_components rows under it, qty in units the database can convert, yield and scrap columns the database checks. Camlica's tax number, the J-370 SKU, and the UN/LOCODE for Jebel Ali are in identifiers, the table the resolver checks before any model is asked anything. Because Zaytoun has an ERP, its authority policy sets objects.authority to erp for the order, obligation and product kinds; Aradus mirrors them and pushes changes. Specifications, versions, asks, messages and decisions are Aradus's own for every tenant and need no such policy row. And in policies, Zaytoun's rules: thresholds for auto-accepting fields, who signs off artwork at Al-Tamimi, how often to remind them, and that a marked-up screenshot counts.

ERP syncfreight and orders Week 1: the number behind the order. Two Gulf chains have open orders for 60,000 jars of tahini between them. The bill of materials turns those orders into a requirement: 60,000 jars, 60,000 lids, and Zaytoun has 22,000 jars in stock. That is where "Omar needs 40,000 jars" comes from; it is a derived quantity rather than a hunch. Omar creates the purchase order to Camlica in the ERP, which is the authority for orders, and Aradus mirrors it: an objects row of kind order, side purchase, with order_line children for jars and lids, and an erp_links row with the ERP's id for it. Expected in six weeks. That expectation is the first fact about this order.

forecastingERP sync The 22,000 in stock is also a number Aradus had an opinion about. The ERP can add up what is on hand and what is already ordered; it has no idea what next month's orders will be, so someone sets the reorder point by hand and it goes stale. Omar set J-370's at 20,000 jars two years ago. A fitted_models row of kind demand, fitted last month on 24 months of order history pulled from the ERP, reads J-370 demand as steady rather than lumpy and holds a backtest: how the model would have done on the last six months if it had been trusted. Its forecast puts the middle guess for demand over the next lead time at 26,000 jars, recorded as a facts row (modality expected), and the guess it exceeds only one time in ten at 31,000. An assertion proposal followed: reorder point 30,000, with the backtest beside it. Omar accepted, the decision materialized as a fact on the product and an erp_commands row changed the ERP's rule. A second fitted model, kind lead_time, holds what Camlica promised against what arrived on the last 14 orders: p50 seven and a half weeks, not six. So the arrival expected on this PO is not the date on the PO. It is an expected fact from the lead-time model, and the at-risk alert in week 3 will count from it. Neither fitted model is the record of anything; both are a memory of how right the guesses were.

order confirmationtracking A purchase order to a supplier does not confirm itself either. Aradus opens one asks row of kind po_acknowledgement, addressed to Camlica's sales contact, with three ask_items: jars, lids and the freight line, each carrying the quantity, price and ship-by date on the PO. Camlica's contact replies by email the same afternoon, confirming quantities and price on all three and moving the ship-by date out two weeks. The reply is read into three proposal_decisions rows, actor counterparty, each quoting the words that support it: "40,000 as ordered," "price unchanged," "ship-by the 24th, the mill is running a holiday order first."

The moved date decides the ask item, and it is also a fact about the order line in its own right: a facts row against the platform's registered attribute_definitions row for ship_by, modality expected, sourced from the same email. That row is what the lead-time forecast's expected arrival and the week 3 at-risk alert count from, so neither one has to know a question was ever put to Camlica.

document pipelineERP sync Camlica next sends proforma PF-2201 for $8,400 and asks for a 30% advance. Aradus stores it as a documents row with doc_class = proforma and binds it to the purchase order as evidence; it does not create an obligation, because it is a request for payment rather than a claim of debt. Omar pays $2,520. The payment is recorded without an application, while the ERP posts it to Zaytoun's supplier-advance account under Zaytoun's existing accounting rules. The money becomes available to settle the final invoice later, without pretending the proforma itself is payable.

freight and ordersintake and conversation Omar also needs a container from Izmir to Jebel Ali. Zaytoun buys from Camlica FOB Izmir, so Camlica delivers the jars to the port and Zaytoun books the ship; had the terms been CIF, Camlica would book it and the bill of lading would arrive from their forwarder instead. The Incoterm in the order object's snapshot is what tells the freight workflow this request is Zaytoun's to raise. He raises an objects row of kind freight_request: one 40-foot container, ready date, ports, and Aradus sends it to three forwarders as three dispatches. Two reply by email with a price, one replies by WhatsApp with a photo of a rate sheet. Each reply is a deliveries row with its file in artifacts, read by the pipeline into a freight_quote object, its snapshot carrying the charges for ocean freight, terminal handling and the documentation fee. A read model puts the three quotes side by side on the same basis, and Omar picks one. That becomes a freight_booking object, and an allocations row ties it to the jar PO's order_lines through booking_id, since no shipment exists yet, so the container and the order stay connected from the moment Omar picks a quote, weeks before the bill of lading creates the shipment row the allocation later also carries.

intake and conversation Week 2: the invoice arrives, twice. Camlica ships the jars and emails the invoice as a PDF: CC-8812, 40,000 jars, $8,400. The mail hits ops@zaytoun.ae. Aradus reads it before anyone else does.

document pipeline What "reads it" means, precisely: the email is a deliveries row, resolved to the Camlica contact through contact_channels, and attached to the conversations row for that contact. The PDF is an artifacts row, stored once, by the hash of its bytes; the body is a second artifact under delivery_artifacts. A runs row opens for the file. The pipeline asks what this artifact is and writes a pipeline_proposals row: "commercial invoice, 0.97." That passes Zaytoun's threshold, so proposal_decisions records the acceptance by policy and a documents row is born as an invoice. The pipeline then proposes each field, one proposal per field, each tagged with the page and box it came from: invoice number CC-8812, seller, forty thousand of J-370 at $0.21, total $8,400. The seller resolves to the Camlica partner because "Camlica Cam San. ve Tic. A.S." is an aliases row Omar confirmed months ago; the product resolves through identifiers on the SKU. Every model call along the way is a model_invocations row, reserved before the call and completed after, which is where billing reads from; the proposal's own uniqueness is what makes a retry within the run cheap rather than a paid repeat. The page images the review screen would show are artifacts rows of kind page_png, a rendition of the source file. Nothing in the ERP is touched yet. These are proposals, awaiting a decision.

document pipelineERP sync Now the cross-document and three-way checks. Aradus links the commercial invoice to the PO and earlier proforma through supplier, PO references, products and shipment evidence; it does not require PF-2201 and CC-8812 to share a number. It compares their products, quantities, prices, charges, currency, total and payment terms, then compares the accepted invoice with the PO and, when the container is unloaded, the receipt quantities recorded as allocations rows against the order_lines. All agree, so the check proposals pass and the invoice materializes: an objects row of kind obligation (payable, debtor Zaytoun, creditor Camlica) with an obligation_revisions row holding revision 1 and its obligation_lines rows, an obligation_heads row pointing at it as the live one, its snapshot carrying $8,400 due 30 days from the BL date, all in one transaction recorded in materializations with a digest of the accepted proposals. An evidence_bindings row ties the obligation to the commercial document that created it, and an append-only payment_applications row applies Omar's $2,520 advance, leaving $5,880 outstanding. Because invoices are ERP-authority for Zaytoun, the posting becomes an erp_commands row, retried until the ERP confirms, and erp_links stores the ERP's id for the bill. Layla sees it in a list of things done, and nobody had to touch it. One auto-approved invoice in twenty is pulled to a person anyway, marked as an audit rather than a review, because a system that learns only from the cases it doubted does not find out how often it was wrong when it was sure.

versioning and review Four days later a second email arrives from Camlica: "Revised invoice attached, please disregard the previous one." Same number, CC-8812. The total is now $8,610: a $210 pallet charge was added. The new PDF has a different hash, so it is a new artifact and a new document, one more row in the document_families row keyed on the obligation's own (kind, counterparty, number) as its chain key, with a document_family_members row for each PDF and exactly one marked current. Instead of creating a second obligation, the pipeline resolves to the same obligation object by that chain key and proposes "this is a new revision of CC-8812." The workflow raises a version review as an asks row in the Command Center: side by side, the only difference is a new line, and the body of the email said "disregard the previous one." Layla clicks once: accept the new revision. A second obligation_revisions row is inserted current, the deferred EXCLUDE constraint demotes revision 1 in the same transaction, and the old revision stays in history, and the three-way match runs again. It now fails by $210, over the 1% threshold, and the obligation goes back to needs approval. Omar looks, sees a pallet charge that was in the PO's small print, approves it, and ticks "save as rule." That writes a policies row: pallet charges from Camlica up to $250 are within tolerance. Next month the same thing will not ask.

The invoice followed one sequence throughout: a message arrived, the pipeline proposed, a rule or a person decided, the ERP was written last, and a rule came out of the intervention.

compliancefreight and orders In the same week the forwarder's freight invoice arrives for the inbound container. An invoice is a claim and the quote is what was agreed, so every line of the claim has to trace to a line of the agreement. It is read like any invoice, and then each charge is compared with the charges carried in the snapshot of the freight_quote object behind the booking Omar chose. Ocean freight and terminal handling match to the dollar. A demurrage line for $340 matches nothing, because the quote had none and the container has not yet reached port, so a check proposal fails and the invoice waits. Omar asks the forwarder, who withdraws the line. The rule that caught it is one check policy row: every charge must match an agreed charge or be explained. The same kind of rule, with hs_codes as its reference table, checks a duty line on a customs invoice against the rate for the code.

document pipelinetracking Week 3: the ship. The container is on a vessel called MSC Adriana, a row in vessels. The bill of lading, which arrived as another PDF from the forwarder, says departure March 10 from Izmir, arrival March 24 at Jebel Ali, both rows in ports. Aradus created an objects row of kind shipment from that document, with a shipment_leg child for the sea leg and a handling_unit child for the one container, its own handling_units row carrying the container number, unique within this shipment and check-digit validated rather than in a global registry (a box comes back on a later shipment), and an evidence_bindings row of kind source says this BL created this shipment. Then it started tracking against the carrier's own data feed.

tracking The feed says the ship left on March 12 and the BL says March 10, so which is right? This is the case the facts and reducer pattern exists for. Each provider report lands first as a shipment_events row, the normalized event with the provider's own identity and payload, and facts are derived from that row. Aradus does not overwrite anything. It records two facts: "BL says departed 10th," "carrier feed says departed 12th." A rule says the carrier's feed outranks a document about dates, so current_facts for the shipment's departure shows the 12th, and if you ask why, the answer is those two rows and that rule's version.

intake and conversationtrackingnotifications Then a carrier email arrives at ops@: "Due to congestion at Jebel Ali, MSC Adriana will now discharge at Khalifa Port, ETA March 27." The email body has no attachment. The pipeline reads the body, and a refers_to proposal resolves "MSC Adriana" and the container number in the text to Zaytoun's one open shipment. Two assertion proposals follow: destination port changed to Khalifa, ETA March 27, each pointing at the words in the email that say so. A carrier email is trusted about routing, so the port change auto-applies as a fact. The ETA lands as an expected fact and a notification goes to Layla and Omar as dispatches, because Zaytoun's rule says "tell me when an inbound container slips by more than two days." The trucking booking from the port has to change, and Layla changes it. In week 4 the feed reports the vessel actually berthed at Khalifa on the 28th. That is an actual fact and it wins over every expected one.

versioning and reviewERP sync When the container is unloaded, 400 jars are broken. Omar tells Camlica, and Camlica emails a credit note for $84. That is not a new invoice. It is an objects row of kind adjustment against CC-8812, negative, bound to the obligation with its own document and evidence_bindings row, and the outstanding balance shrinks to $8,526. When Omar pays on day 30, a payments row, its amount and currency immutable once written, settles the balance through a payment_applications row, and the ERP hears about it through another command.

intake and conversation Week 3, in parallel: the private-label order. Al-Tamimi, the Riyadh chain, sends an order by WhatsApp to Layla's number: a photo of a handwritten list. Three products, quantities, and "new label for the tahini, file attached." A PDF of the label follows.

intake and conversationfreight and ordersERP sync The message lands in the conversations row for Al-Tamimi's buyer, keyed on tenant, channel and number, which is how Aradus knows who is talking before it reads a word. The pipeline reads the photo. It proposes a sales order with three lines, at 0.82 confidence on the quantities because the handwriting is bad. Zaytoun's threshold for creating an order from a photo is 0.95, so this one waits. The conversation workflow sends Layla a question as a dispatch: "Order from Al-Tamimi, three lines, please confirm quantities." She fixes one digit and confirms; her reply is the decision. The order exists, an objects row of kind order, side sale, with three order_line children, pushed to the ERP through a command. This is the back-and-forth case: for a customer who sends clean spreadsheets the same step would have created the order with nobody involved. Two days later the buyer writes "also add 500 of the syrup." That updates the order object rather than editing history away: the order as first confirmed stays on record in its accepted proposal and decision.

order confirmation The order now enters confirmation. Zaytoun cannot print labels until Al-Tamimi confirms the artwork for each line. Two of the three lines match specifications already in the library, "Al-Tamimi Select Date Syrup 500ml" and "Al-Tamimi Select Tahini 350g," each pinned to a specific approved version, a specification_versions row, through its own line_specification_pins row that the line's ask_items row cites. The third line says "tahini, new label," and the PDF that followed is the candidate for it.

order confirmation Aradus reads the label PDF: the artwork says "Al-Tamimi Select Tahini 350g," it scores 0.94 against the current version of that specification, and it came from Al-Tamimi's own WhatsApp number. Because those three signals agree, a refers_to proposal points at the specification at 0.96. Layla's rulebook said auto-replace when the three signals agree, so the decision is by policy: a specification_versions row for version 4 with status current, version 3 marked superseded, and the specification's current pointer moved, in one transaction recorded in materializations. Layla gets a receipt: "Replaced Al-Tamimi Select Tahini 350g v3 with v4." A customer who wants to approve every version would set that rule to require approval on every version. Nobody compared files.

order confirmationnotifications The pack goes out to Al-Tamimi's buyer by email, since the chain has not opted into WhatsApp from Zaytoun: one dispatches row with previews of all three labels, one link per line, and the three lines move to sent. Zaytoun's rulebook for this customer says remind every two days, escalate to the category manager after two reminders. Day two, no reply, a reminder dispatch goes. Day four, the buyer replies: "Syrup and tahini 350 confirmed. The date syrup 1L, please move the barcode to the back." The reply is a delivery, and the pipeline reads it as three assertion proposals, one per line, each pointing at the words that support it: two confirmed, one rejected with an instruction. The two confirmed lines are pinned, decided with the customer as the actor. The rejected line waits for Zaytoun's designer, who uploads version 2 of the 1L label; the loop sends only that line back out. Day six, "1L confirmed." Every line is pinned to a version the customer said yes to, and each yes points at the exact words in the exact email that said it.

order confirmation Only now does production get its work order, and the label print run is released. If the barcode had been in the wrong place on 20,000 labels, that is the ten-thousand-dollar mistake this exists to prevent.

candidate label origin content visual agree? yes auto-replace + receipt no one-tap question pack out per line reminder every 2 days reply verdicts per line: confirmed, or rejected + instruction re-send only rejected line all pinned each line, one exact version print run released
Order confirmation: a candidate label passes three signals before it auto-replaces a version, and every confirmed line ends pinned to one exact version.

intake and conversationfreight and orders Week 4: a new customer asks for a price. A chain in Doha emails ops@: "Please quote 2,000 cartons of tahini 350g, private label, delivered." (a product_packagings row is what turns "60 ctn" on a line further down their tender into 720 pieces, the units and unit_aliases tables resolving "ctn" to the carton unit first.) The pipeline reads the intent as a request for quotation from a partner Zaytoun has not sold to yet, and an objects row of kind commercial_request is created with its lines. The email carries a spreadsheet of 30 lines, the chain's own tender: sizes, cap type, "halal certified", "shelf life 12 months". Each line is an entity_match proposal against Zaytoun's product objects; 27 resolve, one says "500g" in the description but carries the 350g product code, so a check proposal flags the conflict, and two ask for black sesame tahini, which Zaytoun does not make. Those two are rejected with the reason "not in range" and the rejection is what a register of out-of-scope requests is: a read over decisions rather than a table of its own. Layla prices it in Aradus, which writes a quote object (side sale) with a quote_revision child and sends it as a dispatch; when the chain accepts by email, the reply is read as an assertion on that quote and its accepted revision becomes current, and the sales order that follows is created from it, pushed to the ERP like any other. The label artwork for the Doha chain will go through the same confirmation loop when the order comes. Had Zaytoun's ERP been the place Layla types quotes, the same matching would have run under her cursor: a SuggestionQuery call from the ERP screen, answered from a cached frequency table of what this customer and this user have ordered before, with her acceptance or override recorded as a proposal_decisions row on an entity_match proposal. The same tables are written, with no workflow in the way, and the answer is back in under a second.

document generationcompliancetracking Week 4: the export shipment. The Kenya distributor's order is ready. Hana has a loading list: which pallets, which products, which lot numbers, weights. She needs a packing list and a commercial invoice in the exact format Kenyan customs and the distributor's bank expect, and a certificate of origin request; a compliance run checks the shipment against the documents Kenya requires and raises a task for anything missing. This is document generation, where Aradus writes documents instead of reading them. Hana uploads the loading list, which is a delivery and an artifact like anything else; the generation run produces the packing list and commercial invoice as new artifacts and documents rows on the channel generated; she checks the totals against the order, and sends them as dispatches. The commercial invoice is also an obligation in the other direction: receivable, debtor the distributor, creditor Zaytoun, with its own schedule. The bill of lading comes back from the forwarder a few days later, is read like any other BL, and the outbound shipment is tracked to Mombasa the same way the jars were tracked in.

intake and conversationfreight and orders Week 4: a voice note. Al-Tamimi's buyer sends Layla a WhatsApp voice note, forty seconds, Arabic with the product names in English: make the 1L syrup 300 cartons instead of 200, the tahini stays. The audio is an artifacts row by its hash, kept for as long as Zaytoun's retention policy says, because the recording is the record of what was asked. An artifacts row of kind transcript, parented to it, holds the words with their timings. The pipeline reads the transcript as two assertion proposals on the order lines, and each one's evidence is an audio span, so the review shows the eight seconds that say "three hundred" and plays them. The quantity change clears the threshold and materializes; the "tahini stays" assertion is a confirmation with nothing to change and is recorded as such. The segment where the buyer's child interrupts scores low and is marked, and nothing is proposed from it. The transcript is a derivation, and Arabic mixed with English transcribes badly, which is why the audio is the record and the words point into it. At a customer where thirty percent of traffic arrives as voice, this path carries a third of intake, and a manufacturer disputing a quantity a year later is owed the recording.

intake and conversation Any week: the stranger. An email arrives at ops@ from someone in Oman: "Do you sell tahini in Muscat, and what is your price per carton?" The sender matches no contact, so no partner object is created; the delivery is kept with the address unresolved. The pipeline reads the intent as a price inquiry from a non-customer, and the workflow replies with the Oman distributor's contact details, from a template Layla approved once, as a dispatch. No human reads it. If the Omani writes again, the conversation is already there.

What accumulated. By the end of the month Aradus has recorded for Zaytoun: an alias for Camlica's legal name, a rule about their pallet charges, a rule that carrier emails may change a port but not a confirmed arrival, a supplier's acknowledgement with its moved ship-by date, a threshold for photo orders from Al-Tamimi, that customer's reminder and escalation contacts, the fact that marked-up screenshots count for them, four versions of a tahini label, with the current one pinned to a signed-off order, two fitted forecasts with their backtests, a fitted_models row of kind calibration for invoice fields fitted on the month's decisions and audits, a check that caught a demurrage line, two rejected requests for a product Zaytoun does not make, and a forty-second recording behind a quantity. The ERP stores none of it. Next month Aradus applies the saved alias, tolerance, contacts and pins without asking again, and after a year that accumulated operating memory is what a customer would lose by switching.

tag entry alias Camlica Cam legal name resolved to one supplier alias rule pallet charges from Camlica up to $250 auto-approve rule carrier feed outranks documents on port and date threshold photo orders from Al-Tamimi require 95% confidence contact Al-Tamimi reminder every 2 days, escalate after 2 contact Al-Tamimi screenshot with markup counts as an answer pin three private-label lines pinned to signed-off versions
What accumulated at Zaytoun Foods in one month: aliases, rules, a threshold, contact preferences, and the pins that keep each line tied to one version.

The same month at a manufacturer. Swap Zaytoun for a valve maker on Odoo, the case the RVK Factory assessment describes, and the story changes in content but not in tables. The authority policy sets objects.authority to erp for every commercial kind, because a team mid-migration has to be able to switch Aradus off and keep trading. So Aradus does not write a quotation; it writes suggestions, flags and approved values back as erp_commands, and reads the customer's bill of quantities off the ERP record as a delivery like any email. The label PDF becomes an engineering drawing: a DXF read without a model into an artifacts row of kind vector_text where the file allows it, and a photographed sheet read region by region otherwise, with quantities taken from the schedule table as text rather than counted from symbols, because models count dense symbols badly and the table already has the number. The voice note is thirty percent of intake instead of one episode. The 22-character product code gets the suggestion under the cursor and a deterministic check on its eleven segments when two codes on a line disagree. The forecasts are the same two kinds, minimum stock and lead time, over the same fitted_models rows. What Aradus owns at that tenant is what Odoo has no model for: the decisions and their evidence, the drawings and the audio, the fitted models and their scorecards, and the record of every suggestion taken or refused.

Tables used in every step. A few tables are written so often that the episodes do not name them each time: objects, the identity and snapshot every order, shipment, obligation and product gets before anything else points at it; runs for every reading step; artifacts for the page images a reviewer sees, as renditions of the source file; model_invocations for every model call; domain_events and audit_events for every write; facts and current_facts for every observation and the value its reducer computes from it; and the reference tables countries, currencies, ports, carriers, vessels and units that names and quantities resolve against. The workflows themselves, the waiting between these writes, run in Temporal and leave no table behind except their ids on runs and conversations.

Across the month, Operations held Zaytoun's partners, products, orders, shipments, obligations, payments and pending work. The shared mailbox, two WhatsApp numbers and carrier feed supplied the traffic; every PDF, photo, spreadsheet, voice note and email body became proposals with evidence; thresholds, the version review, the three-way match, the confirmation loop and the auto-reply decided; the rules and pins that came out of each human touch were kept. The ERP was written last whenever it owned the record.