Skip to content

Aurora Material Solutions — Order Management & Routing Requirements

Source: two meetings with Robert Walter (Supply Chain lead, champion) — “OrderMatic Demo - Robert Walter” (2026-06-08) and “Ordermatic - Demo (Streetsboro)” (Granola calendar slot 2026-07-16; call already held) — plus the full transcript of the second call. Companion: data-engineering/customers/aurora/README.md · data-engineering/POC-PLAYBOOK.md

[!NOTE] Closed by multi-connection routing This requirements document has been superseded and closed by the general multi-connection ERP routing architecture (Multi-Connection Organizations).

The one-sentence thesis (Robert, verbatim)

Section titled “The one-sentence thesis (Robert, verbatim)”

“Order entry isn’t our number one problem… really, it’s creating that nucleus that all my orders can go to. And then from the nucleus, it says, well, it goes here, here, here and here. They don’t have to input it. This is the one with the problem — so check that one out.”

Order entry automation is table stakes for him; order landing and routing is the buy decision. Every other prospect pitch leads with extraction — for Aurora, lead with the nucleus.

Progress audit — corrections (2026-07-22)

Section titled “Progress audit — corrections (2026-07-22)”

A 31-agent audit of origin/staging (HEAD 0b3dcfbb3, 87 commits since this plan merged as 67b299f99), every finding adversarially verified. Bottom line: 0 of the 17 demo tasks and 0 of the 3 named engineering gaps have been built — every ❌ row in “The real gap” is still exactly true. But the audit corrected two stale claims the plan made on day one, and found four adjacent landings that change the build. Details below; the corrections are folded into the sections they touch.

Corrections to this plan (each fixed in place):

  • A — P1 #7 (price/tier flag) already shipped before this plan. The whole loop is live: tier-mismatch flag + one-click adopt (apps/webapp/src/utils/price-tier-review.ts, 2026-05-24) and doc-price-wins (persist-auto-priced-matches.ts, 2026-07-02 — the decision this plan cites as if it were only a decision). The Venna-correction story needs zero build. See “What already exists”.
  • B — the cross-connection gap row named the wrong table. Connection binds on pdf_documents, not extracted_orders (effective connection resolved at read time via coalesce(emailAliases.erpConnectionId, pdfDocuments.erpConnectionId)). The binding claim holds; the fix is cheaper than the plan implies — a transfer is an UPDATE of an existing column, not a new one. Row corrected in “The real gap”.
  • D — the UOM gate has no KG. It exists but WEIGHT_UOMS = new Set(['pound']) and UOM_SYNONYMS has no kg, so the Ipex KG line abstains to review rather than converting (also double-gated: live only for Cleveland Kitchen). Zero-code fix: seed GPP3003C-3634 AQUA with purchaseUnitOfMeasure='kg' + a conversion factor. Abstaining is itself a fine exception-first demo beat. README corrected.
  • E — four task Files: pointers said scripts/poc-core-and-main/ — editing there would mutate the LIVE Core & Main build. Repointed to scripts/poc-aurora/ (the copy is now task T0).
  • F — P2 #12 (single orders@aurora) got cheaper: delegated shared-mailbox polling landed 2026-07-15 (#2322/#2333); the plan’s “✅ multiple mailboxes” referred only to personal inboxes.
  • G/H/J — informational: open-question #2’s extraction-time-enrichment half is now built and flag-gated (not hypothetical); a rival “zero-code” routing vehicle exists (per-connection extraction-schema extension fields, LIVE, no flag — can surface a “destination site” field on review-v2); and the ck_poc_enhanced_review drag cite should be DocumentOrderReview.tsx, not review.astro:438 (that line is erpVerificationStatus:). Captured where relevant below.

What landed on staging that changes the build:

