toga-ai 1.0.259 → 1.0.260
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/features/surface-resolver.md +57 -2
- package/knowledge/2.0/apps/toga25-supply/features/client-configurable-fields.md +23 -1
- package/knowledge/clients/compass-canada/profile.md +8 -1
- package/knowledge/clients/quad/profile.md +9 -1
- package/package.json +1 -1
|
@@ -14,6 +14,6 @@
|
|
|
14
14
|
| [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 |
|
|
15
15
|
| [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 |
|
|
16
16
|
| [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 |
|
|
17
|
-
| [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, dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql, dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql, dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql, dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql, dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.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 |
|
|
17
|
+
| [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, _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 |
|
|
18
18
|
| [Tracking-Number Bridge Migration (ASN / Item Fulfillment / Item Receipt)](features/tracking-number-bridges.md) | Shipment tracking numbers used to live as **scalar FK columns** (`trackingNumberId`, `returnTrackingNumberId`) directly on the lowest-level "unit"/"item" tables | api2/Component/Api/V2/V2.php, _underscore/Model/Client/AdvanceShippingNoticeItemUnit.php, _underscore/Model/Client/AdvanceShippingNoticeItemUnits/TrackingNumber.php, _underscore/Model/Client/ItemFulfillmentItemUnits/TrackingNumber.php, _underscore/Model/Client/ItemFulfillment.php, _underscore/Model/Prudential/AdvanceShippingNotice.php, _underscore/Model/Compass/AdvanceShippingNotice.php, _underscore/Trait/Netsuite/ItemFulfillment.php, api2/Component/Api/Cxml/Cxml.php, dbchanges2/Client/2026-06-10 - TrackingNumberBridges.sql, dbchanges2/Core/2026-06-10 - TrackingNumberBridges.sql, dbchanges2/Client_Prudential/2026-06-15 - ItemFulfillmentTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Quad/2026-06-18a - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Nychh/2026-06-19b - ItemFulfillmentItemReceiptTrackingNumberAclLogicGroups.sql, dbchanges2/Client_Nychh/2026-06-19a - FixItemFulfillmentTableViewTrackingAndRoot.sql, dbchanges2/Client_Quad/2026-06-19a - FixItemFulfillmentTableViewTrackingAndRoot.sql |
|
|
19
19
|
| [Units for Items for Purchase Orders — Data Structure](features/units-for-items-for-purchase-orders.md) | Describes how unit (serialized inventory) data is linked to sales-order and purchase-order line items behind the `units-for-items-for-purchase-orders` TableView | |
|
|
@@ -6,12 +6,16 @@ project: _Underscore
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-
|
|
10
|
-
owners: [jcardinal]
|
|
9
|
+
updated: 2026-07-01
|
|
10
|
+
owners: [jcardinal, apeterson]
|
|
11
11
|
files:
|
|
12
12
|
- _underscore/Model/Core/Surface.php
|
|
13
|
+
- _underscore/Model/Client/AclRecordScript.php
|
|
14
|
+
- _underscore/Model/Core/RecordScript.php
|
|
13
15
|
- dbchanges2/Core/2026-06-30a - SurfaceMetaGroupAndSalesOrderSections.sql
|
|
14
16
|
- dbchanges2/Client/2026-06-30a - SurfaceMetaGroupAcl.sql
|
|
17
|
+
- dbchanges2/Client_Quad/2026-07-01a - GrantSurfacesMetaGroupScriptAcl.sql
|
|
18
|
+
- dbchanges2/Client_CompassCanada/2026-07-01a - GrantSurfacesMetaGroupScriptAcl.sql
|
|
15
19
|
- dbchanges2/Core/2026-06-29b - SurfaceMetaPublicReadAcl.sql
|
|
16
20
|
- dbchanges2/Client/2026-06-29c - SurfaceRecordScriptAcl.sql
|
|
17
21
|
- dbchanges2/Core/2026-06-29c - SurfaceDebugPhpMethodFix.sql
|
|
@@ -113,6 +117,32 @@ which surfaced latent resolution gaps in `_buildBundle`/`_resolveElement`:
|
|
|
113
117
|
`_Model_<Client>_*` overrides + `Client_ApiPayloadInterceptor` hooks — the Surface layer does
|
|
114
118
|
**not** absorb business logic.
|
|
115
119
|
|
|
120
|
+
## How a surfaces scripted-API call is authorized (route-level gate)
|
|
121
|
+
|
|
122
|
+
Authorizing a surfaces script (`meta`, `meta-group`, `debug`) is a **two-layer** check. Get the
|
|
123
|
+
first layer wrong and you get a **403 `EZ-1 AUTHORIZATION`** before any element ACL runs.
|
|
124
|
+
|
|
125
|
+
1. **Route-level dispatch gate — `Client_<tenant>.AclRecordScripts`.** The surfaces dispatcher
|
|
126
|
+
authorizes each API script (route + method + phpMethod) via the **CLIENT-tier**
|
|
127
|
+
`AclRecordScripts` table (cols `uuid`, `recordScriptId` → `Core.RecordScripts`, `roleId` →
|
|
128
|
+
`Client_<tenant>.Roles`). The check is keyed on the JWT's **`id.client.roles`** (client roles),
|
|
129
|
+
**NOT** the platform `core.roles` and **NOT** the Core `AclRecordPermissions` chain.
|
|
130
|
+
`Core.RecordScripts` maps route/method/phpMethod → an ACL "record" (`recordId`). The three
|
|
131
|
+
surfaces scripts: `meta` (GET, phpMethod `meta`), `meta-group` (GET, `metaGroup`), `debug` (GET,
|
|
132
|
+
`metaDebug`). `_Model_Core_Surface::resolve/metaGroup` read the caller's roles from
|
|
133
|
+
**`id.client.roles`** (Surface.php ~lines 56/87).
|
|
134
|
+
2. **Element-level ACL (runs *inside* `meta`/`metaGroup`, AFTER the route gate passes)** — dropping
|
|
135
|
+
individual surface elements uses a **separate** client-tier table `_Model_Client_AclActionPermission`,
|
|
136
|
+
gated by each `SurfaceElement.aclActionId`. This is the "composition, not absorption" step in
|
|
137
|
+
`resolve()` step 4; it never causes the route-level 403.
|
|
138
|
+
|
|
139
|
+
**Debugging a surfaces 403 EZ-1 (hard-won):** it is the route-level gate — a missing
|
|
140
|
+
`Client_<tenant>.AclRecordScripts` grant resolved by **client role**. Do **not** chase
|
|
141
|
+
`Core.AclRecordPermissions`, `appId` scoping, or `AclLogicGroups`/`AclRecordExpressions` — all were
|
|
142
|
+
investigated and ruled out as red herrings: `appId = NULL` is the normal working pattern, and the
|
|
143
|
+
Core record grants + their logic-group expressions all evaluate `all`/`"1"`. The gate is purely
|
|
144
|
+
"does this client role have an `AclRecordScripts` row for this `recordScriptId`?"
|
|
145
|
+
|
|
116
146
|
## Gotchas
|
|
117
147
|
|
|
118
148
|
- **A Core RecordScript needs `Client.AclRecordScripts` rows per role to be invokable — record-level
|
|
@@ -167,8 +197,33 @@ which surfaced latent resolution gaps in `_buildBundle`/`_resolveElement`:
|
|
|
167
197
|
per-role `Client.AclRecordScripts` dispatch grant. Verified via toga-db — `meta` script id 25 was
|
|
168
198
|
granted roles 1/3/4 but `meta-group` (id 27) had **none** until the grant ran. Any new surfaces
|
|
169
199
|
scripted-API method repeats this: record READ never authorizes dispatch.
|
|
200
|
+
- **The meta-group grant is seeded per-tenant, not globally — new tenants repeat the 403.** When
|
|
201
|
+
`meta-group` shipped, the `AclRecordScripts` grant was seeded **only** for `Client_Compass`
|
|
202
|
+
(recordScriptId → roles 1,3,4). `Client_Quad` and `Client_CompassCanada` had **no** grant for the
|
|
203
|
+
meta-group recordScriptId at all — their `meta` was granted to client role 1 (why `meta` worked but
|
|
204
|
+
`meta-group` 403'd for the same user/token). Same-user-different-script + same-script-different-tenant
|
|
205
|
+
is the fingerprint of this gap. Fix (2026-07-01): two `dbchanges2/Client_<tenant>/` migrations
|
|
206
|
+
granting meta-group to **client role 1** (parity with each tenant's existing `meta` grant),
|
|
207
|
+
id-agnostic (resolve `Core.RecordScripts` id by route/method/phpMethod, cross-DB read of `Core.*`
|
|
208
|
+
per the 2026-06-29c ACL pattern) and re-runnable via `NOT EXISTS`. Surface-layer DB changes ship to
|
|
209
|
+
the **beta** environment only. ⚠ **Root-cause not yet closed:** the meta-group grant should be
|
|
210
|
+
added to the `dbchanges2/Client/` **baseline (blank) seed** so newly-cut clients get it
|
|
211
|
+
automatically — otherwise the next migrated tenant hits the identical 403. Only Compass (already
|
|
212
|
+
correct), Quad, and CompassCanada are addressed. Also note **role breadth**: Compass exposes
|
|
213
|
+
surfaces to roles 1,3,4; Quad/CC got role 1 only (parity with their `meta`). If Quad/CC should
|
|
214
|
+
match Compass, a follow-up migration aligning both `meta` and `meta-group` to roles 1,3,4 is needed.
|
|
170
215
|
|
|
171
216
|
## Change history
|
|
217
|
+
- 2026-07-01 — Documented the full route-level authorization mechanism (new section): the surfaces
|
|
218
|
+
script gate is `Client_<tenant>.AclRecordScripts` keyed on JWT `id.client.roles` (client roles,
|
|
219
|
+
not `core.roles`, not `Core.AclRecordPermissions`); element-drop is a separate
|
|
220
|
+
`_Model_Client_AclActionPermission`/`aclActionId` layer running inside `resolve()` after the route
|
|
221
|
+
gate; captured the red-herring list (`appId=NULL` is normal, Core grants all evaluate `all`/`"1"`).
|
|
222
|
+
Fixed the `meta-group` 403 EZ-1 for **Quad** and **Compass Canada** — the meta-group
|
|
223
|
+
`AclRecordScripts` grant had been seeded for Compass only; added two id-agnostic, NOT-EXISTS-guarded
|
|
224
|
+
`Client_<tenant>/` migrations granting meta-group to client role 1 (beta env only). Flagged the
|
|
225
|
+
open root-cause: add the grant to the `Client/` baseline seed, and decide role breadth (1 vs 1,3,4)
|
|
226
|
+
for Quad/CC. (apeterson)
|
|
172
227
|
- 2026-06-30 — Added `metaGroup()` (`GET /v2/surfaces/meta-group?slugs=a,b,c`): batched composition
|
|
173
228
|
over the existing per-slug `resolve()` cache, capped at `META_GROUP_MAX_SLUGS=25`, unknown slug →
|
|
174
229
|
empty bundle (chosen over a `parentSurfaceId` GROUP row post-CTO-review). Fixed latent
|
|
@@ -6,7 +6,7 @@ project: TOGa 2.5 Supply
|
|
|
6
6
|
client: shared
|
|
7
7
|
type: feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-
|
|
9
|
+
updated: 2026-07-01
|
|
10
10
|
owners: [apeterson]
|
|
11
11
|
files:
|
|
12
12
|
- toga25-supply/src/fieldsConfig/index.ts
|
|
@@ -64,6 +64,22 @@ and the `useClientFields()` hook.
|
|
|
64
64
|
`yourKey: BY_CLIENT[clientSlug] ?? DEFAULT_*`. Avoids editing all ~13 role bundles.
|
|
65
65
|
`DEFAULT_CLIENT_FIELDS` must also carry the new key (ultimate fallback).
|
|
66
66
|
|
|
67
|
+
### De-roling a client×role bundle to client-only
|
|
68
|
+
|
|
69
|
+
Some bundles were role-keyed (`{ADMIN, MANAGER}`) only for historical reasons — the roles held
|
|
70
|
+
byte-identical config. Those are being flattened to **client-only** (part of the ongoing
|
|
71
|
+
backend-driven / de-role goal). `orderViewFields` is now client-only: `COMPASS` and `COMPASSCANADA`
|
|
72
|
+
read their flat client JSON via `mergeOrderView(<client>OrderViewFields)` in
|
|
73
|
+
`src/fieldsConfig/index.ts` instead of reading `.ADMIN`/`.MANAGER` off the file, and
|
|
74
|
+
`FIELDS/COMPASSCANADA/orderViewFields.json` was flattened from `{ADMIN, MANAGER}` to a flat object.
|
|
75
|
+
|
|
76
|
+
When de-roling, watch the read path: `COMPASS`'s JSON was **already flat** but was still being read
|
|
77
|
+
via `.ADMIN` → `undefined` → the client silently fell back to `DEFAULT` and lost its
|
|
78
|
+
`salesOrderDetailsConfig` joins. This is the flat-bundle trap from the gotcha below — the fix is to
|
|
79
|
+
read the bundle itself, not a role key. `approvalViewFields` and `salesOrdersPageFields` remain
|
|
80
|
+
role-keyed (their ADMIN/MANAGER genuinely differ); fully de-roling those and removing `resolveRole`
|
|
81
|
+
is a separate pending task.
|
|
82
|
+
|
|
67
83
|
### Hydration (non-serializable bits)
|
|
68
84
|
|
|
69
85
|
Keep JSON **serializable** — strings, enums, arrays. No JSX, no functions, no Tailwind classes.
|
|
@@ -143,6 +159,12 @@ modal's chrome from the same per-client JSON, not from the component:
|
|
|
143
159
|
`vendorItemRecordViewFields` are record-modal-layout examples living under `src/layout/.../viewModel/FIELDS/`.
|
|
144
160
|
|
|
145
161
|
## Change history
|
|
162
|
+
- 2026-07-01 — De-roled `orderViewFields` from client×role to **client-only**: COMPASS/COMPASSCANADA
|
|
163
|
+
now read a flat client JSON via `mergeOrderView(...)` in `fieldsConfig/index.ts` (COMPASSCANADA's
|
|
164
|
+
JSON flattened from byte-identical `{ADMIN,MANAGER}`). Fixed a latent bug where COMPASS's
|
|
165
|
+
already-flat JSON was read via `.ADMIN` → `undefined` → silent fallback to DEFAULT (lost its
|
|
166
|
+
`salesOrderDetailsConfig` joins). `approvalViewFields`/`salesOrdersPageFields` stay role-keyed;
|
|
167
|
+
full de-role + `resolveRole` removal remains pending. Type-check clean. (apeterson)
|
|
146
168
|
- 2026-06-25 — SalesOrder action buttons render by presentation intent: `kind` (icon/text/viewLog) picks the renderer, `variant` a closed color set, `valueKey` is pure click-dispatch; a `componentRegistry` keyed by `kind` hydrates dedicated components (e.g. ViewLogButton). Added the `recordActionFields`-shape gotcha (per-persona blocks + sibling `poNumber` sub-config; walk `actionOptions` only). (apeterson)
|
|
147
169
|
- 2026-06-25 — Extended to record-modal layouts: per-mode `*ViewFields`/`*EditFields` JSON under `src/layout/.../viewModel/FIELDS/`, JSON-driven modal `header` (modalTag/labelTemplate/statusBadge) + `editItem` button gated via the Flag/Rule engine, and the flat-bundle defensive-default gotcha. (apeterson)
|
|
148
170
|
- 2026-06-23 — Documented from the `add-client-fields` skill during initial knowledge seed. (apeterson)
|
|
@@ -15,12 +15,13 @@ client: compass-canada
|
|
|
15
15
|
type: profile
|
|
16
16
|
status: active
|
|
17
17
|
updated: 2026-06-30
|
|
18
|
-
owners: [jcardinal, bala, tcox]
|
|
18
|
+
owners: [jcardinal, bala, tcox, apeterson]
|
|
19
19
|
files: []
|
|
20
20
|
related:
|
|
21
21
|
- ../compass-usa/profile.md
|
|
22
22
|
- ../../2.0/apps/toga2-commerce/features/expedited-shipping-gating.md
|
|
23
23
|
- ../../2.0/apps/_underscore/features/item-fulfillment-stage-lifecycle-and-order-status.md
|
|
24
|
+
- ../../2.0/apps/_underscore/features/surface-resolver.md
|
|
24
25
|
---
|
|
25
26
|
|
|
26
27
|
## Summary
|
|
@@ -50,6 +51,12 @@ to but distinct from Compass USA. Like Compass USA it spans the **2.0** commerce
|
|
|
50
51
|
see [Config-Driven Expedited Shipping Gating](../../2.0/apps/toga2-commerce/features/expedited-shipping-gating.md).
|
|
51
52
|
|
|
52
53
|
## Notes
|
|
54
|
+
- **Surface layer (beta):** like Quad, `Client_CompassCanada` had **no** `AclRecordScripts` dispatch
|
|
55
|
+
grant for the surfaces `meta-group` script (only `meta`, to client role 1) → `GET /v2/surfaces/meta-group`
|
|
56
|
+
403'd EZ-1 while `meta` worked. Fixed 2026-07-01 via
|
|
57
|
+
`dbchanges2/Client_CompassCanada/2026-07-01a - GrantSurfacesMetaGroupScriptAcl.sql` (meta-group →
|
|
58
|
+
client role 1, id-agnostic + NOT-EXISTS-guarded, beta only). Exposes surfaces to role 1 only, vs
|
|
59
|
+
Compass USA's 1/3/4. See [Surface Resolver](../../2.0/apps/_underscore/features/surface-resolver.md).
|
|
53
60
|
- Customer language preference: `UserGlobalSettings.settingId = 2` (`en` / `fr-CA`); customer-
|
|
54
61
|
facing emails are sent in EN or FR accordingly.
|
|
55
62
|
- Assortment (product-grouping) names are served in fr-CA via the `AssortmentTranslations` sidecar
|
|
@@ -14,11 +14,12 @@ client: quad
|
|
|
14
14
|
type: profile
|
|
15
15
|
status: active
|
|
16
16
|
updated: 2026-06-30
|
|
17
|
-
owners: ["jcardinal", "bala"]
|
|
17
|
+
owners: ["jcardinal", "bala", "apeterson"]
|
|
18
18
|
files: []
|
|
19
19
|
related:
|
|
20
20
|
- ../../2.0/apps/_underscore/features/tracking-number-bridges.md
|
|
21
21
|
- ../../2.0/apps/_underscore/features/item-fulfillment-stage-lifecycle-and-order-status.md
|
|
22
|
+
- ../../2.0/apps/_underscore/features/surface-resolver.md
|
|
22
23
|
---
|
|
23
24
|
|
|
24
25
|
## Summary
|
|
@@ -48,6 +49,13 @@ Client-specific DB change-sets live in `dbchanges2/Client_Quad/`.
|
|
|
48
49
|
(`_underscore/Model/Quad/SalesOrder.php`): non-SA orders use the inline machine, `SA%` orders
|
|
49
50
|
delegate to the base `_Model_Client_SalesOrder`. Contrast Compass, which is shipped-only. See
|
|
50
51
|
[IF stage lifecycle & order status](../../2.0/apps/_underscore/features/item-fulfillment-stage-lifecycle-and-order-status.md).
|
|
52
|
+
- **Surface layer (beta):** the surfaces `meta-group` script had **no** `AclRecordScripts` dispatch
|
|
53
|
+
grant for `Client_Quad` (only `meta` was granted, to client role 1), so `GET /v2/surfaces/meta-group`
|
|
54
|
+
403'd (EZ-1) while `meta` worked. Fixed 2026-07-01 via
|
|
55
|
+
`dbchanges2/Client_Quad/2026-07-01a - GrantSurfacesMetaGroupScriptAcl.sql` (grants meta-group to
|
|
56
|
+
client role 1, id-agnostic + NOT-EXISTS-guarded, beta only). Quad exposes surfaces to role 1 only,
|
|
57
|
+
vs Compass's 1/3/4 — revisit if broader roles are needed. See
|
|
58
|
+
[Surface Resolver](../../2.0/apps/_underscore/features/surface-resolver.md).
|
|
51
59
|
- Tracking data: record 318 (item-level) is currently empty for this client; their tracking
|
|
52
60
|
populates the IF/shipment level (record 317, ~98% coverage) and unit level (record 319). The
|
|
53
61
|
rebuilt views use 318 (per the Compass pattern) and will show tracking once item-level
|
package/package.json
CHANGED