U
CP Liquor · Help & Reference
Loss Detection · Inventory · Operations
← Back to App
Operator Reference · v1

How CP Liquor works

CP Liquor is a three-layer system: it captures what's on your shelf (manual, photo, video, or scale), keeps a live inventory the bar can run from, and surfaces variance and anomaly signals so loss is visible the same shift it happens. This page explains every feature, every flag, and every workflow in plain English. Help icons throughout the app deep-link here.

01The 3-Layer Architecture

Every feature in CP Liquor sits in one of three layers. Understanding the layers makes the rest of the document click into place.

Layer 1 — Capture

How a count enters the system. Eight methods, ranging from a hand slider to thermal imaging. Each method writes to the same liquor_counts table with a confidence score and a method tag, so downstream math doesn't care how the number got there.

  • Manual entry · single-photo · shelf scan · video walk-by · multi-photo · Bluetooth scale · FLIR thermal · photo QA gate

Layer 2 — Inventory

The operational truth your bar runs from. Counts become baselines, POS pours subtract from those baselines in real time, par status flips, and bottles-on-hand updates. This is the layer the bar manager opens at 9pm to know "do I need to drop another bottle of Patrón."

  • Live levels · par status · bottles-on-hand · calibration · quick audit

Layer 3 — Loss Detection

The reason CP Liquor exists. Variance flags catch over-pours, anomaly z-scores surface statistical outliers against a 30-day baseline, the bartender heatmap attributes loss pro-rata, and annualized projections turn one bad shift into a real dollar number management can act on.

  • Variance flags · anomaly flags · bartender heatmap · competing-brand insights · annualized loss

02Capture Methods

Eight ways to turn the bar into numbers. Use whichever the staff actually completes — accuracy is moot if the count never happens.

Manual Entry

A slider per bottle from 0% to 100%. No AI, no camera. Always works, even on a 5-year-old phone in a back-room with bad light. This is the fallback when every other method fails. Confidence is hard-coded at 1.00 because a human eyeballed it.

Single Photo

Snap one bottle. Vision model returns a fill percentage. Best for bottles you wanted to recount or that the shelf-scan flagged as low-confidence. Typical accuracy: ±3-5% on clear glass under decent light. Drops to ±10% on dark glass or backlit shots — that's why we have the QA gate (below).

Shelf Scan

One wide-angle photo of the whole shelf. The vision model identifies every bottle, locates each one in the frame, and reads its level. Fastest method for a 12-bottle wall — under 4 seconds end-to-end. Trade-off: small bottles tucked behind larger ones can be missed; the system flags those as not_seen and asks for a single-photo recount.

Video Walk-by

Record a 10-15 second pan along the shelf. The system extracts 6 frames at even intervals, runs each frame through the vision model in parallel, then merges the results.

How the merge works

For each bottle the system collects every reading across all 6 frames. A bottle "seen in 5 of 6 frames" is high-confidence and the median fill percentage wins. A bottle "seen in 1 of 6 frames" is flagged as low-confidence and the operator is shown a single-photo recount prompt.

Concrete example from a recent test pan: 12 bottles total, 11 seen in 5+ frames (auto-accepted), 1 bottle seen in 2 frames (flagged for recount). Total wall-clock: 8 seconds for the video, 4 seconds for the merge.

Multi-Photo

Take 1-6 deliberate stills with a re-shoot button between each. Same merge logic as video — readings are pooled across frames and median wins. Useful when video pan quality is poor (motion blur, autofocus hunting) or when you want HDR / intentional composition on a tricky bottle.

When multi-photo beats video

Multi-photo wins anywhere photo resolution matters more than speed: dim back-bar with foil-wrapped tequila, a busy shelf with reflections, or when the operator wants to deliberately frame each shot to avoid backlight. Each still gets full sensor resolution and HDR; video frames are compressed and rolling-shutter-blurred.

Bluetooth Scale

Connect a Web Bluetooth scale, place a bottle, and the live grams reading converts to ounces using the bottle's empty_weight_g and full_weight_g calibration values. Most accurate method available — typical ±0.1 oz. There's also a manual grams field for shops with a non-Bluetooth scale: type the number, the math is the same.

Recommended on Pro tier for high-cost bottles ($60+ retail). At those prices, a 0.5 oz misread on a single bottle erases a third of the savings the system delivers — scale closes that gap.

