# Mise Engineering Starter Brief

**For:** Edith · **From:** Vash · **Date:** July 2026
**Companion docs:** `cheftec-legacy-report.pdf` (what to port, plain English), `mise-cheftec-overlap-report.pdf` (decision briefing), `LEGACY_AUDIT_REPORT.md` (schemas/formulas, in the eng repo), `Mise-Wireframe.pdf` (the UX the engine serves)

---

## The one-paragraph mission

You're building the deterministic core of Mise: the costing engine and the data
pipeline that feeds it. Every feature anyone ideates — the camera, the chat, prep
lists, dashboards, voice — sits on top of what you're building and consumes its
output. The engine's credibility test is objective: recompute recipes from a real
customer's legacy database and match ChefTec's own cached answers. Until that diff
is clean, no number we show a chef is trustworthy.

**Two rules that override everything else:**
1. **Money math never comes from a model.** LLMs sit at the edges (reading photos
   in, phrasing sentences out). Every dollar figure is produced by a deterministic,
   unit-tested function.
2. **The engine never returns a bare number.** Every result carries its assumption
   ledger (below). That ledger is simultaneously the API response, the UI's data
   source, and the agent's vocabulary — it's the contract between your work and
   everything still being scoped. Emit it natively from the first commit.

---

## Build order

### Phase 1 — Skeleton (no blockers, start today)
- Django + Postgres + pytest + CI.
- Tenancy spine from day one: `Org → Location`, every domain row tenant-scoped.
  The shared reference corpus is a system-owned tenant, not a special case.
- No auth flows, no React, no deploy polish. Done = tests run in CI.

### Phase 2 — Port the costing chain (fixture: the sample dump)
Port in dependency order, from the audit's table. The legacy source files are the
spec; the audit report maps them.

| # | What | Legacy source |
|---|------|---------------|
| 1 | Units + conversions (universal, item-specific, vendor-specific) | `ConvUnit`, `CTItems.pas` |
| 2 | Ingredient catalog + yield factors (with provenance field) | `Inv`, `UsFacts` |
| 3 | Purchase-history facts | `Trans`, `CTTrans.pas` |
| 4 | `get_unit_cost(ingredient, unit, method, date_window, scope)` | `TInvItem.GetUnitCost` |
| 5 | Recipe costing: recursion, sub-recipes, Q-factors, labor, per-portion | `CalcRecipeCost`, `CTRecipes.pas` |
| 6 | Margin / food-cost / target-price math; batch scaling as a non-destructive view | `FoodCosts.pas`, `SalesCalc.pas`, `ResizeRecp.pas` |

Port the legacy query filters **verbatim** — cost column is line total (unit price
= cost ÷ qty), exclude zero-qty/zero-cost rows, honor ignore-for-costing flags.
Getting this wrong corrupts every derived price (audit Risk 4).

Fixture: `Pricing.txt` + `Conversions.txt` (one real site, 954 priced items,
8,211-item catalog, already profiled — includes real mess: 526 zero-qty rows,
87 unit strings, entry-error outliers like $0.70 vs $50.94 same-unit).

Done = every formula has a spec test; the dump costs synthetic recipes end-to-end.

### Phase 3 — The translator + diff harness (blocked on: .bak files from Mitch)
- Importer for a raw legacy DB → staging, tagged by site/location. **Idempotent:
  re-importing the same site must not duplicate anything** (this same importer is
  the pilot-client onboarding path AND the future corpus-refresh path).
- Diff harness: recompute every recipe in the customer DB with the new engine,
  diff against legacy cached costs (`RecpCost`), output a categorized mismatch
  report (missing conversion / unmatched sub-recipe / excluded rows / real bug).
- First day the customer DB lands: run the cost-method distribution query —
  which of the 13 legacy pricing methods are actually used — so we port ~3 for
  real and stub the rest.
- Sequencing rule: the diff runs against legacy data **as-is** (1.0 yields,
  per-batch labor). It verifies the engine, not the data. Yield seeding is a
  separate, later data layer.

Done = clean diff (or every mismatch category explained), mismatch report doubles
as the data-cleanup worklist.

