Sales & Market Projection Architecture

Companion to: docs/architecture/QC_PROJECTION_ARCHITECTURE_2026-05-18.md (same shape, different domain). Source strategy: docs/product/FIN_DATA_SIGNAL_OFFERINGS_2026-05-15.md (B-1/B-2/B-3/B-4 offerings). Source catalog: docs/projections/PROJECTION_CATALOG_2026-05-15.md §6.1 + §6.2.


0. TL;DR

Every sales / market / pricing event ripples into 5 vault MDs + 4 JSONB projections + ~6 backlink edges. The substrate is mostly built (15 signal.* subtypes live, 3 historical importers shipped, 5 JSONB projections existing); the gap is the vault MD projector family that fuses the signals into agent-readable + human-readable + buyer-actionable digests. The vault MD is the primary read/UI surface; JSONB projections are the computation layer, and CardSpec/tool cards are embedded widgets, diagnostics, drilldowns, or fallback surfaces.

inbound source                        signal.* events emitted
─────────────────────────────────────────────────────────────────
Teams: Joshua "Sunday Night Update"   signal.market_chatter (per commodity section)
Teams: Keith / Mike / David           signal.price_observation
Teams: Paul / Frank / Adam            signal.market_chatter
Teams: Gerard / Tim / Tommy (NEW)     signal.price_observation (after author-route fix)
intel@: Hunts Point / Gary Blair      signal.price_observation + signal.market_chatter
arrivals@: PP daily sales report      signal.pp_arrival_logged + sales.report_ingested
arrivals@: PP daily inventory snap    inventory.snapshot
PO + commodity-fulfillment events     sales.order_created, sales.order_fulfilled,
                                      sales.order_rejected, invoice.generated,
                                      payment.received
                  │
                  ▼
   ┌──────────────────────────────────────────────┐
   │  4 JSONB projections (event-driven, replay)  │
   │  - market_signal_rollup (NEW)                │
   │  - po_timeline_projection (NEW)              │
   │  - customer_commodity_matrix (NEW)           │
   │  - daily_inventory_snapshot_projection (EXT) │
   └──────────────────────────────────────────────┘
                  │
                  ▼
   ┌──────────────────────────────────────────────┐
   │  5 vault MDs (rung 3 tenant projectors)      │
   │  - daily_sales_situation                     │
   │  - customer_situation_brief.<customer_id>    │
   │  - po_intelligence.<po_id>                   │
   │  - sight_picture.weekly                      │
   │  - vendor_scorecard.<vendor_id>              │
   └──────────────────────────────────────────────┘
                  │
                  ▼
       doc_backlink_projection edges
       (~6 per event: commodity, vendor, customer, po, lot, region)

0.5 Central-overlay reads contract (3-rung taproot — see AOL §13.6)

Every projector in this family is a rung-3 tenant overlay renderer. Each one reads tenant operational data (rung-3 inputs) AND reads Central knowledge MDs mirrored under _taproot_mirror/ (rung-1 outputs synced via rung-2 transport). The fusion happens at the projector rendering layer — NOT only at the agent surface via get_entity_profile.

Per Sales & Market projector:

ProjectorCentral MDs read from _taproot_mirror/Why
daily_sales_situationdocs/commodities/<slug>.md (top 20), docs/regions/<slug>.md (origin regions in play today)“What’s the broader market doing on these commodities today” baseline for §4 market context
customer_situation_briefdocs/commodities/<slug>.md (customer’s typical commodities), docs/commodity-situations/<slug>/<year-week>.md (Plane 3 — when federation lights up)Forward-look advisories use Central commodity_situation; frozen today but read path stubbed for activation
po_intelligencedocs/commodities/<slug>.md (per commodity on PO), docs/vendors/<slug>.md (PO’s vendor), docs/grower-profiles/<slug>.md (when populated)“What this vendor normally delivers for this commodity” baseline + grower terminus for upstream chain
sight_picture.weeklydocs/commodities/<slug>.md (top 20), docs/regions/<slug>.md, docs/region-outlooks/<slug>/<year-week>.md (Plane 3 — frozen), GM docs/decisions/ (Joshua Sunday Night Update from Central if cross-mirrored)THE 3-layer formula’s “public KB context” layer (§3 of the sight-picture output) is entirely Central reads
vendor_scorecarddocs/vendors/<slug>.mdCentral vendor MD is the canonical cross-tenant view; tenant overlay adds Nathel-specific reliability/quality/payment on top

