toga-ai 1.0.372 → 1.0.374

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.
@@ -33,19 +33,35 @@ reviewer.
33
33
 
34
34
  ## Design
35
35
 
36
- A single shared table keyed by (local record identity, external system, external id kind):
36
+ A single **source-generic, single-anchor** mapping table in the integration schema
37
+ (`Client_True` / `DB_TRUE`, **not** Forecast). A source system + its record id anchor the entity; a
38
+ target system + its id are the mapping. NetSuite is a `sourceSystem` *value* (`'netsuite'`), never a
39
+ privileged column, and there is deliberately **no** cross-system correlation key (`entityUuid`):
40
+ every integration asks the same single-anchor question — "for this source record, what's its
41
+ ClickUp/Salesforce/… id?" — which needs no id-to-id web.
37
42
 
38
- - **Columns (sketch):** `id`, `entityType` (e.g. `opportunity`), `entityId` (the local business
39
- key, e.g. `netsuiteOpportunityInternalId`), `externalSystem` (e.g. `clickup`), `externalIdKind`
40
- (e.g. `task`), `externalId` (the value/sentinel), plus `dtCreated`/`dtUpdated`.
41
- - **Uniqueness:** a UNIQUE index on `(entityType, entityId, externalSystem, externalIdKind)` — this
42
- is the single-row lock that makes the atomic claim (`UPDATE SET externalId='<uuid sentinel>'
43
- WHERE AND externalId IS NULL`, commit, `affectedRows===1` wins) work exactly as the mandated
44
- column approach would, but without touching the Forecast schema.
45
- - **Atomic claim mechanics are unchanged** from the mandated design — same raw `_Query` guarded
46
- UPDATE (ORM `save()` cannot express it see
47
- [model-save-vs-query-atomic-update](../features/model-save-vs-query-atomic-update.md)), same
48
- commit-before-external-side-effect, same sentinel-guarded compensation-delete on failure.
43
+ - **Columns:** `id`, `entityType` (e.g. `opportunity`), `sourceSystem` (e.g. `netsuite`),
44
+ `sourceId` (the source record id), `targetSystem` (e.g. `clickup`), `targetExternalId` (the value;
45
+ `NULL` = claimed/in-flight), `dtCreated`/`dtUpdated`. No synthetic row `uuid` — `uq_claim` is the
46
+ natural key.
47
+ - **Uniqueness:** `UNIQUE (entityType, sourceSystem, sourceId, targetSystem)` = the atomic claim
48
+ (one mapping per source record per target system); `UNIQUE (targetSystem, entityType,
49
+ targetExternalId)` = no two source records share one target id (NULLs exempt, so many in-flight
50
+ rows coexist).
51
+ - **Atomic claim = one `INSERT IGNORE` + `getAffectedRows()`** no sentinel value, no correlation
52
+ step: the row's presence is the claim, `targetExternalId IS NULL` marks in-flight. Raw `_Query` is
53
+ required because the ORM `save()` cannot express a conditional/affected-rows write — see
54
+ [model-save-vs-query-atomic-update](../features/model-save-vs-query-atomic-update.md). Winner
55
+ writes `targetExternalId` back via the model; failure path deletes the in-flight row
56
+ (`… AND targetExternalId IS NULL`). Because the table stands alone, the claim has **no ordering
57
+ dependency** on the Forecast import (unlike a column claim, which needs the opportunity row
58
+ upserted first).
59
+ - **Scales without schema change:** a new integration adds rows with a new `targetSystem` value; a
60
+ new source adds a new `sourceSystem` value. Keyed on the source record id in the integration
61
+ schema, the mapping is independent of the Forecast DB by construction.
62
+
63
+ The `entityUuid`/cross-system-correlation variant is deliberately avoided — it only pays off if the
64
+ *source* system (NetSuite) itself stopped being the identity anchor, which is not a concern here.
49
65
 
50
66
  ## Rebuttal to the clickupTaskId-column mandate
51
67
 
@@ -75,3 +91,7 @@ holds, the mandated column approach is what ships.
75
91
 
76
92
  - 2026-07-17 — Proposed as a rebuttal to the reviewer-mandated clickupTaskId-column approach
77
93
  (TRUE-80044). (dfranks)
94
+ - 2026-07-17 — Refined to a source-generic, single-anchor design: `(sourceSystem, sourceId,
95
+ targetSystem)` key with a single `INSERT IGNORE` claim; dropped the `entityUuid` correlation/two-
96
+ step as over-engineered for the stated concerns (future integrations + Forecast-sync decoupling),
97
+ both of which the single-anchor key already satisfies. (dfranks)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.372",
3
+ "version": "1.0.374",
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",