Is the workforce earning its keep?
The team report used to tell you whether your agents ran. It now tells you what they produced against a target, where that number came from, how much of your own time it cost, and what it cannot prove. Release notes 2026-09-15 — vocion-core#350.

Status: shipped. vocion-core #350 is merged onto the release branch release/2026-09-15-rail (the commit inside it is 5b499a99) and deployed to a deployment we operate. It adds migration 0100_team_measures.sql; the artifact work that landed after it took 0101. The pull request is still landing on main individually behind that release branch.
The first team report answered did my agents run. That is a question you only ask when you do not yet trust the thing. The question underneath it is different:
Vocion should not tell me whether my agents ran. It should tell me whether my AI workforce is earning its keep, whether I can trust it, and exactly why it believes that.
This rebuild is that report.
Teams on target, goal progress, operating cost, human review time, auto-completed work, and what needs attention. Then, per team: the outcome big, the target beside it, the trend against the prior window, and a chip saying where the number came from.
A team declares what it is for
A team now carries typed measures: instead of loose kpis:. Each measure says what is being counted, what good looks like, over what window, in which direction, and — the part that matters — where the number comes from:
measures:
- key: qualified_referrals
label: Qualified referrals
dimension: outcome # outcome | quality | velocity | economics
target: 10
baseline: 4
unit: referrals
window: 7d # 24h | 7d | 30d | quarter
direction: higher
source:
kind: human-confirmed
actions: [gmail.send]
contributesTo: workspace-goal
weight: 0.4
Four kinds of evidence, and they are not equal
Every reading carries a provenance chip, and the chips are deliberately not the same weight:
- Verified — read from the synced CRM mirror, carrying the mirror's own freshness. The chip says Verified · HubSpot (synced 51m ago), and says stale when the sync is older than its schedule.
- Observed — an action that actually reached
done, or a completed worker run carrying the count. - Human-confirmed — a person approved or edited it, from the alignment ledger; or an ask of that kind was answered with anything other than a rejection.
- Agent-reported — the worker's own count. The chip is muted and dashed, and its tooltip says the worker reported this and nothing independently confirms it.
Verified is HubSpot-only today. That is a schema limit, not a hedge: the source type is a discriminated union whose connector field accepts exactly hubspot, so adding a connector means adding a reader.
Nothing derived is stored. Attainment, trend, cost per outcome and every human-load figure are computed at read time from the rows that already exist, so there is no summary table to drift away from the truth.
What it costs you, not just what it costs
Alongside the outcome, each team shows quality (accepted without edit, over decided), velocity (median turnaround), economics (operating cost over the measure's own window, divided by the outcome in that window) and human load.
Human load is deliberately named decision latency, not review time — the sum of decided-at minus created-at, capped at eight hours per item. Nothing in the schema records when a person first looked at something, so calling it review time would be a number that sounds more precise than it is.
The report says what it cannot prove
Click the primary outcome and a lineage sheet opens: outcomes → approved items → recommendations → agent runs → model and tool cost → human review, each node with its basis, its count and the items behind it.
The interesting part is what it refuses to invent. The sheet carries lines like “A CRM record is not linked to the action that moved it; the records and the actions below share only the window” and “A proposal is not linked to the run that made it” and, on the cost node, “an action carries no cost of its own”. Those links genuinely are not in the schema. The report names the gap rather than joining on a window and calling it causation.
Before any of that, a setup state
No goal, no measured team, or no completed work ever: the page is a four-line checklist and one button, not an empty dashboard.
The gate is no completed work ever, not "none in the window" — a configured workforce that was quiet over a weekend gets a quiet report, not a broken one.
Where this lives in the repo
vocion-core#350, shipped on release/2026-09-15-rail (5b499a99).
- Schema:
packages/core/src/libs/workspace/schemas.ts—TeamMeasureSchema,MeasureSourceSchema; migrationpackages/core/migrations/0100_team_measures.sql(the legacykpiscolumn stays for one release, unwritten) - Provenance readers:
packages/core/src/services/team-report/provenance.ts - Derived figures:
services/team-report/derive.ts,humanLoad.ts(DECISION_LATENCY_CAP_MS,goalProgress) - Setup state:
services/team-report/setup.ts,features/dashboard/team-report/WorkforceSetup.tsx - Lineage:
services/team-report/lineage.tsandfeatures/dashboard/team-report/LineageSheet.tsx - Definitions:
docs/guides/team-performance.md; the spec is committed verbatim asdocs/specs/team-report-v2.md
Named as not done, in the PR and here: per-action cost attribution (an action_run carries no cents, so the chain says "cost not attributed" rather than guessing); a link from a proposal to the run that made it; verified connectors beyond HubSpot; first_viewed tracking that would turn decision latency into real review time. Not live-tested: applying a generated config against a real workspace folder, and a HubSpot mirror synced by the real connector — the tests use HubSpot-shaped fixtures.
Related: Team report: outcome contracts and Earned autonomy.