ADR-024 — Employee Bar Semantics and Contract Matching
ADR-024 — Employee Bar Semantics and Contract Matching
Sección titulada «ADR-024 — Employee Bar Semantics and Contract Matching»Accepted
Context
Sección titulada «Context»The org-chart detail view displays coverage bars per employee. The original implementation calculated effective_hours / position.required_weekly_hours, producing percentages like “12h / 36h = 33%”. This is conceptually incorrect for two reasons:
- An employee with a 12h contract cannot be assigned to a 36h position. Contract hours must match the position’s required hours for regular assignments (not reinforcements).
- The employee bar should represent the employee’s fulfillment of their own contractual obligation, not the fraction they cover of the position.
Showing the utilization percentage of the employee’s weekly pool (assigned hours vs total pool) was considered, but discarded because it requires an additional fetch to the balance API per employee and adds complexity without clear benefit in this view.
Decision
Sección titulada «Decision»Rule 1 — mandatory contract matching. For regular assignments (not reinforcement), assignment.effective_hours must equal position.required_weekly_hours. An employee can only fill a position whose required hours match their contract hours. This rule is enforced in the assignment logic and reflected in the UI.
Rule 2 — employee bar = own fulfillment. The worker row coverage bar shows the employee’s fulfillment percentage relative to their own obligation. With Rule 1, regular assignments always produce 100% (green). The display format is Xh / Xh where both values are the assignment’s effective_hours.
Rule 3 — reinforcements without a denominator. Reinforcements (is_reinforcement = true) contribute additional hours without filling a position slot (see [[adr-001-c-hour-color-vocabulary|ADR-001-c]] Rule 3). Their bar is always blue and shows only the contributed hours (Xh) without a denominator, since they have no position requirement of their own to fulfill.
Rule 4 — unit bar unchanged. The unit-level coverage bar ([[adr-001-c-hour-color-vocabulary|ADR-001-c]]) is not affected. It continues to calculate total_assigned_hours / total_required_hours * 100 from position data aggregated by the API.
Consequences
Sección titulada «Consequences»- The worker row always shows 100% green for regular assignments with well-formed data. The differentiating information lives at the position level (vacant vs covered) and unit level (aggregate coverage).
- Reinforcements are visually distinguished with a blue bar and no hour denominator.
- If for any reason the data contains a mismatch (effective_hours != required_weekly_hours for a regular assignment), the bar still shows 100% of the employee’s contract, not the fraction of the position.
- The
kdx-worker-rowshowcase is updated to reflect these semantics: examples with matching hours and a blue reinforcement example. - Complements [[adr-001-c-hour-color-vocabulary|ADR-001-c]] (unit-level colors) with employee-level semantics.