toga-ai 1.0.274 → 1.0.275

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.
@@ -5,7 +5,7 @@
5
5
  | [Worker (worker2) Architecture](architecture.md) | Worker (repo `worker2`) is an AWS Elastic Beanstalk **Worker Tier** application that processes background jobs. | worker2/Controller/Index.php, worker2/Worker/, worker2/LambdaFunctions/, _underscore/Worker.php |
6
6
  | [Automated PR Merger — Concurrent Force-Push Clobber Race](features/automated-pr-merger-force-push-race.md) | The automated PR merger `_Worker_Team_GitHub::Merge` (`worker2` `Worker/Team/Github.php`) merges approved PRs to `_production` by **force-pushing from a clone t | Worker/Team/Github.php |
7
7
  | [ClickUp Connectivity Watchdog](features/clickup-connectivity-watchdog.md) | A cron watchdog that emails when the ClickUp integration looks disconnected during business hours. | worker2/Worker/Clickup/Health.php, worker2/Database/ClickupHealthWatchdog.sql |
8
- | [ClickUp Design Sprint Automation (Final Design Outcome)](features/clickup-design-sprint-automation.md) | `_Worker_Clickup_Design` is meant to drive the design-sprint workflow in ClickUp via the API, replacing a set of native ClickUp automations. | worker2/Worker/Clickup/Design.php, worker2/Worker/Clickup.php |
8
+ | [ClickUp Design Sprint Automation (Final Design Outcome)](features/clickup-design-sprint-automation.md) | `_Worker_Clickup_Design` is meant to drive the design-sprint workflow in ClickUp via the API, replacing a set of native ClickUp automations. | worker2/Worker/Clickup/Design.php, worker2/Worker/Clickup.php, worker2/Controller/ClickupDesignTest.php |
9
9
  | [ClickUp GitHub-tab Auto-linking & Ticket-id Branch Naming](features/clickup-github-autolink.md) | How ClickUp surfaces branches/PRs/commits in a ticket's **GitHub tab**, and the branch / PR-title naming convention that triggers it. | |
10
10
  | [ClickUp Project & Opportunity Multi-List Routing](features/clickup-project-routing.md) | Routes ClickUp tasks into the correct **secondary multi-list memberships** based on their custom-field values, via the `clickup` webhook. | worker2/Worker/Clickup/Project.php, worker2/Worker/Clickup.php |
11
11
  | [ClickUp Rich-Text Custom Fields via Quill Delta (API)](features/clickup-richtext-api.md) | ClickUp custom text fields (type `text` and long-text) support rich formatting only through a **Quill Delta** written to the undocumented `value_richtext` key o | test/@dave/clickup_md2delta.js, .claude/skills/plan-ticket/scripts/clickup.js |
@@ -6,11 +6,12 @@ project: Worker
6
6
  client: shared
7
7
  type: feature
8
8
  status: active
9
- updated: 2026-07-06
9
+ updated: 2026-07-07
10
10
  owners: ["ajean"]
11
11
  files:
12
12
  - worker2/Worker/Clickup/Design.php
13
13
  - worker2/Worker/Clickup.php
14
+ - worker2/Controller/ClickupDesignTest.php
14
15
  related:
15
16
  - ./clickup-work-type-automation.md
16
17
  - ./team-sprint-management.md
@@ -22,25 +23,32 @@ replacing a set of native ClickUp automations. When a task's **Final Design Outc
22
23
  drop-down is set to an actionable value, the worker either spawns an iteration task or
23
24
  completes the task, and a daily cron reminds the Design Approver of pending reviews.
24
25
 
