Bid Center — Path 1 · email intake

bids@ai-globalfoodsolutions.co → src/email.ts → attachments parsed → HITL on customer match → chat session opens with docs preloaded → 11-skill review

Bid emails arrive at bids@ai-globalfoodsolutions.co. src/email.ts parses the headers and body, the document converter (PDF / XLSX) normalizes attachments to markdown, and we attempt to match the sender to a known customer via name_synonyms.json. A proposed_actions row stages "New bid inbound — customer match <X> — run review?" until Mike approves. On approve, a chat session opens with the bid PDF, the customer's customer.json, and the customer's latest bid_quote_versions row already in context, and the standardized 11-skill review runs. Customer + SY-version is the trace thread.

D1-mirrored HITL on customer match (ADR-031) auto-classifier under bake

Pipeline — email arrives → HITL approve → review runs

idle
Bid Center path 1 - email arrives at bids@ - src/email.ts parses - document converter normalizes PDF/XLSX - customer resolved via name_synonyms - SY-version picked - proposed_action staged - HITL approve by Mike - chat session opens with docs preloaded - 11-skill review dispatched - bid_* writes - .docx regen - STATUS.json refresh - events emitted - customer + SY-version threaded through LANE A / Inbound (Cloudflare Email Routing -> src/email.ts) LANE B / Parse + normalize (document converter, customer match, SY-version) LANE C / HITL gate (proposed_actions + admin notify + Mike approves) LANE D / Run review (chat session opens, 11-skill dispatch, bid_* writes) LANE E / Outputs (.docx, STATUS.json, dashboard, events) WHAT THIS DOES: A bid email lands in the bids@ mailbox. Cloudflare Email Routing forwards it to the Worker. D1 TABLE: none yet - the email itself is the trigger. TECHNICAL DETAILS: EMAIL ARRIVES MAILBOX bids@ai-globalfoodsolutions.co ROUTING Cloudflare Email Routing rule -> Worker email_handler STATUS: REAL email arrives at bids@ bids@ai-globalfoodsolutions.co CF Email Routing -> Worker EXTERNAL i WHAT THIS DOES: src/email.ts is the Worker entrypoint that handles every inbound mailbox. It parses headers, body, and lists attachments. D1 TABLE: events (audit row inserted) TECHNICAL DETAILS: src/email.ts PARSES EXTRACTS from, to, subject, body (text + html) attachments[] array HEADER X-Forwarded-To = bids@ai-globalfoodsolutions.co - routes to bid handler EMIT events row: bid.email_received STATUS: REAL src/email.ts parses headers + body from / subject / body / attachments[] emit events.bid.email_received BACKEND i WHAT THIS DOES: Check if the email has a PDF or XLSX attachment. Most bids arrive with one of these. If no attachment, fall back to parsing the body as the bid itself. D1 TABLE: none TECHNICAL DETAILS: DETECT ATTACHMENTS LOGIC for each att: if mime in ['application/pdf','application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']: route to document_converter else: ignore + log FALLBACK body-only parse if zero supported attachments STATUS: REAL detect attachments (PDF / XLSX) mime sniff · route to document_converter fallback: body-only parse BACKEND i WHAT THIS DOES: PDF or XLSX content is converted to markdown so the LLM can read it cleanly. document_converter is a shared platform service. D1 TABLE: none (R2 stores the source attachment) TECHNICAL DETAILS: DOCUMENT_CONVERTER INPUT Uint8Array PDF or XLSX bytes OUTPUT markdown string STORAGE source bytes -> R2 (bid-attachments bucket) keyed by email_id USE preloaded into chat context downstream STATUS: REAL document_converter -> markdown PDF / XLSX -> markdown string source bytes -> R2 bid-attachments BACKEND · document_converter i WHAT THIS DOES: Match the sender (or extracted account name in the bid) to a known GFS customer. name_synonyms.json handles partials like "ACC Dist" -> "ACC Distributors". Low-confidence matches force HITL. D1 TABLE: bid_customers (READ); customers (READ) TECHNICAL DETAILS: RESOLVE CUSTOMER SOURCE name_synonyms.json + bid_customers ALGORITHM exact -> alias -> fuzzy (Levenshtein) CONFIDENCE >= 0.85 auto-suggest; < 0.85 ambiguous (Mike picks) STATUS: REAL - bake resolve customer (name_synonyms) exact -> alias -> fuzzy confidence >= 0.85 auto-suggest DATABASE · customer match i WHAT THIS DOES: Pick the current SY-version for this customer, or NEW if first-time. The pair (customer + SY-version) is the trace thread for the entire Bid Center pillar. D1 TABLE: bid_quote_versions (READ latest WHERE customer_id=? AND is_latest=1) TECHNICAL DETAILS: PICK SY-VERSION LOGIC latest = SELECT sy_version FROM bid_quote_versions WHERE customer_id=? AND is_latest=1 if none: sy_version = currentSchoolYear() + '-v0.1' THREAD KEY customer_id + '/' + sy_version (e.g. 'ACC Distributors / SY2627-v2.5') STATUS: REAL pick SY-version (trace thread) latest is_latest=1 OR new NEW thread: customer + SY-version DATABASE · bid_quote_versions i WHAT THIS DOES: Bundle the parsed bid markdown, R2 source key, resolved customer, and picked SY-version into a single payload object for HITL review. D1 TABLE: scratch (in-memory only until staged) TECHNICAL DETAILS: BUILD PROPOSED PAYLOAD SHAPE { email_id, email_from, subject_summary, customer_id, customer_match_confidence, sy_version, bid_markdown, r2_source_key, suggested_skill: 'LOG_EXTERNAL_BID' | 'ADD_UPDATE_CUSTOMER_PRICING' | ... } ROUTER if has_pricing_table: ADD_UPDATE_CUSTOMER_PRICING if has_rfp_doc: LOG_EXTERNAL_BID else: ambiguous - Mike picks STATUS: REAL - bake on suggested_skill build proposed payload (customer + SY-version + markdown + suggested skill) heuristic skill suggestion: LOG_EXTERNAL_BID / ADD_UPDATE_CUSTOMER_PRICING all fields prepared for proposed_actions insert BACKEND · payload assembly i WHAT THIS DOES: INSERT the row into proposed_actions with status='pending'. This is the HITL gate - nothing downstream executes until Mike approves. D1 TABLE: proposed_actions (INSERT, kind='bid_email_intake') TECHNICAL DETAILS: STAGE proposed_actions ROW INSERT kind = 'bid_email_intake' customer_id, sy_version, payload (JSON), suggested_skill status = 'pending' risk_level = 3 INVARIANT ADR-031: no downstream write without an approval row STATUS: REAL โ˜… HITL gate · stage proposed_action (ADR-031) kind='bid_email_intake' · status='pending' · risk_level=3 SECURITY · THE customer-match approval gate i WHAT THIS DOES: Surface the staged proposed_action on the admin dashboard (and optionally send a notification). Mike sees: "New bid inbound - customer match X - run review?" D1 TABLE: proposed_actions (READ for dashboard) TECHNICAL DETAILS: NOTIFY MIKE SURFACES admin-dashboard.html (pending HITL queue) optional: notification email or push COPY "New bid inbound - customer match <name> (conf 0.91) - run review?" STATUS: REAL notify Mike (dashboard + optional push) "New bid - customer X - run review?" CLOUD · admin-dashboard surface i WHAT THIS DOES: Mike opens admin-dashboard, sees the proposed bid intake, and chooses: APPROVE (run review), REJECT (discard), or REASSIGN (different customer or different skill). D1 TABLE: proposed_actions (UPDATE status, decided_by_user_id, decided_at) TECHNICAL DETAILS: MIKE REVIEWS + APPROVES INTERACTION open card in admin-dashboard see: customer match, conf, suggested skill, bid markdown preview ACTIONS Approve -> status='approved', fires bid.intake_approved Reject -> status='rejected' Reassign -> updates customer_id or suggested_skill, then approve INVARIANT X-Edit-Token + HITL audit trail STATUS: REAL โ˜… Mike reviews + approves (APPROVE / REJECT / REASSIGN) X-Edit-Token + HITL audit trail FINANCE-KEY · the HITL decision i WHAT THIS DOES: If Mike rejects, the row is closed and no downstream side effects fire. Email is preserved in R2 for audit. D1 TABLE: proposed_actions (status='rejected') TECHNICAL DETAILS: REJECTION BRANCH ACTION proposed_actions.status = 'rejected' emit events.bid.intake_rejected no bid_* writes no chat session opened RECOVERY email stays in R2; can be re-queued via admin tool STATUS: REAL REJECT branch close row · emit bid.intake_rejected SECURITY · recoverable i WHAT THIS DOES: On approve, the worker creates a chat session, attaches the bid markdown + customer.json + latest bid_quote_versions row as preloaded context, and dispatches the suggested skill. D1 TABLE: chat_session (INSERT); proposed_actions (status='approved') TECHNICAL DETAILS: APPROVE BRANCH ACTION open chat_session preloaded: bid_markdown, customer.json, latest bid_quote_versions row dispatcher.run(suggested_skill) STATUS: REAL APPROVE branch · open chat + dispatch chat session + preloaded docs BACKEND i WHAT THIS DOES: A chat session is opened with the bid PDF (markdown), the customer.json, and the customer's latest bid_quote_versions row preloaded into context. Mike or the workflow runner picks up from here. D1 TABLE: chat_session (INSERT); chat_message (system message with preloaded context) TECHNICAL DETAILS: CHAT SESSION OPENED CONTEXT PRELOADED bid_markdown (from R2) customer.json bid_quote_versions latest row RUNNER workflow_runner picks suggested_skill STATUS: REAL chat session opened with docs preloaded bid markdown + customer.json + latest bid_quote_versions CLOUD · chat session i WHAT THIS DOES: The standardized review runs - this is the same dispatcher used by Path 2 and Path 3. One of 11 skills owns the bid (LOG_EXTERNAL_BID for new external bids; ADD_UPDATE_CUSTOMER_PRICING for re-quotes; etc.). D1 TABLES: bid_external_pipeline / bid_quote_versions / bid_price_snapshots / bid_reviews (depending on skill) TECHNICAL DETAILS: DISPATCH 11-SKILL REVIEW SKILL LIBRARY CREATE_NEW_CUSTOMER · ADD_UPDATE_CUSTOMER_PRICING · ADD_UPDATE_ITEM · FILL_REGIONAL_PRICES · REBUILD_REGIONAL_SHEETS · COMPARE_CUSTOMER_QUOTES · LOG_EXTERNAL_BID · BID_PIPELINE · ARCHIVE_CUSTOMER · SYSTEM_HEALTH_CHECK · PREPARE_NEXT_SCHOOL_YEAR DISPATCH router.dispatch(suggested_skill, payload) STATUS: REAL 11-skill dispatcher (standardized review) LOG_EXTERNAL_BID / ADD_UPDATE_CUSTOMER_PRICING / etc. BACKEND · shared with Path 2 + Path 3 i WHAT THIS DOES: Skill output writes to the 8 D1 bid_* tables. NS-bound writes (named price list) DO NOT happen on this path - they happen only on Path 3 (Jul 1 rollover). D1 TABLES: bid_customers / bid_items / bid_external_pipeline / bid_reviews / bid_programs / bid_price_snapshots / bid_quote_versions (UPSERT as appropriate) TECHNICAL DETAILS: D1 bid_* WRITES WRITES UPSERT bid_customers (if new) INSERT bid_external_pipeline (if LOG_EXTERNAL_BID) INSERT bid_quote_versions (sets is_latest=1) DELETE+INSERT bid_price_snapshots WHERE customer_id=? AND sy_version=? HITL no further HITL on path 1 - NS writes are deferred to Path 3 STATUS: REAL - migration 136 in flight (Agent M) write D1 bid_* tables no NS write on this path · deferred to Jul 1 BACKEND · migration 136 (Agent M) i WHAT THIS DOES: If this was an external bid (LOG_EXTERNAL_BID skill), append the row to External_Bids/bids_log.json on disk (and the D1 mirror). The 23 .md review analyses live in External_Bids/reviews/ alongside. D1 TABLE: bid_external_pipeline (already inserted) + bid_reviews (if .md review attached) TECHNICAL DETAILS: LOG TO bids_log.json ACTION append row to External_Bids/bids_log.json if review .md attached: write to External_Bids/reviews/<bid_id>.md INSERT bid_reviews row STATUS: REAL append External_Bids/bids_log.json + 23 review .md set if external bid: row + optional review .md DATABASE · folder + bid_reviews mirror i WHAT THIS DOES: Per-customer .docx quote regenerates from the new bid_quote_versions row. FILE: Customer-Pricing/<customer>/quotes/<sy_version>.docx TECHNICAL DETAILS: .docx REGEN TRIGGER bid_quote_versions write ACTION render docx from template + latest bid_price_snapshots STATUS: REAL .docx quote regen per customer / SY-version CLOUD i WHAT THIS DOES: STATUS.json updated for this customer + last_touched_at, ensuring dashboard freshness shows. FILE: Customer-Pricing/STATUS.json TECHNICAL DETAILS: STATUS.json REFRESH ACTION patch customers.<name>.last_sy_version = <new sy_version> patch customers.<name>.last_touched_at = now() STATUS: REAL STATUS.json refresh last_sy_version + last_touched_at CLOUD i WHAT THIS DOES: gfs-pricing.pages.dev re-renders on next request - reads bid_* tables + STATUS.json, no cache. URL: https://gfs-pricing.pages.dev TECHNICAL DETAILS: DASHBOARD RERENDER HOST Cloudflare Pages DATA D1 bid_* + STATUS.json STATUS: REAL dashboard rerender gfs-pricing.pages.dev CLOUD i WHAT THIS DOES: events.bid.email_intake_completed fires for downstream subscribers (customer health, analytics, dashboard). D1 TABLE: events (INSERT) TECHNICAL DETAILS: EVENTS EMITTED EVENT bid.email_intake_completed (customer_id, sy_version, skill_used) bid.review_completed (customer_id, sy_version) SUBSCRIBERS customer_health, analytics, dashboard STATUS: REAL events emitted bid.email_intake_completed MESSAGEBUS i PDF parsed attachment markdown customer + SY-version PROPOSED surface card visible REJECT APPROVE dispatch bid_id
Glossary
Database / folder JSON
Backend (Worker)
Cloud (dashboard, .docx)
Messagebus (events)
HITL gate
โ˜… Mike approval gate
customer + SY-version: trace thread for the Bid Center pillar
R2 bid-attachments: source PDF / XLSX preserved for audit

Tables, endpoints, code paths

kindnamepurpose
Mailboxbids@ai-globalfoodsolutions.coPath 1 inbound
Code pathsrc/email.tsemail parser + router
Code pathsrc/document_converter.tsPDF / XLSX -> Markdown
R2 bucketbid-attachmentssource attachment audit
D1 tableproposed_actionsHITL gate (kind='bid_email_intake')
D1 tablebid_customerscustomer match
D1 tablebid_quote_versionsSY-version source-of-truth
D1 tablebid_price_snapshotsline-level snapshot
D1 tablebid_external_pipelineif external bid logged
D1 tablebid_reviews23 review .md analyses
EndpointPOST /api/proposed-actions/decideMike approve / reject / reassign
Eventbid.email_intake_completeddownstream subscribers