@drawbridge/drawbridge-agents 0.1.43 → 0.1.47

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.
@@ -31,6 +31,15 @@ skill) so it stops living only in tribal memory.
31
31
 
32
32
  - All socket emits from sync go through `drawbridge-sync/lib/emit.js` — never call
33
33
  `io.to().emit()` directly from a worker.
34
+ - An `sms` identity row is **never created `verified`**: api's purchase route writes
35
+ `status:'pending'` + the `business` details, sync's `queue/identity.js` verify job is the
36
+ ONLY writer of `'verified'` (after Twilio Toll-Free Verification approval, via the utils
37
+ twilio transport — it also renders and uploads the opt-in evidence at submission), and
38
+ sync's `queue/notification.js` sends from `'verified'` rows only. An api route (or script)
39
+ minting `'verified'` ships a number Twilio blocks outright — it looks live and delivers
40
+ nothing. (Collection renamed `networking` → `identity` 2026-09-03, pre-data; the plan
41
+ feature key stays `organization:networking` because custom-plan documents can store
42
+ granted keys — that string is data, never rename it without a migration.)
34
43
  - Cascade cleanup of dependent rows belongs in a sync change-stream listener, not inline in the
35
44
  API route that triggered the delete (see `cascade-cleanup.md`).
36
45
  - A collection with no `queue/<collection>.js` handler is watched but its events are **silently
@@ -134,6 +143,17 @@ skill) so it stops living only in tribal memory.
134
143
  would have zeroed every invoice once the products were archived.
135
144
  - **The v2 pricing-plan layer (`bpp_*`, billing cadences) is never touched by script.** Canceling a
136
145
  billing cadence is terminal and unrecoverable. Dashboard, by hand, only.
146
+ - **The Shopify meter handle is a config contract no code validates** (shopify ↔ Partner
147
+ Dashboard ↔ sync/utils). `SHOPIFY_USAGE_ORDERS_EVENT_HANDLE` in `@drawbridge/shopify`
148
+ (`drawbridge-orders`) must exactly match — case-sensitive, handle not display name — a usage
149
+ meter on the App Pricing plan version each merchant has APPROVED (meters are never
150
+ retroactive). A mismatch, a missing meter, or a merchant on a pre-meter plan still 202s every
151
+ event, logs it as a plain app event, and bills nothing; no error surfaces anywhere in code
152
+ (the 19/99 write-off). Any change to the handle constant, the Partner Dashboard pricing
153
+ config, or a plan version requires verifying a fresh order classifies as a billing event in
154
+ Dev Dashboard → Logs (type "App billing event"). The trace key both sides share is
155
+ `billed.transaction` = the event's `reference` = `drawbridge-orders.<orderId>`. Detail:
156
+ drawbridge-docs `reference/shopify-app.md` (Billing).
137
157
  - **A subscription must open with the plan item.** It used to open with the metered actions price
138
158
  and attach the plan afterwards with `always_invoice`. With no metered item, Stripe rejects an
139
159
  itemless subscription, so the plan goes in at creation — changing the first invoice's shape.
@@ -384,6 +404,21 @@ renaming one orphans what is already enqueued and starts a parallel stream nobod
384
404
  with no error. `bullmq-identity.test.js` in sync spells out the routing table so moving a
385
405
  step between queues requires editing it deliberately.
386
406
 
407
+ **`grant_refused` is minted in utils, keyed on in sync (utils ↔ sync).** Only the two
408
+ dead-grant paths in drawbridge-utils — a refused refresh (`connections/oauth.js`) and an
409
+ unrenewable expiry (`connections/token.js`) — set `error.code = 'grant_refused'`; a network
410
+ failure never does. Sync's step-runner errors the connection on that code during a
411
+ `lifecycle.health` step (the shell mints the token, so the hook can't). Minting the code
412
+ anywhere transient flips healthy connections to error on a blip; renaming it in either repo
413
+ means dead grants retry into Sentry forever (the Shopify 08-16 incident, ecosystem-wide).
414
+
415
+ **The SMS inbound URL is one string two repos must agree on (api ↔ sync ↔ webhooks).**
416
+ `APP_CLIENT_WEBHOOKS_URI + '/connection/drawbridge/sms'` is written to each purchased
417
+ number by api (`route/organization-networking.js`) and re-asserted by sync's daily identity
418
+ sweep (`queue/identity.js`), which re-points any number whose Twilio config drifts. Change
419
+ the path in one place and the sweep "repairs" every number to the wrong URL — inbound SMS
420
+ (STOP included) goes dark with all rows reading healthy.
421
+
387
422
  ## Import surfaces
388
423
 
389
424
  - Import names against a package's **actual exports** — a missing export resolves to `undefined`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawbridge/drawbridge-agents",
3
- "version": "0.1.43",
3
+ "version": "0.1.47",
4
4
  "description": "Shared agent-instruction content (rules, code style, conventions) for the drawbridge-* monorepo.",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {