toga-ai 1.0.184 → 1.0.185
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.
|
@@ -12,5 +12,6 @@
|
|
|
12
12
|
| [NetSuite → TOGA Opportunity Sync (API Message Queue + worker2 webhook)](features/netsuite-opportunity-sync.md) | Outbound sync from NetSuite to TOGA for the record types the Forecast2 importer pulls (opportunities first; sales/items/etc. | worker2/Worker/Netsuite.php, worker2/Worker/Netsuite/Opportunity.php, worker2/Controller/Index.php, _underscore/Worker.php, test/@dave/NetSuite/api-message-queue/lib_amq_queue.js, test/@dave/NetSuite/api-message-queue/ue_api_msg_queue_enqueue.js, test/@dave/NetSuite/api-message-queue/ue_amq_drain.js, test/@dave/NetSuite/api-message-queue/ss_amq_drain.js, test/@dave/NetSuite/api-message-queue/DEPLOY_RUNBOOK.md, test/@dave/clickup/backfill_opportunity_numbers.php, test/@dave/clickup/probe_opportunity_fields.php, test/@dave/probe_clickup_desc_match.php, worker/crons/toga2/forecast2/common_import_sales_from_netsuite.php |
|
|
13
13
|
| [NetSuite → Forecast Open-Orders Sync (salesOrder webhook → OpenOrderItems)](features/netsuite-salesorder-open-orders-sync.md) | Webhook-driven, single-record port of the legacy open-orders importer (TRUE-79142). | worker2/Worker/Netsuite/SalesOrder.php, worker2/Worker/Netsuite.php, test/@dave/probe_salesorder_rest_shape.php, test/@dave/probe_open_order_lines.php, test/@dave/check_so_status.php, test/@dave/check_so_history.php, test/@dave/probe_so_rest_lines.php, test/@dave/probe_missing_oo_timing.php, test/@dave/probe_missing_oo_createdby.php, test/@dave/probe_drift_so_dates.php, worker/crons/toga2/forecast2/import_open_orders.php, worker/crons/toga2/forecast2/common_import_sales_from_netsuite.php |
|
|
14
14
|
| [Startech Webhook Handler (worker2)](features/startech-webhook-handler.md) | Receives inbound webhook events from Startech (Easeedesk) and creates or updates the corresponding ticket in TOGA 2.0. | worker2/Worker/Startech.php |
|
|
15
|
+
| [Team Sprint Management & Reporting](features/team-sprint-management.md) | `_Worker_Team_Sprint` (file `Worker/Team/Sprint.php`) is the engine behind TOGA's internal **development-sprint process and reporting**. | worker2/Worker/Team/Sprint.php |
|
|
15
16
|
| [Teams Meeting Transcript Export](features/teams-transcript-export.md) | `_Worker_Team_Transcripts` (action `Team/Transcripts/Export`) polls Microsoft Graph for Teams meeting transcripts produced by a set of organizers, classifies ea | worker2/Worker/Team/Transcripts.php, worker2/Config/production.ini, worker2/Database/TeamsTranscriptExports.sql, dbchanges2/Core/2026-06-18a - Teams Transcript Export schedule.sql |
|
|
16
17
|
| [WJE Freshservice Sync (worker2)](features/wje-freshservice-sync.md) | WJE ("WJE IT", helpdesk `wje.freshservice.com`) is a **Freshservice**-based help-desk client whose tickets, contacts, assets, groups, categories, and canned res | worker2/Worker/Wje.php, _underscore/Component/Api/Wje/Wje.php, _underscore/Model/Wje/Ticket.php, _underscore/Model/Wje/TicketNote.php, _underscore/Model/Wje/Contact.php, _underscore/Model/Wje/Unit.php, _underscore/Model/Wje/TicketTeam.php, _underscore/Model/Wje/TicketCategory.php, _underscore/Model/Wje/AssetType.php, _underscore/Model/Wje/PredefinedReply.php, library/app/api/wje.php, worker/crons/toga2/wje/import_supporting_records.php, worker/crons/toga2/wje/sync_togasupply_wje.php, worker/crons/notifications/reports/wje/wje_common.php, library/app/systemmonitor/wje.php, dbchanges2/Client_Wje/2024-10-04 - WjeOnboarding.sql |
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Team Sprint Management & Reporting
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: worker2
|
|
5
|
+
project: Worker
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-24
|
|
10
|
+
owners: ["jcardinal"]
|
|
11
|
+
files:
|
|
12
|
+
- worker2/Worker/Team/Sprint.php
|
|
13
|
+
related:
|
|
14
|
+
- ../architecture.md
|
|
15
|
+
- ./creating-worker-actions.md
|
|
16
|
+
- ./clickup-work-type-automation.md
|
|
17
|
+
- ./clickup-project-routing.md
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Summary
|
|
21
|
+
|
|
22
|
+
`_Worker_Team_Sprint` (file `Worker/Team/Sprint.php`) is the engine behind TOGA's internal
|
|
23
|
+
**development-sprint process and reporting**. It is an `abstract` worker class of `static`
|
|
24
|
+
methods — each public method is a dispatchable worker action (`Team/Sprint/<Method>`, e.g.
|
|
25
|
+
`Team/Sprint/SprintEnd`) invoked on a schedule via `_Worker::runTask()`.
|
|
26
|
+
|
|
27
|
+
The feature mirrors the team's two-week (`SPRINT_LENGTH_DAYS = 14`) ClickUp-based sprint
|
|
28
|
+
ceremony into the `DB_TEAM` database, then produces:
|
|
29
|
+
|
|
30
|
+
- **Warning emails** before sprint-end capture and before sprint lock.
|
|
31
|
+
- A **Sprint Lock** snapshot that freezes each task's committed/planned state ("at lock").
|
|
32
|
+
- **Daily** leadership progress reports during the sprint.
|
|
33
|
+
- A comprehensive **Sprint End** run that scores every developer across four metrics,
|
|
34
|
+
emails per-developer report workbooks and a leadership summary workbook.
|
|
35
|
+
- **AI-generated Release Notes** (via TOGa IQ) emailed to leadership.
|
|
36
|
+
|
|
37
|
+
ClickUp is the source of truth for tasks/assignees; `DB_TEAM` is the durable store of
|
|
38
|
+
sprint history and computed metrics; Excel (`PhpOffice\PhpSpreadsheet`) is the report
|
|
39
|
+
format; `_Email` delivers everything.
|
|
40
|
+
|
|
41
|
+
## Key files / entry points
|
|
42
|
+
|
|
43
|
+
- `Worker/Team/Sprint.php` — the entire feature (one abstract class, static methods).
|
|
44
|
+
- `initialize()` — registers the `Logs_True` DB connection used for ClickUp API logging.
|
|
45
|
+
- ClickUp config lives in class constants: `CLICKUP_TEAM_ID`, `CLICKUP_DEV_SPRINTS_FOLDER_ID`
|
|
46
|
+
(the folder whose child lists are the sprints), and the API access token.
|
|
47
|
+
- AI config constants: `AI_API_ENDPOINT` (TOGa IQ `…/api/ai/generate`), `AI_MODEL_ID`
|
|
48
|
+
(`bedrock/us.anthropic.claude-haiku-4-5-…`), temperature, max-tokens, timeout.
|
|
49
|
+
- Report distribution: `SEND_LEADERSHIP_REPORTS_TO` (leadership email list);
|
|
50
|
+
`SEND_EMAILS_FROM` / `SEND_EMAILS_FROM_NAME`.
|
|
51
|
+
|
|
52
|
+
> **Dispatch reminder (2.0 worker contract).** Action `Team/Sprint/SprintEnd` routes to
|
|
53
|
+
> `_Worker_Team_Sprint::SprintEnd`. New actions are only reachable once registered as a
|
|
54
|
+
> `CronJobs` row (or webhook route). See [creating-worker-actions](./creating-worker-actions.md).
|
|
55
|
+
|
|
56
|
+
## The sprint lifecycle (and which action runs when)
|
|
57
|
+
|
|
58
|
+
A sprint runs ~14 days. Across the cycle these actions fire (scheduled as crons):
|
|
59
|
+
|
|
60
|
+
1. **Sprint launch day, 8:30 AM** — `SendSprintEndWarnings` and `SendSprintLockWarnings`
|
|
61
|
+
email every developer who had a task in the latest sprint, reminding them to (a) finalize
|
|
62
|
+
the *previous* sprint's task data before the 9:00 AM End capture, and (b) get their *new*
|
|
63
|
+
sprint commitments ready to lock before the 9:45 AM launch ceremony.
|
|
64
|
+
2. **~9:00 AM** — `SprintEnd` captures and scores the just-finished sprint, emails reports,
|
|
65
|
+
and (optionally) sends release notes.
|
|
66
|
+
3. **~9:45 AM (after launch ceremony)** — `SprintLock` freezes the new sprint's plan.
|
|
67
|
+
4. **Daily during the sprint** — `SprintDaily` emails leadership a progress dashboard.
|
|
68
|
+
|
|
69
|
+
Most methods accept an optional `$sprint` number; when omitted they resolve the relevant
|
|
70
|
+
sprint by date via `getSprint()` (which returns the sprint whose `dateStart…dateEnd` range
|
|
71
|
+
contains today, or, for end-of-sprint, the previous sprint).
|
|
72
|
+
|
|
73
|
+
## Public actions (entry points)
|
|
74
|
+
|
|
75
|
+
### `SendSprintEndWarnings()` / `SendSprintLockWarnings()`
|
|
76
|
+
Look up the latest `Sprints` row, find every distinct developer with a task in that sprint
|
|
77
|
+
(`Developers ⋈ Tasks_Developers ⋈ Tasks`), and email each a templated reminder. End-warning =
|
|
78
|
+
"clean up your data before the 9:00 AM End capture"; Lock-warning = "have your commitments
|
|
79
|
+
ready before the 9:45 AM lock; work added after lock is treated as unplanned/interrupt work."
|
|
80
|
+
Both send via the `Notification/Email/Send` worker action.
|
|
81
|
+
|
|
82
|
+
### `SprintLock($sprint = null, $captureSprintLock = true, $generateSprintLockReport = true, $allowUnplannedTasks = false)`
|
|
83
|
+
Freezes the sprint's plan at launch time. Optionally re-captures ClickUp data first, then for
|
|
84
|
+
each task records the **"at lock" baseline** — `workTypeAtLock`, `sprintPointsAtLock`,
|
|
85
|
+
`statusAtLock` — and initializes the per-sprint tracking counters (rework events, unjustified
|
|
86
|
+
status/work-effort changes, in-progress time). These at-lock values are what later metrics
|
|
87
|
+
measure *against*. If the target sprint list cannot be found in ClickUp it emails a leadership
|
|
88
|
+
alert. With `$generateSprintLockReport`, emits an Excel lock report of committed/conditional/
|
|
89
|
+
unplanned/stretch points and tasks. When `$allowUnplannedTasks` is false, tasks appearing
|
|
90
|
+
after lock with an UNPLANNED work type are flagged.
|
|
91
|
+
|
|
92
|
+
### `SprintDaily($sprint = null, …)`
|
|
93
|
+
In-sprint **leadership dashboard**, read-only with respect to metrics. Optionally re-captures
|
|
94
|
+
ClickUp data, then builds a multi-sheet workbook:
|
|
95
|
+
- **Dashboard** — sprint progress by *time elapsed* vs. *points completed* (and the
|
|
96
|
+
difference, i.e. ahead/behind pace); counts of tasks in attention statuses (Roadblocked,
|
|
97
|
+
On Hold, Awaiting Client, the various Review states); points/tasks by work type.
|
|
98
|
+
- **Team Summary** — per-developer committed/conditional/unplanned/stretch completion plus
|
|
99
|
+
N-sprint historical averages.
|
|
100
|
+
- **Stalled Task Detail** — tasks in Roadblocked / Awaiting Client / On Hold with the reason.
|
|
101
|
+
Emailed to the leadership list as `TeamSprintDailyReport_Sprint{N}_{date}.xlsx`.
|
|
102
|
+
|
|
103
|
+
### `SprintEnd($sprint = null, …)`
|
|
104
|
+
The largest method and the heart of the feature. Phases:
|
|
105
|
+
1. **Resolve** the target (previous) sprint and its developers; optionally call
|
|
106
|
+
`CaptureSprintEnd()` to sync the final ClickUp state into `DB_TEAM`.
|
|
107
|
+
2. **Score every developer** across the four metrics below.
|
|
108
|
+
3. **Per-developer report workbook** (Dashboard, Team Summary, Sprint History, Task Detail,
|
|
109
|
+
and a Score-Trends chart over the last `SPRINTS_BACK_FOR_AVERAGES` sprints), emailed to
|
|
110
|
+
each developer.
|
|
111
|
+
4. **Leadership summary workbook** (team-wide dashboard, all-developer summary with a
|
|
112
|
+
*recommended commitment* for next sprint, and stalled-task detail), emailed to leadership.
|
|
113
|
+
5. Optionally call the release-notes generator.
|
|
114
|
+
|
|
115
|
+
### `SendReleaseNotes($sprint = null)`
|
|
116
|
+
Pulls every **completed** task in the sprint (`statusNow IN (…DONE)`) into a CSV of
|
|
117
|
+
`workType, taskType, stakeholders, applications, sprintPoints, title`, then POSTs it to the
|
|
118
|
+
TOGa IQ AI endpoint with a detailed system prompt that rewrites technical task titles into
|
|
119
|
+
business-friendly, stakeholder-grouped HTML release notes. The returned HTML (code fences
|
|
120
|
+
stripped) is emailed to the leadership list as "Sprint N Release Notes".
|
|
121
|
+
|
|
122
|
+
## The scoring model (Sprint End)
|
|
123
|
+
|
|
124
|
+
Each developer receives four 0–100 sub-scores and a weighted **Final Score**:
|
|
125
|
+
|
|
126
|
+
| Metric | What it measures | Penalized by |
|
|
127
|
+
|--------|------------------|--------------|
|
|
128
|
+
| **Reliability** | Did they deliver what they committed to | Committed points/tasks not completed |
|
|
129
|
+
| **Quality** | Did the work hold up | Rework events |
|
|
130
|
+
| **Hygiene** | Was ClickUp data kept clean | Missing "Task Knowledge" / "Work Knowledge" custom fields (`hygieneMisses`) |
|
|
131
|
+
| **Integrity** | Were estimates honest | Unjustified work-effort (point/estimate) changes |
|
|
132
|
+
|
|
133
|
+
Key rules driven by the class constants:
|
|
134
|
+
- **Team-relative zero-out:** for Quality, Hygiene, and Integrity, if a developer's negative
|
|
135
|
+
rate is more than `FACTOR_OF_TEAM_AVERAGE_*_FOR_ZERO_SCORE` (= 4×) the team average for that
|
|
136
|
+
metric, that sub-score floors at 0. Scores are graded against the team, not an absolute bar.
|
|
137
|
+
- **Weighting:** `Final = 0.7·Reliability + 0.1·Quality + 0.1·Hygiene + 0.1·Integrity`
|
|
138
|
+
(`FINAL_SCORE_WEIGHT_*`). Reliability dominates.
|
|
139
|
+
- **Caps:** a low sub-score caps the final regardless of the others —
|
|
140
|
+
Reliability < 80 caps final at 80; Quality/Hygiene/Integrity < 90 cap final at 90
|
|
141
|
+
(`FINAL_SCORE_CAP_*`).
|
|
142
|
+
- **Recommended next commitment:** `PERCENT_OF_PREVIOUS_COMMITTED_TASK_AVERAGE_FOR_RECOMMENDED_COMMITMENT`
|
|
143
|
+
(= 0.9) × the developer's recent committed-points average, over the last 4 sprints.
|
|
144
|
+
- `scoreHeatMap($score)` interpolates a red→green cell color for the spreadsheets (stops
|
|
145
|
+
roughly at 60/70/80/90/100).
|
|
146
|
+
|
|
147
|
+
## Data model (`DB_TEAM`)
|
|
148
|
+
|
|
149
|
+
All sprint state lives in the Team database (`_underscore::DB_TEAM`). Core tables:
|
|
150
|
+
|
|
151
|
+
- **`Sprints`** — one row per sprint: `id`, `sprint` (number), `dateStart`, `dateEnd`.
|
|
152
|
+
- **`Developers`** — `id`, `name`, `emailAddress`, ClickUp user identifier.
|
|
153
|
+
- **`Tasks`** — one row per sprint task, keyed to ClickUp. Carries the lifecycle snapshots
|
|
154
|
+
(`workTypeAtLock` vs `workTypeNow`, `sprintPointsAtLock` vs `sprintPointsNow`,
|
|
155
|
+
`statusAtLock` / `statusNow` / `statusAtEnd`), classification fields (`taskType`,
|
|
156
|
+
`stakeholders`, `applications`, `link`), and the computed metric counters
|
|
157
|
+
(`reworkEvents`, `hygieneMisses`, `unjustifiedStatusChanges`,
|
|
158
|
+
`unjustifiedWorkEffortChanges`, `timeInProgressThisSprint`). Task statuses use the
|
|
159
|
+
`_Model_Team_Task::STATUS_*` constants (e.g. `STATUS_IN__DONE`).
|
|
160
|
+
- **`Tasks_Developers`** — task ↔ developer assignment join table.
|
|
161
|
+
|
|
162
|
+
`CaptureSprintEnd()` and `CaptureSprintDaily()` are the private sync routines that walk the
|
|
163
|
+
ClickUp sprint list (paginated, `include_timl=true`), upsert `Sprints`/`Developers`/`Tasks`/
|
|
164
|
+
`Tasks_Developers`, count hygiene misses, and archive tasks no longer present. They differ
|
|
165
|
+
mainly in which snapshot columns they write (End → `statusAtEnd`; Daily → `statusNow`, and it
|
|
166
|
+
backfills `workTypeAtLock` the first time a task is seen).
|
|
167
|
+
|
|
168
|
+
## External integrations
|
|
169
|
+
|
|
170
|
+
- **ClickUp API v2** — the dev-sprints **folder** (`CLICKUP_DEV_SPRINTS_FOLDER_ID`) holds one
|
|
171
|
+
list per sprint, named like `Sprint NN (M/D/YY - M/D/YY)`. Tasks are fetched page-by-page;
|
|
172
|
+
custom fields read include Work Type (committed/conditional/unplanned/stretch), Task Type,
|
|
173
|
+
Stakeholders, Application, and the two Knowledge fields used for hygiene scoring.
|
|
174
|
+
- **TOGa IQ / AI** (`api.togaiq.com/api/ai/generate`) — release-notes generation only.
|
|
175
|
+
- **Email** (`_Email`) — all reports and warnings; per-developer reports go to the developer,
|
|
176
|
+
everything else to `SEND_LEADERSHIP_REPORTS_TO`.
|
|
177
|
+
- **Excel** (`PhpOffice\PhpSpreadsheet`) — every report is an `.xlsx` attachment.
|
|
178
|
+
|
|
179
|
+
## Gotchas
|
|
180
|
+
|
|
181
|
+
- **Single source file, huge methods.** `SprintEnd` alone is ~2,700 lines; `SprintLock` and
|
|
182
|
+
`SprintDaily` are each ~1,000. Almost all report layout/formatting is inline. Treat the
|
|
183
|
+
method boundaries (and the constants block at the top) as the map.
|
|
184
|
+
- **At-lock baseline is load-bearing.** Reliability/Integrity compare *now* vs *at lock*. If
|
|
185
|
+
`SprintLock` did not run (or ran without capture), the `*AtLock` columns are empty and the
|
|
186
|
+
end-of-sprint scores are meaningless. Lock must happen at launch.
|
|
187
|
+
- **Sprint list naming is a contract.** Capture matches the ClickUp sprint list by its
|
|
188
|
+
`Sprint NN (dates)` name / date range. A mis-named list is silently not found → leadership
|
|
189
|
+
gets a "sprint not found" alert instead of a report.
|
|
190
|
+
- **Hardcoded credentials.** ⚠ The ClickUp access token and the TOGa IQ AI API key are
|
|
191
|
+
currently **hardcoded as class constants** in `Sprint.php` rather than read from config.
|
|
192
|
+
This is a known security debt (secrets in source) — they should move to `Config/*.ini`
|
|
193
|
+
and the committed values should be rotated. See team coding/security standards.
|
|
194
|
+
- **Worker contract.** Like all 2.0 workers this must return cleanly and commit writes via
|
|
195
|
+
the `_Db`/transaction layer to be durable — uncommitted captures can be silently dropped.
|
|
196
|
+
|
|
197
|
+
## Change history
|
|
198
|
+
|
|
199
|
+
- 2026-06-24 — Initial documentation of `_Worker_Team_Sprint` (`Worker/Team/Sprint.php`):
|
|
200
|
+
the sprint lifecycle (warnings → lock → daily → end → release notes), the four-metric
|
|
201
|
+
developer scoring model (reliability/quality/hygiene/integrity with weights, team-relative
|
|
202
|
+
zero-out, and final-score caps), the `DB_TEAM` data model, and the ClickUp / TOGa IQ / email
|
|
203
|
+
integrations. Flagged hardcoded ClickUp + AI credentials as security debt.
|
package/knowledge/INDEX.md
CHANGED
|
@@ -16,7 +16,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
16
16
|
## 2.0 framework
|
|
17
17
|
|
|
18
18
|
- **_underscore** (_Underscore) _(framework core)_ — 11 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
|
|
19
|
-
- **worker2** (Worker) —
|
|
19
|
+
- **worker2** (Worker) — 13 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
|
|
20
20
|
- **api2** (API) — 6 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
|
|
21
21
|
- **dbchanges2** (Database Changes) _(framework core)_ — 2 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
|
|
22
22
|
- **toga2-supply** (TOGa Supply) — 3 doc(s) → [2.0/apps/toga2-supply/INDEX.md](2.0/apps/toga2-supply/INDEX.md)
|
package/package.json
CHANGED