toga-ai 1.0.422 → 1.0.424
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/knowledge/2.0/apps/_underscore/INDEX.md +1 -1
- package/knowledge/2.0/apps/_underscore/architecture.md +23 -15
- package/knowledge/2.0/apps/_underscore/features/per-client-database-connections.md +19 -1
- package/knowledge/2.0/apps/api2/architecture.md +25 -3
- package/knowledge/2.0/apps/toga-blox/workflows/dynamic-publish-pipeline.md +33 -2
- package/package.json +1 -1
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
| [_Model magic-field access (__get without __isset)](features/model-magic-field-access.md) | `_Model` exposes DB columns as "magic" properties via `__get()`, but it defines **no** `__isset()`. | _underscore/Model/Core/Model.php |
|
|
22
22
|
| [_Model::save() vs raw _Query — no atomic conditional update](features/model-save-vs-query-atomic-update.md) | `_Model::save()` is a plain load-then-write ORM primitive and **cannot express an atomic conditional update** (an optimistic-concurrency / row-claim guard such | _underscore/Model.php, _underscore/Query.php |
|
|
23
23
|
| [NetSuite REST Client (_Component_Api_Netsuite) — record writes & SuiteQL](features/netsuite-rest-client.md) | `_Component_Api_Netsuite` is the **2.0 `_underscore` NetSuite REST client** — the shared primitive every worker2/api2 NetSuite caller uses for record GETs, Suit | _underscore/Component/Api/Netsuite/Netsuite.php |
|
|
24
|
-
| [Per-Client Database Connections & the Local Logs Trap](features/per-client-database-connections.md) | When `_underscore` serves a request for a client it opens **three distinct per-client database connections**, not one. | _underscore/Database.php, _underscore/ApiRequest.php, _underscore/Model/Client/Logs/Api.php |
|
|
24
|
+
| [Per-Client Database Connections & the Local Logs Trap](features/per-client-database-connections.md) | When `_underscore` serves a request for a client it opens **three distinct per-client database connections**, not one. | _underscore/Database.php, _underscore/ApiRequest.php, _underscore/Model/Client/Logs/Api.php, api2/Controller/Index.php |
|
|
25
25
|
| [Persona Name Translation (PersonaTranslations sidecar)](features/persona-name-translation.md) | Serves Persona **names** in multiple languages by adding a per-language **sidecar** table `PersonaTranslations`, reusing the platform's existing metadata-driven | _underscore/Model/Client/PersonaTranslation.php, dbchanges2/Client/2026-07-22b - PersonaTranslations.sql, dbchanges2/Core/2026-07-22a - PersonaTranslationsRecord.sql, dbchanges2/Client/2026-07-22c - PersonaTranslationsAcl.sql, dbchanges2/Client_CompassCanada/2026-07-22 - PersonaTranslationsFrench.sql, toga2-commerce/src/pages/Account/view/MySettingsView.tsx |
|
|
26
26
|
| [Recursive Item Fulfillments (upstream mirroring)](features/recursive-item-fulfillments.md) | In a multi-tier supply chain a sales order (SO) spawns a purchase order (PO) that becomes another SO downstream, and so on. | _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Client/ItemFulfillmentItem.php, _underscore/Model/Client/ItemFulfillmentItemUnit.php, _underscore/Model/Client/ItemFulfillmentPackage.php, _underscore/Model/Compass/AdvanceShippingNotice.php, dbchanges2/Core/2026-02-13 - 75601 - RecursiveItemFulfillmentCreation.sql, dbchanges2/Core/2026-06-04 - RecursiveItemFulfillmentPut.sql, dbchanges2/Client_Compass/2026-07-02a - FixSA133377TrackingSerialAndDuplicateIF.sql |
|
|
27
27
|
| [Surface Resolver (_Model_Core_Surface::resolve — replaces Page::meta)](features/surface-resolver.md) | The runtime for the platform-wide **Surface** UI presentation layer: 9 `_underscore` models plus a cached resolver, `_Model_Core_Surface::resolve(&$api, string | _underscore/Model/Core/Surface.php, _underscore/Model/Client/AclRecordScript.php, _underscore/Model/Core/RecordScript.php, dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql, dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql, dbchanges2/Client_Quad/2026-07-01a - GrantSurfacesMetaGroupScriptAcl.sql, dbchanges2/Client_CompassCanada/2026-07-01a - GrantSurfacesMetaGroupScriptAcl.sql, dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql, dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql, dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql, dbchanges2/Client_Compass/2026-07-15f - SalesOrderRecordActionsRemoveDeadConfigRuleOverrides.sql, dbchanges2/Core/2026-07-17h - Update - ClearApprovalsFilterButtonConfig.sql, dbchanges2/Client_Compass/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Compass/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_CompassCanada/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, dbchanges2/Client_Quad/2026-07-17a - SalesOrderApprovalActionsOverride.sql, dbchanges2/Client_Quad/2026-07-17b - SalesOrderApprovalsFilterButtonOverride.sql, _underscore/Model/Core/SurfaceElement.php, _underscore/Model/Core/Action.php, _underscore/Model/Core/Vocabulary.php, _underscore/Model/Core/VocabularyTerm.php, _underscore/Model/Core/Message.php, _underscore/Model/Client/SurfaceOverride.php, _underscore/Model/Client/MessageTranslation.php, _underscore/Model/Client/ThemeToken.php, _underscore/Model/Core/Page.php, api2/Component/Api/V2/V2.php |
|
|
@@ -6,7 +6,7 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: architecture
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-07-
|
|
9
|
+
updated: 2026-07-23
|
|
10
10
|
owners: ["jcardinal", "rgirish", "mhammontree"]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/_underscore.php
|
|
@@ -344,21 +344,28 @@ multi-file UI components (`.php`/`.html`/`.css`/`.js`) invoked as `<_ComponentNa
|
|
|
344
344
|
- **`_Database::register()` auto-starts a lazy transaction (since Apr 2 2026, commit `fa7835ed`).** Any code that calls `register()` and then writes to that DB must call `_Database::transactionCommit()` before the request ends — otherwise MySQL silently rolls back all writes when the connection closes. Lazy transactions only materialise on the first write, so read-only callers are unaffected. See `_underscore/Database.php:48`. First discovered when Rate SAML user provisioning silently discarded all new user INSERTs (Jun 2026).
|
|
345
345
|
- **PHP "Unclosed '{'" parse errors report a MISLEADING line number.** When a `.php` file loaded by the autoloader (`Loader.php`) has a dropped/unbalanced brace, PHP reports `Unclosed '{' on line N` where N is the **outermost `class X {` line** and fails at EOF — NOT at the true location of the missing `}`. Worse, because the file loads lazily via the SPL autoloader, the runtime trace points at the **caller** that triggered the autoload (e.g. a `new _Email()` call site), not the broken file. **Triage rule:** for an "Unclosed '{'" error, the real culprit is a missing `}` somewhere between the reported line and EOF of the file that failed to load — run `php -l <file>` (it reports the EOF line) and scan the whole file. **Merge-conflict resolutions are a common source of a single dropped brace** — review the entire merge, not just the one file the error appears to name. (First hit: production 500 EO-1, Jul 2026 — a `}` dropped from `_Email::send()` during merge `685e4a14` surfaced as a trace pointing at the `new _Email()` caller.)
|
|
346
346
|
|
|
347
|
-
- **A controller exception
|
|
348
|
-
dispatch, `_underscore/Route.php`
|
|
347
|
+
- **A controller exception used to be silently swallowed by `Route.php`, then masked as a view error
|
|
348
|
+
(FIXED 2026-07-23).** In dispatch, `_underscore/Route.php` previously wrapped the controller call in
|
|
349
349
|
`catch (Exception $e) { _Database::transactionRollback(); }` — **no log, no rethrow, no debug
|
|
350
|
-
bypass.** The controller response
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
exception thrown inside the controller method
|
|
354
|
-
routing/view misconfiguration.
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
returns a response object that gets JSON-encoded —
|
|
360
|
-
|
|
361
|
-
|
|
350
|
+
bypass.** The controller response was left null, so Route.php fell through to its generic throw:
|
|
351
|
+
`Failed to determine how to render view for route '<route>' ... './View/Index/<method>.html'`.
|
|
352
|
+
That "Failed to determine how to render view" fatal was therefore very often a MASK for a real
|
|
353
|
+
exception thrown inside the controller method (commonly `_Controller_Index::api()`), not a genuine
|
|
354
|
+
routing/view misconfiguration. **Fixed 2026-07-23:** the catch now logs the swallowed exception
|
|
355
|
+
(via `error_log`, message + trace) **and rethrows**, and it catches `\Throwable` (not just
|
|
356
|
+
`Exception`) so `Error`s (type errors, fatals) surface too — the rollback is still performed before
|
|
357
|
+
rethrow. The real exception now propagates instead of being reshaped into the misleading line-525
|
|
358
|
+
view error. When diagnosing, you now see the true controller exception directly. (Note: an
|
|
359
|
+
*unmatched host* does NOT trigger this; `api()` returns a response object that gets JSON-encoded —
|
|
360
|
+
only a thrown exception hits this path.) A frequent underlying culprit was a DB connect / "Unknown
|
|
361
|
+
database" failure in `api()`'s pre-execute block — now separately guarded in api2 (see the api2
|
|
362
|
+
architecture doc's front-controller section). See
|
|
363
|
+
`2.0/apps/api2/workflows/environment-configuration-and-provisioning.md`.
|
|
364
|
+
- **Follow-up (deferred, separate ticket): production info-leak from unconditional `display_errors`.**
|
|
365
|
+
Now that Route.php rethrows, whatever global error handling renders the exception can leak the raw
|
|
366
|
+
message/trace to the client if `display_errors` is on unconditionally. Confirm `display_errors` is
|
|
367
|
+
disabled in production and that the framework's error surface returns a sanitized envelope (not a raw
|
|
368
|
+
stack trace) to API consumers. Not yet done — tracked as a follow-up.
|
|
362
369
|
|
|
363
370
|
## Change history
|
|
364
371
|
- 2026-06-11 — Documented lazy transaction gotcha in `_Database::register()` (rgirish)
|
|
@@ -367,3 +374,4 @@ multi-file UI components (`.php`/`.html`/`.css`/`.js`) invoked as `<_ComponentNa
|
|
|
367
374
|
- 2026-07-02 — Fixed framework-wide `FIELD_STORAGE` write-drop and folder-read bugs in `Model.php`; noted the remaining unconditional-refetch dirty-read follow-up. (mhammontree)
|
|
368
375
|
- 2026-07-07 — Documented `_Query` writes-only async mode (`isAsync` → Worker `Infrastructure/Database/Query`) in the database-architecture section, linked `features/async-query-execution.md`, and noted the SQS-first `_Worker::runTask()` enqueue departure (caller does no MySQL; worker tier creates the row on pickup). (jcardinal)
|
|
369
376
|
- 2026-07-16 — Documented the misleading "Unclosed '{'" parse-error gotcha (autoloader reports the outermost `class {` line / caller trace, not the true dropped-brace location; merge conflicts a common cause). First hit production 500 EO-1 via a dropped `_Email::send()` brace. (jcardinal)
|
|
377
|
+
- 2026-07-23 — Fixed the Route.php swallow→mask gotcha: the controller-call catch now log+rethrows and catches `\Throwable` (not just `Exception`), so the true controller exception surfaces instead of the misleading line-525 "Failed to determine how to render view" fatal. Noted the deferred production `display_errors` info-leak follow-up. (jcardinal)
|
|
@@ -6,12 +6,13 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-07-
|
|
9
|
+
updated: 2026-07-23
|
|
10
10
|
owners: ["dfranks", "jcardinal", "mhammontree", "apeterson"]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Database.php
|
|
13
13
|
- _underscore/ApiRequest.php
|
|
14
14
|
- _underscore/Model/Client/Logs/Api.php
|
|
15
|
+
- api2/Controller/Index.php
|
|
15
16
|
related:
|
|
16
17
|
- ../architecture.md
|
|
17
18
|
- ../workflows/local-db-refresh-from-beta.md
|
|
@@ -89,12 +90,29 @@ registration is region-aware in `api2/Controller/Index.php`; the alias const is
|
|
|
89
90
|
set from beta — see [Refreshing a local dev DB from beta](../workflows/local-db-refresh-from-beta.md).
|
|
90
91
|
This is a **local-environment** gap, not a code bug — do not "fix" it by disabling logging in
|
|
91
92
|
shared code.
|
|
93
|
+
- **The shared Core Logs DB (`DB_LOGS`) has the same trap — and its name is resolved dynamically,
|
|
94
|
+
so "I have all the databases installed" can still fail.** api2's `Controller/Index.php::api()`
|
|
95
|
+
bootstrap registers `DB_LOGS` using a schema name read from a **`Core.Database` row**
|
|
96
|
+
(`id = CORE_LOGS_DATABASE_ID`), not a fixed literal. A Logs DB you created locally whose *name*
|
|
97
|
+
doesn't match that Core row still reads as **missing** → `mysqli_connect` `Unknown database`. Match
|
|
98
|
+
the local schema name to the `Core.Database` row (or fix the row), don't just "create a logs DB."
|
|
99
|
+
- **This Core Logs bootstrap runs OUTSIDE the try/catch that wraps `$api->execute()`** (the env
|
|
100
|
+
lookup, region/host `search()`, `_Model_Core_Database` instantiation, and `_Database::register()`
|
|
101
|
+
for `DB_CORE`/`DB_LOGS` all run before the guarded block at ~line 202 of `Controller/Index.php`).
|
|
102
|
+
A connect failure here threw past `api()` and got masked by `Route.php` as the misleading line-525
|
|
103
|
+
"Failed to determine how to render view" error — see the Route.php swallow→mask gotcha in
|
|
104
|
+
[_underscore architecture](../architecture.md#gotchas--known-issues).
|
|
92
105
|
- Related 1.0 analogue: the legacy `App_` worker has the same hazard writing to `Logs.API`
|
|
93
106
|
(`db_logs`) — the laptop trap there is documented separately in the worker NetSuite bootstrap
|
|
94
107
|
notes.
|
|
95
108
|
|
|
96
109
|
## Change history
|
|
97
110
|
|
|
111
|
+
- 2026-07-23 — Documented the shared **Core Logs** (`DB_LOGS`) analogue of the logs trap: its schema
|
|
112
|
+
name is resolved from a `Core.Database` row (`id = CORE_LOGS_DATABASE_ID`) in
|
|
113
|
+
`api2/Controller/Index.php::api()`, so a name-mismatched local Logs DB still reads as missing; and
|
|
114
|
+
this bootstrap runs outside `api()`'s guarded block, so a connect failure was masked by Route.php's
|
|
115
|
+
line-525 view error. (jcardinal)
|
|
98
116
|
- 2026-07-09 — Linked the new [Running a 2.0 app locally](../workflows/running-a-2.0-app-locally.md) runbook, which frames these three connections as one requirement of a full local browser run. (mhammontree)
|
|
99
117
|
- 2026-07-09 — Linked the new [local-DB-refresh-from-beta workflow](../workflows/local-db-refresh-from-beta.md)
|
|
100
118
|
from the logs-trap fix (refreshing all local schemas from beta covers the missing `Logs_<Id>`). (apeterson)
|
|
@@ -6,7 +6,7 @@ project: API
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: architecture
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-07-
|
|
9
|
+
updated: 2026-07-23
|
|
10
10
|
owners: [jcardinal, bala]
|
|
11
11
|
files:
|
|
12
12
|
- api2/Controller/Index.php
|
|
@@ -65,8 +65,21 @@ lands in `api()`.
|
|
|
65
65
|
- **CORS:** permissive `Access-Control-Allow-*`; returns 200 for `OPTIONS` preflight.
|
|
66
66
|
- **`/health`:** 200 + empty object (EB/LB probe — keep it working).
|
|
67
67
|
- **Sentry:** initialized per request; EC2 instance metadata attached.
|
|
68
|
-
- **Core DB:** registers `Core` (`DB_CORE`), preferring a
|
|
69
|
-
(`CORE_READHOST`)
|
|
68
|
+
- **Core DB bootstrap (now guarded, 2026-07-23):** registers `Core` (`DB_CORE`), preferring a
|
|
69
|
+
region-local read host (`CORE_READHOST`), then registers the **Core Logs DB** region-aware as
|
|
70
|
+
`DB_LOGS`. This whole block runs in a **pre-execute phase that executes *before* the `execute()`
|
|
71
|
+
try/catch**, so a failure here historically escaped that guard and became a fatal. Two traps:
|
|
72
|
+
(1) the Core Logs **schema name is resolved from a `Core.Database` row** (`id =
|
|
73
|
+
CORE_LOGS_DATABASE_ID`), so a **name-mismatched local Logs DB** (one whose actual schema name
|
|
74
|
+
differs from the Core-recorded name) reads as **missing** and `mysqli_connect` throws `Unknown
|
|
75
|
+
database` — a common local-dev breakage, not a code bug. (2) That connect failure used to be a
|
|
76
|
+
fatal. **Fixed 2026-07-23:** the pre-execute Core/Logs bootstrap is wrapped in a
|
|
77
|
+
`try/catch (\Throwable)` that, on failure, returns the standard **`INVALID_CONFIGURATION`**
|
|
78
|
+
error envelope and reports to **Sentry** instead of dying with an unguarded fatal. Note the
|
|
79
|
+
rollback in that catch is a **guarded no-op** — with no transaction started yet,
|
|
80
|
+
`_Database::transactionRollback()` short-circuits safely (`Database.php:219–226`). See
|
|
81
|
+
[_underscore architecture — Route.php log+rethrow gotcha](../_underscore/architecture.md) for the
|
|
82
|
+
upstream masking behavior this pairs with, and the per-client-database-connections feature doc.
|
|
70
83
|
- **Host dispatch:** lowercase `HTTP_HOST`, strip trailing domain, switch on the remainder.
|
|
71
84
|
- **Transaction/logging invariant (JSON path):** wraps the call in transactions; on
|
|
72
85
|
**success** commit logs then data; on **failure** commit logs but **roll back data**; on
|
|
@@ -153,6 +166,12 @@ Core/Client/Logs DB passwords, **AWS access key id + secret**, and third-party A
|
|
|
153
166
|
carries a **GitHub PAT**. These should be rotated and moved to SSM Parameter Store / EB env
|
|
154
167
|
properties. **Flag this if you touch config or deploy.**
|
|
155
168
|
|
|
169
|
+
**Follow-up (deferred, separate ticket): raw exception disclosure to clients.** The error paths that
|
|
170
|
+
surface a caught `\Throwable` (now that Route.php rethrows and the bootstrap guard reports failures)
|
|
171
|
+
must not return raw `getMessage()`/`getTrace()` output in the client-facing envelope — that leaks
|
|
172
|
+
internal paths, schema names, and stack frames to API consumers. Sanitize the client envelope
|
|
173
|
+
(generic message + code; full detail to Sentry/logs only). Not yet done.
|
|
174
|
+
|
|
156
175
|
## When making changes here
|
|
157
176
|
|
|
158
177
|
- **Adding/altering an endpoint is usually a data change, not code** — define `Records` +
|
|
@@ -167,3 +186,6 @@ properties. **Flag this if you touch config or deploy.**
|
|
|
167
186
|
the duplicate check.
|
|
168
187
|
- Preserve the commit-logs / rollback-data-on-failure invariant when editing the controller
|
|
169
188
|
or `execute()`.
|
|
189
|
+
|
|
190
|
+
## Change history
|
|
191
|
+
- 2026-07-23 — Documented the now-guarded Core/Logs DB bootstrap in the front controller: the pre-execute block runs before the `execute()` try/catch, the Core Logs schema name is resolved from a `Core.Database` row (`id = CORE_LOGS_DATABASE_ID`) so a name-mismatched local Logs DB reads as missing, and the failure is now wrapped in `try/catch (\Throwable)` returning `INVALID_CONFIGURATION` + Sentry instead of a fatal (guarded no-op rollback, `Database.php:219–226`). Added the deferred raw-getMessage/getTrace client-disclosure follow-up to the Security note. (jcardinal)
|
|
@@ -6,8 +6,8 @@ project: TOGa Blox
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: workflow
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-07-
|
|
10
|
-
owners: [jcardinal]
|
|
9
|
+
updated: 2026-07-23
|
|
10
|
+
owners: [jcardinal, apeterson]
|
|
11
11
|
files:
|
|
12
12
|
- toga-blox/.github/workflows/publish.yml
|
|
13
13
|
- toga-blox/src/utils/getFontAwesomeIcon.tsx
|
|
@@ -35,6 +35,26 @@ resolve in a consuming app's build, or touching `publish.yml`.
|
|
|
35
35
|
- **Every** branch (including `_production`) publishes a **prerelease** version
|
|
36
36
|
`X.Y.Z-<mode>.<run>` under dist-tag `<mode>`. There is no longer a production special case.
|
|
37
37
|
Verified live: `production:1.0.315-production.96`, `sandbox-client:1.0.315-sandbox-client.97`.
|
|
38
|
+
Observed 2026-07-23: `sandbox-client:1.0.317-sandbox-client.101`, `sandbox-dev:1.0.316-sandbox-dev.102`.
|
|
39
|
+
|
|
40
|
+
### Version derivation (CI owns the suffix; dev owns only the base)
|
|
41
|
+
|
|
42
|
+
- CI reads `version` from `package.json`, **strips any `-<suffix>`**, does **`patch + 1`**, then
|
|
43
|
+
appends `-<mode>.<GITHUB_RUN_NUMBER>`. So base `1.0.317` on `_sandbox-client` run 104 publishes
|
|
44
|
+
`1.0.318-sandbox-client.104` under dist-tag `sandbox-client`.
|
|
45
|
+
- **The developer controls only the BASE version** committed in `package.json` on the feature
|
|
46
|
+
branch. **Never hand-write the `-<mode>.N` prerelease suffix** — CI generates it. There is no
|
|
47
|
+
manual `npm publish`; CI is the only publisher.
|
|
48
|
+
|
|
49
|
+
### Deploy procedure (e.g. `_sandbox-client`)
|
|
50
|
+
|
|
51
|
+
1. Ensure a clean tree; optionally bump the base version in `package.json` on the feature branch.
|
|
52
|
+
2. Merge the feature branch into `_sandbox-client`, then push (this triggers the CI publish).
|
|
53
|
+
3. Monitor with `gh run watch`; verify with `npm dist-tag ls @agilant/toga-blox`.
|
|
54
|
+
4. Consuming apps (e.g. `toga25-supply` on `_sandbox-client`) install from the `sandbox-client`
|
|
55
|
+
dist-tag or a pinned `1.0.x-sandbox-client.N` version and must **re-install** to pick up a new
|
|
56
|
+
build. The `deploy-sandbox-client` project skill (`.claude/skills/` in this repo) drives this
|
|
57
|
+
procedure end-to-end.
|
|
38
58
|
|
|
39
59
|
### What was removed (and why it's safe)
|
|
40
60
|
|
|
@@ -66,6 +86,12 @@ environment needs its own maintained `_<mode>` branch in `toga-blox-npm`.
|
|
|
66
86
|
- **Publish before build.** `npm install @agilant/toga-blox@<mode>` fails `ETARGET No matching
|
|
67
87
|
version` in the app build until this repo has published that channel. GitHub Actions runs the
|
|
68
88
|
workflow version *on the pushed branch*, so the branch must carry the current `publish.yml`.
|
|
89
|
+
- **`publish.yml` has diverged across branches (2026-07-23).** The dynamic `_*` wildcard trigger
|
|
90
|
+
lives on `_sandbox-client`, but older/feature branches (e.g. `feature-new-table`) still carry the
|
|
91
|
+
*old* `publish.yml` that triggers only on `_production/_gamma/_beta`. Because Actions runs the
|
|
92
|
+
copy on the pushed branch, a new `_<mode>` channel will **not** publish unless the branch you push
|
|
93
|
+
carries the wildcard-trigger version. When standing up a new channel, merge from a branch that has
|
|
94
|
+
the dynamic `publish.yml` (or update it first).
|
|
69
95
|
- **FontAwesome v7 `style`-prop TS2322** (fixed 2026-07-21 in `getFontAwesomeIcon.tsx`, and a
|
|
70
96
|
reusable pattern for any consumer). FA v7 types the `FontAwesomeIcon` `style` prop as
|
|
71
97
|
`CSSProperties & CSSVariables`, where `CSSVariables` requires a `--fa-*` custom-property index
|
|
@@ -78,6 +104,11 @@ environment needs its own maintained `_<mode>` branch in `toga-blox-npm`.
|
|
|
78
104
|
the pattern the consuming apps should follow (see the commerce workflow's secret-hygiene note).
|
|
79
105
|
|
|
80
106
|
## Change history
|
|
107
|
+
- 2026-07-23 — Documented CI version derivation (strip suffix → patch+1 → append `-<mode>.<run>`;
|
|
108
|
+
dev owns only the base version, never the suffix) and the `_sandbox-client` deploy procedure now
|
|
109
|
+
driven by the `deploy-sandbox-client` project skill. Recorded that `publish.yml` has diverged
|
|
110
|
+
across branches: the dynamic `_*` trigger is on `_sandbox-client` while older/feature branches
|
|
111
|
+
still trigger only on `_production/_gamma/_beta`. (apeterson)
|
|
81
112
|
- 2026-07-21 — Made `publish.yml` fully dynamic: trigger `_*`, branch→dist-tag by stripping the
|
|
82
113
|
leading underscore (mode == channel 1:1), every branch (incl. `_production`) publishes a
|
|
83
114
|
`X.Y.Z-<mode>.<run>` prerelease; removed the `_production`→`latest` special case (workflow no
|
package/package.json
CHANGED