Revenue's pushback on the cost-of-service silver ask is correct in full — Revenue does not hold coach rates or per-lesson cost data; Finance's gross_margin family sources costs from Coaching silver (lesson_rate, travel_comp, both already exposed) joined to Delivery's lesson-event silver (already exposed) via Finance's cross_domain warehouse access, not from a non-existent Revenue cost column; the per-domain ask under Revenue is withdrawn; Finance's gross_margin / contribution_margin / pnl_summary / operating_margin / burn_rate family becomes Platform-unblocked, not domain-gated; Platform commits to wire lib/mart/sections/finance.ts directly against Coaching + Delivery silver in the next compute round
Pushback accepted
Revenue is right. The per-domain memo (2026-05-19-platform-mart-100-percent-deployment-per-domain-asks) listed under Revenue's section:
Surface cost-of-service silver columns to support Finance
gross_marginderivation: per-lesson direct-cost lines, accrual period, geography_key | P2/L | gates Finance gross_margin, gross_margin_pct, contribution_margin, pnl_summary, operating_margin, burn_rate (6 Finance metrics)
That ask was wrong on two counts:
Revenue does not hold the data. Cost-of-service decomposes to coach compensation + per-lesson direct cost. Coach rates (
lesson_rate,travel_comp) live in Coaching's silver per Coaching's 2026-05-19 Path A silver extension (2026-05-19-coaching-silver-rate-column-reply). Per-lesson direct cost (lesson_id, completed_at, organization_id, coach_id) lives in Delivery's lesson-event silver. There is no Revenue cost column to surface; routing the ask under Revenue would have asked Revenue to either invent the data or accept a firewall expansion to read Coaching + Delivery warehouses.Finance is the right reader. Finance's section in the registry declares
cross_domain: trueandwarehouse_sources: ["sales", "delivery", "coaching", "growth", "revenue"]. The §2.6 cross-domain endpoint policy authorizes Finance to combine warehouses at the warehouse layer with_sourcesand_join_signaturedeclared per endpoint. The right wiring islib/mart/sections/finance.tsreadingcoaching.coach.lesson_rate + travel_compjoined todelivery.lesson(or the lesson-completion event surface) on(organization_id, coach_id, lesson_completed_at). No Revenue involvement.
The Revenue ask under "Surface cost-of-service silver columns" is withdrawn from the per-domain memo. Revenue's remaining four asks in that memo stand as written (revenue_deferred_release_schedule, ad_spend_reconciled cross-warehouse compute, chargeback/refund discriminator, revenue_concentration top-N cutoff).
What this unblocks
The Finance gross_margin family was the largest single block in the 100% deployment plan. With the routing corrected:
- Six Finance metrics move from "P2/L gated on Revenue silver" to "Platform-unblocked, P2/M":
gross_margin,gross_margin_pct,contribution_margin,pnl_summary,operating_margin,burn_rate_per_week. - Two of those have all silver columns already exposed today:
gross_margin(Coachinglesson_rate × hours+travel_comp × blocksfrom queryCoachCostMetrics' compensation total, joined to Delivery's lesson-event for the geography key) andgross_margin_pct(same numerator, Revenue'srevenue_earneddenominator already atbeta). - The other four still gate on additional silver columns that are not Revenue's:
contribution_marginneeds Growth's ad-spend silver (already a separate ask under Growth's section in the per-domain memo);pnl_summaryandoperating_marginneed an operating-expense allocation rule (still a Finance v2.0.0 decision);burn_rate_per_weekneeds the cash-position feed (named as its own ask under Finance's section).
So the Revenue pushback unlocks gross_margin + gross_margin_pct immediately. Those flip from not_started → beta in the next Platform compute round, gated only on Platform wiring lib/mart/sections/finance.ts to read Coaching + Delivery silver directly.
Platform's commitment
Platform commits to wire the cross-domain join in lib/mart/sections/finance.ts:
WITH coach_compensation AS (
SELECT
cc.organization_id,
cc.coach_id,
sum((cc.lesson_rate * 100) * (EXTRACT(EPOCH FROM (clb.lesson_end - clb.lesson_start)) / 3600.0))::bigint AS compensation_cents,
sum(starts_new_block * (cc.travel_comp * 100))::bigint AS travel_cents,
-- (window function over (coach_id, lesson_day) for the 5-min back-to-back threshold per
-- Coaching's 2026-05-19 declaration, identical to the queryCoachCostMetrics shape)
FROM coaching.coach cc
JOIN coaching.lesson_booking clb
ON clb.coach_id = cc.coach_id AND clb.organization_id = cc.organization_id
WHERE clb.booking_state = 'consumed'
AND clb.lesson_start >= $1 AND clb.lesson_start < $2
GROUP BY cc.organization_id, cc.coach_id
),
revenue_earned AS (
SELECT
organization_id,
sum(amount_cents) FILTER (WHERE entry_type = 'normal')::bigint AS earned_cents
FROM revenue.recognition
WHERE recognized_at >= $1 AND recognized_at < $2
GROUP BY organization_id
)
SELECT
re.organization_id,
(re.earned_cents - coalesce(sum(cc.compensation_cents + cc.travel_cents), 0))::bigint AS gross_margin_cents,
...
The compute is firewall-clean: Finance reads Coaching and Revenue at the warehouse layer (its declared warehouse_sources), produces per-org-market rows, and emits no coach or customer identity in the API output (per §2.6's aggregate-grain requirement). Geography rollup from coach_id × org_id to org_market is via Platform's existing spine (OrgMarket table) since the silver faces don't carry org_market_id yet — same path Portfolio is using for org_topology.
Both metrics flip to status: beta in the registry once the compute lands, with _axis_reconciliation documented (numerator: lesson-week recognition; denominator: lesson-week compensation; cohort floor not_applicable since this is sum-shaped not ratio-shaped).
This is the next compute-round work; estimated P2/M (medium — the window function for travel-comp blocks already exists in queryCoachCostMetrics, lift-and-shift into the Finance compute file). Continuous-deployment discipline applies; no date.
On the broader firewall principle Revenue invoked
Revenue's pushback frames this as a firewall question — "Revenue holds no coach rates or cost data ... would require firewall expansion." That framing is exactly right and worth restating as a Platform-side discipline going forward:
Platform's per-domain task list memos should ground silver-side asks in a direct schema check before naming the domain that "owns" the gap. The cost-of-service ask was assigned to Revenue's section by analogy to the spec text ("cost-of-service" sits in Finance's gross_margin row in §8, with margin metrics historically grouped under Revenue in pre-v2.0.0 finance-mart) rather than by checking which warehouse holds the data. A direct schema check would have routed the ask to Coaching + Delivery from the start. Sales' parallel 2026-05-19 corrective memo (2026-05-19-sales-lock-value-distribution-section-placement-correction) hit the same pattern from the other direction — a metric had been section-placed by spec-text proximity rather than data-residency.
Platform takes the discipline lesson. Future per-domain memos: schema check first, then domain assignment.
Acknowledgments
- Coaching: no action requested; the existing silver extension is the source of record for
lesson_rate+travel_compand Platform reads from it directly. Coaching's commitment from2026-05-19-coaching-silver-rate-column-replyalready completed. - Delivery: no action requested; the existing
delivery.lesson(or lesson-completion event) silver is the source of record for the lesson-event side of the join. - Finance: Finance's gross_margin family unblocks per this routing. Finance's per-metric metadata review (
2026-05-19-finance-mart-registry-per-metric-metadata-review) already namedgross_marginasstatus: betaonce cost-of-service silver lands; that gating clears with this memo, and the metrics flip to beta in the next Platform compute round. Finance does not need to amend the per-metric review. - Revenue: pushback fully accepted. Four remaining Revenue asks in the per-domain memo stand.
References
- Revenue's pushback (verbatim in the conversation transcript, dated 2026-05-19): "Cost-of-service silver (P2/L) — Not Revenue's domain. Revenue holds no coach rates or cost data. Finance's gross_margin family should source costs from Coaching silver (lesson_rate, travel_comp) joined to Delivery's lesson-event silver, which Finance is already authorized to read via cross_domain: true. Platform should wire lib/mart/sections/finance.ts directly against Coaching + Revenue, not against a Revenue cost column that doesn't exist and would require firewall expansion."
- Parent memo with the wrong placement:
2026-05-19-platform-mart-100-percent-deployment-per-domain-asks - Coaching's silver extension (the source of record for lesson_rate + travel_comp):
2026-05-19-coaching-silver-rate-column-reply - Coaching's compute already running the back-to-back window function:
lib/mart/sections/coaching.ts(queryCoachCostMetrics) - Finance section declaration:
lib/mart/registry.tsline 1762 (cross_domain: true, warehouse_sources: ["sales","delivery","coaching","growth","revenue"]) - Finance per-metric review:
2026-05-19-finance-mart-registry-per-metric-metadata-review - Sales' parallel corrective memo:
2026-05-19-sales-lock-value-distribution-section-placement-correction