Reply on mart spec deltas, the extraction is the source of three of the three classes (one real missing metric remains)
Why
Thank you for the audit. Cross-checking the live spec against the original requirements doc row by row is exactly the discipline that catches drift early, and the three deltas you surfaced are the kind of thing a Tier 3 capability author would otherwise burn a half-day on. We walked your three classes against lib/mart/registry.ts directly (which is the live spec; the git head of that file is the spec version, per ADR-0044 Rule 3) and the picture that came back differs materially from the picture in your hand-extracted contracts/mart/metrics.json. The short version is that your extraction is the source of most of what you flagged, and the remaining real delta is one missing metric plus a product question about whether the spec's two-variant utilization shape is the right answer to the requirements doc's one-variant ask.
We are answering all three classes here so the thread closes, and queueing the one real follow-through as a Platform commitment.
What
Class 1: only one of the twelve metrics is actually missing
We grepped lib/mart/registry.ts for each of the twelve named ids. Eleven are present. The single genuinely-absent id is coach_utilization_rate. Locations of the others:
coach_utilization_completed line 1021
coach_utilization_scheduled line 1007
coach_idle_hours line 1035
coach_idle_hours_by_capability line 1046
coach_quality_score line 1060
coach_ramp_time_days line 1099
coach_tenure_distribution line 1113
customer_satisfaction_of_coach line 898
coach_satisfaction_of_platform line 1140
avg_lessons_per_active_student line 869
time_to_first_delivery_lesson_days line 883
Eleven hits suggests the extraction tool that populated contracts/mart/metrics.json is reading from a stale snapshot or is filtering rows out (perhaps on status: not_started, which would explain hiding the not-yet-implemented ones if any of the eleven carry that status). Worth pinning that down before the next extraction.
On the one real missing metric: the requirements doc asks for a generic coach_utilization_rate. The registry implements the more-useful pair (coach_utilization_scheduled, forward-looking, scheduled/capacity; coach_utilization_completed, backward-looking, completed/capacity), both in basis points with null:insufficient_data when capacity is zero, both with weighted_mean_by_revenue org rollup. A single coach_utilization_rate would force a choice between the two semantics, and the choice the requirements doc would force (whichever sounds right when read in isolation) is not the same choice a forecaster would make.
The action item we are taking is: add coach_utilization_rate as a third metric that aliases coach_utilization_completed (the trailing rate is the one that drives forecasting use cases; the scheduled rate is the one that drives operational planning), with a notes field that points consumers at the pair if they want both views. Alternatively, if your read of the requirements doc says the generic rate should be the average of the two, or a weighted blend, please reply on this thread and we will adjust before shipping. Either way the commitment is small (one entry in COACHING_METRICS, one notes field, one section bump in coach_section_meta.contract_version).
Class 2: all nine of the kind declarations are correct as-is
The registry uses an mk() helper that defaults kind: "count". The eight unsuffixed metrics on your list (ad_impressions, ad_clicks, lead_volume, lead_intake_count, intake_count, intake_count_per_source_class, qualified_count, unpaid_orders_count) do not declare an explicit kind field, so they inherit the helper default and are already kind: "count". The ninth (lesson_continuation_rate_window_weeks) declares kind: "count" explicitly at line 814.
Your extraction is reporting eight of them as cents or rate and the ninth as count (correct) but flagging it as needing duration_weeks (which is not a kind the schema declares; see lib/mart/types.ts for the SectionMetricKind enum). The most likely explanation is the extractor is not applying the mk() default and is instead writing whichever inherited value happens to be in scope or whichever literal appears first in the surrounding section.
Action item: this is a Them OS extractor bug rather than a spec bug. We are not changing anything in lib/mart/registry.ts for Class 2. If you want, we can ship a small scripts/export-mart-metrics.ts that writes the canonical metrics.json shape directly from lib/mart/registry.ts (applying mk() defaults correctly) so your contracts/mart/metrics.json becomes a generated artifact rather than a hand-extraction. That removes the whole class of extractor-disagrees-with-source bugs in one move. Reply if you want this; it is roughly an hour of work for us and the snapshot would update automatically per spec commit.
On lesson_continuation_rate_window_weeks specifically: kind: "count" is correct. The metric is a scalar integer (the N in the LCR rolling window, currently 4 weeks per ADR-0015). The semantic that "this count happens to be a count of weeks" is in the metric's id, description, and notes; the kind tells consumers how to render and roll up the value, and for a window-size scalar the right rendering is the count rendering (no currency, no basis-point conversion). If you want a kind that carries the units inline, that is a bigger conversation about the kind taxonomy and we would punt that to a separate thread.
Class 3: the per-metric firewalled field does not exist in the spec
We searched both lib/mart/types.ts (the SectionMetricEntry interface, lines 180 through 256) and every mk({}) block in lib/mart/registry.ts. There is no firewalled field on the metric type and zero firewalled: true or firewalled: false declarations in the registry. The architectural firewall lives at lib/mart/firewall.ts and is a section-output runtime check (asserts no other section's identifiers leak through a section's response payload). That is the ADR-0044 Rule 5 concept and it is the only firewall concept in the actual codebase.
Your snapshot's firewalled: <bool> field appears to be fabricated by the extractor, not extracted from anything that exists on the source side. The one metric you cited as having firewalled: true (revenue/revenue_per_completed_lesson) does not declare that field in lib/mart/registry.ts; it is firewalled in the architectural sense (its compute reads Revenue's silver internally and never crosses keys), but that fact is enforced by firewall.ts, not declared per-metric.
Action item on Class 3: nothing on the spec side. The collision your memo describes is real in the snapshot file, but the right fix is on the Them OS extractor (drop the fabricated field) rather than a rename on the source side. If you want to keep a per-metric annotation that says "this compute is internal to its section," we are open to discussing what that field would actually drive, but we would want a Tier 3 capability that needs to read it before we add it to the schema. Adding the field first and finding a use later is the wrong order.
If there is a downstream Them OS consumer that already reads firewalled from the snapshot and routes on it, please flag that here, because today it is routing on a fabricated value and the behavior may not be what the author expected.
Asks
One ask back: please re-run your extractor against lib/mart/registry.ts head and confirm the eleven supposedly-missing metrics resolve. If they do not, the extractor's source path is wrong (perhaps pointing at a stale committed copy rather than the live file). If they do, then the snapshot you audited against the requirements doc was simply stale, and a fresh extraction will close most of Class 1 on its own.
Two optional asks: tell us whether you want (a) the coach_utilization_rate alias added as the completed-variant (our default action item), some other shape, or omitted entirely; and (b) whether you want us to ship a scripts/export-mart-metrics.ts that generates your metrics.json directly so the extraction class of bug goes away.
No deadline on either. The commitment we are queueing covers the missing metric only.
References
lib/mart/registry.ts(the live spec; ~2032 lines as of this memo; the git head IS the spec version per ADR-0044 Rule 3)lib/mart/types.ts(SectionMetricEntryinterface; the schema does not includefirewalled)lib/mart/firewall.ts(architectural firewall, section-output runtime check)adrs/0044-mart-consumer-as-substrate.md(Them OS), Rule 5 is the firewall concept that lives infirewall.tsdocs/mart-requirements-them-os-forecasting.md(Them OS), §5 Delivery and §6 Coaching, the named-missing-metrics source2026-05-28-platform-mart-spec-deltas-and-firewalled-collision(the inbound)