You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
src/dashboards/duty-health.dashboard.ts (new), pushed into dulyDashboards in src/dashboards/index.ts
a type: 'dashboard' nav entry in src/apps/duly.app.ts under the existing Team group
test/dashboard.test.ts (new)
Layout, in reading order
Not moving — count of open tasks untouched >14d, with the >30d count beside it. Top-left, largest, because it is the earliest actionable signal and the one no other tool gives them.
Late — count past due_date + grace_days, still open.
On-time rate, current period — governed work only, with the previous period beside it for direction.
By unit — a bar per business unit showing late and not-moving counts. Sorted by unit name or org order, never by the count.
Coming up — tasks due in the next 14 days, by week, so an overloaded period is visible before it arrives.
Rules
Every widget binds to a dataset from Analytics datasets — duty health, on-time rate, stagnation #9, never to an object. A dangling binding renders an empty chart while authoring reports success — pnpm validate checks binding integrity, so a clean validate is part of the acceptance here, not a formality.
No ranking of people. Not a "top late owners" table, not a sort-by-count on a person dimension, not a "most improved". Unit comparison is fine — unit comparison is a workload question. Person comparison is a performance score, and this product does not have one.
Nothing on this dashboard is editable. Managers read here; their only write in the product is assigning.
The on-time tile must carry a one-line caliber note — governed duties only; self-declared work is excluded — visible on the dashboard, not buried in a tooltip. Someone will eventually ask why the number differs from a raw task count, and the answer belongs next to the number.
Colour and contrast
Late and not-moving are warnings, not failures — the palette should read as attention, not blame. Check text-on-fill contrast on every slice and label; a light fill with white labels is a contrast failure that reads fine on the author's screen and nowhere else.
Acceptance
every widget resolves to a real dataset field; pnpm validate clean
no widget sorts a person dimension by a count measure
the not-moving tile is the visual focus
the caliber note is rendered on the dashboard
the dashboard is reachable from the app's Team group
One screen that answers a manager's whole question, entered by nobody.
Blocked-by: #9 (datasets).
Files you own
src/dashboards/duty-health.dashboard.ts(new), pushed intodulyDashboardsinsrc/dashboards/index.tstype: 'dashboard'nav entry insrc/apps/duly.app.tsunder the existing Team grouptest/dashboard.test.ts(new)Layout, in reading order
due_date + grace_days, still open.Rules
pnpm validatechecks binding integrity, so a clean validate is part of the acceptance here, not a formality.Colour and contrast
Late and not-moving are warnings, not failures — the palette should read as attention, not blame. Check text-on-fill contrast on every slice and label; a light fill with white labels is a contrast failure that reads fine on the author's screen and nowhere else.
Acceptance
pnpm validatecleanGates
pnpm validate && pnpm typecheck && pnpm test && pnpm build.