sdm-expert-strengthrun.md00_intake/stub.mdThe expert strength table (expertStrength in apps/web/lib/mock/sdm.ts,
rendered by expert-strength-table.tsx
type (Freelance/Agency), region, country, taxonomy
productSkills, skillLevel, activeWork, slaAdherence, csat, escalationRate, completionRate,
repeatUsage, a status (strong/ok/at-risk), and the per-expert demand/supply/gap + availability.
Almost all of these metrics are owned by the expert epic (quality metrics, SLA, active work) and the
demand/supply/gap is derived from the coverage grid — but nothing assembles them into the SDM's
per-expert, area-scoped row today.slaAdherence from sla-stage-targets; csat/escalationRate/completionRate/
repeatUsage from expert-quality-metrics (+ the existing csat model); activeWork from
expert-active-projects.productSkills, the status classification
(reuse the strong/ok/at-risk logic from sdm-supply-coverage so the two agree), the per-expert
demand/supply/gap (read from the coverage grid for the cells the expert serves) and
availability ("Available now" / "Available soon" from capacity).lib/mock/sdm.status (strong/ok/at-risk) classification identical to the one in sdm-supply-coverage
so the grid and the per-expert view never disagree — share one derivation.expert-quality-metrics, sla-stage-targets and expert-active-projects have landed; define
a minimal read interface and coordinate if not — do not fork.touches: packages/services/src/server (per-expert strength assembly),
apps/web/components/dashboard/sdm/{expert-strength-table.tsx,expert-strength-row.tsx}.01_define/output/spec.mdThe expert strength table on the web SDM "Go live readiness" dashboard
(expertStrength in apps/web/lib/mock/sdm.ts, rendered by
apps/web/components/dashboard/sdm/expert-strength-table.tsx +
expert-strength-row.tsx) is the per-expert supply view: for each expert in the SDM's area it shows
type (Freelance/Agency), region, country, taxonomy productSkills, skillLevel, activeWork,
slaAdherence, csat, escalationRate, completionRate, repeatUsage, a status
(strong/ok/at-risk), and the per-expert demand/supply/gap + availability. Today it is wholly
mock: the table reads from lib/mock/sdm and even derives status with a placeholder client-side
ranking (top 20% / bottom 20% by SLA), which is unrelated to the real coverage classification. Almost
all of these metrics are owned by the expert epic (quality metrics, SLA, active work) and the
demand/supply/gap is derived from the coverage grid — but nothing assembles them into the SDM's
per-expert, area-scoped row.
This is sequence 6 of 8 in the sdm-dashboard-data epic and advances Build the Bridge / Q2 2026
Objective 3 — Validate Technical Infrastructure & Payout Flow: the SDM cockpit can only validate
that the marketplace's supply data is trustworthy once each section, including the per-expert strength
view, reflects real per-tenant, per-area data instead of the mock.
Extend the shared expert quality model with two real, reused metrics. getExpertQualityMetrics
(packages/services/src/db/services/matching/expert-quality.ts) today returns csat,
vendorRating, repeatWorkRate, reworkRate. Add two additive fields so escalation and
completion are first-class, reusable quality figures (not invented in the SDM feature):
escalationRate — the share of the expert's completed leads that had at least one escalated
blocker (a blocker record on the lead with escalated: true), as a percentage; null when the
expert has no completed leads. Sourced from the existing blocker model, over the same
completed-lead set the other rates already use — exactly mirroring how reworkRate reads the
per-lead isReworked flag.completionRate — of the leads assigned to the expert (lead.expert == id, excluding
unassigned bid-pool matches), the share that are completed (the existing completed-lead definition:
isActiveProject: false, bidPool: false, isBrdApproved: true), as a percentage; null when the
expert has no assigned leads.Both are additive — existing consumers of ExpertQualityMetrics (e.g. the expert-workbench Quality
card) keep working unchanged.
Assemble a per-expert strength row over the experts in the SDM's area — reading the in-scope
experts[] from the sdmAreaService area envelope (sdm-area-foundation) so the row honours the
"my area" vs "all" scope and tenant isolation, never re-querying experts itself.
Reuse the expert epic's models — do not recompute in the SDM feature:
slaAdherence from sla-stage-targets (the per-stage SLA timing engine), derived per expert over
their active leads the same way sdm-supply-coverage already derives it (shared, not reforked).csat, escalationRate, completionRate, repeatUsage (the model's repeatWorkRate) from the
extended getExpertQualityMetrics above (which itself reuses the csat model).activeWork (load) from the expert-active-projects / matching context (activeProjectCount).Add the SDM-specific fields:
productSkills (from the area envelope), region and country (from
location), and skillLevel (from the expert's seniority);type — Freelance vs Agency derived from the expert's vendor link: an expert
attached to a vendor (the expert.vendor ref is set) is an Agency expert; a standalone expert
(no vendor link) is Freelance. This is an explicit derived field of this feature (not a plain
reused read), blessed in-scope here because IExpert carries no type field of its own;status classification (strong/ok/at-risk) reused from the sdm-supply-coverage
derivation — the per-expert view and the coverage grid must share one derivation and never
disagree. sdm-supply-coverage's per-expert classification (bid-ready / delivery-ready / strong)
is extracted into a shared helper and consumed here; this feature only maps it to the row's
label: strong → strong, delivery-ready (but not strong) → ok, otherwise → at-risk. The
placeholder SLA-ranking computedStatus in the table is removed;demand/supply/gap, aggregated from the sdm-supply-coverage grid over the
cells the expert is matched into (the cells whose bid-ready set includes the expert), so the
per-expert numbers reconcile with the grid: demand = Σ of those cells' demand, supply = Σ of
those cells' availableExperts, gap = Σ of those cells' shortfall;availability ("Available now" / "Available soon") derived from the expert's capacity — "Available
now" when isAvailable is true and the expert has no future availability.earliestStartDate,
"Available soon" otherwise.Expose one typed per-expert strength assembly from @sustentus/services/server — a new
sdmStrengthService sibling in the db/services/ SDM family (alongside sdm-area, sdm-demand,
sdm-coverage, sdm-risk), exported through db/services/index.ts after sdm-coverage (it
consumes that service) — that takes the area scope and returns the strength rows.
Wire the expert strength table (expert-strength-table.tsx / expert-strength-row.tsx) to the
real assembly via the SDM dashboard page (apps/web/app/(app)/sdm/dashboard/page.tsx), surfacing
the SDM-specific fields (product skills, type, status, demand/supply/gap, availability) alongside the
reused metrics. Remove the expertStrength mock from lib/mock/sdm.ts and the placeholder ranking;
render a clean empty state when the SDM's area has no experts.
This run was defined ahead of its upstreams; they have since merged to main, so Build may proceed.
The spec still assumes the epic sequence — it does not re-implement the area envelope, the coverage
derivation, or the reused expert models (it only extends the quality model additively, above).
/sdm page scoped to
the signed-in SDM and the sdmAreaService area envelope (in-scope experts[] / leads[]) this
assembly plugs into.sdm-demand-aggregation (#521) and sdm-supply-taxonomy
(#524) are also merged.)getExpertQualityMetrics returns two new additive fields: escalationRate (% of the expert's
completed leads with at least one escalated blocker, null when none completed) and
completionRate (% of leads assigned to the expert that are completed, null when none
assigned), both sourced from real data (the blocker model and the lead-assignment/completed
definitions); existing consumers keep compiling and behaving unchanged.csat / slaAdherence / escalationRate / completionRate / repeatUsage /
activeWork come from the reused expert models (the extended expert-quality-metrics for the
quality figures, sla-stage-targets for SLA adherence, expert-active-projects / matching context
for active work), not recomputed in the SDM feature.expert.vendor link), region/country, skill level (from seniority), a status, the
demand/supply/gap aggregated from the sdm-supply-coverage grid, and availability —
scoped to the SDM's area and honouring the "my area" vs "all" scope.status classification reuses the same per-expert derivation as sdm-supply-coverage
(its bid-ready / delivery-ready / strong classification is extracted into a shared helper, not
reimplemented), mapped to strong / ok / at-risk; the placeholder top/bottom-20%-by-SLA
ranking is removed from the table.expertStrength from apps/web/lib/mock/sdm.ts, and that mock array is
removed.blocker model;
this run adds no new escalation-raising surface.sdm-supply-coverage; this
feature reads its derivation and grid (sharing, not forking, the per-expert classification).sdm-area-foundation; this feature plugs into it.sdm-supply-taxonomy;
this feature consumes the resolved skills/product-skill keys.escalationRate and completionRate are resolved as additive, real-data extensions of the
shared getExpertQualityMetrics model (escalation from the blocker model's escalated flag over
completed leads; completion as completed ÷ assigned leads). The type field is resolved as a
Freelance/Agency derivation off the expert.vendor link. The status-derivation sharing with
sdm-supply-coverage, the per-expert demand/supply/gap aggregation over the grid cells, and the
(now-merged) dependency sequencing were resolved at Define.
</content>02_build/output/notes.mdfeat: sdm-expert-strength — real per-expert strength table (+ the Define
spec-revision commits already on the branch)packages/services/src/db/services/matching/expert-quality.ts — extended
getExpertQualityMetrics (and its ExpertQualityMetrics type) with two additive, real-data fields:escalationRate — % of the expert's completed leads that have ≥1 escalated blocker
(escalated: true), over the same completed-lead set the other rates use.completionRate — completed ÷ all leads assigned to the expert (lead.expert == id).
Both default to null when there's no denominator. Existing consumers (expert-workbench Quality
card) are untouched — additive only (verified: web typecheck passes).packages/services/src/db/services/sdm-coverage/index.ts — extracted the per-expert
classification out of SdmCoverageService into an exported classifyExpertsForCoverage and made
ExpertClassification public. The classification now also surfaces slaAdherence, the full
quality record, and activeProjectCount (all already computed) so the strength view reuses the
one derivation rather than re-deriving anything. getCoverageForSdm calls the shared function;
coverage's cell output is unchanged.packages/services/src/db/services/sdm-strength/{index.ts,instance.ts} (new) — sdmStrengthService,
a sibling of sdm-area/sdm-demand/sdm-coverage/sdm-risk. getStrengthForSdm reads the
area envelope (in-scope experts, scope-aware), runs the shared classification, reads the coverage
grid + demand cells, and assembles one row per area expert: reused metrics, shared
strong/ok/at-risk status, type (Agency when expert.vendor is set, else Freelance),
region/country, skill level (from seniority), availability, and per-expert demand/supply/gap
summed from the grid cells the expert is matched into.packages/services/src/db/services/index.ts — export sdmStrengthService (after
sdm-coverage) + the strength types and the now-public ExpertClassification.apps/web/components/dashboard/sdm/expert-strength-table.tsx / expert-strength-row.tsx — render
the real SdmExpertStrengthRow[]; removed the placeholder top/bottom-20%-by-SLA computedStatus
ranking; status renders as a badge; added an empty-state row.apps/web/app/(app)/sdm/dashboard/page.tsx — resolve sdmStrengthService.getStrengthForSdm
alongside coverage/risk (degrading to [] on error, same as the other sections) and pass it to the
table.apps/web/lib/mock/sdm.ts — removed the expertStrength mock array (the other still-mock
sections — market signals, service performance — are out of scope and untouched).getExpertQualityMetrics returns escalationRate + completionRate from real data; consumers unchanged — verified via web typecheck.csat / slaAdherence / escalationRate / completionRate / repeatUsage / activeWork come from the reused models (extended quality model, shared SLA derivation, matching context), not recomputed here.expert.vendor), region/country, skill level (from seniority), status, grid-derived demand/supply/gap, and availability — area-scoped, scope-aware.sdm-supply-coverage's derivation via the shared classifyExpertsForCoverage helper, mapped to strong/ok/at-risk; placeholder ranking removed.expertStrength mock removed from lib/mock/sdm.ts.pnpm --filter @sustentus/services typecheck and pnpm --filter web typecheck locally (after
rebuilding the services package so the new cross-package exports resolve) — both pass.escalationRate/completionRate now live on the shared
getExpertQualityMetrics, per the Define decision (rather than dropping them or faking them in the
SDM feature). They're additive; double-check the chosen definitions (escalation over completed leads
via the blocker model; completion as completed ÷ assigned) match intent.classifyExpertsForCoverage is the single derivation behind both
the coverage grid and this view — the strength status is just a label mapping over it.03_release/output/changelog.mdYour go live readiness dashboard's expert strength table now shows real data for every expert in your area, not placeholder rows:
03_release/output/investor-update.mdWho it's for: Service delivery managers What shipped: The go live readiness dashboard's expert strength table now shows real per-expert quality, SLA, load, coverage status and gaps for every expert in an SDM's area. Why it matters: Advances Build the bridge, Q2 objective 3 — validate technical infrastructure & payout flow — by making the SDM's supply data trustworthy.
Escalation and completion rates are now real, reused metrics across the platform.
Dig deeper: <merged-PR URL> · <changelog entry URL>