toga-ai 1.0.434 → 1.0.435
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -6,7 +6,7 @@ project: Worker
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-07-
|
|
9
|
+
updated: 2026-07-24
|
|
10
10
|
owners: ["jcardinal", "kyalamarthi"]
|
|
11
11
|
files:
|
|
12
12
|
- worker2/Worker/Team/Sprint.php
|
|
@@ -178,7 +178,28 @@ All sprint state lives in the Team database (`_underscore::DB_TEAM`). Core table
|
|
|
178
178
|
(`reworkEvents`, `hygieneMisses`, `unjustifiedStatusChanges`,
|
|
179
179
|
`unjustifiedWorkEffortChanges`, `timeInProgressThisSprint`). Task statuses use the
|
|
180
180
|
`_Model_Team_Task::STATUS_*` constants (e.g. `STATUS_IN__DONE`).
|
|
181
|
-
- **`Tasks_Developers`** — task ↔ developer assignment join table.
|
|
181
|
+
- **`Tasks_Developers`** — task ↔ developer assignment join table. This is a **many-to-many**
|
|
182
|
+
relationship: a task can have several assigned developers. Any per-developer points rollup
|
|
183
|
+
(e.g. "points by dev") credits **each** assigned developer the task's *full* points — the
|
|
184
|
+
points are not split across assignees.
|
|
185
|
+
|
|
186
|
+
**Column vocabularies & datetime columns (dashboard-relevant).** For current-state reporting the
|
|
187
|
+
exact values matter:
|
|
188
|
+
|
|
189
|
+
- **`workTypeNow` / `workTypeAtLock`** — enum `COMMITTED / CONDITIONAL / STRETCH / UNPLANNED`.
|
|
190
|
+
MySQL string comparison is **case-insensitive** by default, so `'Committed'`/`'STRETCH'`/etc.
|
|
191
|
+
all match regardless of case.
|
|
192
|
+
- **`statusNow` / `statusAtLock` / `statusAtEnd`** — free-form varchar, values stored
|
|
193
|
+
**lower-case**: `complete`, `to do`, `in progress`, `stage review`, `hotfix review`,
|
|
194
|
+
`back-end review`, `ui review`, `on hold`, `roadblocked`, `awaiting client`, `rework`,
|
|
195
|
+
`pseudocode`, `ongoing`, `archived` (list is open-ended — treat unknown values as "review", see
|
|
196
|
+
the status rollup below).
|
|
197
|
+
- **`dtDone` vs `dtCompleted` are two different datetime columns** and are **not**
|
|
198
|
+
interchangeable. `dtDone IS NOT NULL` is the Power BI "done" test used by the KPI tiles and
|
|
199
|
+
burndown; `dtCompleted IS NOT NULL` is the "Complete" test used by the per-dev segment
|
|
200
|
+
breakdown. Do not substitute one for the other.
|
|
201
|
+
- **`sprintPointsNow` / `sprintPointsAtLock`** — the points measured by every dashboard metric
|
|
202
|
+
below use `sprintPointsNow` (current state), not the at-lock value.
|
|
182
203
|
|
|
183
204
|
`CaptureSprintEnd()` and `CaptureSprintDaily()` are the private sync routines that walk the
|
|
184
205
|
ClickUp sprint list (paginated, `include_timl=true`), upsert `Sprints`/`Developers`/`Tasks`/
|
|
@@ -249,8 +270,102 @@ Neither is "wrong" — they answer different questions (scored performance vs. l
|
|
|
249
270
|
If a tile or report must **agree with TOGa IQ's canonical scoring**, reconcile it to definition
|
|
250
271
|
(1); otherwise expect current-state tiles to diverge from sprint scores.
|
|
251
272
|
|
|
273
|
+
## Power BI dashboard metric definitions (DAX → SQL)
|
|
274
|
+
|
|
275
|
+
These are the **current-state / Power BI-parity** definitions behind the TOGa IQ sprint
|
|
276
|
+
dashboard (the same set of tiles and charts the Power BI report shows). They translate the
|
|
277
|
+
Power BI DAX into SQL against the `Team` schema so any consumer — a worker2 report, an api2
|
|
278
|
+
Record Script tile, or a local prototype — produces numbers that match Power BI. All of them
|
|
279
|
+
use current-state columns (`workTypeNow`, `statusNow`, `sprintPointsNow`) except where noted,
|
|
280
|
+
and follow the **Power BI / current-state definition** above (`dtDone IS NOT NULL`), not the
|
|
281
|
+
canonical scoring definition.
|
|
282
|
+
|
|
283
|
+
### KPI tiles — points by work type
|
|
284
|
+
Per tile: `points = SUM(sprintPointsNow)`, `done = dtDone IS NOT NULL`, filtered by a work-type
|
|
285
|
+
column + value. **Non-uniform on purpose — the column differs by tile:**
|
|
286
|
+
|
|
287
|
+
- **Committed / Stretch / Unplanned** filter on **`workTypeNow`** (`'Committed'` / `'STRETCH'` /
|
|
288
|
+
`'UNPLANNED'`).
|
|
289
|
+
- **Conditional** filters on **`workTypeAtLock` = `'Conditional'`** — a *different column*
|
|
290
|
+
(the at-lock baseline), not `workTypeNow`. Miss this and the Conditional tile is wrong.
|
|
291
|
+
|
|
292
|
+
MySQL string comparison is case-insensitive, so casing of the literal does not matter.
|
|
293
|
+
|
|
294
|
+
### Status rollup (status pie) — "Status now Category Group" DAX SWITCH
|
|
295
|
+
A `SWITCH` over `statusNow` (case-insensitive) into five buckets:
|
|
296
|
+
|
|
297
|
+
| Bucket | `statusNow` values |
|
|
298
|
+
|--------|--------------------|
|
|
299
|
+
| **Complete** | `complete`, `archived` |
|
|
300
|
+
| **In Progress** | `in progress`, `rework` |
|
|
301
|
+
| **Stalled** | `on hold`, `roadblocked`, `awaiting client` |
|
|
302
|
+
| **To Do** | `to do` |
|
|
303
|
+
| **Review** | **everything else (SWITCH default)** — all the review-type statuses fall here |
|
|
304
|
+
|
|
305
|
+
The default → **Review** case is load-bearing: any new/unknown status is a Review, not an error.
|
|
306
|
+
Shown by **task count** (dashboard.html) or by **`SUM(sprintPointsNow)`** (dashboard1.html donut
|
|
307
|
+
variant) — same rollup, different measure.
|
|
308
|
+
|
|
309
|
+
### Work Type pie
|
|
310
|
+
`SUM(sprintPointsNow) GROUP BY workTypeNow` — all four work-type values live in `workTypeNow` for
|
|
311
|
+
this chart (unlike the KPI tiles, Conditional is *not* read from `workTypeAtLock` here).
|
|
312
|
+
|
|
313
|
+
### Sprint Points By Dev — "New Status" DAX SWITCH
|
|
314
|
+
Points = `sprintPointsNow`; each task is assigned **one** segment via a SWITCH evaluated in order:
|
|
315
|
+
|
|
316
|
+
1. `dtCompleted IS NOT NULL` → **Complete** (note: `dtCompleted`, not `dtDone`).
|
|
317
|
+
2. else `statusNow NOT IN ('to do','in progress','rework','on hold','roadblocked','awaiting client')`
|
|
318
|
+
→ **In Review**.
|
|
319
|
+
3. else → the task's **`workTypeNow`** value (Committed / Conditional / Unplanned).
|
|
320
|
+
|
|
321
|
+
Joined `Tasks → Tasks_Developers → Developers` and grouped by developer. Because the join is
|
|
322
|
+
many-to-many, each assigned developer is credited the task's **full** `sprintPointsNow`.
|
|
323
|
+
|
|
324
|
+
### Sprint Burndown (over working days)
|
|
325
|
+
Plotted over **working days only** (Mon–Fri, ~10 per two-week sprint; call the count `N`,
|
|
326
|
+
`dayNumber` 1-based):
|
|
327
|
+
|
|
328
|
+
- **Target line:** `CCU_total × (1 − dayNumber / N)`, clamped to `≥ 0`.
|
|
329
|
+
- **Committed actual:** `CCU_total − (CCU points with dtDone on or before that day)`.
|
|
330
|
+
- **All actual:** `CCUS_total − (CCUS points done-to-date)`.
|
|
331
|
+
- Actual series **stop at today** (no future points).
|
|
332
|
+
|
|
333
|
+
Two work-type universes: **CCU** = Committed + Conditional + Unplanned; **CCUS** = CCU + Stretch.
|
|
334
|
+
|
|
335
|
+
### Time Progression
|
|
336
|
+
Business-hours elapsed vs. total. Working days are Mon–Fri only, each **8h (09:00–17:00)**, so a
|
|
337
|
+
10-working-day sprint = **80h**. `% = elapsed business hours ÷ 80`, using the local clock.
|
|
338
|
+
|
|
339
|
+
### Current-sprint auto-resolution
|
|
340
|
+
Dashboards must **never hardcode a sprint number.** Resolve the current sprint as:
|
|
341
|
+
|
|
342
|
+
1. the sprint whose date range contains today: `CURDATE() BETWEEN dateStart AND dateEnd`;
|
|
343
|
+
2. else the most recently started: `ORDER BY (dateStart <= CURDATE()) DESC, dateStart DESC LIMIT 1`.
|
|
344
|
+
|
|
345
|
+
In the local prototype this is exposed as `GET /v2/sprints/current`, and a `/v2/sprints`
|
|
346
|
+
middleware defaults every tile/chart endpoint to it when no `?sprint=` is supplied.
|
|
347
|
+
|
|
348
|
+
> **Prototype provenance & credentials.** These definitions were reverse-engineered and verified
|
|
349
|
+
> against the live `Team` schema (which resolves to the **core cluster reader** — see
|
|
350
|
+
> [per-client database connections](../../_underscore/features/per-client-database-connections.md))
|
|
351
|
+
> by a local Node/React + Express (mysql2) prototype that stands in for the api2 `/v2` engine and
|
|
352
|
+
> returns the standard api2 envelope. The prototype's DB credentials live in an **uncommitted
|
|
353
|
+
> `.env`** (never in the repo or this doc). When productionized, the tiles become api2 Record
|
|
354
|
+
> Scripts registered via **dbchanges2** — see
|
|
355
|
+
> [Record Scripts](../../api2/features/record-scripts.md).
|
|
356
|
+
|
|
252
357
|
## Change history
|
|
253
358
|
|
|
359
|
+
- 2026-07-24 — Documented the full **Power BI dashboard metric definitions (DAX → SQL)** for the
|
|
360
|
+
TOGa IQ sprint dashboard: KPI tiles by work type (with the non-uniformity that **Conditional
|
|
361
|
+
filters on `workTypeAtLock`** while Committed/Stretch/Unplanned filter on `workTypeNow`), the
|
|
362
|
+
status-rollup SWITCH (default → Review), the work-type pie, the per-dev "New Status" segment
|
|
363
|
+
SWITCH (`dtCompleted`-based, many-to-many full-points-per-dev), the burndown target/actual over
|
|
364
|
+
working days (CCU vs CCUS), time-progression (Mon–Fri 8h days, 80h/sprint), and current-sprint
|
|
365
|
+
auto-resolution. Enriched the data model with column vocabularies (workType/status enums), the
|
|
366
|
+
**`dtDone` vs `dtCompleted`** distinction, and the Tasks↔Developers many-to-many points rule.
|
|
367
|
+
Reverse-engineered/verified via a local Node/React + Express prototype (creds in uncommitted
|
|
368
|
+
`.env`). (kyalamarthi)
|
|
254
369
|
- 2026-07-23 — Recorded that two intentionally-different "committed/done" definitions coexist:
|
|
255
370
|
the canonical sprint-scoring definition (`statusNow IN (STATUS_IN__DONE)` + `workTypeAtLock`,
|
|
256
371
|
incl. the reusable `_pointsByWorkType`/`_tasksByWorkType` helpers on `_Model_Team_Sprint` in
|
package/package.json
CHANGED