Loop FIN-4 · Finance · reports to Shahbaz / Waseem

No expense claim should rot in a queue.

Watches the new expense app's review queue and nudges — weekly, and only when something has actually been stuck for more than a week.

Built & tested — pilotWave 3🕐 Weekly, speaks when stuck⚙️ Hermes bizops (planned)
Part 1 — the plain-english view

A small loop with one job: keep the claims queue moving.

What it watches
  • Claims stuck pending review > 7 days
  • Correction requests unanswered > 7 days
  • Per-division submission counts — is anyone not using the app at all?
When & how it speaks

Weekly, and only when something is stuck. An empty week means no email (the dead-man's switch still proves it ran).

Why it exists

The expense app is new — and a queue nobody watches is how a good pilot quietly dies. The loop found 4 claims already stuck on its first run. It also surfaced a real product gap: the app stores submission dates as display text, so precise aging needs an app fix first — requested, honestly, rather than guessed around.

4
claims stuck in the queue on the very first run
7 days
the stuck threshold — long enough to be real, short enough to matter
1 app fix
surfaced by the loop: store real timestamps so aging can be exact

Weekly

Monday morning

👀

Reads the queue

Directly from the app's database, read-only

📋

Applies thresholds

Stuck >7d, unanswered corrections, silent divisions

💬

Nudges if needed

Short email; quiet when the queue is healthy

💓

Proof-of-life

Healthchecks ping either way

What it will never doNever approves or rejects a claim.
Where it stands today · July 2026Built and live-tested against the pilot app's database (its claims live in a single JSON array — the loop reads it faithfully). Full go-live is gated on the app's own production sign-off, and on the timestamp fix for exact aging.
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.

ReadsExpense app database
Read-only, via a tunnel — not the app's undocumented API
Stepfin4_expense.py
Queue aging + division counts
DeliversWeekly nudge
Only when something is stuck
Human gateReviewers act
Approve/reject/correct in the app as normal
System we read Automated step State / memory Human decision
SystemRole in this loop
Expense apppilot at expenseapptestThe new receipt-capture app. Its Postgres database is read through a read-only role over a tunnel; the loop never calls its write endpoints.
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.
State & memory

Last week's stuck list — so a nudge says “still stuck, second week” instead of repeating itself blankly.

Delivery

Weekly email, quiet when healthy. Claims are deliberately unlinked — the app has no per-claim URL yet, and we never fake links.

Safety rails

Read-only database role. Gated on the app's production sign-off (including its backup/restore drill) before anyone relies on it.

Before it can run for real
  • The expense app's production sign-off
  • App fix: store submission timestamps as real dates (feature request pending)
Full build sheet →