@drawbridge/drawbridge-agents 0.1.71 → 0.1.72

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.
@@ -36,6 +36,26 @@ session scratch directory that reuses the saved session
36
36
  (`drawbridge-tests/e2e/.auth/user.json`, `lib/basic-auth.js`), performs the steps, and
37
37
  screenshots after each. `drawbridge-tests/e2e/walk.js` is the pattern to copy.
38
38
 
39
+ ## How to seed an entrant (a scenario that needs a lead, an entry or a winner)
40
+
41
+ Never insert a lead by hand. A hand-written lead carries subtotals the product never
42
+ counted, and removing it afterwards drives the campaign's Entries and Submissions below zero
43
+ (Asana 1218811920761541). Seed the way the product does, through
44
+ `drawbridge-tests/lib/seed.js`:
45
+
46
+ ```js
47
+ const { removeEntrant, seedEntrant } = require( './lib/seed' );
48
+
49
+ const seeded = await seedEntrant({ campaign : '<campaign id>', email : 'qa+<task id>@…', entries : 1 });
50
+ // … walk the scenario; seeded.lead, seeded.entry, seeded.submission are the ids …
51
+ await removeEntrant( seeded );
52
+ ```
53
+
54
+ It writes a zero-count lead plus one pending submission and waits for the sync worker to
55
+ process it, exactly as a share-page submission does; removing it nets every counter back to
56
+ zero. If a scenario needs something the helper cannot seed, the scenario is `blocked` with
57
+ that as the reason, never seeded by hand.
58
+
39
59
  ## How to check an inbox (`@inbox` scenarios)
40
60
 
41
61
  The connected Gmail account is the QA mailbox. Trigger the email with a recipient of the form
@@ -242,6 +242,13 @@ skill) so it stops living only in tribal memory.
242
242
  breaks the audit. Detail: drawbridge-docs `reference/billing.md`.
243
243
  - Every `$inc` on a `totals.*` counter needs a matching entry in `drawbridge-sync/lib/totals.js`
244
244
  `SOURCES` — that map is the only drift backstop.
245
+ - **A count never reads below zero.** Every decrement of a `totals.*` counter goes through
246
+ `drawbridge-sync/lib/totals.js` `adjustTotals` / `flooredTotals`, a pipeline update that clamps
247
+ each field at zero in the same write. A bare `$inc` with a negative delta, or a `{ $gt : 0 }`
248
+ query guard that skips the whole write, is the shape that drove a campaign to Entries -5
249
+ (Asana 1218811920761541). Test data is seeded through `drawbridge-tests/lib/seed.js` so the
250
+ worker does the counting; a lead inserted by hand with subtotals was never counted and its
251
+ delete decrements what was never added.
245
252
  - The `invoice` collection's **unique partial index on `stripeInvoiceId`** (drawbridge-api
246
253
  `schema/invoice.js`) and sync's `upsertInvoice` E11000 catch (`lib/buffer.js`) are one contract:
247
254
  sync upserts the same invoice from three concurrent webhooks (finalized/payment_succeeded/voided)
@@ -66,6 +66,26 @@ write the comment from what is on it. Quote labels from the printed list, never
66
66
  The full smoke pack (`npm test`) and the dashboard functional run (`npm run dashboard`)
67
67
  use the same session; see `drawbridge-tests/readme.md`.
68
68
 
69
+ ### Seeding an entrant for a walk
70
+
71
+ A walk that needs a lead, an entry or a winner seeds it through
72
+ `drawbridge-tests/lib/seed.js`, never with a hand-written `insertOne`:
73
+
74
+ ```js
75
+ const { removeEntrant, seedEntrant } = require( './lib/seed' );
76
+
77
+ const seeded = await seedEntrant({ campaign : '<campaign id>', email : 'walk+<date>@…', entries : 1 });
78
+ await removeEntrant( seeded ); // when the walk is done
79
+ ```
80
+
81
+ `seedEntrant` writes what the api's thin ingest writes — a zero-count lead and one submission
82
+ flagged pending — and waits for the sync worker to materialize the entries and every counter.
83
+ `removeEntrant` deletes the draws that picked the lead and then the lead; sync's cascade does
84
+ the rest and each counter nets back to zero. A lead inserted with its subtotals filled in was
85
+ never counted on its campaign, so deleting it decremented Entries and Submissions below zero
86
+ (Asana 1218811920761541, 2026-09-23). Counters now floor at zero in sync, but the seed still
87
+ has to go through the worker or the counts on the walked screen are wrong.
88
+
69
89
  ## 2. Claude in Chrome (optional, interactive sessions only)
70
90
 
71
91
  Claude Code can drive the developer's own Chrome through the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawbridge/drawbridge-agents",
3
- "version": "0.1.71",
3
+ "version": "0.1.72",
4
4
  "description": "Shared agent-instruction content (rules, code style, conventions) for the drawbridge-* monorepo.",
5
5
  "license": "UNLICENSED",
6
6
  "publishConfig": {
File without changes