Skip to content

Analytics datasets — duty health, on-time rate, stagnation #9

Description

@os-warren

The semantic layer (ADR-0021) everything on the manager side reads. Dashboards bind to datasets, never to objects directly — a widget with a dangling binding renders an empty chart and reports success.

Files you own

  • src/datasets/*.dataset.ts (new), pushed into dulyDatasets in src/datasets/index.ts
  • test/datasets.test.ts (new)

Datasets

duly_duty_health — the on-time picture.

  • dimensions: business_unit, owner, period_key, frequency, source
  • measures: tasks due, done, done on time, late, skipped, on-time rate

On time = completed_at on or before due_date + grace_days. Late = past that and not done. Both derive from the stored, indexed columns — do not add a flag to duly_task to make this easier.

duly_stagnation — the early-warning picture.

  • dimensions: business_unit, owner
  • measures: open tasks, open tasks untouched >7d, >14d, >30d, oldest last_update_at

duly_workload — forward look, for spotting a period that is about to overload.

  • dimensions: business_unit, owner, due_date bucketed by week and month
  • measures: tasks due

The filter that must be on every governed measure

source IN ('catalog', 'assigned').

self duties are the owner's own record-keeping. They are surfaced, never scored. A single on-time rate that quietly includes self-declared work punishes exactly the people who declared the most, which is how a system teaches everyone to declare nothing.

source is available as a dimension so someone can look at self-declared work deliberately. It is never in the default measure.

duly_log_entry does not appear in this issue

No dataset reads it. No dataset will. If a later ticket asks for one, that is a product decision, not an analytics one — file needs-user-decision rather than adding it.

Do not build

  • any measure that counts items per person for comparison — no "tasks logged", no "most active", no contributor leaderboard dimension. This is the specific mechanism by which the caliber separation gets undone one reasonable-looking ticket at a time.
  • a completion-percentage measure. Progress lives in status and last_update_at; a percentage is a number nobody can verify, which is exactly why it becomes the number everyone reports.

Acceptance

  • every governed measure is filtered to source IN ('catalog','assigned'); assert it in the test
  • on-time honours grace_days — a task completed inside grace counts on time
  • stagnation buckets are computed from last_update_at, and an untouched-but-not-yet-due task still appears (stagnation is not lateness)
  • no dataset references duly_log_entry
  • no measure ranks or compares item counts across people

Gates

pnpm validate && pnpm typecheck && pnpm test && pnpm build.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions