toga-ai 1.0.99 → 1.0.101

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  | Doc | Framework | Summary | Files |
4
4
  |-----|-----------|---------|-------|
5
- | [Compass ASN → ItemFulfillment Auto-Creation](features/asn-to-item-fulfillment.md) | 2.0 | For Compass USA, posting an AdvanceShippingNotice (ASN) auto-creates the ItemFulfillment (IF) on the upstream SalesOrder. | _underscore/Model/Compass/AdvanceShippingNotice.php, api2/Component/Api/Cxml/Cxml.php, dbchanges2/Client_Compass/2026-06-11 - AsnItemTrackingNumberAcl.sql, dbchanges2/Client_Compass/2026-06-15b - BackfillSA132781ItemFulfillmentTracking.sql |
5
+ | [Compass ASN → ItemFulfillment Auto-Creation](features/asn-to-item-fulfillment.md) | 2.0 | For Compass USA, posting an AdvanceShippingNotice (ASN) auto-creates the ItemFulfillment (IF) on the upstream SalesOrder. | _underscore/Model/Compass/AdvanceShippingNotice.php, _underscore/Model/Compass/PurchaseOrder.php, api2/Component/Api/Cxml/Cxml.php, dbchanges2/Client_Compass/2026-06-11 - AsnItemTrackingNumberAcl.sql, dbchanges2/Client_Compass/2026-06-15b - BackfillSA132781ItemFulfillmentTracking.sql, dbchanges2/Client_Compass/2026-06-16 - CleanupSA132763CrossLineTracking.sql, dbchanges2/Client_Compass/2026-06-16b - CleanupSA132743CrossLineTracking.sql, dbchanges2/Client_Compass/2026-06-16c - BackfillSA132763C40QYUCTracking.sql |
6
6
  | [Compass: Item-Fulfillment TableViews (for-sales-order-items & for-sales-orders, tracking via bridge)](features/item-fulfillment-tracking-tableview.md) | 2.0 | Two sibling Compass TableViews in `Client_Compass` display fulfilled items in toga2-supply, both driven by `TableViews` / `TableViewJoins` / `TableViewFields` c | dbchanges2/Client_Compass/2026-06-10 - ItemFulfillmentsForSalesOrderItemsTableView.sql, dbchanges2/Client_Compass/2026-06-11 - ItemFulfillmentsForSalesOrdersTableView.sql, dbchanges2/Client_Compass/2026-06-15a - FixItemFulfillmentTrackingNumberJoins.sql |
7
7
  | [Compass MITS PO → SO Item Linking](features/mits-po-to-so-item-linking.md) | 2.0 | MITS sends Compass inbound Purchase Orders (`POST /v2/purchase-orders`) against a Sales Order (`mitsSalesOrder`). | _underscore/Model/Compass/PurchaseOrder.php, worker/crons/toga2/compass/workflow/3a_import_office_depot_purchase_orders.php |
8
8
  | [Compass USA](profile.md) | 2.0 | Compass USA is a TOGA client running a multi-tier supply-chain commerce operation. | |
@@ -5,13 +5,17 @@ project: _Underscore
5
5
  client: compass-usa
6
6
  type: client-feature
7
7
  status: active
8
- updated: 2026-06-15
8
+ updated: 2026-06-16
9
9
  owners: [jcardinal]
10
10
  files:
11
11
  - _underscore/Model/Compass/AdvanceShippingNotice.php
12
+ - _underscore/Model/Compass/PurchaseOrder.php
12
13
  - api2/Component/Api/Cxml/Cxml.php
13
14
  - dbchanges2/Client_Compass/2026-06-11 - AsnItemTrackingNumberAcl.sql
14
15
  - dbchanges2/Client_Compass/2026-06-15b - BackfillSA132781ItemFulfillmentTracking.sql
16
+ - dbchanges2/Client_Compass/2026-06-16 - CleanupSA132763CrossLineTracking.sql
17
+ - dbchanges2/Client_Compass/2026-06-16b - CleanupSA132743CrossLineTracking.sql
18
+ - dbchanges2/Client_Compass/2026-06-16c - BackfillSA132763C40QYUCTracking.sql
15
19
  related:
16
20
  - ../../../2.0/apps/_underscore/features/recursive-item-fulfillments.md
17
21
  ---
@@ -143,9 +147,43 @@ Compass Canada (`Model/Compass/Canada/`) is a separate sub-client. The Compass c
143
147
  number) straight into queries. These are now passed through `_Database::escape()`.
144
148
  - Separate latent bug in the 1.0 worker: the Strategic Systems cron's no-serials branch
145
149
  builds `$itemLevelTrackingNumbers` but never attaches it to the ASN payload.
150
+ - **Cross-line tracking contamination from bad SOI↔POI bridge rows (root cause, fixed
151
+ forward 2026-06-11):** `postPost` resolves which IFI(s) a tracking number attaches to by
152
+ joining `AdvanceShippingNoticeItems → SalesOrderItems_PurchaseOrderItems → SalesOrderItems`.
153
+ It trusts that bridge completely, so a wrong bridge row silently sends one ASN's tracking
154
+ onto an unrelated part's IFI. Two distinct pre-fix bugs produced bad bridge rows on Compass
155
+ SA orders: (1) `_Model_Compass_PurchaseOrder` linked SO↔PO items by matching
156
+ `SalesOrderItems.lineNumber = PurchaseOrderItems.lineNumber` — but a PO item's lineNumber is
157
+ **PO-local** (each PO starts at 1), so when one SO is split across multiple POs the PO line
158
+ numbers collide with unrelated SO lines (e.g. SA132743: PO `50305071-1` line 1 = 910-006272
159
+ wrongly linked to SO line 1 = C40QYUC). Fixed in `_underscore` commit `ec935478` (2026-06-11,
160
+ "Only link SO/PO items for MR orders") — the lineNumber join is now MR-only; SA orders link
161
+ via `createdFromSalesOrderItem` (item identity). (2) The 1.0 worker cron
162
+ `3a_import_office_depot_purchase_orders.php` paired API-returned PO items to SOIs by array
163
+ index, producing off-by-one neighbor links (fixed forward to pair by lineNumber; see
164
+ SA132763 cleanup file header). **Diagnosing:** a bridge row is provably wrong when its
165
+ `SalesOrderItems.itemId <> VendorItems.itemId` (the linked SOI's product differs from the PO
166
+ item's actual product). The `2026-06-16*` cleanup migrations delete exactly those rows plus
167
+ the tracking they spilled, scoped to one order.
168
+ - **Retroactive cleanup MUST be paired with a backfill — a cleanup-only repair leaves the
169
+ line blank.** Removing the *wrong* tracking from a contaminated IFI does not restore the
170
+ *correct* one: the correct number often never reached the IF side (the SO was fulfilled
171
+ out-of-band before the 2026-06-15 reconcile fix, and the cleanup adds nothing). The original
172
+ `2026-06-16 - CleanupSA132763CrossLineTracking.sql` was cleanup-only and left C40QYUC on
173
+ SA132763 with no tracking at all; `2026-06-16c` backfilled it. When repairing an order, also
174
+ backfill each affected IFI's correct tracking (the tn carried by an ASN item whose
175
+ `VendorItems.itemId` matches the IFI's SOI item) at both item and package level, guarded by
176
+ `NOT EXISTS`. ~116 PO items across other Compass orders share the off-by-one fingerprint and
177
+ are not yet repaired — a broader reviewed backfill is still outstanding.
146
178
 
147
179
  ## Change history
148
180
  Dated one-liners, newest first.
181
+ - 2026-06-16 — Identified cross-line tracking contamination root cause: bad
182
+ `SalesOrderItems_PurchaseOrderItems` rows (PO-local lineNumber collision in
183
+ `_Model_Compass_PurchaseOrder`, fixed forward 2026-06-11 `ec935478`; and the worker ODP-PO
184
+ cron's array-index pairing). Repaired SA132743 (`2026-06-16b`, cleanup + backfill) and
185
+ backfilled SA132763's C40QYUC (`2026-06-16c`) after finding the `2026-06-16` SA132763 cleanup
186
+ was cleanup-only and left the line blank. (jcardinal)
149
187
  - 2026-06-15 — `postPost` + helpers refactored so **UUID is the reference field**, dropping all
150
188
  reliance on the integer `id` returned from `internalApiRequest` (not always present). Helper
151
189
  returns are uuid-only; `$trackingTargets`/`$packageTrackingByItemFulfillment` are uuid-keyed;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.99",
3
+ "version": "1.0.101",
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",
@@ -1,217 +0,0 @@
1
- ---
2
- name: create-elastic-beanstalk
3
- description: Generates a ready-to-paste AWS CloudShell command that creates a new Elastic Beanstalk environment following True/Agilant conventions. Use this skill whenever the user wants to create, spin up, or provision a new Elastic Beanstalk environment, add an EB environment to an existing application, or asks for the CloudShell command to launch a beanstalk. Trigger immediately even if they just say "make me a new beanstalk for X" or "new EB env in the API app".
4
- ---
5
-
6
- # Create Elastic Beanstalk Environment
7
-
8
- ## What this skill does
9
-
10
- You interview the user, then output a **single copy-paste CloudShell command** that creates a new
11
- Elastic Beanstalk *environment* inside an *existing* EB *application*. The command must run as-is
12
- when pasted into AWS CloudShell — no placeholders left behind, no editing required.
13
-
14
- You do **not** run any AWS commands yourself (you are not in CloudShell). You gather the answers,
15
- fill in the proven values below, and print the final command for the developer to paste.
16
-
17
- ## The core rule: PRODUCTION vs everything else
18
-
19
- The value of the `ENVIRONMENT` variable decides almost everything. If the user's `ENVIRONMENT`
20
- value is exactly `production`, use the **PRODUCTION profile**. Any other value
21
- (`client-alpha`, `qa-beta`, `sandbox-dev`, etc.) uses the **NON-PROD profile**.
22
-
23
- These two profiles live in **different AWS accounts** with different VPCs, subnets, roles, and
24
- storage. The developer's CloudShell session must be logged into the matching account — always tell
25
- them which account to confirm before they paste.
26
-
27
- ### PRODUCTION profile — AWS account `654654170868`
28
-
29
- | Setting | Value |
30
- |---|---|
31
- | VPC | `vpc-08030daf1c2dad280` |
32
- | Instance (private) subnets | `subnet-0e135d4093ab60b2f,subnet-0c6579c05a0f51ac6,subnet-096d9f8f0617949ef` |
33
- | ELB (public) subnets | `subnet-016ceecffa8c484dd,subnet-0a03a9af3536ab3e2,subnet-0f4272cd10edeee8d` |
34
- | Instance profile | `ElasticBeanstalk-EC2-Instance-Profile` |
35
- | Service role | `arn:aws:iam::654654170868:role/service-role/aws-elasticbeanstalk-service-role` |
36
- | Storage | `gp2` (SSD), 10 GB |
37
- | Load balancer | **Dedicated** application LB (`LoadBalancerIsShared=false`), public-facing |
38
- | Default instance type | `t4g.large` |
39
- | Default instance count | Min = Max = `2` |
40
-
41
- ### NON-PROD profile — AWS account `975050298201`
42
-
43
- | Setting | Value |
44
- |---|---|
45
- | VPC | `vpc-0c5319e7df6f736c5` |
46
- | Instance (private) subnets | `subnet-0d6acbaf19ee03fa9,subnet-0f5085f369274c305,subnet-0133a6098281928c7` (`true-test-private-web-a/b/c`) |
47
- | Instance profile | `aws-elasticbeanstalk-ec2-role` |
48
- | Service role | `arn:aws:iam::975050298201:role/aws-elasticbeanstalk-service-role` |
49
- | Storage | `standard` (magnetic), 10 GB |
50
- | Load balancer | **Shared** application LB (`LoadBalancerIsShared=true`) — must pick one (see list) |
51
- | Default instance type | `t4g.micro` |
52
- | Default instance count | Min = Max = `1` |
53
-
54
- > Non-prod uses a **shared** ALB, so do NOT set `ELBScheme`, `ELBSubnets`, or
55
- > `AssociatePublicIpAddress`. Elastic Beanstalk rejects subnet config on a shared load balancer; it
56
- > simply attaches a listener rule to the existing ALB.
57
-
58
- ## Always-true conventions (both profiles)
59
-
60
- - **Platform:** PHP on Amazon Linux 2023, Apache proxy, **arm64** (`SupportedArchitectures=arm64`,
61
- `t4g` family). Default solution stack: `64bit Amazon Linux 2023 v4.13.1 running PHP 8.5`.
62
- - **Key pair:** `true-aws-infrastructure-production`.
63
- - **Deployments:** `AllAtOnce` — **always**, no exceptions.
64
- - **No real autoscaling:** AWS won't let you disable it, so neuter the trigger — watch
65
- `CPUUtilization` with `LowerThreshold=2000000` and `UpperThreshold=6000000` so it never breaches.
66
- Always use `Unit=Percent`. Set Min = Max instance count so the group size is pinned.
67
- - **Instances** always go in the **private** subnets; load balancers in **public** subnets.
68
- - **On-Demand only** — always default to On-Demand instances (`EnableSpot=false`), never Spot.
69
-
70
- ## Interview the user (ask before generating anything)
71
-
72
- Ask these together in one message. Don't generate the command until you have the answers.
73
-
74
- 1. **`ENVIRONMENT` value** — what string goes in the `ENVIRONMENT` variable? (e.g. `production`,
75
- `client-delta`, `qa-hotfix`). This selects the profile. Treat exactly `production` as PRODUCTION.
76
-
77
- 2. **EB application** — which existing application? It must already exist (this skill never creates
78
- the application). Known applications: `SAML`, `talos-backend`, `TOGA Technology`, `API`,
79
- `TOGaCommerce`, `TOGaIQ`, `Worker`. If unsure, have them run:
80
- `aws elasticbeanstalk describe-applications --query 'Applications[].ApplicationName' --output table`
81
-
82
- 3. **Environment name** — the name for the new environment (e.g. `api-client-delta`). Lowercase,
83
- hyphenated, ≤ 40 chars.
84
-
85
- 4. **Shared ALB (NON-PROD only)** — which shared ALB should it attach to? Ask for the ALB **name**;
86
- the generated command resolves the ARN at runtime so it can't go stale. Known shared ALBs in
87
- account `975050298201` (`describe-load-balancers` to refresh):
88
- `true-alb-sandbox-dev`, `true-alb-sandbox-client`, `true-alb-client-alpha`,
89
- `true-alb-client-beta`, `true-alb-client-gamma`, `true-alb-qa-alpha`, `true-alb-qa-beta`,
90
- `true-alb-qa-gamma`, `true-alb-qa-hotfix`, `true-alb-qa-task`, `true-alb-qc-alpha`,
91
- `true-alb-qc-beta`, `true-alb-qc-gamma`, `true-alb-qc-hotfix`, `true-alb-qc-performance`,
92
- `true-alb-qc-security`, `true-alb-qc-task`.
93
-
94
- 5. **Instance type** — confirm or change. Default `t4g.micro` (non-prod) / `t4g.large` (prod). Must
95
- be arm64 `t4g` family; `t4g.micro` is the floor.
96
-
97
- 6. **Instance count** — confirm or change. Default Min = Max = `1` (non-prod) / `2` (prod). It's
98
- pinned (no scaling), so Min and Max are set equal.
99
-
100
- 7. **PHP version** *(optional)* — default `8.5`. Other current AL2023 options: `8.1`, `8.2`, `8.3`,
101
- `8.4`. Maps to solution stack `64bit Amazon Linux 2023 v4.13.1 running PHP <ver>`.
102
-
103
- 8. **CNAME prefix** *(optional)* — defaults to the environment name.
104
-
105
- ## Generating the command
106
-
107
- Substitute every value at generation time so the printed command has no placeholders. Build the
108
- option settings as a JSON heredoc, then call `create-environment`.
109
-
110
- Before the command, print a one-line **account check** banner, e.g.:
111
- > ⚠️ Confirm your CloudShell is logged into account **975050298201** (non-prod) before pasting.
112
-
113
- ### NON-PROD template (shared ALB)
114
-
115
- ```bash
116
- # Target account: 975050298201 | App: <APP> | Env: <ENV_NAME> | ENVIRONMENT=<ENV_VALUE>
117
- SHARED_ALB_ARN=$(aws elbv2 describe-load-balancers \
118
- --names "<SHARED_ALB_NAME>" \
119
- --query 'LoadBalancers[0].LoadBalancerArn' --output text)
120
-
121
- cat > /tmp/eb-options.json <<EOF
122
- [
123
- {"Namespace":"aws:autoscaling:asg","OptionName":"MinSize","Value":"<COUNT>"},
124
- {"Namespace":"aws:autoscaling:asg","OptionName":"MaxSize","Value":"<COUNT>"},
125
- {"Namespace":"aws:ec2:instances","OptionName":"InstanceTypes","Value":"<INSTANCE_TYPE>"},
126
- {"Namespace":"aws:ec2:instances","OptionName":"SupportedArchitectures","Value":"arm64"},
127
- {"Namespace":"aws:ec2:instances","OptionName":"EnableSpot","Value":"false"},
128
- {"Namespace":"aws:autoscaling:launchconfiguration","OptionName":"IamInstanceProfile","Value":"aws-elasticbeanstalk-ec2-role"},
129
- {"Namespace":"aws:autoscaling:launchconfiguration","OptionName":"EC2KeyName","Value":"true-aws-infrastructure-production"},
130
- {"Namespace":"aws:autoscaling:launchconfiguration","OptionName":"RootVolumeType","Value":"standard"},
131
- {"Namespace":"aws:autoscaling:launchconfiguration","OptionName":"RootVolumeSize","Value":"10"},
132
- {"Namespace":"aws:autoscaling:launchconfiguration","OptionName":"DisableIMDSv1","Value":"true"},
133
- {"Namespace":"aws:ec2:vpc","OptionName":"VPCId","Value":"vpc-0c5319e7df6f736c5"},
134
- {"Namespace":"aws:ec2:vpc","OptionName":"Subnets","Value":"subnet-0d6acbaf19ee03fa9,subnet-0f5085f369274c305,subnet-0133a6098281928c7"},
135
- {"Namespace":"aws:elasticbeanstalk:environment","OptionName":"LoadBalancerType","Value":"application"},
136
- {"Namespace":"aws:elasticbeanstalk:environment","OptionName":"LoadBalancerIsShared","Value":"true"},
137
- {"Namespace":"aws:elasticbeanstalk:environment","OptionName":"ServiceRole","Value":"arn:aws:iam::975050298201:role/aws-elasticbeanstalk-service-role"},
138
- {"Namespace":"aws:elbv2:loadbalancer","OptionName":"SharedLoadBalancer","Value":"${SHARED_ALB_ARN}"},
139
- {"Namespace":"aws:elasticbeanstalk:command","OptionName":"DeploymentPolicy","Value":"AllAtOnce"},
140
- {"Namespace":"aws:elasticbeanstalk:environment:proxy","OptionName":"ProxyServer","Value":"apache"},
141
- {"Namespace":"aws:autoscaling:trigger","OptionName":"MeasureName","Value":"CPUUtilization"},
142
- {"Namespace":"aws:autoscaling:trigger","OptionName":"Statistic","Value":"Average"},
143
- {"Namespace":"aws:autoscaling:trigger","OptionName":"Unit","Value":"Percent"},
144
- {"Namespace":"aws:autoscaling:trigger","OptionName":"LowerThreshold","Value":"2000000"},
145
- {"Namespace":"aws:autoscaling:trigger","OptionName":"UpperThreshold","Value":"6000000"},
146
- {"Namespace":"aws:autoscaling:trigger","OptionName":"LowerBreachScaleIncrement","Value":"-1"},
147
- {"Namespace":"aws:autoscaling:trigger","OptionName":"UpperBreachScaleIncrement","Value":"1"},
148
- {"Namespace":"aws:autoscaling:trigger","OptionName":"BreachDuration","Value":"5"},
149
- {"Namespace":"aws:autoscaling:trigger","OptionName":"Period","Value":"5"},
150
- {"Namespace":"aws:autoscaling:trigger","OptionName":"EvaluationPeriods","Value":"1"},
151
- {"Namespace":"aws:elasticbeanstalk:application:environment","OptionName":"ENVIRONMENT","Value":"<ENV_VALUE>"}
152
- ]
153
- EOF
154
-
155
- aws elasticbeanstalk create-environment \
156
- --application-name "<APP>" \
157
- --environment-name "<ENV_NAME>" \
158
- --cname-prefix "<CNAME_PREFIX>" \
159
- --solution-stack-name "64bit Amazon Linux 2023 v4.13.1 running PHP <PHP_VER>" \
160
- --option-settings file:///tmp/eb-options.json
161
- ```
162
-
163
- ### PRODUCTION template (dedicated public ALB)
164
-
165
- Same shape, but in account `654654170868`, with the dedicated-LB differences:
166
-
167
- - Drop the `SHARED_ALB_ARN` lookup and the `aws:elbv2:loadbalancer SharedLoadBalancer` line.
168
- - `LoadBalancerIsShared` → `false`.
169
- - `IamInstanceProfile` → `ElasticBeanstalk-EC2-Instance-Profile`.
170
- - `ServiceRole` → `arn:aws:iam::654654170868:role/service-role/aws-elasticbeanstalk-service-role`.
171
- - `RootVolumeType` → `gp2`.
172
- - `VPCId` → `vpc-08030daf1c2dad280`; `Subnets` → the three prod private subnets.
173
- - Add the public-facing LB lines:
174
- ```
175
- {"Namespace":"aws:ec2:vpc","OptionName":"ELBScheme","Value":"public"},
176
- {"Namespace":"aws:ec2:vpc","OptionName":"ELBSubnets","Value":"subnet-016ceecffa8c484dd,subnet-0a03a9af3536ab3e2,subnet-0f4272cd10edeee8d"},
177
- {"Namespace":"aws:ec2:vpc","OptionName":"AssociatePublicIpAddress","Value":"false"},
178
- ```
179
- - Defaults: `InstanceTypes=t4g.large`, count `2`.
180
- - Everything else identical: AllAtOnce, `Unit=Percent` trigger 2000000–6000000, `EnableSpot=false`,
181
- arm64, Apache, key pair, 10 GB root volume.
182
-
183
- ## After printing the command
184
-
185
- Tell the developer, concisely:
186
-
187
- 1. **Confirm the account** — CloudShell must be in `654654170868` (prod) or `975050298201`
188
- (non-prod). Paste fails or misbehaves if they're in the wrong account.
189
- 2. The application must already exist; this only creates the environment.
190
- 3. Watch it come up: `aws elasticbeanstalk describe-environments --environment-names "<ENV_NAME>" --query 'Environments[0].{Status:Status,Health:Health,CNAME:CNAME}' --output table`
191
- 4. If EB complains about a missing listener rule on a shared ALB, the env still creates; the rule is
192
- added automatically once the environment is `Ready`.
193
-
194
- ## Reviewing / cloning an existing environment
195
-
196
- To copy settings from a known-good environment, dump its full config (this is how this skill's
197
- values were sourced):
198
-
199
- ```bash
200
- aws elasticbeanstalk describe-configuration-settings \
201
- --application-name "<APP>" --environment-name "<EXISTING_ENV>" \
202
- --query 'ConfigurationSettings[0].OptionSettings[].{NS:Namespace,Opt:OptionName,Val:Value}' \
203
- --output table
204
- ```
205
-
206
- If the user is targeting an account other than the two above, ask them to run that command (plus
207
- `aws ec2 describe-subnets` and `aws elbv2 describe-load-balancers`) and paste the output so you can
208
- build a matching profile rather than guessing.
209
-
210
- ## Conventions baked in (don't silently change these)
211
-
212
- - All-at-once deploys, arm64/t4g, Apache, private-subnet instances, public-subnet LBs, the
213
- 2000000–6000000 never-trigger CPU hack (`Unit=Percent`), pinned Min=Max instance count, the
214
- `true-aws-infrastructure-production` key pair, 10 GB root volume (SSD `gp2` prod / magnetic
215
- `standard` non-prod), On-Demand instances.
216
- - If the user explicitly asks to deviate (e.g. enable Spot, change storage), honor it but call out
217
- that it departs from the standard.