@hogsend/db 0.5.0 → 0.6.0

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.
@@ -92,6 +92,13 @@
92
92
  "when": 1780489463074,
93
93
  "tag": "0012_fixed_sebastian_shaw",
94
94
  "breakpoints": true
95
+ },
96
+ {
97
+ "idx": 13,
98
+ "version": "7",
99
+ "when": 1780734148043,
100
+ "tag": "0013_illegal_firedrake",
101
+ "breakpoints": true
95
102
  }
96
103
  ]
97
104
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hogsend/db",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -39,6 +39,18 @@ export const bucketMemberships = pgTable(
39
39
  entryCount: integer("entry_count").notNull().default(1),
40
40
  source: text("source"), // "event" | "reconcile" | "backfill" | "manual"
41
41
  context: jsonb("context").$type<Record<string, unknown>>().default({}),
42
+ // Per-membership dwell bookkeeping. JSON map keyed by dwellLabel → ISO of
43
+ // last dwell fire for THIS continuous membership. A re-join is a NEW row
44
+ // (empty map). NULL/{} = never fired.
45
+ dwellState: jsonb("dwell_state")
46
+ .$type<Record<string, string>>()
47
+ .default({}),
48
+ // Historical dwell anchor for backfilled members (NULL for live joins → use
49
+ // enteredAt). The dwell gate reads coalesce(dwellAnchorAt, enteredAt) so the
50
+ // dwell clock starts at the derived historical instant, not the backfill
51
+ // instant. Kept separate from enteredAt (which minDwell/maxDwellAt/criteria
52
+ // cron key on) — strictly additive.
53
+ dwellAnchorAt: timestamp("dwell_anchor_at", { withTimezone: true }),
42
54
  deletedAt: timestamp("deleted_at", { withTimezone: true }),
43
55
  ...timestamps,
44
56
  },
@@ -68,5 +80,23 @@ export const bucketMemberships = pgTable(
68
80
  index("bucket_memberships_expires_at_idx").on(table.expiresAt),
69
81
  // the cron TTL sweep: active rows past their max_dwell_at
70
82
  index("bucket_memberships_max_dwell_at_idx").on(table.maxDwellAt),
83
+ // dwell continuous-member scan anchor
84
+ index("bucket_memberships_dwell_idx").on(
85
+ table.bucketId,
86
+ table.status,
87
+ table.enteredAt,
88
+ ),
89
+ // keyset member-access pagination (ordered by id)
90
+ index("bucket_memberships_bucket_id_status_id_idx").on(
91
+ table.bucketId,
92
+ table.status,
93
+ table.id,
94
+ ),
95
+ // every-dwell oldest-served-first ordering (§6.5)
96
+ index("bucket_memberships_dwell_lastfired_idx").on(
97
+ table.bucketId,
98
+ table.status,
99
+ table.lastEvaluatedAt,
100
+ ),
71
101
  ],
72
102
  );