25
- **Critical current state (as of 2026-07-06):** the worker's
26
- `handleFinalDesignOutcome` has been **silently no-opping in production** — the native
27
- ClickUp automations it was supposed to replace were never disabled and had been doing the
28
- real work all along, masking the failure. Do not assume the API path is live. See Gotchas
29
- and the open action item below before touching this code.
26
+ **Current state (as of 2026-07-07):** the silent no-op is **fixed and shipped**
27
+ (worker2 PR #98, branch `fix/clickup-design-outcome-resolver` off `_production`). Root cause
28
+ was a **strict `===` type mismatch** in `resolveFinalDesignOutcomeOptionId`, confirmed and
29
+ corrected. The spurious "Design Review" email (both vectors) is also fixed. Once the worker
30
+ is verified live, the native ClickUp automations that were masking the no-op must stay
31
+ disabled — see Gotchas.
30
32
 
31
33
  ## Key files / entry points
32
34
  - `Worker/Clickup/Design.php` → `_Worker_Clickup_Design` — the design-sprint engine.
33
- - `handleFinalDesignOutcome(...)` — the entry that decides spawn vs. complete (currently a
34
- silent no-op in prod).
35
+ - `handleFinalDesignOutcome(...)` — the entry that decides spawn vs. complete.
35
36
  - `resolveFinalDesignOutcomeOptionId(...)` (Design.php:298-317) — maps the drop-down value
36
- to an option ID.
37
+ to an option ID; now **string-compares** value/orderindex/id (see Gotchas).
37
38
  - `spawnIterationTask(...)` / `carryDesignApprover(...)` — duplicate the task and copy the
38
39
  Design Approver.
39
- - `completeTask(...)` — closes an approved task.
40
+ - `completeTask(...)` — closes an approved task (iterated → complete).
40
41
  - `SendReviewReminders(...)` — daily reminder cron action.
41
42
  - `TRUE_DESIGN_SPRINTS_FOLDER_ID` constant (Design.php:27,50).
42
- - `Worker/Clickup.php` (dispatcher ~lines 822-875) — routes ClickUp webhooks; the Design
43
- Approver / status guard lives at 822-833.
43
+ - `Worker/Clickup.php` — routes ClickUp webhooks.
44
+ - `shouldEmailDesignApprover($payload, $taskDetails)` — the single predicate gating the
45
+ "Action Needed: Design Review" email (requires history_items[0] is a Design Approver
46
+ custom_field change, task status still `iterated`, and user-driven: `user.id != -1`).
47
+ - `taskUpdated` path (~822) and `taskStatusUpdated` path (~230) both gate the email on this
48
+ predicate.
49
+ - `Controller/ClickupDesignTest.php` — regression tests reached via the
50
+ `?controller=ClickupDesignTest` route (worker2 has **no PHPUnit harness**; mirrors the
51
+ `CompassPeopleTest` convention). Uses `ReflectionMethod` to reach the private methods.
44
52
 
45
53
  ## How it works
46
54
  1. A ClickUp webhook reaches `_Worker_Clickup`; the dispatcher (Clickup.php ~822-875) routes
@@ -68,41 +76,49 @@ undefined-constant theory was ruled out.
68
76
  None — internal TOGA Technology (`true`) design-sprint tooling.
69
77
 
70
78
  ## Gotchas / known issues
71
- - **Silent no-op masked by native automations (root cause of TRUE-79685).** The worker's
72
- docstring claims it replaced the native automations, but they were never disabled. Native
73
- automation `c25fd345` ("When Final Design Outcome is Iterated, duplicate the ticket and
74
- close the original") was doing the duplicate+close and **hiding** that the worker never
75
- spawned. Only after disabling **all** native automations did setting Final Design Outcome →
76
- "Iterated – New Task" on TRUE-80046 (prod job 295376, isSuccess=1) produce **no** spawn,
77
- exposing the failure.
78
- - **OPEN — two prime suspects for the silent no-op** (need a combined code + live-API session
79
- to confirm/fix):
80
- 1. **Folder-gate ID mismatch.** `TRUE_DESIGN_SPRINTS_FOLDER_ID = '90115939842'`
81
- (Design.php:27,50) vs. the file-header comment naming `90020178491`. `90115939842` is a
82
- valid folder (the daily reminder cron GETs `/folder/90115939842/list` successfully) but
83
- may not be the folder the automation-test tasks live in — in which case the folder gate
84
- returns early on every task. **Verify:** compare `getTaskDetails` `folder.id` for
85
- TRUE-80046 against the constant.
86
- 2. **Strict `===` mismatch in `resolveFinalDesignOutcomeOptionId`** (Design.php:298-317). If
87
- `getTaskDetails` returns the `drop_down` value in a shape (string `orderindex`, or an
88
- option-id) that matches neither `option->id === value` nor `option->orderindex === value`,
89
- it returns `null` → silent no-op. Fix should be an explicit **cast/validate at the
90
- ClickUp-payload boundary**, not merely switching `===` to `==`.
91
- - **Latent bug — spurious "Design Review" email on freshly spawned tasks.** Spawned iteration
92
- tasks transiently pass through "iterated" status during creation (a ClickUp list
93
- automation), and `spawnIterationTask → carryDesignApprover` copies the Design Approver onto
94
- the new task. If that copy lands while the new task is momentarily "iterated", the dispatcher
95
- guard (Clickup.php:822-833: `custom_field.name == 'Design Approver' && status == 'iterated'`)
96
- fires a **spurious** "Action Needed: Design Review" email. Candidate fix: gate
97
- `sendDesignApproverEmail` on the change being user-driven (history `user.id != ClickBot -1`).
98
- - **Native automations must be disabled once the worker is fixed.** The worker was meant to
99
- replace: `c25fd345`, `272f743e` (Automation #39, native "email Aaron when iterated"),
100
- `a64c863a`, `7739cc41`, `08570f31`, `70b09962`. Keep sprint-readiness automations only:
101
- `10df1786`, `f6214678`. **INTERIM:** if the design team needs the workflow before the worker
102
- is fixed, re-enable **only** `c25fd345` (temporary — this reintroduces the Iteration-reset
103
- and spurious-email issues).
79
+ - **Never use strict `===` when reading a ClickUp `drop_down` value/orderindex/id (ROOT CAUSE
80
+ of the silent no-op).** ClickUp returns `value`/`orderindex` with **inconsistent int-vs-string
81
+ typing** (`"2" !== 2`), so `resolveFinalDesignOutcomeOptionId` matched nothing, returned
82
+ `null`, and `handleFinalDesignOutcome` hit its early return (job still `isSuccess=1`). Fixed
83
+ by comparing **as strings**: `(string)$option->orderindex === (string)$field->value` (and the
84
+ same for `$option->id`). Note that **every other** drop_down reader in `Worker/Clickup.php`
85
+ relies on PHP **array-key coercion** (`$optionsByIndex[$option->orderindex]` then indexed by
86
+ `$customField->value`) precisely because of this typing inconsistency — strict `===` anywhere
87
+ reading a ClickUp drop_down value is a bug. The native automation `c25fd345` had been masking
88
+ this no-op in prod.
89
+ - **`taskStatusUpdated` switches on `before->status`, NOT `after->status`** (Clickup.php ~71).
90
+ A `case '<status>'` in that switch therefore fires when a task **LEAVES** that status — the
91
+ in-code comment claiming "just changed TO iterated" is misleading. This is the trap behind the
92
+ second spurious-email vector: the `iterated` case fired on `completeTask()`'s
93
+ `iterated → complete` transition during `spawnIterationTask`. Anyone adding status-transition
94
+ logic must account for this direction. A correctly-placed "entering iterated" trigger would go
95
+ under `switch(after->status)` and is **not** currently wired.
96
+ - **Spurious "Design Review" email — fixed on a single predicate.** Both vectors (the
97
+ `taskUpdated` Design-Approver-field path ~822 and the `taskStatusUpdated` `iterated` path
98
+ ~230) now gate on `shouldEmailDesignApprover($payload, $taskDetails)`, which requires:
99
+ `history_items[0]` is a Design Approver custom_field change, task status still `iterated`, and
100
+ the change is **user-driven** (`user.id != -1`; ClickBot/automation writes carry
101
+ `user.id == -1`). The dead `$isDesignApproverSet` block was removed. Consequence: a pure status
102
+ change **into** iterated (approver already set, no field change) no longer emails from the
103
+ status path — the legitimate review email flows from the `taskUpdated` field handler.
104
+ - **Native automations must stay disabled once the worker is verified.** The worker replaces:
105
+ `c25fd345`, `272f743e`, `a64c863a`, `7739cc41`, `08570f31`, `70b09962`. Keep sprint-readiness
106
+ automations only: `10df1786`, `f6214678`. Re-enabling any of the replaced set reintroduces the
107
+ duplicate+close and spurious-email behavior.
108
+ - **Not the bug (ruled out):** `_underscore` PR #624 field/option constants were confirmed
109
+ present and correct — no `_underscore` change was needed. The earlier folder-gate ID-mismatch
110
+ suspicion was also not the cause.
104
111
 
105
112
  ## Change history
113
+ - 2026-07-07 — Fixed and shipped the silent no-op (worker2 PR #98, branch
114
+ `fix/clickup-design-outcome-resolver`). Confirmed root cause: strict `===` on ClickUp
115
+ `drop_down` value/orderindex/id in `resolveFinalDesignOutcomeOptionId` (inconsistent int/string
116
+ typing) — now string-compared. Fixed the spurious "Design Review" email (both the `taskUpdated`
117
+ and `taskStatusUpdated` vectors) behind a single `shouldEmailDesignApprover` predicate that
118
+ requires a user-driven Design-Approver field change on an `iterated` task. Documented that
119
+ `taskStatusUpdated` switches on `before->status` (fires on LEAVING a status). Added regression
120
+ tests in `Controller/ClickupDesignTest.php` (run via `?controller=ClickupDesignTest`). Ruled
121
+ out `_underscore` PR #624 constants as the cause. (ajean)
106
122
  - 2026-07-06 — Diagnosed the "design-sprint API automation not running" report (TRUE-79685;
107
123
  tests TRUE-80026/80046): `handleFinalDesignOutcome` is silently no-opping in prod, masked by
108
124
  never-disabled native automation `c25fd345`. Narrowed to two suspects (folder-gate ID
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.274",
3
+ "version": "1.0.275",
4
4
  "description": "TOGA Technology Team Claude Knowledge System — shared AI coding harness with skills, knowledge base CLI, and project installer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",