New tools (reports group)
- project_subtask_hours — delivery/allocated/effective hours from sub-tasks, with closed-stage + single-assignee filters and optional by-month grouping.
- project_dashboard — one-call detail page: core (project, milestones, finance, weekly logged), hours, budgets, budget_detail, delivery_monthly; per-section soft-fail via the
errorskey, section picking viainclude. - portfolio_health — one-call overview of every active project with derived health verdicts and budget burn %.
Shared infrastructure
project_shared.py: budget-model abstraction,derive_project_health(single source of truth for health verdicts),analytic_moneypositive-cost convention,paged_search_read,periods_domain, sub-task fetch/filter/aggregate helpers.
Hardening (11-finding review pass)
- Unknown
budget_idswarn for every budget-consuming section;_budget_contextfailure lands on every requested budget section — a requested section never vanishes silently. portfolio_healthdegrades instead of hard-failing on milestone errors; core's finance/weekly_logged soft-fail independently.- Strict
_parse_ymddate validation (rejects trailing garbage, normalises whitespace). - Perf: sub-tasks fetched once for hours + delivery_monthly; core's project row reused by
_budget_context.
451 tests green. Live-verified against production baseline (The Body Shop, project 59) on 2026-07-17: planned 1,593,314,320 / practical 1,736,086,746, full dashboard load 13.2s, zero errors.