FLIR Thermal (Optional)

An optional Pro-tier hardware add-on. A FLIR phone-clip camera reads the temperature differential between liquid and air inside the bottle — works through opaque foil, frosted glass, and dark amber where vision models struggle. Honest framing: 90% of bars never need this. It exists for the operator with a wall of mezcal in colored glass who otherwise can't get reliable counts.

Photo QA Gate

Before any photo enters the model, a client-side check measures average brightness and contrast. Photos that fail the gate are rejected with a "too dark / re-shoot" or "too low contrast" message and never charged against the AI cost budget. Saves ~12% of vision calls and stops garbage-in-garbage-out variance.

03Inventory Operating Layer

The bar runs from this layer. Counts establish baselines, POS pours subtract in real time, par status flips, alerts fire.

Live Levels

The single most important formula in the app:

// what's actually in the bottle right now
live_oz = last_count.total_oz − SUM(pos_pours since last_count)

Every count writes a row to liquor_counts with the total ounces measured. Every POS pour writes a row to liquor_pos_pours. Live oz is the difference, computed on demand. No nightly cron, no stale snapshot — open the app at 11:42 pm and the number reflects the pour that hit the rail at 11:41.

Par Status

Each bottle has a par_level_oz. Live oz is colored against it:

StatusThresholdWhat it means
OKlive_oz ≥ parStocked. No action.
LOW50% ≤ live_oz < 100% of parPlan an order on the next supplier cycle.
CRITICALlive_oz < 50% of parAuto-fires an in-app alert. Manager dashboard widget pings.

Bottles on Hand

Operators think in bottles, not ounces. The display computes:

full_bottles = floor(live_oz / size_oz)
partial_oz   = live_oz − (full_bottles × size_oz)
display      = "{full_bottles} full + {partial_oz}oz"  // e.g. "2 full + 14oz"

Calibration ("Digital Twin")

Each bottle in the library carries a calibration profile that the vision model uses as a fingerprint:

  • Reference photo — a clean front shot at full pour, used as the visual anchor for fill estimation.
  • Empty weight (g) + full weight (g) — used by the Bluetooth scale path to convert grams to ounces.
  • Position memory — the bottle's typical (x,y) on the shelf scan, so the model finds it even when partially occluded.
  • Trained vs Training — bottles need 3+ confirmed counts before they're marked trained; until then they're training and the system biases toward higher confidence thresholds and more frequent recount prompts.

This per-bottle profile is what the team internally calls the "digital twin" — a stored representation of each bottle that persists across counts.

Quick Audit

Adjust a single bottle without opening or closing a session. Useful for: a delivery dropped 4 fresh bottles of vodka mid-shift, a bartender broke a bottle and wrote it off, or you spotted a count that was clearly wrong on the morning report. Quick audit writes a liquor_counts row tagged method='audit' and is excluded from variance attribution.

04Sessions & Counts

A session is the unit of measurement loss is computed against — bracket the shift, capture both ends, the math becomes possible.

Open Count

Start of shift. The session is created, baseline ounces are recorded for every bottle, and the timer starts. POS pours from this moment forward are attributed to this session. The session card on the home screen shows the open dot lit and the elapsed time.

Close Count

End of shift. The system asks for a fresh capture using any of the eight methods. The moment counts are saved, three things happen automatically:

  1. Variance is computed for every bottle: expected_oz = open_oz − pos_pours; variance_oz = expected_oz − close_oz
  2. Anomaly z-scores are computed against the rolling 30-day baseline.
  3. Shift-close report auto-fires (in-app + Slack if configured).

Audit (No Session)

Spot-check a bottle without bracketing a shift. Writes to counts but not to a session. Doesn't trigger variance compute. Useful when you walk in mid-day and want a number for one specific bottle without disturbing the open session.

Auto-advance & Auto-fire

Sessions advance automatically: open at 4pm, close at 2am, system marks the open count with auto_started if no one tapped Open. The same is true on close — if 30 minutes pass after the POS terminal goes idle, the system prompts to close. Alerts fire automatically on critical par, anomaly detection, and order-sent events.

05Loss Detection

Two flag families, one heatmap, and two dollar projections. Together they answer "is something wrong tonight?" and "is something wrong systemically?"

