Bid Center — Path 1 · email intake

bids@ai-globalfoodsolutions.co → src/email.ts (handleBidIntake / augmentBidCenterIntake) → attachments parsed → HITL on customer match → chat session opens with docs preloaded → 11-skill review · As of 2026-05-27

Bid emails arrive at bids@ai-globalfoodsolutions.co. src/email.ts (entrypoint handleBidIntake, augmented by augmentBidCenterIntake per R570 / Agent N) 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 is staged with action_type='bid_inbound_review', entity_type='bid_email', status='pending', risk_level=2, idempotent on entity_ref='bid_inbound:<email_uuid>'. The row surfaces on the new Bid Intake tab (R632) at gfs-pricing.pages.dev/#bids-intake — one row per inbound email with sender, subject, classification, received-at, status (Pending / Approved / Dismissed), and a deep-link to admin-dashboard.html#hitl/<action_id>. 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, the standardized 11-skill review runs, and the event lands on the Pipeline tab (R624) chronological feed. Customer + SY-version is the trace thread.

D1-mirrored HITL on customer match (ADR-031) Bid Intake tab live (R632) auto-classifier under bake
Verified 2026-05-27
Canonical action_type is bid_inbound_review (not the older bid_email_intake label). Confirmed in src/email.ts lines 934-996. Sibling action_types on the platform: log_external_bid, send_customer_quote_email. The Bid Intake dashboard pulls via apiFetch('bid-center/proposed-actions?type=bid_inbound_review&limit=100'); approved rows graduate to the Pipeline feed (R624).

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. As of 2026-05-27 (R632) the row also surfaces on the Bid Intake dashboard tab. D1 TABLE: proposed_actions (INSERT, action_type='bid_inbound_review') TECHNICAL DETAILS: STAGE proposed_actions ROW INSERT action_type = 'bid_inbound_review' entity_type = 'bid_email' entity_ref = 'bid_inbound:<email_uuid>' (idempotency key) caused_by = 'email:bids@ai-globalfoodsolutions.co' status = 'pending' risk_level = 2 CODE src/email.ts handleBidIntake -> augmentBidCenterIntake (R570 / Agent N) lines 934-996 INVARIANT ADR-031: no downstream write without an approval row STATUS: REAL (verified 2026-05-27) โ˜… HITL gate · stage proposed_action (ADR-031) action_type='bid_inbound_review' · entity_type='bid_email' · status='pending' · risk_level=2 SECURITY · THE customer-match approval gate i WHAT THIS DOES: Surface the staged proposed_action on (a) the new Bid Intake tab at gfs-pricing.pages.dev/#bids-intake (R632), and (b) the admin dashboard HITL queue. Mike sees: "New bid inbound - customer match X - run review?" D1 TABLE: proposed_actions (READ for dashboard, filter action_type='bid_inbound_review') TECHNICAL DETAILS: NOTIFY MIKE SURFACES (as of 2026-05-27) PRIMARY: gfs-pricing.pages.dev/#bids-intake (Bid Intake tab, R632) fetch: apiFetch('bid-center/proposed-actions?type=bid_inbound_review&limit=100') columns: sender / subject / classification / received-at / status (Pending|Approved|Dismissed) row deep-link -> admin-dashboard.html#hitl/<action_id> SECONDARY: admin-dashboard.html (full pending HITL queue) optional: notification email or push COPY "New bid inbound - customer match <name> (conf 0.91) - run review?" STATUS: REAL (R632 tab live 2026-05-27) notify Mike (Bid Intake tab R632 + admin queue) gfs-pricing.pages.dev/#bids-intake CLOUD · Bid Intake tab + admin dashboard 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 (CF Email Routing -> handleBidIntake)
Code pathsrc/email.ts · handleBidIntake @ L839email parser + router (R570 / Agent N)
Code pathsrc/email.ts · augmentBidCenterIntake @ L880bid-center-specific augmentation; idempotent on entity_ref
Code pathsrc/document_converter.tsPDF / XLSX -> Markdown
R2 bucketbid-attachmentssource attachment audit
D1 tableproposed_actionsHITL gate · action_type='bid_inbound_review' · entity_type='bid_email' · risk_level=2
D1 tableinbound_email_logidempotency on message_id
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
Dashboardgfs-pricing.pages.dev/#bids-intakeNEW (R632, 2026-05-27) Bid Intake tab · apiFetch('bid-center/proposed-actions?type=bid_inbound_review&limit=100')
Dashboardgfs-pricing.pages.dev Pipeline tabR624 chronological feed of approved bid events (downstream of approval)
Dashboardadmin-dashboard.html#hitl/<action_id>deep-link from Bid Intake row to HITL decision
EndpointGET /api/bid-center/proposed-actions?type=bid_inbound_reviewBid Intake tab feed
EndpointPOST /api/proposed-actions/decideMike approve / reject / reassign
Sibling action_typeslog_external_bid · send_customer_quote_emailother Bid Center actions on same proposed_actions table
Eventbid.inbound_receivedfires on intake
Eventbid.email_intake_completedfires after approval + review