toga-ai 1.0.271 → 1.0.273

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.
@@ -3,7 +3,9 @@
3
3
  | Doc | Summary | Files |
4
4
  |-----|---------|-------|
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
+ | [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 |
6
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 |
7
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. | |
8
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 |
9
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 |
@@ -0,0 +1,71 @@
1
+ ---
2
+ title: Automated PR Merger — Concurrent Force-Push Clobber Race
3
+ framework: "2.0"
4
+ repo: worker2
5
+ project: Worker
6
+ client: shared
7
+ type: feature
8
+ status: active
9
+ updated: 2026-07-06
10
+ owners: [dfranks]
11
+ files:
12
+ - Worker/Team/Github.php
13
+ related:
14
+ - ./clickup-github-autolink.md
15
+ ---
16
+
17
+ ## Summary
18
+
19
+ The automated PR merger `_Worker_Team_GitHub::Merge` (`worker2` `Worker/Team/Github.php`)
20
+ merges approved PRs to `_production` by **force-pushing from a clone taken before the read,
21
+ without rebasing**. When two merges run concurrently, the second force-push silently
22
+ overwrites the first merge's commit, orphaning it. This is a silent data-loss failure mode
23
+ in shared deploy tooling — it affects **every repo** merged through the automated merger,
24
+ not just one file.
25
+
26
+ ## How it works (the failure mode)
27
+
28
+ - The merger clones/reads `_production`, applies the merge, then `git push --force`.
29
+ - Because the push is a `--force` from a stale clone with no rebase, a merge that landed
30
+ in the window between the read and the push is **overwritten** — its commit is no longer
31
+ an ancestor of `_production`.
32
+ - GitHub still reports the clobbered PR as **MERGED** (the merge happened; it was just
33
+ force-pushed away afterward), so **no error surfaces**. The changed files never reach the
34
+ deployed bundle.
35
+ - Real occurrence: a merged `worker2` webhook handler file was orphaned ~40s later by a
36
+ concurrent automated merge — MERGED on GitHub, absent from `_production`.
37
+
38
+ ## Diagnostic — auditing for clobbered PRs
39
+
40
+ For every PR GitHub reports as MERGED into `_production`, test whether its merge commit is
41
+ still an ancestor of the branch:
42
+
43
+ ```
44
+ gh pr list --repo <repo> --base _production --state merged --json number,mergeCommit
45
+ git merge-base --is-ancestor <mergeCommitSHA> origin/_production # exit 0 = ancestor (fine)
46
+ ```
47
+
48
+ If `--is-ancestor` is **false**, the PR was clobbered (orphaned). Then **confirm real loss**:
49
+ check whether the PR's changed files actually exist on `_production` today. A stale
50
+ force-push artifact can be non-ancestor yet have had its content re-applied by a later
51
+ merge — that case is benign.
52
+
53
+ ## Fix direction (do NOT just add a rebase)
54
+
55
+ Rebasing alone is **insufficient**: it only narrows the check-then-act window. A `--force`
56
+ push after a rebase can still clobber a merge that lands between the rebase and the push.
57
+
58
+ Durable fix:
59
+ - **Drop `--force`** — use a plain `push` (or `--force-with-lease`) so a stale push is
60
+ **rejected as non-fast-forward** instead of silently overwriting.
61
+ - Add a **retry loop** (re-fetch → re-rebase → retry) on rejection, **or serialize merges
62
+ behind a lock**.
63
+ - Rebase makes the non-force push succeed on the happy path; **dropping `--force` is what
64
+ makes it safe.**
65
+
66
+ ## Change history
67
+
68
+ - 2026-07-06 — Initial doc: documented the `_Worker_Team_GitHub::Merge` concurrent
69
+ force-push clobber race (MERGED-on-GitHub-but-orphaned, silent), the `git merge-base
70
+ --is-ancestor` audit procedure with the benign-artifact caveat, and the fix direction
71
+ (drop `--force`/use `--force-with-lease` + retry/lock, not rebase alone) (dfranks)
@@ -0,0 +1,111 @@
1
+ ---
2
+ title: ClickUp Design Sprint Automation (Final Design Outcome)
3
+ framework: "2.0"
4
+ repo: worker2
5
+ project: Worker
6
+ client: shared
7
+ type: feature
8
+ status: active
9
+ updated: 2026-07-06
10
+ owners: ["ajean"]
11
+ files:
12
+ - worker2/Worker/Clickup/Design.php
13
+ - worker2/Worker/Clickup.php
14
+ related:
15
+ - ./clickup-work-type-automation.md
16
+ - ./team-sprint-management.md
17
+ ---
18
+
19
+ ## Summary
20
+ `_Worker_Clickup_Design` is meant to drive the design-sprint workflow in ClickUp via the API,
21
+ replacing a set of native ClickUp automations. When a task's **Final Design Outcome**
22
+ drop-down is set to an actionable value, the worker either spawns an iteration task or
23
+ completes the task, and a daily cron reminds the Design Approver of pending reviews.
24
+
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.
30
+
31
+ ## Key files / entry points
32
+ - `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
+ - `resolveFinalDesignOutcomeOptionId(...)` (Design.php:298-317) — maps the drop-down value
36
+ to an option ID.
37
+ - `spawnIterationTask(...)` / `carryDesignApprover(...)` — duplicate the task and copy the
38
+ Design Approver.
39
+ - `completeTask(...)` — closes an approved task.
40
+ - `SendReviewReminders(...)` — daily reminder cron action.
41
+ - `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.
44
+
45
+ ## How it works
46
+ 1. A ClickUp webhook reaches `_Worker_Clickup`; the dispatcher (Clickup.php ~822-875) routes
47
+ design-folder events into `_Worker_Clickup_Design`.
48
+ 2. The worker acts on **only two** Final Design Outcome values:
49
+ - **"Iterated – New Task"** (option `3f835ac8…`) → `spawnIterationTask` — duplicates the
50
+ ticket into a new iteration task and carries over the Design Approver.
51
+ - **"Approved"** (option `2d17868b…`) → `completeTask`.
52
+ 3. The full Final Design Outcome option set is: In Progress, In Review, **Iterated – New
53
+ Task**, **Approved**, Cancelled. Only the two bolded values are actionable.
54
+ 4. A separate ClickUp automation (`a64c863a`) sets the outcome to **"In Review"** when a
55
+ task's *status* changes to Iterated. "In Review" is **not** actionable — so
56
+ `status → Iterated` alone never triggers the API. The worker acts only when the Design
57
+ Approver **manually** selects one of the two actionable outcome values.
58
+ 5. Daily reminder cron `Core.CronJobs` id 21 ("Design Review Reminders", `0 9 * * 1-5`,
59
+ action `Clickup/Design/SendReviewReminders`) nudges the approver about pending reviews.
60
+
61
+ ## Data model
62
+ Configuration lives as ClickUp identifiers (folder IDs, custom-field IDs, drop-down option
63
+ UUIDs), not in the DB. The custom-field / option-ID constants are defined in `_underscore`
64
+ (`_production`) — confirmed present (worker2 PR #80, _underscore PR #624); the
65
+ undefined-constant theory was ruled out.
66
+
67
+ ## Client variations
68
+ None — internal TOGA Technology (`true`) design-sprint tooling.
69
+
70
+ ## 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).
104
+
105
+ ## Change history
106
+ - 2026-07-06 — Diagnosed the "design-sprint API automation not running" report (TRUE-79685;
107
+ tests TRUE-80026/80046): `handleFinalDesignOutcome` is silently no-opping in prod, masked by
108
+ never-disabled native automation `c25fd345`. Narrowed to two suspects (folder-gate ID
109
+ mismatch, strict-`===` option resolution) pending a code+live-API fix session. Also
110
+ identified a latent spurious-email bug on spawned tasks and clarified that only
111
+ "Iterated – New Task" and "Approved" outcomes are actionable. (ajean)
@@ -17,7 +17,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
17
17
  ## 2.0 framework
18
18
 
19
19
  - **_underscore** (_Underscore) _(framework core)_ — 22 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
20
- - **worker2** (Worker) — 25 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
20
+ - **worker2** (Worker) — 26 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
21
21
  - **api2** (API) — 7 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
22
22
  - **dbchanges2** (Database Changes) _(framework core)_ — 3 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
23
23
  - **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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.271",
3
+ "version": "1.0.273",
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",