Variance Flag

A static threshold flag. A bottle is flagged if either:

  • Dollar variance > $20 (lost retail value), or
  • Volume variance > 4 oz (about 3 standard pours)

Variance is the gap between what the POS said you poured and what the bottle actually shows. It is not an accusation. Five things can cause it, in roughly this order of frequency:

  1. Over-pour — bartender free-pours and hits 1.7 oz when the recipe says 1.5
  2. Comps & spillage — drinks given away or knocked over that were never rung in
  3. Recipe drift — a margarita is now made with 2.0 oz tequila by house custom, but the recipe in the POS still says 1.5
  4. Mismeasurement — a bad count, low-confidence photo, scale calibration off
  5. Theft — last on the list, but real, especially over a 30-day pattern

The tonight-only variance number on the live demo is $164.46. Annualize that — see below — and it becomes a number management can react to.

Anomaly Flag

A statistical flag. For every bottle, the system keeps a 30-day rolling distribution of nightly variance ($). When tonight's variance arrives, it's converted to a z-score:

z = (tonight_variance − mean_30d) / stddev_30d

A z-score of 2 means tonight is two standard deviations from the bottle's normal — about a 5% probability under typical statistics. Bands:

SeverityZ-scoreTrigger
Warning2.0 ≤ z < 3.0Logged in report. No alert.
Criticalz ≥ 3.0In-app + Slack alert.
Over-creditedz ≤ −2.0POS rang in more than the bottle shows poured. Often a recipe error, sometimes a comp adjustment.

Plain-English version: a z-score above 2 means "this bottle is way outside its normal." On the live demo, Patrón Silver is currently flagged at z = 40.6. That's not a typo. That bottle's variance tonight is 40 standard deviations beyond its 30-day mean, which is the system saying "stop reading the rest of the report and look at this bottle first."

Bartender Heatmap

For any flagged bottle, the system attributes variance to bartenders pro-rata by share-of-pours. If a bottle has $40 of variance and bartender A poured 60% of the night's pours from it while B poured 40%, A is attributed $24 and B is attributed $16.

Honest about the approximation: this assumes loss is proportional to volume. It isn't always — one bartender may pour heavier and another lighter. The heatmap is a starting point, not a verdict. Use it to know who to watch on the next shift, not who to fire.

Competing-Brand Insights

Within a category (vodka, tequila, gin), the system shows variance spreads across competing brands. When Patrón Silver shows $150 of variance and four other tequilas show $5-$15 each, that's a brand-specific signal — likely an over-pour problem on that one bottle, not a category-wide drift.

Annualized Loss

The headline number for any conversation with ownership: annualized_loss = nightly_variance × 365. With $164.46 of variance on the live demo night, that projects to $60,028/year. Even with conservative assumptions (operate 300 nights, account for half being recipe drift not loss), the residual is meaningful real dollars.

This is a projection, not a guarantee. One bad night doesn't mean every night is bad. The 30-day baseline tells the truer story — and after 30 days of data, the annualized number is precise rather than projected.

06Recipes & Cocktails

30 cocktails seeded out of the box. 8 featured signatures. Every recipe ingredient links back to the bottle library — that's what makes recipe-level variance possible.

Categories & Counts

  • Cocktail — classic and craft mixed drinks (most of the 30)
  • Shot — single-pour and layered shots
  • Highball — spirit + mixer over ice
  • Texas signature — the regional house style; 8 of the 30 are featured signatures

Recipe-to-Bottle Linking

Every ingredient on a recipe carries a bottle_id reference. When a cocktail is rung in at the POS, the system knows which exact bottles should have been touched and in what amounts. That's how the loss-detection layer can distinguish "lots of margaritas were sold tonight" (expected pour pattern) from "someone is over-pouring tequila on margaritas" (variance against recipe spec).

Recipe Fields

FieldPurpose
GlassCoupe, rocks, highball, etc. — guidance for the bartender; not enforced.
IceCubed, crushed, neat, single rock.
GarnishString list. Surfaced on the prep card.
TechniqueStir, shake, build, blend.
InstructionsStep-by-step prep, free-text.

Pour Cost & Margin

cost   = SUM(ingredient.oz × bottle.cost_per_oz)
margin = (retail_price − cost) / retail_price × 100

