Loop INV-3 · Inventory & purchasing · reports to Lerris / Ajeesh

“Order the fabric by the 15th, or production waits.”

Compares stock and incoming orders against supplier lead times and real demand — and speaks only when someone must order something by a date.

Built & tested — pilotWave 4🕐 Daily, speaks when needed⚙️ Hermes bizops (planned)
Part 1 — the plain-english view

The warning we never get: out-of-stock, seen weeks early.

What it watches
  • Available stock + open purchase orders vs lead time × demand rate per item
  • Long-lead materials first — fabric can take 40–95 days to arrive
  • Value at risk: what production would stall if the item ran dry
When & how it speaks

Daily check, but it only messages when action is needed: “order X by <date>” with the evidence. No news is genuinely good news here (the dead-man's switch still proves it ran).

Why it exists

Because almost no items had lead times on record, nobody could compute “will we run out before a new order arrives?” As INV-2's approved coverage grows, this loop's answers sharpen from provisional to firm.

127
items at reorder risk on the first provisional run
AED 331,586
of stock value at risk across those items
40–95 days
fabric lead times — the reason a daily early warning matters

Daily

After the overnight data sync

👀

Stock vs pipeline

On-hand + on-order per item

🧮

Risk math

Days of cover vs lead time + demand rate

💬

Speaks when needed

“Order by <date>” list, evidence attached

💓

Silent proof-of-life

Healthchecks ping on clean runs

What it will never doNever places a purchase order.
Where it stands today · July 2026Built and live-tested — provisional. Lead-time coverage is still thin (approved values ~9.5%; the rest run on proxies from PO history), so it labels itself PROVISIONAL in every digest until INV-2's approved coverage passes ~60%. A chassis lesson from this build now protects all loops: the BI layer silently truncates very large queries, so aggregate first, then fetch bounded detail.
Part 2 — under the hood

How it's wired: systems, models, and the path a number takes.

For implementers and the technically curious. The full build sheet — verified queries, thresholds, and build notes — lives on the specs page.

ReadsNetSuite warehouse
Stock, open POs, demand lines, planning fields
Stepinv3_reorder.py
Days-of-cover math; provisional proxies where no approved lead time exists
StateRisk state
Yesterday's risk list — so only changes get spoken
DeliversAction list
“Order by date” — only when the list is non-empty
Human gateLerris / Ajeesh order
Humans raise the PO; the loop just made sure they knew in time
System we read Automated step State / memory Human decision
SystemRole in this loop
NetSuite warehousePostgres on our serverOur nightly read-only copy of NetSuite (ERP) data — items, stock, transactions — refreshed by the ETL sync every morning. The loop queries this copy, never NetSuite itself.
Metabasebi.huxapps.comThe BI layer over the warehouse. The loop runs its SQL through Metabase's API, and every number in the digest links to a live, clickable Metabase list so you can drill into the exact records.
Postgres “loops” schemareporting databaseA small dedicated schema where loops keep snapshots and history that need SQL (week-over-week diffs, mirrors for drill-down links). Scoped role; Metabase can read it for the clickable aggregate links.
Hermesagent runtime on our serverThe scheduler that wakes the loop up. Each loop is a cron job under a Hermes profile; the planned bizops profile will host the business digests (IT loops run under vpsops).
Healthcheckshealthchecks.huxapps.comThe dead-man's switch. The loop pings it only after a clean run — if the loop dies or errors, the ping stops and Healthchecks raises the alarm independently. This is how 'never silent' is enforced by machinery, not promises.
Email renderer + gwsrender_email.pyAll digests pass through one shared renderer: Huxberry-branded HTML, tables for repeated rows, a coral 'needs your response' box when the loop has questions, and an arrow link on every record. Sent from the loops mailbox via the Google Workspace CLI.
Loop chassisloop_common.pyShared plumbing every loop reuses instead of reinventing: state files, run-over-run diffing, Metabase drill-down link building, quiet-on-green notify logic.
Model / brainWhat it does here
None at run timedeterministic scriptA normal cycle is a plain Python script — no AI tokens are spent unless a diagnosis or judgment step is actually needed. AI wrote the script; the script does the rounds.
GPT-5.5 via Codexthe bulk-work modelWrote and maintains the mechanical parts — SQL, diffing, digest assembly. Effectively free on our existing subscription, so routine cycles cost almost nothing.
Claude Opusthe judgment modelReviews alert wording, thresholds, and anything a human will read and act on. Post-Fable, Opus owns everything that ships.
State & memory

Yesterday's risk list — the loop reports newly-at-risk and resolved items, not the same list every day.

Delivery

Email only when action is needed; every item links to its ERP record and the aggregate links to a live list.

Safety rails

Read-only; PROVISIONAL label until lead-time coverage is real; never touches purchasing.

Before it can run for real
  • INV-2 approved lead-time coverage >60% to drop the PROVISIONAL label
  • Nish's answer on the risk thresholds (open question from the Wave-4 results email)
Full build sheet →