toga-ai 1.0.1014 → 1.0.1016
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.
- package/CLAUDE.md +2 -2
- package/agents/backend-lead.md +1 -1
- package/agents/frontend-lead.md +1 -1
- package/knowledge/2.0/apps/_underscore/INDEX.md +1 -1
- package/knowledge/2.0/apps/_underscore/architecture.md +2 -4
- package/knowledge/2.0/apps/_underscore/features/autoincrement-record-numbering.md +32 -45
- package/knowledge/2.0/apps/dbchanges2/architecture.md +6 -1
- package/knowledge/2.0/standards/backend-php.md +4 -1
- package/knowledge/clients/prudential/profile.md +5 -6
- package/knowledge/standalone/apps/claude/workflows/clickup-ticket-workflow.md +6 -3
- package/package.json +1 -1
- package/rules/common/git-workflow.md +30 -51
- package/rules/common/review-process.md +2 -2
- package/scripts/install.js +1 -1
- package/skills/commit/SKILL.md +10 -7
- package/skills/finish/SKILL.md +4 -4
- package/skills/start/SKILL.md +3 -2
package/CLAUDE.md
CHANGED
|
@@ -19,7 +19,7 @@ as `/skill-name` inside Claude Code.
|
|
|
19
19
|
| Skill | Command | When to use |
|
|
20
20
|
|-------|---------|-------------|
|
|
21
21
|
| **start** | `/start TRUE-1234` | **Start of every session.** ClickUp ticket id only. Reads the ticket (apps, clients, task type, pseudocode), checks branches, then primes the framework architecture, coding standards, repo knowledge, and client context. Edits are blocked until it runs. |
|
|
22
|
-
| **commit** | `/commit` | Commit only the files this session changed, with the session notes in the message
|
|
22
|
+
| **commit** | `/commit` | Commit only the files this session changed, with the session notes in the message, then pushes the ticket branch. |
|
|
23
23
|
| **pseudocode** | `/pseudocode` | Major tickets only. Writes the agreed approach as plain text to the ticket's Pseudocode field, after approval. |
|
|
24
24
|
| **finish** | `/finish` | **End of every session.** Records what was built or changed into the knowledge base, checks the ticket fields, and when the ticket is done pushes, opens the PRs, comments on the ticket, and sets it to development finished. |
|
|
25
25
|
| **toga-loop** | `/toga-loop` | Orchestrate a bigger or iterative change (multi-file feature, refactor, migration, sweep, or "keep going until X") as an explore→implement→verify loop driven by subagents, with progress tracked on a state file so it survives compaction and can resume. Run after `/start`. |
|
|
@@ -251,7 +251,7 @@ ticket — edits are blocked until you run it.
|
|
|
251
251
|
```
|
|
252
252
|
/commit
|
|
253
253
|
```
|
|
254
|
-
Commits only the files this session changed, with the session notes
|
|
254
|
+
Commits only the files this session changed, with the session notes, then pushes the ticket branch (never force).
|
|
255
255
|
|
|
256
256
|
**End of every session — run this before closing:**
|
|
257
257
|
```
|
package/agents/backend-lead.md
CHANGED
|
@@ -59,7 +59,7 @@ You are the maker; you never sign off your own work.
|
|
|
59
59
|
- `sql-reviewer` on any SQL (file or inline).
|
|
60
60
|
- `cso` on anything touching auth, user input, credentials, or queries.
|
|
61
61
|
Fix what they find and re-run until clean.
|
|
62
|
-
5. **
|
|
62
|
+
5. **Report what changed.** Commit and push happen through `/commit` (ticket branch, never force).
|
|
63
63
|
|
|
64
64
|
## Output
|
|
65
65
|
|
package/agents/frontend-lead.md
CHANGED
|
@@ -59,7 +59,7 @@ reviewer checks your work, not you.
|
|
|
59
59
|
stale bundle until a full restart; don't trust a live browser check until then.
|
|
60
60
|
4. **Review (required, via the Agent tool, off your thread):** `ecc:react-reviewer` on all
|
|
61
61
|
`.jsx`/`.tsx`; `ecc:typescript-reviewer` on non-React `.ts`. Fix and re-run until clean.
|
|
62
|
-
5. **
|
|
62
|
+
5. **Report what changed.** Commit and push happen through `/commit` (ticket branch, never force).
|
|
63
63
|
|
|
64
64
|
## Output
|
|
65
65
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
| [_ApiRequest — JSON encode/decode & api-logging behavior](features/apirequest-json-content-type.md) | `_ApiRequest`, the 2.0 outbound HTTP client — JSON encode/decode, retry, and api-logging traps; open before calling it or reading `Logs.Api`. |
|
|
11
11
|
| [Assortment Name Translation (AssortmentTranslations sidecar)](features/assortment-name-translation.md) | Serves Assortment names in multiple languages via an `AssortmentTranslations` sidecar table on the metadata-driven translation layer; open when translating asso |
|
|
12
12
|
| [Asynchronous Query Execution (writes-only, via Worker)](features/async-query-execution.md) | Run a slow WRITE asynchronously via the Worker tier so a long request write cannot hold a stale connection and hit "MySQL server has gone away"; open before usi |
|
|
13
|
-
| [
|
|
13
|
+
| [Record numbering (platform-wide FIELD_AUTOINCREMENT: Core.Records prefix + counter, scrambled)](features/autoincrement-record-numbering.md) | ORM record numbers (`SA1000000`, `AJ1419`, `CL519`) from one platform-wide counter per record type in `Core.Records`; open when adding a numbered model/prefix, |
|
|
14
14
|
| [Calculated-column filter options (`<field>FilterOptions` model static → table meta)](features/calculated-column-filter-options.md) | Lets a calculated (`FIELD_SQL`) table column supply its own filter dropdown options via a `<field>FilterOptions` model static; open when adding a data-driven co |
|
|
15
15
|
| [FIELD_SQL calculated fields — the underscore-prefix + same-name-method contract](features/calculated-sql-fields.md) | A `FIELD_SQL` (calculated) field on a `_Model` is bound by a **two-part contract that `_Model` enforces by throwing at model-construction time**, not by convent |
|
|
16
16
|
| [Carrier Shipping Labels (UPS/FedEx) & NetSuite Item Fulfillment](features/carrier-shipping-labels.md) | Backend mechanics behind Fulfill & Ship: buying/persisting a carrier label (UPS/FedEx) and creating the NetSuite Item Fulfillment; open for label, reprint, retu |
|
|
@@ -6,7 +6,7 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: architecture
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
9
|
+
updated: 2026-10-13
|
|
10
10
|
owners: ["jcardinal", "rgirish", "mhammontree", "ajean"]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/_underscore.php
|
|
@@ -282,9 +282,7 @@ Columns are declared as `public` properties set to field-type constants:
|
|
|
282
282
|
- **Calculated:** `FIELD_SQL` (see below).
|
|
283
283
|
|
|
284
284
|
**Field options** (the `FIELDOPT_*` array keys that tune a field): `FIELDOPT_DEFAULT` (default
|
|
285
|
-
value), `FIELDOPT_FOREIGNKEY_MODEL` (target model class), `
|
|
286
|
-
`FIELDOPT_AUTOINCREMENT_FIRSTNUMBER` / `FIELDOPT_AUTOINCREMENT_SUFFIX` (numbering scheme, see the
|
|
287
|
-
autoincrement feature), and `FIELDOPT_SQL_STORED` / `FIELDOPT_SQL_TYPE` (calculated fields, below).
|
|
285
|
+
value), `FIELDOPT_FOREIGNKEY_MODEL` (target model class), and `FIELDOPT_SQL_STORED` / `FIELDOPT_SQL_TYPE` (calculated fields, below).
|
|
288
286
|
|
|
289
287
|
**Foreign keys** are arrays with the target model:
|
|
290
288
|
|
|
@@ -1,85 +1,72 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
2
|
+
title: "Record numbering (platform-wide FIELD_AUTOINCREMENT: Core.Records prefix + counter, scrambled)"
|
|
3
3
|
framework: "2.0"
|
|
4
4
|
repo: _underscore
|
|
5
5
|
project: _Underscore
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
10
|
-
owners: ["bala", "rgirish"]
|
|
9
|
+
updated: 2026-10-13
|
|
10
|
+
owners: ["bala", "rgirish", "jcardinal"]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Model.php
|
|
13
13
|
- _underscore/Database.php
|
|
14
14
|
- _underscore/Model/Client/SalesOrder.php
|
|
15
|
+
- _underscore/Model/Client/ServiceRequest.php
|
|
15
16
|
- _underscore/Model/Client/TransferOrder.php
|
|
16
|
-
- _underscore/Model/
|
|
17
|
+
- _underscore/Model/Compass/Canada/SalesOrder.php
|
|
18
|
+
- _underscore/Model/Core/Client.php
|
|
19
|
+
- dbchanges2/Core/2026-10-13d - RecordNumbering.sql
|
|
17
20
|
related:
|
|
18
21
|
- ../architecture.md
|
|
22
|
+
- ../../dbchanges2/architecture.md
|
|
19
23
|
- ../../api2/features/v2-deadlock-retry.md
|
|
20
|
-
- ../../api2/features/environment-variable-drives-underscore-branch.md
|
|
21
24
|
- ../../worker2/features/netsuite-transferorder-outbound-push.md
|
|
22
25
|
- ../../worker2/features/netsuite-salesorder-outbound-push.md
|
|
23
26
|
---
|
|
24
27
|
|
|
25
|
-
ORM
|
|
28
|
+
ORM record numbers (`SA1000000`, `AJ1419`, `CL519`) from one platform-wide counter per record type in `Core.Records`; open when adding a numbered model/prefix, debugging a 1062 on `number`, or touching `formatRecordNumber`.
|
|
26
29
|
|
|
27
30
|
## Summary
|
|
28
31
|
|
|
29
|
-
A
|
|
30
|
-
|
|
31
|
-
```php
|
|
32
|
-
public $number = [
|
|
33
|
-
self::FIELD_AUTOINCREMENT,
|
|
34
|
-
self::FIELDOPT_AUTOINCREMENT_PREFIX => 'TA',
|
|
35
|
-
self::FIELDOPT_AUTOINCREMENT_FIRSTNUMBER => 100000,
|
|
36
|
-
];
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
12 models use it (SalesOrder `SA`, PurchaseOrder `P`, ServiceRequest `SR`, TransferOrder `TA`, Ticket, ItemReceipt, InventoryAdjustment, ...). For `DB_CLIENT` models the next number comes from a **counter row in the tenant's `Parameters` table**, taken on its own connection, so concurrent creates never get the same number.
|
|
40
|
-
|
|
41
|
-
**Branch state (verified 2026-10-02):** counter code (TRUE-82209, `1760b58a` + caps-key follow-up `bf22215b`) is on `_underscore` `_beta`, `_sandbox-dev`, `TRUE-82209`. **Not** on `_production` or `_sandbox-client` — prod still runs the old `MAX()+1` path and the Prudential `usleep` stopgap.
|
|
32
|
+
A model declares `public $number = [self::FIELD_AUTOINCREMENT];` — nothing else (the old `FIELDOPT_AUTOINCREMENT_PREFIX/FIRSTNUMBER/SUFFIX` options, the `MAX()+1` path and the per-tenant `Parameters` counter / PR `_underscore#756` are gone; PR 756 must NOT be merged). Prefix and counter live in `Core.Records`, so numbers are unique across all clients. TRUE-82715.
|
|
42
33
|
|
|
43
34
|
## How it works
|
|
44
35
|
|
|
45
|
-
1. **
|
|
46
|
-
2. **
|
|
47
|
-
3. **Allocate
|
|
48
|
-
4.
|
|
49
|
-
5. **
|
|
50
|
-
6. **
|
|
51
|
-
|
|
36
|
+
1. **Columns:** `Core.Records.numberPrefix CHAR(2) UNIQUE`, `nextNumber BIGINT UNSIGNED`. No `RecordFields` rows on purpose → not editable through the API.
|
|
37
|
+
2. **Row lookup:** `_Model` walks its class + parents against `Records.model` (stored with leading backslash, UNIQUE). Client overrides (`_Model_Compass_Canada_SalesOrder`) use the base row (SA). No row / NULL prefix / NULL counter → plain `Exception` (fail loud).
|
|
38
|
+
3. **Allocate:** `UPDATE Records SET nextNumber = LAST_INSERT_ID(nextNumber + 1) WHERE id = X` on `_Database::DB_CORE_SEQUENCE` (`'CoreSequence'`), committed at once; counter = insertId − 1. CoreSequence follows `DB_CORE` when registered (api2), else falls back to the config path of the physical Core DB (worker2 prod, saml). Re-registering Core with other settings closes the CoreSequence link.
|
|
39
|
+
4. **Format:** `prefix + formatRecordNumber(counter)` — no hyphen, no check digit. d = digit count of counter, c = offset within that width: `shown = 10^(d-1) + (c * 387419) % (9*10^(d-1))`. Bijection per width (multiplier coprime to 2, 3, 5) → no uniqueness check or retry loop; same digit count as the counter; length grows on its own.
|
|
40
|
+
5. **Start counters** (dbchanges2 seed): SA(14), SR(35), TK(99), ET(191) at 1000000 — 7 digits so they never equal old 6-digit numbers; PU(17), TR(312), RC(78), FF(28), AJ(154), CS(222) at 1000; CL(51) at 100 + client count. `Core.Clients.number VARCHAR(16) NOT NULL UNIQUE` added + backfilled in id order (RecordFields 2740).
|
|
41
|
+
6. **Hand-set number wins** (counter untouched). 1062 retry up to 5 only when the dup is the number this save generated. `forSearching` with null number skips the field (keeps `load()`'s empty-WHERE guard).
|
|
42
|
+
|
|
43
|
+
**Format rules (jcardinal):** 2-letter prefix, stored in `Core.Records` not the model; letters O, I, B banned (look like 0, 1, 8), L allowed; validate in PHP (no CHECK — see [dbchanges2 rule 15](../../dbchanges2/architecture.md)). TA → TR.
|
|
52
44
|
|
|
53
|
-
**Rejected
|
|
54
|
-
- Whole-request replay via `DEADLOCK_RETRIABLE_ROUTES` for every numbered route — unsafe per tenant: Adyen / Elite / Growrk `postPost` hooks have external side effects. See [V2 request retry](../../api2/features/v2-deadlock-retry.md).
|
|
55
|
-
- Derive number from the AUTO_INCREMENT `id` — `number` is NOT NULL UNIQUE and hand-set numbers break it.
|
|
56
|
-
- `GET_LOCK` — the lock is held to request end, so creates serialize.
|
|
45
|
+
**Rejected:** plain counter (type unreadable); numeric million bands (break at 1M); client id/date in number (long, leaks); check digit; Crockford base32 (hard to read aloud); random + exists-check loop; per-type multiplier column (edits break numbers); `numberMinDigits` column (start counter sets length). Block allocation of 1,000 deferred — one write per create is fine for now.
|
|
57
46
|
|
|
58
47
|
## Gotchas
|
|
59
48
|
|
|
60
|
-
- **⚠
|
|
61
|
-
-
|
|
62
|
-
- **
|
|
63
|
-
-
|
|
64
|
-
- **
|
|
65
|
-
- **
|
|
66
|
-
- **Reproducing
|
|
67
|
-
- **
|
|
68
|
-
- **Run `php -l Model.php Database.php` after resolving merge conflicts on env branches.** The TRUE-82209 merge into `_sandbox-dev`/`_beta` dropped `public static $_aliases` / `private static $_parked` in `Database.php` and duplicated `private $_model_generatedAutoincrementFields` in `Model.php` → beta outage (`Access to undeclared static property _Database::$_aliases`). The error page also dumped `$_SERVER`.
|
|
49
|
+
- **⚠ NEVER change `AUTOINCREMENT_MULTIPLIER = 387419`** — every issued number depends on it.
|
|
50
|
+
- **New numbered model needs a `Core.Records` row with `numberPrefix` + `nextNumber`** or creates throw. `Model/Client/Scope.php` (Desk branch TRUE-82615, prefix `'SC-'`) has no row: on merge make it plain `FIELD_AUTOINCREMENT` + seed a Records row prefix `SC`.
|
|
51
|
+
- **Local DB with an old `Clients.number` (CL1…)** → the migration's ADD COLUMN fails; fix by hand locally. Prod had no such column though `_Model_Core_Client` declared one.
|
|
52
|
+
- **SA / TR numbers are placeholders** — NetSuite `tranId` overwrites them on write-back (accepted). Never key a match on `number`; pushes key `externalId` on uuid.
|
|
53
|
+
- **Old `MAX()+1` race (why this exists):** concurrent creates got one number → 1062 → HTTP 400 `EV-10`, record lost (Prudential SR, TRUE-82209). Staggering callers did not fix it.
|
|
54
|
+
- **Gaps are possible** (a rolled-back request still used its number).
|
|
55
|
+
- **Reproducing a race needs distinct rows per call** (different contact + serial) and a gate-file release ([V2 request retry](../../api2/features/v2-deadlock-retry.md)); sandbox-dev `max_connections = 90` → keep bursts ~10.
|
|
56
|
+
- **Run `php -l Model.php Database.php` after merge conflicts on env branches** — a past merge dropped `_Database::$_aliases` → beta outage.
|
|
69
57
|
|
|
70
58
|
## Verification
|
|
71
59
|
|
|
72
|
-
|
|
60
|
+
2026-10-13 local (Client_Elite): single create AJ1419 for counter 1000; 10 concurrent creates distinct, counter +10, no 1062; hand-set `TEST-HAND-1` kept, counter unchanged; Compass Canada → row 14 SA. 2,000,000-counter uniqueness test passed.
|
|
73
61
|
|
|
74
62
|
## Related
|
|
75
63
|
|
|
76
64
|
- [_underscore architecture](../architecture.md)
|
|
77
|
-
- [
|
|
65
|
+
- [dbchanges2 architecture](../../dbchanges2/architecture.md)
|
|
78
66
|
- [NetSuite TransferOrder outbound push](../../worker2/features/netsuite-transferorder-outbound-push.md)
|
|
79
67
|
- [NetSuite SalesOrder outbound push](../../worker2/features/netsuite-salesorder-outbound-push.md)
|
|
80
68
|
|
|
81
69
|
## Change history
|
|
82
|
-
- 2026-10-
|
|
83
|
-
- 2026-10-02 —
|
|
84
|
-
- 2026-09-
|
|
85
|
-
- 2026-09-02 — `TA` / 100000 added to the shared `_Model_Client_TransferOrder`. (bala)
|
|
70
|
+
- 2026-10-13 — Replaced per-tenant Parameters counter (PR 756, not merged) with platform-wide prefix + counter in `Core.Records`, scrambled format; removed FIELDOPT_AUTOINCREMENT_* options and Prudential usleep. TRUE-82715. (jcardinal)
|
|
71
|
+
- 2026-10-02 — Per-tenant Parameters counter on `_beta` (superseded). (rgirish)
|
|
72
|
+
- 2026-09-02 — `TA` added to shared TransferOrder (now TR). (bala)
|
|
@@ -6,7 +6,7 @@ project: Database Changes
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: architecture
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
9
|
+
updated: 2026-10-13
|
|
10
10
|
owners: [jcardinal, mhammontree, bala, ajean]
|
|
11
11
|
files:
|
|
12
12
|
- Core/
|
|
@@ -258,6 +258,7 @@ This lifecycle is automated by a local browser tool — see the [TOGa 2.0 Client
|
|
|
258
258
|
- No prose preamble in a migration file: one short line per statement; narrative goes to the ticket.
|
|
259
259
|
- Before running on prod, confirm each tenant's existing natural-key values match EXACTLY, or a mismatch inserts a duplicate instead of a no-op.
|
|
260
260
|
14. **Never assume a migration has or has not run — verify (ask, or SELECT the live schema) before claiming state or editing a file.** An applied file is immutable: to undo it, RESTORE the original file to match what ran, then add a NEW dated forward-only file that drops/changes it (fresh envs run both and converge; run envs run only the new one). MySQL has no `DROP COLUMN IF EXISTS`, so restoring the add is what makes the later drop safe everywhere.
|
|
261
|
+
15. **Never add MySQL `CHECK` constraints in schema changes** — they caused problems with database backups (jcardinal, 2026-10-13). Validate allowed values in PHP instead.
|
|
261
262
|
|
|
262
263
|
## Bulk data loads — batch, and stage large sets in a temp table
|
|
263
264
|
|
|
@@ -393,3 +394,7 @@ The extra `SELECT … FROM ( … ) existing` layer both dodges error 1093 and pi
|
|
|
393
394
|
- **A `Client/` fan-out file that hardcodes a `customRecordFieldId` wires the wrong field for 29 of 30 tenants with no error** (rule #10). Custom-field ids are per-client `AUTO_INCREMENT`; keep custom-field work in the tenant's own folder.
|
|
394
395
|
- **An unguarded registration/seed insert can double-register** on a fresh environment (rule #7) — guard on the semantic identity, not the description.
|
|
395
396
|
- **The `dbchanges2` folder name IS the target database.** Running a `Core/` file against a client DB fails as `Table 'Client_X.<Table>' doesn't exist` (files are unqualified by design) — which names a missing table, not the real mistake. See [targeting the right database](workflows/targeting-the-right-database.md).
|
|
397
|
+
|
|
398
|
+
## Change history
|
|
399
|
+
|
|
400
|
+
- 2026-10-13 — Added rule 15: no MySQL `CHECK` constraints (TRUE-82715). (jcardinal)
|
|
@@ -5,7 +5,7 @@ project: _Underscore
|
|
|
5
5
|
client: shared
|
|
6
6
|
type: standard
|
|
7
7
|
status: active
|
|
8
|
-
updated: 2026-10-
|
|
8
|
+
updated: 2026-10-13
|
|
9
9
|
owners: [jcardinal, mhammontree, dfranks, bala, ajean]
|
|
10
10
|
files: []
|
|
11
11
|
related:
|
|
@@ -51,6 +51,8 @@ conventions.
|
|
|
51
51
|
10. Text/Blob fields
|
|
52
52
|
11. Custom fields
|
|
53
53
|
|
|
54
|
+
**No `CHECK` constraints.** Never add MySQL `CHECK` constraints in schema changes; they caused problems with database backups. Validate allowed values in PHP. See [dbchanges2 rule 15](../apps/dbchanges2/architecture.md).
|
|
55
|
+
|
|
54
56
|
### UUIDs
|
|
55
57
|
|
|
56
58
|
* All records inserted in the 2.0 database must be given a random UUID in the second column of each table called `uuid`
|
|
@@ -1026,5 +1028,6 @@ See: 2.0/apps/worker2/features/cross-account-aws-access.md (role model),
|
|
|
1026
1028
|
|
|
1027
1029
|
## Change history
|
|
1028
1030
|
|
|
1031
|
+
- 2026-10-13 — Table Design: no MySQL `CHECK` constraints; validate in PHP (TRUE-82715). (jcardinal)
|
|
1029
1032
|
- 2026-10-12 — AWS access rule now covers 1.0 + 2.0: no IAM keys, assume WorkloadsRuntime; static-key grandfathering removed (TRUE-82705). (jcardinal)
|
|
1030
1033
|
- 2026-10-07 — Added the short-file-docblock rule (design history belongs in the knowledge base). (mhammontree)
|
|
@@ -17,7 +17,7 @@ project: _Underscore
|
|
|
17
17
|
client: prudential
|
|
18
18
|
type: profile
|
|
19
19
|
status: active
|
|
20
|
-
updated: 2026-10-
|
|
20
|
+
updated: 2026-10-13
|
|
21
21
|
owners: ["jcardinal", "rgirish", "bala", "mhammontree"]
|
|
22
22
|
files: []
|
|
23
23
|
related:
|
|
@@ -120,11 +120,10 @@ The order-created cron branches on this id; the shipped/delivered crons branch o
|
|
|
120
120
|
The 15-minute `prudential_auth_rejection_alert.php` cron now alerts on them — see
|
|
121
121
|
features/service-request-auth-rejection-alert.md.
|
|
122
122
|
|
|
123
|
-
- **SR number race (ServiceNow bursts → 1062 `Duplicate entry 'SR…'` → 400 `EV-10`, SR lost).** Fixed
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
(
|
|
127
|
-
`customer.uuid` set. See [FIELD_AUTOINCREMENT record numbering](../../2.0/apps/_underscore/features/autoincrement-record-numbering.md).
|
|
123
|
+
- **SR number race (TRUE-82209: ServiceNow bursts → 1062 `Duplicate entry 'SR…'` → 400 `EV-10`, SR lost).** Fixed by
|
|
124
|
+
platform-wide record numbers (TRUE-82715); the `usleep` stopgap in `_Model_Prudential_ServiceRequest::prePost()`
|
|
125
|
+
is removed. Load-test with a distinct contact + serial per call and `customer.uuid` set. See
|
|
126
|
+
[Record numbering](../../2.0/apps/_underscore/features/autoincrement-record-numbering.md).
|
|
128
127
|
|
|
129
128
|
## Monitoring
|
|
130
129
|
- `Monitor/Prudential/{SalesOrderGenerationBacklog,DellPurchaseOrderTransmissionBacklog,OrderShippedUpdateBacklog}`
|
|
@@ -6,7 +6,7 @@ project: Claude Harness
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: workflow
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
9
|
+
updated: 2026-10-13
|
|
10
10
|
owners: ["jcardinal"]
|
|
11
11
|
files:
|
|
12
12
|
- claude/skills/start/SKILL.md
|
|
@@ -43,11 +43,12 @@ writes, and agents until the session has a ticket. These replaced `/kickoff`, `/
|
|
|
43
43
|
KB, moves the status `to do` -> `in progress`, and loads PR review feedback if an open PR
|
|
44
44
|
exists (rework: same branch, same PR). If ClickUp can't be read, it stops — no offline mode.
|
|
45
45
|
2. **`/commit`** — commits only this session's files, ticket from the session file, then the
|
|
46
|
-
branch.
|
|
46
|
+
branch. Then pushes the ticket branch (`git push -u origin <TICKET>`, never force).
|
|
47
47
|
3. **`/pseudocode`** — major tickets only. Writes the agreed approach to the Pseudocode field
|
|
48
48
|
after the developer approves. Touches no other field.
|
|
49
49
|
4. **`/finish`** — always writes the team KB first. Then one approval list for ticket fields
|
|
50
|
-
(Application, Stakeholders, Task Type, title, Has UI Changes).
|
|
50
|
+
(Application, Stakeholders, Task Type, title, Has UI Changes). Then it asks "Is this ticket finished?" — a yes is the permission (no extra asks): commit any
|
|
51
|
+
uncommitted session files, push each
|
|
51
52
|
repo with work, open or update a PR per repo, post a PM comment, set status
|
|
52
53
|
`development finished`. The PM comment is plain bullets for a non-technical PM: "What
|
|
53
54
|
changed" always; "Manual steps", "Still open", "Ticket fields changed by Claude" only when
|
|
@@ -177,6 +178,8 @@ All tested 2026-10-08:
|
|
|
177
178
|
- 2026-10-09 — TRUE-82605: `/start` names the session `<TICKET>: <short title>` (set-title +
|
|
178
179
|
SessionStart `sessionTitle`; `/rename` to paste). (jcardinal)
|
|
179
180
|
|
|
181
|
+
- 2026-10-13 — `/commit` now pushes the ticket branch; `/finish`'s "finished" yes covers commit,
|
|
182
|
+
push, and PR with no extra asks; Claude may switch to the ticket branch in normal work. (jcardinal, TRUE-82715)
|
|
180
183
|
## Related
|
|
181
184
|
|
|
182
185
|
- [Ticket-branch creation safety](./ticket-branch-creation-safety.md)
|
package/package.json
CHANGED
|
@@ -9,37 +9,25 @@ Start every session with `/start TRUE-1234` (the ClickUp ticket id only). The `s
|
|
|
9
9
|
blocks edits, writes, and agents until a session has a ticket. The ticket drives the branch name,
|
|
10
10
|
the commit prefix, the PR title, and the ticket updates at `/finish`.
|
|
11
11
|
|
|
12
|
-
##
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
Invoking one of these skills **is** explicit authorization, but only for what that skill
|
|
32
|
-
describes. It does not authorize publishing anything else in the session.
|
|
33
|
-
|
|
34
|
-
- `/commit` — local commits of only the files this session changed. Never pushes.
|
|
35
|
-
- `/finish` — the KB push to `_main`, the ticket-branch pushes, the PRs, and the ticket writes.
|
|
36
|
-
If this session's files are uncommitted, `/finish` asks once and, on "yes", runs the
|
|
37
|
-
`/commit` steps itself (same rules as `/commit`). Claude writes and posts the PM comment,
|
|
38
|
-
PR subject/body, commit notes, and KB summary itself — no approval prompt (secret scan
|
|
39
|
-
still runs). Ticket field changes still need the one approval list; pushes still ask.
|
|
40
|
-
- `/ship`, `/land-and-deploy` — the commits, pushes, and PRs they describe.
|
|
41
|
-
|
|
42
|
-
Force-pushing is never automatic in any repo, including the knowledge repo.
|
|
12
|
+
## Commit, push, and PR — what Claude does (decided 2026-10-13, TRUE-82715)
|
|
13
|
+
|
|
14
|
+
1. **`/commit`** commits only this session's files **and pushes the ticket branch**
|
|
15
|
+
(`git push -u origin <TICKET>`). Never force.
|
|
16
|
+
2. **`/finish`** does the KB capture, then asks one question: **"Is this ticket finished?"**
|
|
17
|
+
On yes it: commits any uncommitted session files, pushes, opens (or updates) one PR per
|
|
18
|
+
repo, comments on the ticket, and sets the status. No extra "may I push?" or "may I open
|
|
19
|
+
the PR?" questions — that yes is the permission. Ticket field changes still use the one
|
|
20
|
+
approval list.
|
|
21
|
+
3. **Branches.** Claude may create or switch to the ticket branch as part of normal work.
|
|
22
|
+
4. `/ship`, `/land-and-deploy` — the commits, pushes, and PRs they describe.
|
|
23
|
+
5. The KB repo (`~/toga-tech`) — `/finish` commits and pushes to `_main`.
|
|
24
|
+
|
|
25
|
+
Always, in every repo:
|
|
26
|
+
|
|
27
|
+
- Never force-push.
|
|
28
|
+
- Never stash, and never discard someone's uncommitted changes.
|
|
29
|
+
- Never commit straight to `_main` or the default branch of an app repo.
|
|
30
|
+
- Never commit secrets, `.env` files, or local paths (secret scan still runs).
|
|
43
31
|
|
|
44
32
|
## Claude never creates git worktrees
|
|
45
33
|
|
|
@@ -63,25 +51,12 @@ that repo, Claude may run `start-helper.js create-branch` to create (from the de
|
|
|
63
51
|
or check out the ticket branch `<TICKET>`. Nothing else: no worktree, no stash, never on a
|
|
64
52
|
repo with uncommitted changes, never force-push. See *Branch naming*.
|
|
65
53
|
|
|
66
|
-
##
|
|
67
|
-
|
|
68
|
-
Many developers work across many projects and switch branches constantly. A change that is
|
|
69
|
-
"missing" from the working tree is almost always **on another branch** — not lost.
|
|
70
|
-
|
|
71
|
-
If Claude notices that work it made earlier in the conversation is gone from the working tree,
|
|
72
|
-
or sees it in the git history on a different branch, it **must stop and ask**. It must not:
|
|
54
|
+
## Missing work is usually on another branch
|
|
73
55
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
The correct response is to **pause the conversation** and say what it observed — which changes
|
|
80
|
-
appear absent, and which branch they seem to live on — then ask the developer to switch to that
|
|
81
|
-
branch so the existing code can be reviewed. Reviewing what is actually there beats regenerating
|
|
82
|
-
it: a rewrite silently discards whatever the developer (or a teammate) changed in the meantime.
|
|
83
|
-
|
|
84
|
-
Only rewrite when explicitly told to.
|
|
56
|
+
If work Claude made earlier is gone from the working tree, it is almost always on another
|
|
57
|
+
branch — not lost. Do not re-write it from memory. Find the branch it lives on (`git log
|
|
58
|
+
--all`), say so, and switch to it if the working tree is clean. If the tree has uncommitted
|
|
59
|
+
changes, stop and ask — never stash or discard them.
|
|
85
60
|
|
|
86
61
|
## Check git before stating commit state
|
|
87
62
|
|
|
@@ -124,13 +99,17 @@ Never force-push to `_main` under any circumstances.
|
|
|
124
99
|
The branch is the bare ClickUp ticket id — e.g. `TRUE-82600`. No prefix, no description.
|
|
125
100
|
ClickUp may create it, or `/start` creates it. One branch per ticket per repo.
|
|
126
101
|
|
|
102
|
+
**Base branch.** Only the new platform app repos (today `toga25-desk` and `toga25-iq`) branch from
|
|
103
|
+
`toga25` and open their PR back to `toga25`. Every other repo (`_underscore`, `api2`, `worker2`,
|
|
104
|
+
`dbchanges2`, …) uses its own default branch, even in the same session.
|
|
105
|
+
|
|
127
106
|
`/start` checks that every repo on the ticket (from its Application values) is on the ticket
|
|
128
107
|
branch. On a mismatch it asks once per repo: "Create/switch to `<TICKET>` in `<repo>` from
|
|
129
108
|
`<base>`?" On yes it runs `start-helper.js create-branch` (checks out `origin/<TICKET>` or the
|
|
130
109
|
local branch if one exists, else creates it from the default branch and pushes it with
|
|
131
110
|
`git push -u`, never force). A repo with uncommitted changes is refused — Claude stops and
|
|
132
|
-
says so.
|
|
133
|
-
|
|
111
|
+
says so. Claude may also create or switch to the ticket branch later in normal work, with the
|
|
112
|
+
same limits.
|
|
134
113
|
|
|
135
114
|
The KB/harness repo (`toga-tech`) is the exception: work there goes on `_main`.
|
|
136
115
|
|
|
@@ -44,5 +44,5 @@ statement so its view is genuinely independent.
|
|
|
44
44
|
3. A lead implements (`backend-lead` / `frontend-lead` / `database-architect`).
|
|
45
45
|
4. Reviewers + `qa-engineer` verify (maker ≠ checker).
|
|
46
46
|
5. `documentation-engineer` / `knowledge-writer` capture what's durable.
|
|
47
|
-
6.
|
|
48
|
-
|
|
47
|
+
6. `/commit` commits and pushes the ticket branch; `/finish` opens the PRs once the developer
|
|
48
|
+
says the ticket is finished. Never force-push.
|
package/scripts/install.js
CHANGED
|
@@ -588,7 +588,7 @@ ticket — edits are blocked until you run it.
|
|
|
588
588
|
\`\`\`
|
|
589
589
|
/commit
|
|
590
590
|
\`\`\`
|
|
591
|
-
Commits only the files this session changed, with the session notes
|
|
591
|
+
Commits only the files this session changed, with the session notes, then pushes the ticket branch (never force).
|
|
592
592
|
|
|
593
593
|
**End of every session — run this before closing:**
|
|
594
594
|
\`\`\`
|
package/skills/commit/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: commit
|
|
3
|
-
description: Commit ONLY the files this Claude Code session changed, in every repo it touched, and write the session's notes (why the task exists, what was found, approach, turned-down options, who decided) into the commit message so the PR reviewer can build the PR summary from it. The ticket comes from the /start session ticket, then the branch. Safe when several sessions work on the same branch in the same checkout.
|
|
3
|
+
description: Commit ONLY the files this Claude Code session changed, in every repo it touched, and write the session's notes (why the task exists, what was found, approach, turned-down options, who decided) into the commit message so the PR reviewer can build the PR summary from it. The ticket comes from the /start session ticket, then the branch. Safe when several sessions work on the same branch in the same checkout. Then pushes the ticket branch (never force); /finish opens the PRs. Trigger on "/commit", "commit this", "commit my changes".
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /commit — commit this session's files, with the session's notes
|
|
@@ -13,9 +13,11 @@ ticket comes from the `/start` session ticket file
|
|
|
13
13
|
|
|
14
14
|
## Step 0 — Rules
|
|
15
15
|
|
|
16
|
-
- Running `/commit` IS the
|
|
17
|
-
-
|
|
18
|
-
|
|
16
|
+
- Running `/commit` IS the authorization to commit these files and push the ticket branch.
|
|
17
|
+
- Push only the ticket branch: `git -C <repo> push -u origin <TICKET>`. Never force-push. Never
|
|
18
|
+
push or commit straight to `_main` / the default branch of an app repo.
|
|
19
|
+
- Never `git add -A` or `git add .`. Never `--no-verify`. Never `--amend`.
|
|
20
|
+
Never stash or discard uncommitted changes. Never commit a file the developer did not approve.
|
|
19
21
|
|
|
20
22
|
## Step 1 — Find your own session id
|
|
21
23
|
|
|
@@ -129,7 +131,8 @@ Then, per repo:
|
|
|
129
131
|
|
|
130
132
|
1. `helper forget --session=<id> --repo=<repo> --files=<committed files, comma-separated>`
|
|
131
133
|
2. Report per repo: short hash, subject, file count.
|
|
132
|
-
3.
|
|
133
|
-
|
|
134
|
-
4. Say:
|
|
134
|
+
3. Push: `git -C <repo> push -u origin <TICKET>` (never force). If the push is rejected, stop
|
|
135
|
+
and report it — do not force or rebase on your own.
|
|
136
|
+
4. Say: "Committed and pushed. Run /finish when the ticket is done; it opens the PRs."
|
|
137
|
+
5. Say: changes made by hand outside Claude can still be committed the normal way in VS Code;
|
|
135
138
|
the PR reviewer will show those as manual changes.
|
package/skills/finish/SKILL.md
CHANGED
|
@@ -13,7 +13,8 @@ ClickUp reads run in the `ticket-reader` subagent. The main thread distills and
|
|
|
13
13
|
|
|
14
14
|
Claude writes and posts all summary text itself — PM comment, PR subject and body, commit
|
|
15
15
|
notes, KB capture summary. Never ask the developer to approve that wording. Approvals are only
|
|
16
|
-
for real decisions: ticket field changes (one list), ELEVATED KB docs, and
|
|
16
|
+
for real decisions: ticket field changes (one list), ELEVATED KB docs, and "Is this ticket finished?". A yes to
|
|
17
|
+
that question is the permission to commit, push, and open the PRs — no extra asks.
|
|
17
18
|
|
|
18
19
|
## Step 0 — Rules, helpers, session ticket
|
|
19
20
|
|
|
@@ -349,10 +350,9 @@ skip Steps 12–14 and go to Step 15 (PM comment) and Step 16 (status).
|
|
|
349
350
|
`origin/<TICKET>` if pushed). This includes commits from other sessions — that is intended.
|
|
350
351
|
Keep for each: repo path, `owner/repo`, ahead count, pushed or not.
|
|
351
352
|
2. `COMMIT status --session=<sid> --root="$CLAUDE_PROJECT_DIR"`. If any repo has `toCommit`
|
|
352
|
-
files: ask
|
|
353
|
-
**Yes** → run the `/commit` skill's steps yourself (same rules as `skills/commit/SKILL.md`:
|
|
353
|
+
files: do not ask again — the "finished" yes covers it. Run the `/commit` skill's steps yourself (same rules as `skills/commit/SKILL.md`:
|
|
354
354
|
only this session's files, the `Claude-Notes: v1` format), then re-run step 1 and continue.
|
|
355
|
-
|
|
355
|
+
(Changes outside
|
|
356
356
|
Claude's list, `otherChanged`, are the developer's — mention them, do not block.)
|
|
357
357
|
3. If `gh auth status` fails, say exactly: "Run `gh auth login` in a terminal, then tell me
|
|
358
358
|
'done'". When they say done, run `gh auth status` again and continue only if it passes.
|
package/skills/start/SKILL.md
CHANGED
|
@@ -158,8 +158,9 @@ developer has not named the session.
|
|
|
158
158
|
Branches named with the ticket id link to the ClickUp ticket through the GitHub
|
|
159
159
|
integration — on the first real run, confirm the link shows on the ticket.
|
|
160
160
|
|
|
161
|
-
|
|
162
|
-
|
|
161
|
+
Here Claude asks first. Later in the session Claude may create or switch to the ticket branch
|
|
162
|
+
as part of normal work, with the same limits — never stash, never discard changes, never
|
|
163
|
+
force (`rules/common/git-workflow.md`). On no, say: "Switch these repos to `<T>`, then tell me.
|
|
163
164
|
Or say 'continue anyway'." Only on an explicit "continue anyway":
|
|
164
165
|
|
|
165
166
|
```
|