Live example: a margarita with 1.5 oz of $0.85/oz tequila ($1.28), 1 oz of $0.40/oz triple sec ($0.40), and 0.75 oz of $0.18/oz lime ($0.14) costs $1.82 to make. Sold at $12 retail, that's a $10.18 margin and 84.8% margin percentage. Drift the tequila pour to 2.0 oz and cost jumps to $2.24 — margin drops to 81.3%. Across 200 margaritas that's $84 of unbooked cost.

07Suppliers & Ordering

A supplier directory plus a single ordering edge function that picks the right dispatch method per supplier — EDI, email, webhook, or portal link.

Supplier Directory

Each supplier carries a default_dispatch field with one of four values. The directory also stores contact name, email, phone, EDI partner ID (if applicable), webhook URL (if applicable), and portal URL (if applicable).

EDI 850 Purchase Order

X12 850 is the legacy electronic format big distributors (Southern Glazer's, RNDC, Breakthru) accept. It's a flat ASCII file made of segments, each segment ends with ~, fields are split with *, sub-fields with :. Every distributor's EDI inbox accepts it without setup work — that's why we generate it.

What each segment means (plain English)

ISA — interchange envelope. Tells the distributor "here's a transmission from sender X to receiver Y, version Z."

GS — functional group header. Wraps one or more transactions of the same type.

ST — transaction set start. ST*850 means "this is a purchase order."

BEG — beginning of PO. PO number, PO date, purpose code.

N1 — name segments. Buyer and seller, with addresses.

PO1 — line item. Quantity, unit, price, item ID.

PID — product description. Free-text bottle name + size.

CTT — total line count.

SE / GE / IEA — closing envelopes for ST / GS / ISA respectively.

Real generated example (one PO from a recent demo run):

ISA*00*          *00*          *ZZ*UNION28        *ZZ*SOUTHERN       *250428*1142*U*00401*000000001*0*P*>~
GS*PO*UNION28*SOUTHERN*20260428*1142*1*X*004010~
ST*850*0001~
BEG*00*NE*PO-2026-0428-001**20260428~
N1*BY*UNION 28 TAPROOM~
N1*SE*SOUTHERN GLAZER'S*92*SG-DAL~
PO1*1*6*EA*32.50**BP*PATRON-SLV-750~
PID*F****PATRON SILVER TEQUILA 750ML~
PO1*2*4*EA*45.00**BP*WOODFRD-RES-750~
PID*F****WOODFORD RESERVE BOURBON 750ML~
CTT*2~
SE*8*0001~
GE*1*1~
IEA*1*000000001~

Email Dispatch

For mid-size distributors that don't accept EDI but expect formatted orders. The system builds a pre-filled HTML email draft with PO number, line items, totals, and a polite cover paragraph. If the user's mail client is wired up, one click sends it. If not, the system falls back to a mailto: with the body URL-encoded.

Webhook Dispatch

For modern suppliers running their own POS-integration API. The system POSTs a JSON payload to the supplier's webhook URL with HMAC-signed headers and waits for a 2xx. Any non-2xx response surfaces a manual-fallback dialog.

POST {supplier.webhook_url}
Content-Type: application/json
X-CP-Signature: sha256=...

{
  "po_number": "PO-2026-0428-001",
  "buyer": "Union 28 Taproom",
  "ordered_at": "2026-04-28T11:42:00Z",
  "lines": [
    { "sku": "PATRON-SLV-750", "qty": 6, "unit_price": 32.50 },
    { "sku": "WOODFRD-RES-750", "qty": 4, "unit_price": 45.00 }
  ]
}

For suppliers whose only acceptance method is their own web portal. The dispatch UI opens the portal URL in a new tab, drops the generated PO into the clipboard, and shows a "Paste this into the supplier portal" toast. Less elegant, but works for every supplier.

Mailto Fallback

Universal escape hatch. Any supplier without API or portal can be ordered via mailto: with a fully-populated body. The PO is also saved to the orders table so receiving and reconciliation still work.

Predictive Ordering

The get_pour_forecast RPC predicts how many ounces of a given bottle will be poured in the next N days. Formula:

daily_avg = mean(pos_pours_oz over last 30 days)
dow_mult  = day_of_week_multiplier  // e.g. Friday=1.42, Tuesday=0.78
forecast  = daily_avg × dow_mult × forecast_days

Day-of-week multipliers are computed from the bar's own history — every bar has a different Friday-vs-Tuesday ratio, so we don't use industry averages.

Auto-reorder Draft

For any bottle below par, the system drafts a reorder quantity:

shortfall_oz = par_oz − live_oz + forecast_oz(7 days)
qty_bottles  = ceil(shortfall_oz / size_oz)

The draft is grouped by supplier, totals are computed, and the user reviews & approves before send. No order goes out without explicit confirmation.

08Receiving & Invoice OCR

Snap the invoice that came on the truck. The system OCRs it, matches lines against the open PO, lets you adjust discrepancies, and confirms in one tap.

The Receive Flow

  1. Open the PO on the receiving screen.
  2. Tap "Snap Invoice" — the camera opens.
  3. Photo is uploaded; OCR runs server-side.
  4. OCR'd lines are matched against PO lines using a fuzzy scorer.
  5. Each line shows expected qty / received qty / discrepancy badge.
  6. Operator adjusts any flagged line, taps Confirm.
  7. PO row updates, live inventory recomputes immediately.

Discrepancy Types

TypeWhat it means
qty_shortTruck delivered fewer than ordered. Backorder credit owed.
qty_overTruck delivered more than ordered. Operator decides accept or refuse.
price_changedInvoice price differs from PO price by more than $0.50/unit.
substitutedDifferent SKU shipped (e.g. 1.0L instead of 750mL).
missingPO line doesn't appear on the invoice at all.

How Matching Works

OCR text is folded (diacritics removed, lowercased) and tokenized. Each invoice line scores against each PO line on:

  • Brand-token overlap — common tokens between names (e.g. "patron" + "silver" both present)
  • Size match — 750mL = 750mL is high-value, 1.0L vs 750mL is a flag
  • Price proximity — within ±10% scores well, beyond that flags price_changed

The composite score must clear 0.55 for an auto-match. Below that, the line surfaces as "needs operator review" with the top three candidates ranked.

What Gets Written on Confirm

For each line: received_qty, received_total_cost. For the order: status='received', received_at timestamp. Live inventory recomputes the moment confirm is tapped — no batch job, no nightly reconcile.

09Chat Agent

Ask questions in plain English. The agent grounds every answer in real data via 9 tools — never invents.

The 9 Tools

ToolPurpose
get_inventory_statusLive oz, par status, bottles-on-hand for one bottle or the whole library.
get_variance_reportTonight's or any date's variance, ranked by dollars or volume.
get_anomaly_flagsBottles currently flagged with z ≥ 2, severity-banded.
get_bartender_attributionPro-rata variance by bartender for a date range.
get_pour_forecastPredicted ounces poured for next N days, by bottle.
get_recipeFull recipe with ingredients, glass, technique, pour cost, margin.
get_supplier_ordersOpen / received / cancelled POs by supplier or date.
draft_reorderCompute auto-reorder quantities for bottles under par. Returns a draft, never sends.
export_chat_summarySave the current conversation as a report row for sharing.

Multi-turn Grounding

The agent keeps the last 8 turns of context. If you ask "why is Patrón flagged?" then "what about the night before?", the second question inherits the bottle context. Every numerical claim cites the tool that produced it. If a tool returns no data, the agent says so — it doesn't fill gaps with plausible-sounding numbers.

Cost

~$0.01 per question on average. A typical conversation runs 3-5 questions and costs under $0.05. The cost ceiling is enforced server-side; runaway loops get cut off at $0.25.

Sample Questions

  • "Which bottles are below par right now?"
  • "Why is Patrón Silver flagged tonight?"
  • "How much tequila will we need for the next 7 days?"
  • "Show me the margin on our top 5 cocktails."
  • "Draft a reorder for Southern Glazer's."
  • "What was last Friday's variance?"

What It Can't Do

Honest limits, posted up front:

  • It will not place an order, void a count, or modify inventory without an explicit confirmation tap from a human.
  • It only knows what its 9 tools expose — it can't read scheduling, payroll, or POS settings beyond pours.
  • It does not predict theft. It surfaces variance and anomaly. The interpretation is the manager's job.

10Reports

Three report types. One auto-fires every close. One is on-demand. One is generated when chat surfaces something report-worthy.

Shift-Close Report (Auto)

Generated automatically the moment a close-count session lands. Payload includes: total variance ($ and oz), flagged bottle count, anomaly count, top 5 variance bottles, bartender attribution, total pours, total revenue from those pours. A short prose summary is generated alongside the structured payload so the report can be shared as text.

Daily Brief (Manual)

Chat-agent-generated executive summary spanning the trailing 24 hours. Fired manually with the "Daily Brief" button on the Reports tab — useful for sending to ownership before the morning meeting. Pulls from the same 9 tools the chat agent uses.

Chat Export

When a chat conversation surfaces something report-worthy ("here's why three bottles are flagged tonight" with the supporting data), tap Export. The conversation is saved to the reports table with full message history and any tool outputs cited.

Where Reports Surface

  • In-app Reports tab — full history, searchable.
  • Manager Dashboard widget — most recent 5 reports, with one-tap drill-in.

11Alerts

Two channels. Three auto-fire conditions. One rate limit so the system never spams.

Channels

  • In-app — toast notifications + alerts panel badge.
  • Slack — webhook, posts a structured block with the variance amount, bottle name, and a link back to the app.

Auto-fire Conditions

TriggerWhat fires
Bottle drops below 50% of par (CRITICAL)Order-soon alert, in-app + Slack.
Anomaly z-score ≥ 3.0Critical-anomaly alert, in-app + Slack.
Order successfully sent to supplierConfirmation alert, in-app only.

Rate Limit

30 minutes per (kind, bottle_id). If Patrón Silver fires a critical anomaly at 8:14pm, another anomaly on Patrón Silver won't fire until 8:44pm — even if it's still flagged. This stops a single misbehaving bottle from spamming an entire shift.

Slack Setup

Set the SLACK_WEBHOOK_LIQUOR environment variable on the edge functions to a Slack incoming-webhook URL. No further config needed — the system auto-detects the variable and starts posting. Unset the variable to disable.

12Manager Dashboard Widget

Where ownership and managers consume CP Liquor without opening the bar app.

Where

admin.conciergepilot.coOperationsFulfillmentLiquor Inventory

Stat Strip

Four large numbers at the top:

  • Tonight's variance — running total in dollars
  • Flagged — count of bottles currently flagged (variance + anomaly)
  • Below Par — count of bottles in LOW or CRITICAL
  • Open Orders — count of POs in sent or partial status

Recent Reports List

The five most recent reports — auto shift closes, daily briefs, chat exports — with timestamp, type, and one-line summary. Tap any row to read the full report.

Top Variance Bottles

The five bottles with the highest dollar variance over the last 7 days, ranked descending. Each row links to the bottle detail in the live app.

Live App Link

One-tap deep link to the running bar app, which opens to the same view the bartender sees.

13Database & Edge Functions

For developers and integrators. Reference list of every table, edge function, and RPC.

Tables

TablePurpose
liquor_bottlesThe library. One row per SKU. Includes calibration JSONB.
liquor_countsOne row per bottle per count event. Method, oz, confidence, photo URL.
liquor_sessionsOpen/close brackets. One row per shift.
liquor_pos_poursEvery pour event from the POS. Bottle, oz, bartender, timestamp.
liquor_varianceComputed at session close. One row per bottle per session.
liquor_anomaly_flagsZ-score detections. Severity, baseline, current value.
liquor_recipes30 cocktails seeded. Plus per-tenant additions.
liquor_recipe_ingredientsRecipe-to-bottle joins, oz per ingredient.
liquor_suppliersDirectory of distributors with dispatch config.
liquor_ordersPOs with status (draft / sent / partial / received).
liquor_order_linesPer-line qty, price, received_qty.
liquor_reportsAuto + manual + chat-export reports. Full payload as JSONB.
liquor_alertsAlert event log with channel, kind, fired_at.

Edge Functions

FunctionPurpose
cp-liquor-vision-countVision model wrapper. Single-photo + shelf-scan + multi-photo merge.
cp-liquor-video-framesExtract 6 frames from video, run vision in parallel, merge.
cp-liquor-close-sessionCompute variance + anomaly, write report, fire alerts.
cp-liquor-place-orderDispatch PO via supplier's configured method.
cp-liquor-receive-invoiceOCR an invoice photo, match to PO, return discrepancies.
cp-liquor-chatChat agent with 9 tools, multi-turn context.
cp-liquor-daily-briefGenerate the on-demand daily executive summary.
cp-liquor-alert-dispatchSend to in-app + Slack with rate-limit logic.

RPCs

RPCPurpose
get_live_inventoryReturn current live_oz + par_status for all bottles.
get_pour_forecast30-day rolling avg × day-of-week multiplier.
compute_varianceVariance + z-score for a session. Idempotent.
get_bartender_attributionPro-rata variance by bartender for a date range.
draft_reorderQuantity math for bottles under par.

Calibration JSONB Shape

{
  "reference_photo_url": "https://...",
  "empty_weight_g": 530,
  "full_weight_g":  1410,
  "position_xy":    [0.42, 0.18],
  "trained":        true,
  "training_count": 7
}

14Glossary

One-line definitions, alphabetical.

TermDefinition
AnomalyA bottle whose tonight's variance is ≥ 2 standard deviations from its 30-day mean.
Bottles-on-handDisplay format: full bottles + remaining ounces. e.g. "2 full + 14oz".
CalibrationPer-bottle profile of reference photo, weights, position, training status.
Close countEnd-of-shift count that triggers variance compute and shift report.
Confidence score0-1 value attached to every count row indicating measurement reliability.
Dispatch methodHow a PO is sent: EDI / email / webhook / portal / mailto.
EDI 850X12 electronic purchase order standard accepted by major distributors.
FlaggedA bottle hit either a variance threshold or an anomaly z-score.
Live ozlast_count.total_oz minus POS pours since that count.
Margin %(retail − cost) / retail × 100.
Open countStart-of-shift count establishing the baseline for variance.
Par levelTarget ounces on hand for a bottle. Below 50% triggers CRITICAL.
Position memoryStored (x,y) of a bottle on the shelf-scan frame, used for occluded matches.
Pour costSum of ingredient ounces times bottle cost per ounce.
POS poursPour events written by the POS, attributed to bottles via recipe ingredients.
Reference photoClean front-shot of a bottle at full pour, used as the visual anchor for fill.
Shift reportAuto-generated end-of-shift summary fired the moment close-count completes.
VarianceGap between expected ounces (open − pours) and actual ounces (close).
Z-scoreStandardized measure of how far a value is from its baseline mean.

15Quick-start Workflows

Three step-by-step recipes for the things you'll do in the first week.

First-time Setup

  1. Add bottles. Open the bottle library, tap Add. Enter name, size (e.g. 750mL), category, retail price. Repeat for every bottle on the wall — for the live demo we seeded 12 to start.
  2. Set par levels. For each bottle, tap the par field and enter target ounces on hand. A reasonable starting point: 1.5 × your typical weekly pour volume.
  3. First open count. Open a session, run a shelf scan or manual entry, save. This becomes the baseline.
  4. Calibrate references. For each bottle, snap a clean front-shot at full pour and tap "Set as reference." This is the visual anchor the model uses on every future scan.

Nightly Close Routine

  1. Open the app at end of shift.
  2. Tap Close Session.
  3. Run a shelf scan (fastest), video walk-by, or multi-photo capture.
  4. Review the auto-merged counts. Re-shoot any low-confidence bottle.
  5. Save. The session closes, variance computes, and the shift-close report fires automatically.
  6. Skim the report. Anything flagged in red is worth a 30-second look before you walk out.

Investigating a Flagged Bottle

  1. Tap the flagged bottle on the home screen.
  2. Open chat. Ask: "Why is X flagged tonight?"
  3. Review the pour timeline the agent surfaces — look for clusters by hour.
  4. Open the bartender heatmap on the variance card. Note who poured the most from this bottle.
  5. Cross-check: does this bottle's recipe pour spec still match what the bar is actually pouring?
  6. Two outcomes: (a) update the recipe pour spec to match house custom, which collapses the variance, or (b) schedule a brief with the high-share bartender on next shift.
One last thing. Variance is information, not accusation. Most flagged bottles trace back to a recipe drift the bar has been doing for months — easy fix, no awkward conversation required. The 5% that don't are why this system pays for itself.