Read graceful-degradation contract: if a _taproot_mirror/ MD is missing (mirror not yet synced or entity not in Central), the projector MUST render the tenant overlay alone with a central_pending: true flag in frontmatter + a sources_missing[] array listing which Central reads degraded. Never block.

Write contract: projectors write to tenant paths (docs/sales/...) only. Never write to _taproot_mirror/ (that’s rung-2’s space).

Federation-readiness note: the customer_commodity_matrix JSONB (§2.3) is tenant-private always; only a downstream anonymized aggregator (B-4 Demand Pattern Intelligence offering) writes to Central — and only after federation lights up. The projectors in this family DO NOT federate.


0.6 MD-first read contract

Sales, market, and pricing workflows follow the intranet projection standard:

  1. Events are the source-of-truth write plane.
  2. JSONB projections compute replayable state, rollups, and fast joins.
  3. Vault MD projections are the default agent/operator read surface.
  4. CardSpec components, including VendorQuoteSignal, render inside MD/workflow surfaces or serve as drilldown, diagnostic, or fallback views.
  5. Direct MCP tools may feed projectors or support fallback inspection, but they should not be the primary answer path when a fresh MD projection exists.

Acceptance proof for this family therefore requires MD frontmatter inspection (source_events[], source_artifacts[], content_hash, projection_version, renderer_version, freshness/citation metadata), pixel proof of the MD/workflow surface, click proof of source drilldowns, and backend inspection of the JSONB/event inputs. Each MD projection must also expose machine-readable agent_evidence chunks so the harness can cite compact, stable evidence units instead of parsing long markdown bodies. A standalone CardSpec proof proves the data path, not final market/pricing UX.


1. Vault MD projectors (rung 3)

All 5 follow the QC arch §1 pattern: pure renderer + tenant-projector orchestrator + injectable deps. Output paths under nathel-intranet:docs/sales/ mirror the QC docs/qc/ layout. All read both tenant operational data AND Central MDs per §0.5.

1.1 daily_sales_situation

  • doc_kind: event_digest
  • audience: operator agent + employee (sales role) + employee (executive role)
  • cadence: daily 06:00 tenant-local + on-demand refresh
  • path: nathel-intranet:docs/sales/daily/<YYYY-MM-DD>.md
  • sources:
    • PP daily sales report (sales.report_ingested event from arrivals@ today’s intake)
    • Open orders (sales.order_created not yet sales.order_fulfilled)
    • Customer rejections (sales.order_rejected in last 24h)
    • signal.price_observation from yesterday (internal Nathel + Hunts Point)
    • signal.market_chatter from yesterday (Joshua + buyers + intel@)
    • signal.availability_observation from yesterday
  • output shape:
    • Section 1: yesterday’s sales snapshot (units / dollars / margin by commodity)
    • Section 2: today’s open commitments + fill-rate forecast
    • Section 3: attention list (orders at risk, declining-fill customers, vendor shortfalls)
    • Section 4: market context (yesterday’s price observations + GM commentary)
    • Section 5: suggested outreach (3 customers to call, 2 vendors to verify)

1.2 customer_situation_brief.<customer_id>

  • doc_kind: portal_page
  • audience: operator agent + employee (sales) + customer (filtered self-view via portal)
  • cadence: weekly Friday 16:00 customer-local
  • path: nathel-intranet:docs/sales/customers/<customer_slug>/<YYYY-WW>.md
  • sources:
    • customer_360_projection (already live)
    • This customer’s order history (sales.order_* events) last 12 weeks
    • customer_commodity_matrix projection (NEW — see §2.3)
    • Forward-looking commodity availability (commodity_360 + supply_chain_position)
    • Public Harvest Directory commodity_situation for their typical commodities
  • output shape:
    • Their typical week-N order pattern + this week’s variance
    • Commodities they bought last quarter but not this quarter (substitution risk)
    • Forward look: 2-week outlook on their primary commodities
    • Their fill-rate trend (last 12 weeks line chart)
    • Suggested outreach (when their pattern says they should be ordering but haven’t)
  • customer-facing variant (audience=customer):
    • Strip cost basis, vendor identity, margin, internal commentary
    • Show only: their orders, their delivery status, forward-look advisories, “ask your account rep”