### Phase 4 — Extraction spike (timeboxed, 2–3 days, anytime)
Photo → structured recipe lines (JSON: qty, unit, ingredient text, prep note) on
~10 real recipe photos (Vash supplies from Jeff's kitchens). Measure line-level
accuracy. This is a de-risking spike, not the capture build — its output shapes
the Verify screen design, so results go to Vash, not into main.

---

## The assumption ledger (draft contract — finalize in kickoff session)

Every costing call returns `{ cost, ledger: [entries] }`. Draft entry shape:

```json
{
  "line_id": "…",
  "raw_text": "2 shallots, minced",
  "type": "assumption | error",
  "variance_source": "identity | price | quantity_interpretation | yield",
  "resolved": {"item_id": "…", "value": "medium ~30g", "provenance": "kitchen_memory | profile_prior | corpus_default | seeded_reference | chef_confirmed"},
  "candidates": [
    {"label": "Medium ~30g", "plate_cost_delta": 0.00},
    {"label": "Large ~50g",  "plate_cost_delta": 0.14},
    {"label": "by weight",   "plate_cost_delta": null}
  ],
  "price_scope": "tenant | corpus_nearby | corpus_wide",
  "error_code": null
}
```

Design notes:
- Legacy error codes ("no purchase found", "missing conversion", "no unit") become
  `type: "error"` entries — same structure, `candidates` empty, `error_code` set.
- `plate_cost_delta` is what powers ask/don't-ask: the question layer (not yours)
  ranks entries by dollar swing and applies a friction budget.
- `provenance` + `price_scope` are load-bearing: the UI renders "market estimate"
  vs "your price" from them, and the %-confirmed metric is derived from them.

## Price resolution ladder (policy for `get_unit_cost` scope)

1. Tenant's own purchase history
2. Tenant's confirmed answers (ask-once memory)
3. Corpus (recency-filtered; vicinity/segment filters come later; return a range,
   not a point)
4. Nothing → emit an `error` ledger entry ("no price on file") — the product asks
   the chef; the answer writes into layer 2 forever

Aggregate-first is product policy: corpus answers are the default experience;
tenant data upgrades them. Architecturally it's just the `scope` parameter — build
the ladder, let product tune the policy.

---

## Tool contract sheet (v1 — the agent's hands)

| Tool | Type | Phase |
|------|------|-------|
| `extract_recipe(image) → draft lines` | LLM | 4 (spike), build later |
| `match_ingredient(text) → candidates+scores` | deterministic + LLM fallback | 2–3 |
| `get_unit_cost(item, unit, method, window, scope)` | deterministic | 2 |
| `cost_recipe(recipe, mode=diagnostic|final) → cost+ledger` | deterministic | 2 |
| `generate_questions(ledger, budget) → top-N` | deterministic policy | after 2 |
| `save_answer(tenant, entry, answer)` | deterministic | 2–3 |
| `simulate_batch(recipe, portions)` | deterministic (view, never mutates) | 2 |
| `margin_report(book) → per-dish margins, at-risk` | deterministic | 2 |
| `corpus_price_lookup(item, geo, window) → range` | deterministic | 3 |
| `explain_line(ledger_entry) → phrasing` | LLM | later |

Rule for every tool: **it must be useful without the agent** — callable directly
from the React app. If a capability only makes sense "inside the agent," it's not
a tool, it's vapor.

---

## Explicitly NOT in scope now
React screens · full capture pipeline · question phrasing/Ask Mise · kitchen
profiles/onboarding · alerts · POS/EDI integrations · prep lists/inventory/
ordering · voice · multi-agent framework of any kind. (Most of these are NEXT/
LATER by roadmap; the rest are Vash's scoping lane. The ledger contract is what
makes it safe for those to churn while you build.)

## What you're owed (blockers, with owners)
- **.bak of internal CSS ChefTec + one customer DB** — Mike/Mitch (asked; chase if >1 week)
- **`LEGACY_AUDIT_REPORT.md` + Delphi source access** — Mitch (you'll want
  `CTItems.pas` / `CTRecipes.pas` / `CTTrans.pas` open while porting, not summaries)
- **Ledger-schema kickoff session (90 min)** — Vash, this week, before Phase 2 starts
- **10 real recipe photos for the spike** — Vash via Jeff

## Definition of done, overall
1. Diff harness clean against one real customer DB.
2. Every tool in the sheet's deterministic rows implemented, spec-tested, exposed
   as an internal API endpoint.
3. Ledger emitted on every costing call, validated against the agreed schema.
4. Importer re-runnable end-to-end (import → cost → diff) in one command.