What Why it matters Live for Aurora?
Approval-only “Finished” CTA (mark-approved.ts, e631724db) Biggest enabler — Aurora has no ERP connection, so without it the review loop dead-ends at an unfireable Submit INERT + UNREGISTERED — flag review_approval_only_mode is absent from Flagsmith; must be created by hand
Ship-to persisted + type-classified (extracted_orders.extracted_addresses, 0103) The plan’s #1 routing signal became a queryable field with mismatch detection in review-v2 INERT — extraction_classified_addresses_v1 off, CK-only
Per-connection extraction-schema extension fields (259b892d2) No-code way to put a “destination site” field on the review page — the rival demo mechanic (H) LIVE, no flag
Delegated shared-mailbox polling (#2322/#2333) The orders@aurora nucleus shape (F) only became supported 2026-07-15 LIVE
Demo tooling (8a53a60ba): sweep_auto_validate.py, xref learner, session mint, tour recorder The plan’s blocking rehearsal gate is now a runnable script; xref learner fits the flywheel finale LIVE, reusable — grows the poc-aurora copy surface by 4 files

Two land mines the plan cannot know about:

  • suppressNameBucket lever (#2309, typesense-search-service.ts) deletes the exact name bucket codeless lines bind through, with abstention made terminal. Defaults OFF, but lives under the same matchingConfig key — copy-pasting a Core & Main config into Aurora silently kills the verbal-order beat. Added as a negative check to the rehearsal gate.
  • pricing_source_price_authoritative_v1 defaults disagree across runtimes: false in the TS worker (persist-auto-priced-matches.ts), true in the Python worker (agentic_validation.py). On a Flagsmith blip mid-demo the two paths disagree about who owns the price. Pin it ON for the Aurora connection — added to the gate.

Operating reality (constraints the features must respect)

Section titled “Operating reality (constraints the features must respect)”
Fact Detail Implication
11 sites, ~9–10 ERP instances 7× Microsoft Great Plains (each instance a separate ERP), 2× IQMS (“IQ Mess”), Business Central mentioned in call 1 Routing target is (site, ERP instance, CSR), not a warehouse picker inside one ERP
Regional CSR teams Ohio, Texas, North Carolina, Massachusetts, Quebec — 13 CSRs total, each tied to specific reps/customers, personal siloed inboxes Assignment model must encode CSR↔customer/rep affinity, not round-robin
CSR time budget 30 min–2 hr/day order entry (~20 orders/day); 2+ hr/day order movement (~50+ orders/day); 3–4 hr general management Movement > entry. Cross-site transfer is a first-class flow, not an edge case
Customer burden “We have customers that order from all 11 sites. They got to send POs to all 11 people.” (his Amazon analogy) Single intake address is part of the value prop — but see security constraint
Pricing Venna financial modeling tool is pricing source of truth; frequent changes, upload-to-ERP delays; CSRs spend real time validating/correcting; security sensitivity around price exposure Price flagging (doc-price-wins + tier-price flag, per 2026-07-02 precedence decision) fits; Venna API integration is a later seam
Security posture Mutual NDA (done — ours worked, Connecteam’s didn’t); no customer-facing portals; internal-only access acceptable; on-prem everything No portal features in the pitch; intake stays email-based
IT capacity 10-person team, stretched by acquisition integrations; sandbox access unlikely near-term Offline POC first; semi-online only if their IT lead volunteers it; 6+ month full-implementation expectation is already set
Management/PE lens Robert does network forecasting himself; PE sponsor wants rest-of-year visibility; biggest month ever but forecast dips Org-level volume/status reporting is a champion-level (not CSR-level) feature
Trust arc 90-day learning period, manual validation → exception-based; CSRs “will pick it apart,” which Robert wants Demo must show the review/correction flow prominently, not hide it

P0 — the nucleus (what the POC must demonstrate)

Section titled “P0 — the nucleus (what the POC must demonstrate)”
  1. Single landing zone for all inbound orders. Every PO — any site, any customer, any channel (structured PDF, email-thread PO, verbal confirm) — lands in one shared inbox with org-wide visibility. Product today: review-v2 inbox already does this per org. ✅
  2. Site/ERP routing decision per order. The system reads the order and proposes the destination: which site → which ERP instance → which CSR. Robert’s words: “how it looks at the order and deciphers what’s important… what are the inputs, the rules, and then how does it distribute.” Routing signals visible in the 10 sample POs: vendor entity on the doc (S&E Lunenburg vs. Aurora Streetsboro), ship-to/plant address, customer identity, item-number families. Product today: ⚠️ gap — see “The real gap” below. Short version: multi-mailbox/multi-alias intake already exists and the app layer is multi-connection aware; the DB allows only one active ERP connection per org, and there is no content-based routing step or cross-connection order movement.
  3. Site-scoped queues with one-click confirm/re-route. “This is Ohio, you click on it… yep good, good, good — or no, this one goes to North Carolina.” Confirm-or- override per order, with the override being a routing correction the system learns from (same flywheel shape as xref writeback). Product today: partial — kanban + assignment exist; site tabs and route-override-as-training-signal do not.
  4. Exception-first surfacing. Clean orders route silently; problems (price mismatch, unknown item, ambiguous site) surface for review. Product today: ✅ core product — abstention/review queue is the pitch (playbook Phase 6).
  5. Supervisor visibility + reassignment. Org-level and per-CSR inbox views, workload distribution, reassignment. Resonated in demo 1. Product today: ✅ supervisor dashboard.

P1 — makes it stick (post-POC / early implementation)

Section titled “P1 — makes it stick (post-POC / early implementation)”
  1. Cross-site order movement. 50+ orders/day get moved, 2+ hrs/CSR/day — the single biggest time sink. Moving an order = re-route to another site’s ERP + notify the other site’s CSR. Product today: ⚠️ partial — PR #2652 makes a split routable (quote_splits.target_connection_id), but a non-split order is still bound to one connection for life. The proposed shape for that half — facilities in the item search, local results ranked first, remote facilities surfaced only when there is no local option, and the pick itself being the routing decision — is noted in facility-aware item routing (design note only, nothing built).
  2. Price validation flag against the tier/list price. ✅ ALREADY SHIPPED (pre-plan — see correction A). Doc price stays authoritative (doc-price-wins is live in persist-auto-priced-matches.ts, 2026-07-02), tier mismatch = non-blocking flag + one-click adopt (price-tier-review.ts + CockpitDetail.tsx, 2026-05-24). Maps directly onto CSRs’ Venna-correction time — zero build. Venna API pull is the later real-time seam Robert floated.
  3. CSR↔customer affinity in assignment. Each CSR owns specific reps/customers; default assignee should follow that mapping (per-connection/org config), with supervisor override.
  4. Learning/flywheel narrative. 90-day manual-validation → exception-based automation arc, stated up front — Robert already accepted this framing; Angel (CSR manager) is the skeptic to win (“she’s been doing things a certain way for a long time — this probably scares her”).

P2 — roadmap gestures (name them, don’t build them)

Section titled “P2 — roadmap gestures (name them, don’t build them)”
  1. IQMS coverage. “Not as concerned about the IQMS ones today. But if we could do an all-encompassing thing, that would be great.” Pitch GP-first, IQMS on roadmap.
  2. Network-level volume/forecast reporting. Order volume by site/customer/product family, rest-of-year run-rate — the artifact Robert hand-builds for the CEO/PE sponsor today. A champion-retention feature, not a CSR feature.
  3. Single customer-facing intake address (orders@aurora…): solves “send POs to 11 people” — but keep it as email alias intake, never a portal (security posture).

The real gap (verified against schema + app code, 2026-07-12)

Section titled “The real gap (verified against schema + app code, 2026-07-12)”

Claim to check: “we’d need multiple email syncs per org AND multiple ERP connections per org.” Half of that already exists:

Layer State Evidence
Multiple synced mailboxes per org ✅ already supported email_pull_connections is unique on (email, provider, org) — an org can poll many mailboxes (packages/db/src/schema/email-pull-connections.ts:80-83)
Multiple intake aliases per org ✅ already supported, connection-aware email_aliases is unique on (subaddress, org); aliasType includes branch with a branchLabel (“West Coast”-style), and every alias carries a NOT NULL erpConnectionId — per-site alias → per-site connection routing is already modeled (email-aliases.ts:14,35-43,61-64)
App-layer connection resolution ✅ already multi-connection aware getOrganizationERPConnections is a findMany; getOrgScopedConnectionOrDefault explicitly documents multi-connection orgs (apps/webapp/src/utils/erp-connections.ts)
Multiple active ERP connections per org ❌ the hard blocker erp_connections_active_org_unique partial unique index on (org) where active=true (packages/db/src/schema/erp-connections.ts:290-292) — the schema forbids what the alias table and app helpers are already built for
Content-based routing ❌ missing Alias-based routing (site alias → site connection) exists structurally; deciding the site from the document when everything arrives at one shared nucleus address does not
Cross-connection order movement ❌ missing Binds on pdf_documents.erpConnectionId at intake, for life (NOT extracted_orders — corr. B); effective connection resolved at read via coalesce(emailAliases.erpConnectionId, pdfDocuments.erpConnectionId). Movement is refused in UI (SupervisorKanban.tsx:316,506). Fix = UPDATE existing column, not a new one

So the productization work, in order: (1) relax the active-connection index (audit the ~10 modules that call the connection resolvers for one-active assumptions — Dagster sync, billing, and intake assignment especially), (2) add a routing step that picks the connection at intake (rules on extracted fields first — ship-to, vendor entity, customer — LLM fallback for ambiguity, abstain to review), (3) order transfer across connections. None of this blocks the POC — see below.

Zero-ask POC plan (simulate everything; nothing more from Robert)

Section titled “Zero-ask POC plan (simulate everything; nothing more from Robert)”

Decision 2026-07-12: don’t send a data-request list. Robert’s procurement is slow, his time is the scarce resource, and the sale is the routing story — which we can stage from what we already hold. Everything below uses only the 10 POs + public data.

Need Zero-ask source
Site list Public facilities page (scraped 2026-07-12): Streetsboro OH (HQ/tech/production), Welcome NC, Marieville QC, Lunenburg MA, Pasadena TX, Evansville IN ×2, Louisville KY (Lastique). 8 public sites vs. Robert’s “11” — present as best-known demo assumptions; corrections are captured only if challenged (live map-correction is a recovery move, not a stage trick — see Demo risk controls)
ERP-per-site map Simulate: label GP-1…GP-7 / IQMS×2 across the sites; presented as assumptions, corrected if challenged
Routing rules Derive from the docs themselves: vendor entity (S&E Lunenburg vs. Aurora Streetsboro on real POs), ship-to state, customer identity, product family (wire & cable compounds → Lunenburg; profiles/siding → Streetsboro)
CSR roster Simulate 13 CSRs across the 5 regional teams he named (Ohio/Texas/NC/MA/Quebec). Demo mechanic: site = assignee. Create per-site demo CSR users and route via auto-assignment — the existing supervisor dashboard + per-CSR inboxes then ARE the site queues, and reassignment IS cross-site movement. Zero product changes
Item master Synthesize: seed with the ~15 real item codes on the POs (GTPE211010, CR-105/50.2071.CR105AP, GPP3003C-3634 AQUA, 18042-70A, AP3249CJWH3081, AP3249EWBK3003, AP3444FNT1000, I-AP1426AWH1037, G-3469SL 405, GTPE 2011108 406BK, WCP-LI/GA7056FR, Honeywell 416…), expand to a few hundred plausible SKUs following their real nomenclature + the public Product Finder / brand families (AuroraFlex, AuroraGuard, AuroraTec…). Say it’s simulated — “with one item-master export this runs on your full catalog” becomes the post-wow ask Robert volunteers, not homework we assigned
Cross-references The POs contain real buyer↔Aurora part pairs printed side-by-side (Lake Cable C20084-AP→GTPE211010, Encore 50.2071.CR105AP→CR-105, ACT WCP-LI→GA7056FR, Ipex 20000018→GPP3003C-3634). Seed manual_cross_references from these — the learned-mapping flywheel demos on real pairs, no ask
Exceptions Already in the doc set: hand-annotated wrong item # (BPS email thread), 405BK/406BK digit discrepancy (TriCab), verbal order with no qty/price/item (VinylOne), $0.00-grand-total trap (MI Profiles), two revisions (Vytron Rev 3, ACT “revised”)
Labeled pairs / match rate Skip the quoted-lift number entirely (playbook honesty creed — no held-out pairs, no benchmark claim). Demo the flow, not a statistic

Open product questions (for eng, before contract)

Section titled “Open product questions (for eng, before contract)”
  1. Multi-connection orgs: relax erp_connections_active_org_unique to (org, site)-scoped, or model sites as child entities of one connection? GP-per-site means real per-site credentials/endpoints either way.
  2. Where does the routing decision live — extraction-time enrichment (LLM proposes site from doc signals) vs. rules engine on extracted fields vs. both (rules first, LLM fallback)?
  3. Order transfer semantics: re-parent extracted_orders across connections vs. duplicate + tombstone? Audit trail matters to a supervisor.
  4. GP write path: eConnect/Web Services vs. file-drop integration — on-prem tunneling per site; IQMS entirely unscoped.
  5. Alias-first phasing (v1 before content-based routing): one public nucleus address for customers + internal per-site branch aliases (email_aliases.aliasType='branch', already modeled) fanning out to per-site connections. Ships “send POs to one place” months before LLM routing exists and reduces the blocker set to the unique index alone. Content-based routing becomes the v2 differentiator, not the entry ticket.
  6. Routing-rules substrate: inbox_routing_rules already exists (org-scoped trigger→action engine with jsonb configs + priority, today used for no-action-timeout → reassign, packages/db/src/schema/inbox-routing-rules.ts). Content/site routing should extend this table (new trigger type on extracted fields), not introduce a parallel rules concept.
  7. Routing authority & governance (flagged by outside voice): who may move an order across sites, what audit trail finance needs, duplicate/revised-PO handling across sites, and which ERP is source of truth during a transfer. Answer before building cross-connection movement.

Competitive positioning (added by review, 2026-07-12)

Section titled “Competitive positioning (added by review, 2026-07-12)”

The real field is NOT Connecteam (workforce management — category error). It is: Conexiom (the incumbent Robert evaluated — “the big boy”; mature multi-ERP connectors), Esker (enterprise order-to-cash), Workist, plus the non-vendor alternatives: Microsoft-ecosystem work during a BC migration (Copilot order entry), an SI with Power Automate building a “good-enough nucleus,” and do-nothing-until- acquisitions-settle. Defensible claims none of them demo: (1) the learning flywheel — route-override- and confirmation-as-training-signal; (2) abstention/exception-first review; (3) the cross-ERP order-transfer network. Prepared objections: “why not wait for the BC migration?” → the nucleus is the migration-proof order layer — order intake stays stable while the PE sponsor consolidates ERPs underneath it (7× GP is end-of-life; consolidation is a when, not an if — turn it into the wedge).

Deal economics & close (added by review, 2026-07-12)

Section titled “Deal economics & close (added by review, 2026-07-12)”
  • ROI math to lead with: 13 CSRs × (2+ hr/day movement + 0.5–2 hr/day entry) ≈ 40–50 CSR-hours/day ≈ 5–6 FTEs of recoverable capacity. That is the PE-sponsor number; CSR convenience is the departmental justification.
  • Economic buyer: unidentified — Robert is champion, not signer. Identify before or at the on-site (CEO ran the mid-year check-in; PE sponsor wants visibility).
  • Exit criteria for the on-site (the close): a demo “success” = (1) item-master export commitment for one GP site, (2) pilot-site selection, (3) security-review kickoff (cloud vs. Ordermatic Local decision), and a named next meeting. Walk-away condition: no data commitment and no named next step.
  • On-site question list: ERP roadmap / consolidation program + owner? · security posture — may POs/pricing flow through cloud SaaS, or is this an Ordermatic Local prospect? · who signs? · which site do the 10 sample POs belong to? · confirm 8-public-sites vs “11 sites” delta (leased/co-located sites?).
  • Angel gets a scripted win: she (not a demo driver) confirms the flywheel correction on stage — the skeptic becomes the operator of the moment.

Demo risk controls (added by review, 2026-07-12)

Section titled “Demo risk controls (added by review, 2026-07-12)”
  • Rehearsal gate (blocking): see “Rehearsal gate — the test plan” below — all 8 items green before the on-site.
  • Live map-correction demoted to recovery move — plan-of-record is presenting the best-guess map; inviting corrections is the fallback when someone challenges it (13 primed skeptics + an 8-vs-11 site count is not a stage trick to lead with).
  • Real multi-connection product build (index relaxation, content routing, cross-connection transfer) — spec’d as open questions; sized before contract, built after.
  • IQMS + Business Central integration — named roadmap, not POC.
  • Venna API integration — later seam; demo uses doc-price-wins + tier flag only.
  • Customer-facing portal of any kind — Aurora security posture; email intake only.
  • Network forecast/reporting build — P2 gesture in the deck, not built.
  • Sales collateral / leave-behind (E7) — deferred to TODOS.
  • review-v2 org-wide inbox; supervisor dashboard w/ per-CSR views + reassignment (work_items.assigned_to_user_id).
  • inbox_routing_rules engine (extend, don’t duplicate) · inbox_delegations.
  • Full C&M POC script set + workbench/poc.py helpers + POC-PLAYBOOK.
  • Real in-doc cross-references (4 customers) to seed manual_cross_references.
  • codelessLines gate (PR #2250) for the verbal order; xref writeback flywheel.
  • Price/tier validation loop (corr. A — the whole of P1 #7): doc-price-wins (persist-auto-priced-matches.ts, 2026-07-02) + tier-mismatch flag + one-click adopt (price-tier-review.ts, CockpitDetail.tsx, 2026-05-24). The Venna-correction story is live; zero build.
  • Approval-only “Finished” close (mark-approved.ts) — the demo’s closing action for a connection-less org. ⚠️ flag review_approval_only_mode is unregistered; create it by hand (rehearsal gate 3b).
  • Delegated shared-mailbox polling (2026-07-15) — makes the single orders@aurora nucleus address (P2 #12) real, not just personal-inbox polling.
  • Per-connection extraction-schema extension fields (LIVE, no flag) — a no-code way to put a “destination site” field on review-v2 (rival to the demo-branch routing card; see corr. H / run of show).

CURRENT: one-active-connection orgs, no routing concept, extraction-led pitch. THIS PLAN: proves the routing story on a simulated fan-out; spec + sizing questions for the real thing; competitive frame shifts from “order entry” to “order command center / migration-proof layer.” 12-MONTH IDEAL: multi-connection orgs; alias-first v1 routing shipped; content-based routing v2; governed cross-connection transfer; network-level reporting. This plan moves toward it; the one anti-pattern to avoid is Aurora-shaped one-off scripts — every routing mechanism built for the demo must map to a named product primitive.

Codepath What can go wrong Rescued? Rescue action User/operator sees
Gemini extraction (10 POs) 0-item extraction cached Y (playbook) never cache 0-item results rerun extracts fresh
Extraction of 7-pg email thread picks pricing-thread items, not the PO (“wrong item #” annotation read as data) GAP → rehearsal gate prompt carries direction note + “PO-inside-thread” instruction; rehearsal verifies wrong lines in demo order
Verbal order (no items) auto-validate skips (empty item_ids) Y (E4) enable codelessLines gate + Flagsmith flag line matches live on stage
seed_staging_org re-run duplicates order graph Y (playbook) cleanup first; notebook checks pdf_documents per filename duplicate inbox rows
ALT_CACHE unset silently zero aliases Y (playbook) always pass explicitly; check alias count post-reseed quiet count in logs
Typesense reseed wipes learned xrefs Y (playbook) re-run learn_xref after any reseed xref demo moment fails
Clerk org creation 422 reuses existing org (C&M trap) Y parameterization checklist; unique slug aurora-poc wrong org seeded
Staging deploy drift demo-day behavior differs from rehearsal GAP → pin staging same-day rehearsal against deployed revision feature missing on stage
Codepath Failure mode Rescued? Test? User sees Logged?
Routing proposal wrong site guess live Y (narrative) rehearsal correction flow = the product staging logs
Auto-validate on stage wrong bind (worse than no bind) Y (abstention) rehearsal + wrong-rate check review line, not wrong product order events
Xref flywheel finale learned xref doesn’t bind sibling partial rehearse exact sequence flat ending Typesense query
Supervisor dashboard dead/empty site queue Y (E6) seed check “this looks fake” —
Sim_ orders leak into metrics/billing Y is_test_order=true everywhere — billing tables
# Phase Decision Class Principle Rationale Rejected
1 CEO Mode = SELECTIVE EXPANSION Mechanical ctx default feature iteration on existing system EXPANSION/HOLD
2 CEO Approach A (zero-ask sim, one org) Mechanical P1+P3 per-site orgs break org-scoped dashboard; C re-litigates user decision B, C
3 CEO E7 leave-behind collateral → TODOS Auto P2 outside build blast radius build now
4 CEO E8 real multi-connection build → defer Mechanical P2 multi-quarter; sized before contract build now

Approved expansions E1–E6 and all design/eng decisions: outcomes are recorded in the sections they produced (Demo risk controls, Demo design spec, Eng resolution).

Demo design spec (added by design review, 2026-07-12)

Section titled “Demo design spec (added by design review, 2026-07-12)”

Resolves the pixel-level ambiguities both design voices flagged. The demo surfaces are the SHIPPED product (review-v2 inbox, supervisor kanban, cockpit detail) styled per apps/webapp/DESIGN.md; the items below are the only demo-specific UI work.

  1. Site is a first-class label, not an assignee disguise. Seed 8 site-team users (not 13 fake individuals): display name carries both facts — “Ohio — Streetsboro · GP-1”, “Lunenburg MA · GP-4”, “Marieville QC · IQMS-1”. The 13-CSR figure appears in the narration (workload math), never as 13 seeded users. SupervisorKanban’s by-assignee lens then IS the by-site lens. (The kanban’s existing 'connection' lens is the honest dimension the product gains after the index relaxation — say so on stage when IT asks.)
  2. Routing card in cockpit detail — the demo’s spine, committed (no fallback). Rendered above the order-entry hierarchy: Routed: Ohio — Streetsboro → GP-1 · Signals: ship-to "Streetsboro, OH" + vendor entity "Aurora Plastics" + item family GTPE · Confidence: High. Ambiguous variant (mandatory, distinct visual): Ambiguous — needs routing review: ship-to TX vs. vendor entity MA. Vehicle: per Eng resolution #3 — org-gated component on staging, new Aurora flag.
  3. Destination-ERP chip on row + detail from routing time: → GP-Ohio. The word “simulated” appears ONCE globally (env banner: “Offline POC — no ERP writes”), never per order.
  4. UI states (per Eng resolution #3): routed · ambiguous · submitted-simulated chip. Everything else (route-corrected, moved-to-site, partial, codeless framing, provenance) is narration in the run of show, not UI.
  5. Land → route reveal is hybrid: pre-seed sims + 7 real POs; live-forward 2–3 real POs at ~12:05 (mechanism + latency criterion: Eng resolution #2 and rehearsal-gate item 2).
  6. The “mis-route” is a scripted ambiguity, not a wrong system result: an order the system abstains on (ambiguous variant above); Angel resolves it — her win is a real UI moment (her machine, CSR account, one click + confirm), positioned mid-demo ~12:40.
  7. Flywheel finale is a before/after reveal: open sibling doc (line unmatched) → Angel confirms on primary → reopen sibling: line bound, provenance marker “matched via cross-reference learned from C20084-AP”.
  8. Personas & choreography: presenter drives the supervisor account on the projector; Angel gets a CSR account on a second machine. Opening screen at 12:00: supervisor dashboard, shaped volume, org name “Aurora — Order Nucleus” visible. Nucleus inbox default: ungrouped, newest-first (routing chips carry beat 2).
  9. Volume shaping numbers: no visible site queue under 3 items; sites without sample-PO coverage get sims or are collapsed. ~25 orders total across the shown sites.
  10. Run of show (minute-by-minute): 12:00 pain mirror (11 inboxes → one nucleus) · 12:05 live-forward landing beat · 12:15 routing + reasoning beat · 12:25 exceptions beat (verbal order + TriCab digit catch + their own annotated wrong-item email) · 12:40 Angel’s correction + flywheel beat · 12:50 supervisor / network view (Robert’s PE story: 5–6 FTE math) · 13:00 lunch · 13:30 sanctioned “pick it apart” hands-on block (Robert asked for exactly this) · 13:50 the close (exit criteria: item-master commitment, pilot site, security-review kickoff).

Eng resolution (added by eng review, 2026-07-12)

Section titled “Eng resolution (added by eng review, 2026-07-12)”

Both eng voices verified the plan’s schema/code claims accurate and the seeded demo path playbook-sound. Three additions beyond the C&M template carry most of the demo-day risk (live email beat, demo UI component, 8 Clerk users) and interact. The resolutions below are binding for the build:

  1. Two tracks with separate acceptance checks: demo-seeded path (playbook-proven) and live-email path (new). Rehearsing a live PO via the seed script proves nothing — the live path exercises CF email-worker → inbound-email.ts → the production python extractor with erp_connections.prompt_config (a DIFFERENT prompt than the seed script’s). The direction note + PO-inside-thread instruction MUST be written into prompt_config at seed time.
  2. Live beat mechanism (fixes the unassigned-landing break): forward the 2 live POs to per-site user-type aliases bound to the site users (inbound-email.ts auto-assigns only for aliasType='user'). “One nucleus address” is narration; the plumbing is invisible to the room. Rehearsed fallback: land-only beat + supervisor assigns live on stage. Sender optics scripted (“forwarded from our intake this morning” — the row shows the forwarder’s address).
  3. Routing card, de-scoped and deploy-safe: org-gated component merged INTO staging proper (auto-deploy can’t remove it), gated by a new Aurora-specific flag — do NOT reuse ck_poc_enhanced_review (it drags CK pricing/profile UI with it, review.astro:438). States cut from 9 to 3: routed / ambiguous / submitted-simulated chip. Signals via a hardcoded po_number→signals map in the component. The remaining 6 states from the design table are narration, not UI. There is no order-note rendering surface in the cockpit — the “seeded order-note block” vehicle is not buildable and is dropped.
  4. “Pin staging” now has a mechanism: demo component on staging + declared merge freeze window (team channel) + verify served revision hash at 11:45 + hotspot for Angel’s machine. If freeze is refused, pin Cloud Run traffic to a named revision AND disable the staging deploy workflow for the window — both steps.
  5. Roadmap-flywheel beat (honesty creed): route-override learning DOES NOT EXIST in the product (xref learning is real; route learning is not). The beat is presented as a scripted preview of the roadmap flywheel — seeded, explicitly narrated as “this is where the product goes,” never implied live.
  6. Cleanup/retirement expanded (NDA obligation): the copied scripts/poc-aurora/cleanup_staging_org.py must also delete org-scoped email_events (live-forwarded PO bodies), email_aliases, email_pull_connections, inbox_routing_rules, Clerk invitations/memberships — and purge poc/aurora/raw + poc/aurora/cache from R2 (or record a dated deletion commitment). Shared-Typesense residency of NDA’d price data recorded as an accepted risk in the customer README.
  7. Registry additions: $0.00-grand-total doc (null→0.0 coercion precedent — rehearse what the review surface actually flags; script or drop), revision docs (seed as sibling orders, C&M duplicate-detection precedent), verbal order zero-line case (if extraction yields no line rows, codelessLines has nothing to match — the beat becomes abstention narration; decide at rehearsal).
  8. codelessLines is a three-part gate (deployed #2250 revision + extra_config deep-merge + matching_codeless_lines_v1 not-OFF in the Staging Flagsmith env — verify via deployed env, never local .env). ⚠️ corr. per audit: the flag reader is flag?.enabled ?? true, so an absent flag still yields TRUE — a rehearsal that fails to find it is not a red gate. But extra_config->'matchingConfig' must NOT contain suppressNameBucket (land mine — deletes the bucket codeless binds through). Explicit rehearsal-checklist item with the verify SQL.
  9. Clerk users: accept all 8 invites during the build (david+aurora-<site>@ordermatic.co), set display names post-acceptance, and verify the assignee lens renders 8 labeled columns as part of the seed check.
  10. Synthetic-SKU quarantine, concretely: a committed manifest (real vs. invented item numbers) in data-engineering/customers/aurora/ at generation time; on deal close, graduation creates a NEW connection and the demo connection retires — demo erp_products never migrate.
  11. Hands-on block constraints: prepared doc set + the 10 real POs only; the “simulated catalog” line delivered BEFORE the block; verify what connection-settings expose to CSR-role accounts and restrict roles.
  12. Copy fix: stop implying branch-alias → per-site-connection fan-out is demoable today (one-active-connection index blocks it on staging too). Demo copy is “site team + simulated ERP label.”

Demo-build architecture (required diagram)

Section titled “Demo-build architecture (required diagram)”
Robert's 10 POs ──upload──▶ R2 poc/aurora/raw ──▶ Gemini extract (seed script; cache poc/aurora/cache)
│
synthetic catalog (committed manifest) ──▶ erp_products ─▶ Typesense (connection-scoped docs)
▼
seed_staging_org.py ──▶ Clerk org "Aurora — Order Nucleus" (8 accepted site users)
│ │
▼ ▼
pdf_documents ─▶ extracted_orders ─▶ work_items (assigned_to = site user · is_test_order=true)
▲
live-forward ×2 ─▶ CF email-worker ─▶ inbound-email.ts ─▶ user-type alias ─▶ auto-assigned
▼
review-v2 inbox / supervisor kanban (by-assignee lens = site queues)
▼
routing card (org-gated, on staging, flag: aurora demo · states: routed/ambiguous/submitted-sim)
▼
cleanup_staging_org.py (+ email_events, aliases, pull-conns, rules, memberships, R2 purge)

Rehearsal gate — the test plan (blocking, run against pinned staging)

Section titled “Rehearsal gate — the test plan (blocking, run against pinned staging)”
  1. All 10 seeded POs: extract + route + match correctly (incl. thread, verbal, $0.00, both revisions). Record per-doc results in the customer README work log.
  2. Live path E2E for the exact 2 chosen POs: send through the real email path; record land→routed latency here: ____ s (target < 60 s; else pre-send before the room arrives). ⚠️ Scope: this exercises the per-site user-alias demo path (Eng resolution #2), NOT delegated orders@aurora shared-mailbox polling — that capability is real (corr. F) but is P2 #12 roadmap narration, not demoed here. If the demo pivots to the shared address, add a separate shared-mailbox E2E check.
  3. Gate SQL (updated per audit): extra_config->'matchingConfig' shows xref/uomConversion/xrefWriteback/codelessLines AND does NOT contain suppressNameBucket (land mine — kills the verbal-order beat). Flags: matching_codeless_lines_v1 not-OFF (absent = TRUE, so “not found” is not a red gate); pricing_source_price_authoritative_v1 ON for the Aurora connection identity (owns doc-price-wins; TS/Python defaults disagree — Genfit-segment-override precedent). 3b. Create review_approval_only_mode in Flagsmith by hand and enable it for the Aurora org — it is UNREGISTERED and defaults OFF everywhere; without it the demo has no closing action (Aurora has no ERP connection, so Submit can’t fire — the “Finished” approval-only CTA is the only close). 3c. Re-run index_typesense.py after ANY erp_customers insert (each needs a matching Typesense doc {connection_id}_{erp_customer_id} — playbook gotcha 19; C&M lost Zanesville to this), and mint a fresh Clerk session per automation run (stale storage_state reads as “button not found”).
  4. Assignee lens renders 8 labeled site columns; no visible queue < 3 items.
  5. Xref finale dry-run: sibling-doc before/after binds with provenance visible.
  6. Angel’s CSR account signs in on a second machine (hotspot tested), can open the ambiguous order and confirm the correction.
  7. Verify served staging revision hash; freeze window announced.
  8. Cleanup dry-run passes (all Aurora tables + R2 prefixes enumerated).
Step Modules touched Depends on
A: scripts copy + catalog + seed scripts/poc-aurora/, data-engineering/customers/aurora/ —
B: routing-card component + flag apps/webapp/src/components/inbox/ —
C: live email path setup (aliases, prompt_config) staging DB config A
D: rehearsal + run-of-show none (staging) A+B+C

Lane A and Lane B are independent → parallel worktrees. C follows A (needs the org). D is the integration gate. Conflict flags: none (disjoint modules).

Implementation tasks (aggregated by /autoplan, 2026-07-12)

Section titled “Implementation tasks (aggregated by /autoplan, 2026-07-12)”

P1 blocks the demo; P2 lands before rehearsal. Effort: human / CC-assisted.

⚠️ Audit correction E: the four Files: lines below that named scripts/poc-core-and-main/… have been repointed to scripts/poc-aurora/…. Editing the C&M scripts in place would mutate the LIVE Core & Main build. The copy itself is now T0 (prerequisite for every poc-aurora/* task — NOT the routing card; Lane B is independent per the worktree parallelization table).

  • P1 (~30min / ~5min) — demo-build — T0: copy scripts/poc-core-and-main → scripts/poc-aurora and work the parameterization checklist (playbook §1.0); prerequisite for all poc-aurora/* tasks below
    • Source: audit — README open item L74 + Eng resolution #6 / worktree lane A; was never a tracked task
    • Files: scripts/poc-aurora/ (new, copied from scripts/poc-core-and-main/)
    • Done: copied; seed_staging_org.py and cleanup_staging_org.py fully rewritten for Aurora (org slug/name, 8-site roster, real 10-PO customer/item-code data, synthetic catalog). The other 14 scripts (generate_alt_descriptors.py, reseed_from_d265.py, verify_match_lift.py, etc.) are copied but NOT yet parameterized — they’re not needed until later playbook phases (real item master, held-out eval) that haven’t started.
  • P1 (~30min / ~5min) — sales-ops — Confirm on-site date with Robert and resolve which site each of the 10 sample POs belongs to before writing routing rules
    • Source: ceo-review — Both voices + README open item: PO-to-site mapping unknown attacks the routing-rules premise
    • Files: data-engineering/customers/aurora/README.md
  • P1 (~half day / ~1h) — demo-build — Rehearsal gate: dry-run all 10 real POs end-to-end (extract+route+match) against pinned staging before the on-site
    • Source: ceo-review — Demo risk controls — 13 primed skeptics; email-thread PO and verbal order are the risky extractions
    • Files: docs/poc/aurora-order-routing-requirements.md
  • P1 (~1 day / ~2h) — eng-sizing — One-page eng sizing of multi-connection index relaxation + routing step + cross-connection transfer + GP write path, before contract
    • Source: ceo-review — Claude CEO voice C1: capability demoed but unsized; gate the pitch with a scoped integration phase
    • Files: packages/db/src/schema/erp-connections.ts, docs/poc/aurora-order-routing-requirements.md
    • Done: aurora-multi-connection-eng-sizing.md — verified call-site counts (17 single-connection call sites, 0 callers of the multi-connection helper, Dagster already connection_id-partitioned); ~3wk for index relaxation + rules-based routing + transfer, GP write path unscoped pending IT engagement.
  • P1 (~half day / ~1h) — demo-build — Build the routing card + destination-ERP chip + ambiguous variant (demo branch or seeded order-note vehicle per Phase 3 decision)
    • Source: design-review — Design F2/Codex: the demo’s spine must be on-screen, not narrated; no printed-map fallback
    • Files: apps/webapp/src/components/inbox/cockpit/CockpitDetail.tsx
    • Done: per Eng resolution #3 (3 states, hardcoded po#→signals map, new aurora_poc_routing_card_v1 flag — not ck_poc_enhanced_review). New files: apps/webapp/src/components/inbox/cockpit/AuroraRoutingCard.tsx, apps/webapp/src/lib/poc/aurora-routing-signals.ts. Wired through inbox.astro → InboxCockpit → CockpitDetail, org-gated, default off (no Flagsmith flag exists yet, so this is a no-op until one is created and targeted at the Aurora demo org — infra step, not code). Only 2 PO numbers seeded in the signal map (the design spec’s own worked examples); the real PO→site assignments are still an open item pending confirmation with Robert (see customer README). Skipped: the destination-ERP chip on the row (list view) — only the detail-pane card was in scope per the file list above; add to CockpitRow.tsx if the row-level chip is wanted too. Skipped: the global “Offline POC — no ERP writes” env banner (design spec #3) — separate small UI piece, not the card itself.
  • P1 (~2h / ~30min) — demo-build — Seed 8 site-team users (site+ERP in display name); drop the 13-user fiction; verify by-assignee kanban reads as site queues
    • Source: design-review — Design F1: site=assignee collapses site and CSR dimensions; 13 users vs per-site users are mutually exclusive
    • Files: scripts/poc-aurora/seed_staging_org.py (T0 copy — NOT poc-core-and-main)
    • Done: SITES list (8 sites, site+ERP-label display names e.g. “Ohio — Streetsboro” / GP-1) drives invite loop + set_site_display_names() (Clerk first_name/last_name patch, runs automatically on re-run once an invite is accepted). Not verified live — needs a real staging DB + Clerk creds run, which this session doesn’t have; “verify by-assignee kanban reads as site queues” still needs a human to actually run it.
  • P1 (~1h / ~15min) — demo-build — Implement hybrid landing beat: pre-seed 7 real POs + sims; live-forward 2-3 real POs by email; record land-to-routed latency at rehearsal
    • Source: design-review — Design F4: fully pre-seeded org makes the nucleus reveal a static screen
    • Files: docs/poc/aurora-order-routing-requirements.md
    • Partial: seed_staging_org.py pre-seeds all 10 real POs + Sim_ filler (the “pre-seed” half). “Live-forward 2-3 by email” + “record latency at rehearsal” still need a live run against staging — not codeable without infra access.
  • P1 (~2h / ~30min) — demo-build — Live beat: per-site user-type aliases + prompt_config carries direction note + PO-inside-thread instruction; rehearse the 2 live POs through the REAL email path
    • Source: eng-review — Eng F1/F4 both voices: org/branch aliases land work items unassigned (inbound-email.ts:152); seed-script rehearsal proves nothing for the live path
    • Files: apps/webapp/src/pages/api/webhook/inbound-email.ts
    • Done: the alias-mechanism half. seed_staging_org.py creates aliasType='user' aliases per accepted site (matches inbound-email.ts’s existing auto-assign-on-user-alias behavior — no app code change needed there, confirmed by reading it) and the connection’s prompt_config.notes now carries the direction note + PO-inside-thread instruction for the 7pg email-thread doc. Not done: actually rehearsing the 2 live POs through the real email path — needs a live staging run.
  • P1 (~1-2 days / ~2-3h) — webapp — Routing card: org-gated component on staging, NEW aurora flag (not ck_poc_enhanced_review), 3 states only, hardcoded po#-to-signals map
    • Source: eng-review — Eng F2 + Codex 1/5: no order-note surface exists; 9-state table is a week; CK flag drags CK UI
    • Files: apps/webapp/src/components/inbox/cockpit/CockpitDetail.tsx, apps/webapp/src/pages/orders/pdf/[documentId]/review.astro
    • Done: duplicate of the task at line 542 above (same component, same flag, same 3-state design) — see that entry for what shipped. This bullet and that one describe the same build from two different review voices; not separate work.
  • P1 (~1h / ~20min) — demo-build — Expand cleanup_staging_org.py: email_events, email_aliases, email_pull_connections, inbox_routing_rules, Clerk memberships, R2 purge of poc/aurora/*
    • Source: eng-review — Eng F5 both voices: NDA’d PO bodies + price data persist indefinitely after retirement
    • Files: scripts/poc-aurora/cleanup_staging_org.py (T0 copy — NOT poc-core-and-main)
    • Done: all four tables added (email_events, email_aliases, email_pull_connections, inbox_routing_rules), in correct FK order; R2 purge of poc/aurora/raw/ + poc/aurora/cache/ added (unlike the C&M original, which leaves R2 alone); Clerk org deletion already cascades memberships/invitations (verified — no separate API call needed).
  • P1 (~1h / ~15min) — demo-build — Staging pin mechanism: merge card to staging, freeze window, verify revision hash 11:45, hotspot; codelessLines 3-part gate verify SQL in rehearsal checklist
    • Source: eng-review — Eng F3/F10: pin-staging was a wish; gate is deploy+config+flag
    • Files: docs/poc/aurora-order-routing-requirements.md
  • P2 (~2h / ~20min) — demo-build — Implement E1 mocked ‘Submitted → GP- (simulated)’ landing labels + E6 volume shaping in seed scripts
    • Source: ceo-review — Premise gate PR3 mitigation; Robert asked to see distribution into the ERP
    • Files: scripts/poc-aurora/seed_staging_org.py (T0 copy — NOT poc-core-and-main)
    • Done: 2 real orders seeded with work_items.status='submitted' (the DB status that resolves to uxState: 'submitted', which the routing card renders as the compact → GP-1 chip — verified against work-item-ux-state.ts). SIM_FILLER_COUNT_BY_SITE distributes Sim_ orders so every site has ≥3 items; org totals 28 (10 real, unevenly distributed 6 Streetsboro/4 Lunenburg per the real POs, + 18 sim across the other 6 sites). Verified 2026-07-23: dry-ran the actual script against a throwaway local Postgres (Drizzle schema pushed via db:push, Clerk calls stubbed) — zero SQL errors, confirmed the verbal order has empty item_ids, both submitted-status orders carry the right item, and the TriCab digit discrepancy (405BK) survives un-“fixed.”
  • P2 (~1h / ~15min) — demo-build — Enable codelessLines gate (extraConfig deep-merge) + matching_codeless_lines_v1 flag for the demo connection; verify verbal order auto-validates
    • Source: ceo-review — E4 — VinylOne verbal order has no item codes; ineligible without the gate
    • Files: data-engineering/POC-PLAYBOOK.md
  • P2 (~1h / ~10min) — sales-ops — Identify economic buyer + take the on-site question list (ERP consolidation roadmap, cloud-vs-Local security posture, signer)
    • Source: ceo-review — Both voices: champion-only qualification; GP EOL consolidation risk unasked
    • Files: docs/poc/aurora-order-routing-requirements.md
  • P2 (~2h / ~30min) — demo-build — Cover the 9-row interaction-state table — superseded, won’t build
    • Source: design-review — Design pass 2: states unspecified; Codex enumerated 9 missing states
    • Files: apps/webapp/src/components/inbox/types.ts
    • Done: per this doc’s own Eng resolution #3 and its explicit tie-breaker rule (“Where a design task conflicts with the Eng resolution (9-state table, order-note vehicle), the Eng resolution wins”) — the routing card ships 3 states only (routed/ambiguous/submitted chip), already built at line 542. The other 6 states from the design table are narration in the run of show, not UI, by design. Not a gap; a resolved conflict.
  • P2 (~1h / ~20min) — sales-ops — Script Angel’s UI moment (second machine, CSR account) + sixth beat (override taught the router) + minute-by-minute run of show
    • Source: design-review — Design F5/F8: 90 of 120 minutes unscripted; learning asserted but never shown
    • Files: docs/poc/aurora-order-routing-requirements.md
  • P2 (~2h / ~30min) — demo-build — Accept all 8 Clerk site-user invites, set display names, verify 8 labeled kanban columns; synthetic-SKU manifest committed at generation
    • Source: eng-review — Eng F7/F8: ghost invited users may not render; Sim_ prefix is a filename convention, not a product flag
    • Files: scripts/poc-aurora/seed_staging_org.py, scripts/poc-aurora/backfill_assignments.py
    • Partial (2026-07-23): display-name-setting + alias + work-item assignment are automated in backfill_assignments.py (safe idempotent re-run). 1/8 accepted (Louisville) — backfilled and verified. Accepting the other 7 invites is a manual step (each is a Clerk account creation, which the agent is not permitted to do); re-run the backfill as they’re accepted. “Verify 8 labeled kanban columns” blocked on all 8 being accepted.
  • P2 (~1h / ~15min) — demo-build — Rehearse $0.00 doc + revision-sibling seeding + verbal zero-line fallback; reword flywheel finale as scripted roadmap preview
    • Source: eng-review — Eng F6 + Codex 7: registry rows missing; route learning does not exist in product
    • Files: docs/poc/aurora-order-routing-requirements.md

Where a design task conflicts with the Eng resolution (9-state table, order-note vehicle), the Eng resolution wins — see Demo design spec pointers.