1.3 po_intelligence.<po_id>

  • doc_kind: event_digest
  • audience: operator agent + employee
  • cadence: event-driven on any event carrying this po_id
  • path: nathel-intranet:docs/sales/po/<po_id>.md
  • sources:
    • Every event with this po_id (per project_po_is_the_spine memo’s 5 intelligence dimensions)
    • Cross-referenced lots (lot.received linked via load_id)
    • Cross-referenced invoices (invoice.generated)
    • Vendor label parses from QC photos (signal.vendor_label_observed — feeds from QC architecture B1 parser sibling)
    • Vendor label mismatches (signal.vendor_label_mismatch)
    • Reconcile-inbound-load tool outputs
  • output shape:
    • PO timeline (chronological strip)
    • Linked lots (rolled up: # cases per commodity per vendor)
    • Linked invoices + payment status
    • Vendor label evidence chain (GTIN + harvest date + origin + pack date verified from photo)
    • Exceptions (label mismatches, quality fails, missing shipments, temperature exceptions)
    • Expected vs actual position (variance breakdown)
    • Provenance walk available to agent for “show me the photo Glenn took on this lot”

1.4 sight_picture.weekly

  • doc_kind: event_digest
  • audience: operator agent + FIN operator + employee (executive role)
  • cadence: weekly Friday 14:00 tenant-local
  • path: nathel-intranet:docs/sales/sight-picture/<YYYY-WW>.md
  • sources:
    • PO + sales + inventory projections (3-layer formula per project_sight_picture_formula memo)
    • Cross-tenant Hunts Point market intel (signal.market_chatter + signal.price_observation from intel@)
    • GM strategy memo (most recent Joshua “Sunday Night Update”)
    • Public Harvest Directory commodity_situation for tenant’s top 20 commodities
    • supply_chain_position_projection (current substrate)
  • output shape:
    • Section 1: this week’s operational outcomes (PO delivery, sales fill, inventory turn)
    • Section 2: organizational coordination (which crews / which doors / which exceptions)
    • Section 3: public KB context (what the wider market did this week per Hunts Point + GM read)
    • Section 4: forward look (next 2 weeks of expected arrivals + outbound demand)
    • Section 5: executive summary (3-bullet leadership read)
    • Embedded: multi-commodity chart (price trend + fill rate + inventory turn)

1.5 vendor_scorecard.<vendor_id> (vault MD form)

  • doc_kind: entity_profile (entity_type: vendor)
  • audience: FIN operator + employee (procurement) + vendor (filtered self-view)
  • cadence: monthly snapshot 1st of month 06:00 + live updated on vendor-related events
  • path: nathel-intranet:docs/sales/vendors/<vendor_slug>/<YYYY-MM>.md
  • sources:
    • vendor_360_projection (already live)
    • lot.received from this vendor + qc.failed/qc.passed filtered by vendor
    • signal.temperature_exception filtered by vendor
    • signal.vendor_label_mismatch filtered by vendor (NEW from QC photo path)
    • Payment history (invoice.generated + payment.received)
    • GM commentary mentioning vendor (signal.market_chatter filtered by vendor_raw)
    • Comms history extracts (operational_memory keyed by vendor)
  • output shape:
    • Vendor reliability score (composite: on-time + quality + label-accuracy + payment-terms)
    • Defect rate trend (line chart) + label-mismatch rate (line chart, NEW from QC integration)
    • Commodity mix (bar chart)
    • Notable incidents (recent significant defects, label mismatches, comm issues)
    • Payment terms summary
    • Eventually feeds B-3 federation when multi-tenant
  • vendor-facing variant (audience=vendor):
    • Strip other vendors’ data, strip margin, strip customer-specific complaint detail
    • Show only their own lots, their own QC outcomes, their own payment status

2. JSONB projections (event-driven, replayable)

2.1 market_signal_rollup (NEW)

  • migration: 069_market_signal_rollup_projection.sql
  • schema: tenant_id × commodity_id × vendor_id × region_id × week → { observations[], price_band, sentiment_distribution, sample_count }
  • source events: signal.market_chatter, signal.price_observation, signal.vendor_quote_observed, signal.availability_observation
  • replay command: pnpm cli replay-projection --projection=market_signal_rollup --tenant=<tenant_id>
  • RLS: required
  • fed-by: event-handlers/projection-market-signal-rollup.ts (NEW)
  • consumed-by: daily_sales_situation renderer + sight_picture.weekly renderer + commodity_situation.<x>.<year-week> (Plane 3, frozen until multi-tenant)

2.2 po_timeline_projection (NEW)

  • migration: 070_po_timeline_projection.sql
  • schema: tenant_id × po_id → { events_chronological[], linked_lots[], linked_invoices[], vendor_label_evidence[], exceptions[], variance_summary }
  • source events: ALL events carrying a po_id discriminator (per spine memo)
  • replay command: pnpm cli replay-projection --projection=po_timeline_projection --tenant=<tenant_id>
  • RLS: required
  • fed-by: event-handlers/projection-po-timeline.ts (NEW)
  • consumed-by: po_intelligence.<po_id> renderer

2.3 customer_commodity_matrix (NEW — Robert’s matrix)

  • migration: 071_customer_commodity_matrix_projection.sql
  • schema: tenant_id × customer_id × commodity_id → { weekly_order_volume[], weekly_fill_rate[], preference_score, substitution_history[], price_sensitivity_band, last_order_at, frequency_pattern, lifetime_dollars }
  • source events: sales.order_created, sales.order_fulfilled, sales.order_rejected, sales.report_ingested (PP daily) + customer_360_projection
  • replay command: pnpm cli replay-projection --projection=customer_commodity_matrix --tenant=<tenant_id>
  • RLS: required
  • fed-by: event-handlers/projection-customer-commodity-matrix.ts (NEW)
  • consumed-by:
    • customer_situation_brief.<customer_id> renderer (§1.2)
    • ChartCard on customer drill-through (workspace)
    • B-4 “Demand Pattern Intelligence” offering when multi-tenant (anonymized aggregate)
    • Proactive outreach trigger: weekly cron compares last 12-week pattern → if missing this week’s expected order, fires actor_pulse.outreach_suggested

2.4 daily_inventory_snapshot_projection (extension)

  • migration: existing (per IAR-RM-036) — extend with reconciliation diff materialization
  • schema additions: tenant_id × snapshot_date → { snapshot_rows[], diff_from_prior_day[], reconciliation_status, missing_lots[], unexpected_lots[] }
  • source events: inventory.snapshot (PP daily) + lot.received + sales.order_fulfilled + outbound shipments
  • replay command: pnpm cli replay-projection --projection=daily_inventory_snapshot_projection --tenant=<tenant_id>
  • fed-by: existing handler + extension for diff materialization
  • consumed-by: daily_sales_situation renderer + sight_picture.weekly renderer

3. Inbound sources (the EIF fan-in)

SourcePath todayRoutes toGap
Teams: QC inspectors (Glenn / Anthony / Pedro / IR Ops)teams-chat-importer.ts + qc-narrative-importer.ts (live + historical)signal.quality_observationnone — covered by QC arch §1
Teams: GM strategy (Joshua Gatcke)gm-memo-importer.ts (per-commodity section extraction)signal.market_chatternone — already correctly routed
Teams: salesman pricing (Keith / Mike Donovan / David Frangiosa)author-routing.ts closed mapsignal.price_observationnone
Teams: buyer commentary (Paul Milito / Paul Memoli / Frank Fuentes / Adam Cohen)author-routing.ts closed mapsignal.market_chatternone
Teams: UNMAPPED internal pricing (Gerard Milito / Tim Gagliano / Tommy Cifu)falls to signal.teams_message raw archive(no structured extraction)GAP A — extend author-routing.ts
Teams: DM threads (blank-channel)importer may skip(lost)GAP B — extend channel-kind filter to include DMs
intel@: Hunts Point / Gary Blair pricing reportshunts-point-market-importer.ts (historical only)(no live consumer)GAP C — add EIF S0.5 classifier route + live consumer
intel@: other external market intelclassifier today routes to raw extractorsignal.market_chatter (generic)optional refinement post-Gap C
arrivals@: PP daily sales reportimport-pp-data.ts + arrivals classifiersales.report_ingested + signal.pp_arrival_loggedlive (per IAR-RM ledger)
arrivals@: PP daily inventory snapshotimport-pp-data.ts + arrivals classifierinventory.snapshotlive (per IAR-RM-036) — extend with reconciliation diff (§2.4)
QC photos: vendor label parses(running in user’s other session: B1 vendor-label parser)signal.vendor_label_observed + signal.vendor_label_mismatch (NEW additive subtypes)(in progress)

Before this family scales, intel@ sources must be governed by a closed classification taxonomy: source class, sender/domain rule, subject/body rule, expected artifact types, extractor route, terminal state, freshness class, source license/class, confidence, downstream consumer, and backlog owner when the terminal state is not extracted. The same discipline applies to Produce Pro reports: every high-value report field must have a downstream use or a deliberate parked/not-used rationale before it is treated as complete ingestion.

Gap A — Author-routing extension (Gerard / Tim / Tommy)

Closed-vocab additions to packages/mcp-server/src/ingestion/historical/author-routing.ts:

{ email: "gerard@nnproduce.net", display: "Gerard Milito", poster_role: "salesman", signal_subtype: "signal.price_observation", default_body_kind: "morning_pricing_read", inspector_voice_profile: null, expected_count_v10: 1 },
{ email: "tim@nnproduce.net", display: "Tim Gagliano", poster_role: "salesman", signal_subtype: "signal.price_observation", default_body_kind: "morning_pricing_read", inspector_voice_profile: null, expected_count_v10: 1 },
{ email: "tommy@nnproduce.net", display: "Tommy Cifu", poster_role: "salesman", signal_subtype: "signal.price_observation", default_body_kind: "morning_pricing_read", inspector_voice_profile: null, expected_count_v10: 1 },

Confirm emails — corpus shows display names; verify actual UPNs via a Teams admin probe before merging.

Sample bodies (from corpus) that should be extracted into per-commodity signal.price_observation rows:

Gerard Milito: "Anise $45 / Beans FLS $32 / Bunch broccoli $42-45 / Almost so..." (5+ commodities × 1 price each → 5+ events)

Tim Gagliano: "Anise $45 steady / Beans $50 on the 5 bros / Broccolini $50 around / Cabbage $20-22 / Red $24" (5+ commodities × 1 price each → 5+ events; “steady” → sentiment=“flat”)

The body-section parsing pattern is the same shape as gm-memo-importer.ts — commodity-emoji-prefix style or commodity-then-dollar-amount inline. Reuse extractPriceObservationFromMorningRead() as a new pure function in historical/ (or its live/ sibling).

Gap B — DM-thread (blank-channel) handling

The v10 corpus has 23 messages with empty channel_name. These are 1-on-1 DM threads — currently dropped by the importer’s channel filter. Action:

  • Add channel_kind: "teams_dm" discriminator
  • Importer accepts both teams_channel and teams_dm kinds
  • DM-thread messages keep author-routing logic but stamp data.delivery_context: "direct_message" for audience filtering downstream

Gap C — Hunts Point / Gary Blair live consumer (spawned as separate chip)

The historical importer (hunts-point-market-importer.ts) has a pure-function core that takes the report body and emits per-commodity events. Wrap that core in:

  1. EIF S0.5 classifier rule: body_kind = hunts_point_market_report when sender domain = Gary Blair’s known domain + subject pattern matches
  2. New consumer file event-handlers/intel-hunts-point-live-consumer.ts that calls the pure core on each email.received event with this classification
  3. Emits signal.price_observation + signal.market_chatter with data.source = hunts_point_market_report + data.source_url = <r2://intel-attachments/...> for provenance

Approximately 1.5 days standalone; spawn as a chip separate from this arch doc.


4. Native comms integration

SurfaceWhere Sales & Market projections land
Sales role Work Threads raildaily_sales_situation becomes a daily-pinned MD-first thread per project_qc_rail_eq_queue analog pattern; customer_situation_brief.<customer_id> becomes per-customer thread; pricing cards render as embedded/drilldown widgets
Buyer role railpo_intelligence.<po_id> becomes per-PO thread; sight_picture.weekly becomes pinned exec thread
GM/Exec role railsight_picture.weekly pinned; full vendor scorecard rollup pinned monthly
SlackDaily sales situation digest posted to #sales-ops Slack at 06:30 tenant-local; sight_picture weekly posted to #leadership Friday 14:30
Email digestcustomer_situation_brief emails the customer’s primary contact Friday 16:00 (customer-facing variant only)
Voice / SMSPer actor_pulse.outreach_suggested trigger from customer_commodity_matrix: SMS the salesman “Joe usually orders X by now; call him?“

5. Frontmatter contract

Every projector MUST emit MDs with this frontmatter (mirrors QC arch §5 exactly so doc_backlink_projection works without renderer-specific handling):

---
schema_version: 1
doc_id: <projector-output-doc-id>      # e.g. sales_daily_situation_2026_05_18
doc_kind: event_digest | portal_page | entity_profile
title: <human-readable>
slug: <kebab-case>
source_attribution:
  - producer:<projector-name>           # e.g. producer:daily_sales_situation
  - source_events:<comma-separated event_ids that drove this render>
  - source_projections:<comma-separated projection rows>
lifecycle_status: active
created_at: <iso>
updated_at: <iso>
maintained_by: <projector-name>
visibility: company | customer_visible | restricted
data_plane: relationship_data
linked_entities:                        # P0-12 contract — drives doc_backlink_projection
  - { type: commodity, slug: <slug> }
  - { type: vendor, slug: <slug> }
  - { type: customer, slug: <slug> }
  - { type: po, id: <po_id> }
  - { type: lot, id: <lot_id> }
  - { type: region, slug: <slug> }
tags: [sales, market, ...]
agent_evidence:
  projection_version: <semver>
  renderer_version: <semver-or-git-sha>
  content_hash: <sha256>
  chunks:
    - chunk_id: <stable-doc-section-id>
      chunk_hash: <sha256>
      title: <section-title>
      freshness_class: operational_daily | pricing_intraday | curated_reference
      citation_tier: operational | citable | background
      role_scope: [sales, buyer, executive]
      source_events: [<event_id>]
      source_artifacts: [<artifact_uri>]
      source_projection_rows: [<projection-row-ref>]
---

The linked_entities array is THE thing that makes drill-through work — every commodity / vendor / customer / PO mentioned in a projector output becomes a clickable backlink in the agent surface.

The agent_evidence block is THE thing that makes the same MD performant for the harness. It gives retrieval, citation verification, freshness checks, and role filtering stable units without requiring the agent to infer evidence boundaries from rendered prose.


6. Build sequence

Mirrors QC arch §6 (Q1/Q2/Q3/Q4 → S1/S2/S3/S4 for Sales):

Sequence S1 — 4 JSONB projections (~2-3 days)

Build in parallel as 4 chip tasks. Each follows the QC event-handlers/projection-<name>.ts pattern:

  • S1-A market_signal_rollup (migration 069 + handler + dispatcher registration + test)
  • S1-B po_timeline_projection (migration 070 + handler + dispatcher registration + test)
  • S1-C customer_commodity_matrix (migration 071 + handler + dispatcher registration + test)
  • S1-D daily_inventory_snapshot_projection (extension only — handler addition for diff materialization)

Sequence S2 — 5 vault MD renderers (~3-4 days)

Build in parallel as 5 chip tasks. Each follows the QC workers/tenant-projector/<name>.ts pattern (pure renderer + GitHub Contents API writer + orchestrator with injectable deps):

  • S2-A daily_sales_situation (06:00 cron + reads market_signal_rollup + writes docs/sales/daily/)
  • S2-B customer_situation_brief (Friday 16:00 cron + reads customer_commodity_matrix + writes docs/sales/customers/)
  • S2-C po_intelligence (event-driven on po_id-tagged events + reads po_timeline_projection + writes docs/sales/po/)
  • S2-D sight_picture.weekly (Friday 14:00 cron + reads market_signal_rollup + supply_chain_position + writes docs/sales/sight-picture/)
  • S2-E vendor_scorecard (monthly cron + event-driven updates + reads vendor_360 + writes docs/sales/vendors/)

Sequence S3 — Author-routing + DM-thread extension (~1 day)

Single chip:

  • S3-A Extend author-routing.ts with Gerard / Tim / Tommy entries + verify UPNs; extend importer to accept teams_dm channel_kind; backfill v10 corpus’s 23 DM messages + 3 unmapped author messages; emit per-commodity signal.price_observation events

Sequence S4 — Intel@ Hunts Point / Gary Blair live consumer (~1.5 days)

Single chip (separate from this arch doc spawn):

  • S4-A EIF S0.5 classifier rule + live consumer file + provenance attachment storage

Sequence S5 — Agent surface + UI (~2 days)

  • S5-A Add get_sales_situation, get_customer_situation, get_po_intelligence, get_sight_picture, get_vendor_scorecard MCP tools (read the vault MDs + JSONB projections)
  • S5-B Wire Sales / Buyer / Exec role catalogs to include these tools
  • S5-C Customer × Commodity matrix ChartCard on customer drill-through
  • S5-D Sales role rail integration (daily_sales_situation pinned)

7. Coordination with other arch docs

Other arch docSales & Market dependency
QC Projection Architecture (2026-05-18)Reads QC photo signal.vendor_label_observed + signal.vendor_label_mismatch events from the B1 vendor-label parser (running in user’s other session) into po_timeline_projection (§2.2) and vendor_scorecard (§1.5)
Recall & Proof Projection Architecture (forthcoming)Uses po_timeline_projection as the chronological evidence backbone; uses vendor_scorecard + vendor_label_mismatch rollups as evidence of due-diligence; uses customer_commodity_matrix to determine recall reach
Agent Audit Projection Architecture (forthcoming)Tags agent sessions with the Sales & Market tools they invoked (get_sales_situation, get_customer_situation, etc.) for replay

8. Open questions

IDQuestionDefault until answered
SM-Q1Should customer_situation_brief customer-facing variant ship before Wave 3 customer portal goes live?No — render only the company-internal variant until portal lands; customer variant gated on portal
SM-Q2Daily PP sales report cadence: 6 AM render reads yesterday’s 3 PM rollover, or wait for today’s 3 PM and render at 4 PM?6 AM — aligns with operator morning-briefing pattern; matches project_pp_day_rollover semantics
SM-Q3customer_commodity_matrix outreach trigger window — when does “haven’t ordered” become “should call”?Default: customer’s median inter-order interval × 1.5; configurable per-customer in actor.memory
SM-Q4sight_picture.weekly Friday 14:00 vs 16:00 — leadership wants pre-weekend or post-weekend planning?14:00 — gives leadership 2h to digest before EOW; matches PP day rollover semantics
SM-Q5Should Gerard / Tim / Tommy DM-thread routing emit a data.audience_inferred: "private_internal" tag to suppress federation?Yes — DM threads are internal-Nathel only; federation publisher MUST drop these even when multi-tenant lights up
SM-Q6vendor_scorecard vendor-facing variant: shipped now (Wave 2) or deferred to vendor portal (Wave 5+)?Deferred — company-internal scorecard only until vendor portal lands
SM-Q7market_signal_rollup JSONB schema — pre-compute price_band percentiles or compute on read?Pre-compute on insert; replay handles backfill

9. Productization mapping (FIN_DATA_SIGNAL_OFFERINGS coverage)

Offering (from strategy doc)Sales & Market projector this arch enables
B-1 Weekly Commodity Situation Briefs (999/mo)commodity_situation.<x>.<year-week> (Plane 3, frozen until multi-tenant) — but this arch’s market_signal_rollup is the substrate the Plane 3 projector will read when federation activates
B-3 Vendor Benchmarking ($2K/mo Tier 2+)vendor_scorecard.<vendor_id> (§1.5) anonymized aggregate when multi-tenant
B-4 Demand Pattern Intelligence ($1.5K/mo)customer_commodity_matrix (§2.3) anonymized aggregate when multi-tenant
B-5 Custom Reports (50K/report)po_intelligence + vendor_scorecard + customer_commodity_matrix joined ad-hoc
G-2 Supply Chain Resilience Signals (federal 2M/agency)market_signal_rollup (§2.1) + supply_chain_position_projection extended

This arch ships the tenant-side substrate for 5 of the 17 strategy doc offerings.


10. Sign-off

This arch is the canonical reference for any future Sales / Market / Pricing projection work. Future projectors in this family MUST cite this doc in their PR description. Cross-mirrored to fin-central-intranet:docs/architecture/SALES_MARKET_PROJECTION_ARCHITECTURE_2026-05-18.md.

claude_orchestrator (Opus 4.7 1M-context, session 7612a827-b892-47e3-86cd-08835737208e)