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:
| Projector | Central MDs read from _taproot_mirror/ | Why |
|---|---|---|
daily_sales_situation | docs/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_brief | docs/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_intelligence | docs/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.weekly | docs/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_scorecard | docs/vendors/<slug>.md | Central 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:
- Events are the source-of-truth write plane.
- JSONB projections compute replayable state, rollups, and fast joins.
- Vault MD projections are the default agent/operator read surface.
- CardSpec components, including
VendorQuoteSignal, render inside MD/workflow surfaces or serve as drilldown, diagnostic, or fallback views. - 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_ingestedevent from arrivals@ today’s intake) - Open orders (
sales.order_creatednot yetsales.order_fulfilled) - Customer rejections (
sales.order_rejectedin last 24h) signal.price_observationfrom yesterday (internal Nathel + Hunts Point)signal.market_chatterfrom yesterday (Joshua + buyers + intel@)signal.availability_observationfrom yesterday
- PP daily sales report (
- 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_matrixprojection (NEW — see §2.3)- Forward-looking commodity availability (commodity_360 + supply_chain_position)
- Public Harvest Directory
commodity_situationfor 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_spinememo’s 5 intelligence dimensions) - Cross-referenced lots (
lot.receivedlinked 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
- Every event with this po_id (per
- 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_formulamemo) - Cross-tenant Hunts Point market intel (
signal.market_chatter+signal.price_observationfrom intel@) - GM strategy memo (most recent Joshua “Sunday Night Update”)
- Public Harvest Directory
commodity_situationfor tenant’s top 20 commodities supply_chain_position_projection(current substrate)
- PO + sales + inventory projections (3-layer formula per
- 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.receivedfrom this vendor +qc.failed/qc.passedfiltered by vendorsignal.temperature_exceptionfiltered by vendorsignal.vendor_label_mismatchfiltered by vendor (NEW from QC photo path)- Payment history (
invoice.generated+payment.received) - GM commentary mentioning vendor (
signal.market_chatterfiltered 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_situationrenderer +sight_picture.weeklyrenderer +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_iddiscriminator (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_situationrenderer +sight_picture.weeklyrenderer
3. Inbound sources (the EIF fan-in)
| Source | Path today | Routes to | Gap |
|---|---|---|---|
| Teams: QC inspectors (Glenn / Anthony / Pedro / IR Ops) | teams-chat-importer.ts + qc-narrative-importer.ts (live + historical) | signal.quality_observation | none — covered by QC arch §1 |
| Teams: GM strategy (Joshua Gatcke) | gm-memo-importer.ts (per-commodity section extraction) | signal.market_chatter | none — already correctly routed |
| Teams: salesman pricing (Keith / Mike Donovan / David Frangiosa) | author-routing.ts closed map | signal.price_observation | none |
| Teams: buyer commentary (Paul Milito / Paul Memoli / Frank Fuentes / Adam Cohen) | author-routing.ts closed map | signal.market_chatter | none |
| 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 reports | hunts-point-market-importer.ts (historical only) | (no live consumer) | GAP C — add EIF S0.5 classifier route + live consumer |
| intel@: other external market intel | classifier today routes to raw extractor | signal.market_chatter (generic) | optional refinement post-Gap C |
| arrivals@: PP daily sales report | import-pp-data.ts + arrivals classifier | sales.report_ingested + signal.pp_arrival_logged | live (per IAR-RM ledger) |
| arrivals@: PP daily inventory snapshot | import-pp-data.ts + arrivals classifier | inventory.snapshot | live (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_channelandteams_dmkinds - 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:
- EIF S0.5 classifier rule:
body_kind = hunts_point_market_reportwhen sender domain = Gary Blair’s known domain + subject pattern matches - New consumer file
event-handlers/intel-hunts-point-live-consumer.tsthat calls the pure core on eachemail.receivedevent with this classification - Emits
signal.price_observation+signal.market_chatterwithdata.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
| Surface | Where Sales & Market projections land |
|---|---|
| Sales role Work Threads rail | daily_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 rail | po_intelligence.<po_id> becomes per-PO thread; sight_picture.weekly becomes pinned exec thread |
| GM/Exec role rail | sight_picture.weekly pinned; full vendor scorecard rollup pinned monthly |
| Slack | Daily sales situation digest posted to #sales-ops Slack at 06:30 tenant-local; sight_picture weekly posted to #leadership Friday 14:30 |
| Email digest | customer_situation_brief emails the customer’s primary contact Friday 16:00 (customer-facing variant only) |
| Voice / SMS | Per 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 + writesdocs/sales/daily/) - S2-B
customer_situation_brief(Friday 16:00 cron + reads customer_commodity_matrix + writesdocs/sales/customers/) - S2-C
po_intelligence(event-driven on po_id-tagged events + reads po_timeline_projection + writesdocs/sales/po/) - S2-D
sight_picture.weekly(Friday 14:00 cron + reads market_signal_rollup + supply_chain_position + writesdocs/sales/sight-picture/) - S2-E
vendor_scorecard(monthly cron + event-driven updates + reads vendor_360 + writesdocs/sales/vendors/)
Sequence S3 — Author-routing + DM-thread extension (~1 day)
Single chip:
- S3-A Extend
author-routing.tswith Gerard / Tim / Tommy entries + verify UPNs; extend importer to acceptteams_dmchannel_kind; backfill v10 corpus’s 23 DM messages + 3 unmapped author messages; emit per-commoditysignal.price_observationevents
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_scorecardMCP 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 doc | Sales & 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
| ID | Question | Default until answered |
|---|---|---|
SM-Q1 | Should 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-Q2 | Daily 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-Q3 | customer_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-Q4 | sight_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-Q5 | Should 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-Q6 | vendor_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-Q7 | market_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)