Effort: thorough
scidex/agora/skill_evidence.py:SKILL_GROUPS dispatches by topic with a
hardcoded order — the agent will call uniprot_protein_info even when
alphafold_structure would have been cheaper and equally informative. With
agent_skill_invocations now logging latency_ms, and
q-skills-quality-leaderboard providing per-skill composite quality, we
can build a cost-rationality router that picks the cheapest skill in each
group whose composite is within ε of the group max, falling back to the
quality leader only when nothing else clears the bar. This converts skill
selection from a static table into a measured decision.
scidex/forge/skill_router.py exposingpick(group: str, available: list[str], constraint: dict) -> str.constraint accepts latency_budget_ms, min_composite,forbid_drifted (default True).
cost(skill) = p50_latency_ms / 1000 plusexternal_call_cost_usd if the skill row carries anexternal_call_cost_usd annotation in its SKILL.md frontmattermin_composite (default 0.4).is_drifted events at severity=high in theforbid_drifted=True.q*.q* - 0.05.scidex/agora/skill_evidence.py calls skill_router.pick insteadSKILL_GROUPS[group] directly. The legacy orderedskill_router_decisions(id, group, candidates_json, picked,
reason, picked_composite, picked_cost, decided_at) so we canmigrations/20260428_skill_router_decisions.sql./forge/skills/router shows a stacked bar ofSCIDEX_SKILL_ROUTER_SHADOW=1 returns legacy pick but logs thetests/test_skill_router.py:pick("gene", available=[...], constraint={}) againstscidex/agora/skill_evidence.py:SKILL_GROUPS to understandmv_skill_usage_daily +skill_quality_scores (created by previous skills tasks); cache forpick() so it never raises — on any error, fall back to theskill_router_decisions withreason='router_error_fallback'.
SCIDEX_SKILL_ROUTER_SHADOW=1q-skills-usage-telemetry — mv_skill_usage_daily.q-skills-quality-leaderboard — composite score.q-skills-versioning-drift — skill_drift_events for theforbid_drifted filter.q-skills-bundle-auto-discovery — bundles annotated withexternal_call_cost_usd plug straight into the router.696ce0f89skill_router.py, migration, test file, HTML page, skill_evidence wiring all presentpick('gene', [...], {}) returned uniprot_protein_info, wrote decision row to DBskill_router_decisions verified live on PG{
"completion_shas": [
"1c68e3319",
"696ce0f89"
],
"completion_shas_checked_at": "2026-04-27T13:12:09.139794+00:00"
}