@topy-ai/maggie 0.7.47 → 0.7.49

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.
Files changed (91) hide show
  1. package/README-zh-TW.md +2 -2
  2. package/README.md +76 -15
  3. package/bin/maggie.js +23 -6
  4. package/bundled-contracts/google-integrations/capability-report-v2.schema.json +2 -1
  5. package/bundled-contracts/maggie-content/email-localization-v1.schema.json +89 -0
  6. package/bundled-contracts/maggie-content/lifecycle-email-v1.schema.json +76 -0
  7. package/bundled-contracts/maggie-deployment/readiness-v1.schema.json +6 -1
  8. package/bundled-contracts/maggie-design/palette-roles-v1.schema.json +47 -0
  9. package/bundled-contracts/maggie-marketplace/template-content-v1.schema.json +103 -0
  10. package/bundled-contracts/maggie-ops/marketing-run-v1.schema.json +89 -0
  11. package/bundled-contracts/maggie-ops/notification-catalogue-example-v1.json +941 -0
  12. package/bundled-contracts/maggie-ops/notification-catalogue-v1.schema.json +273 -0
  13. package/bundled-contracts/maggie-service-booking/fact-provenance-v1.schema.json +128 -0
  14. package/bundled-contracts/maggie-service-booking/import-stages-v1.schema.json +191 -0
  15. package/bundled-contracts/maggiedash/booking-browser-evidence-v1.json +21 -0
  16. package/bundled-contracts/maggiedash/booking-browser-evidence-v2.json +191 -0
  17. package/bundled-contracts/maggiedash/booking-email-templates-v1.json +3 -1
  18. package/bundled-contracts/maggiedash/booking-voucher-lifecycle-v1.json +85 -0
  19. package/bundled-contracts/maggiedash/execution-board.json +4629 -1553
  20. package/bundled-contracts/maggiedash/stripe-booking-capabilities-v1.json +1 -0
  21. package/bundled-marketplace/README.md +17 -0
  22. package/bundled-marketplace/catalog.json +56 -7
  23. package/bundled-references/browser-inspection.md +25 -0
  24. package/bundled-references/google-integrations-runbook.md +54 -0
  25. package/bundled-references/maggiedash-booking/CURRENT-STATE.md +128 -10
  26. package/bundled-references/maggiedash-booking/EXECUTION-BOARD.json +4629 -1553
  27. package/bundled-references/maggiedash-booking/HOST-ADAPTER.md +5 -0
  28. package/bundled-references/maggiedash-booking/ORAWELLNESS-INTEGRATION-AUDIT.md +64 -21
  29. package/bundled-references/maggiedash-booking/PRD.md +9 -1
  30. package/bundled-references/maggiedash-booking/PROGRESS.md +244 -2399
  31. package/bundled-references/maggiedash-booking/QA-TEST-PLAN.md +37 -6
  32. package/bundled-references/maggiedash-booking/README.md +23 -6
  33. package/bundled-references/maggiedash-booking/RUNTIME-OPERATIONS.md +64 -8
  34. package/bundled-references/maggiedash-booking/SKILLS-AND-CLI.md +11 -2
  35. package/bundled-references/maggiedash-booking/STRIPE-INTEGRATION.md +66 -2
  36. package/bundled-references/maggiedash-booking/TASK-RUNBOOK.md +1 -1
  37. package/bundled-references/maggiedash-booking/TASKS.md +44 -3
  38. package/bundled-references/maggiedash-booking/VOUCHERS.md +47 -0
  39. package/bundled-references/provider-adapter-contract.md +33 -0
  40. package/bundled-skills/maggie-booking/SKILL.md +8 -0
  41. package/bundled-skills/maggie-clone-to-template/SKILL.md +26 -0
  42. package/bundled-skills/maggie-content-localization/SKILL.md +17 -1
  43. package/bundled-skills/maggie-content-localization/references/email-and-lifecycle.md +83 -0
  44. package/bundled-skills/maggie-deployment/SKILL.md +141 -7
  45. package/bundled-skills/maggie-deployment/references/vps.md +74 -1
  46. package/bundled-skills/maggie-design/SKILL.md +154 -0
  47. package/bundled-skills/maggie-feedback/SKILL.md +67 -1
  48. package/bundled-skills/maggie-marketplace/SKILL.md +91 -0
  49. package/bundled-skills/maggie-ops/SKILL.md +37 -0
  50. package/bundled-skills/maggie-ops/references/notifications-operations.md +154 -0
  51. package/bundled-skills/maggie-qa-workflow/SKILL.md +41 -1
  52. package/bundled-skills/maggie-service-booking/SKILL.md +82 -0
  53. package/bundled-skills/maggie-social-share/SKILL.md +56 -7
  54. package/bundled-skills/maggie-social-share/references/marketing-run.md +57 -0
  55. package/bundled-skills/maggie-social-share/references/queue-and-connections.md +152 -0
  56. package/bundled-skills/maggie-template/SKILL.md +57 -3
  57. package/bundled-skills/maggie-template/references/template-content-v1.example.json +34 -0
  58. package/bundled-tools/clis/maggie_booking.py +199 -26
  59. package/bundled-tools/clis/maggie_booking_vouchers.py +185 -0
  60. package/bundled-tools/clis/maggie_clone_to_template.py +14 -0
  61. package/bundled-tools/clis/maggie_deployment.py +307 -18
  62. package/bundled-tools/clis/maggie_deployment_auth_canary.py +216 -0
  63. package/bundled-tools/clis/maggie_deployment_collect.py +225 -0
  64. package/bundled-tools/clis/maggie_deployment_readiness.py +53 -3
  65. package/bundled-tools/clis/maggie_design.py +17 -0
  66. package/bundled-tools/clis/maggie_design_lint.py +277 -0
  67. package/bundled-tools/clis/maggie_design_verify.py +359 -0
  68. package/bundled-tools/clis/maggie_docs.py +82 -4
  69. package/bundled-tools/clis/maggie_email_localization.py +382 -0
  70. package/bundled-tools/clis/maggie_feedback.py +115 -5
  71. package/bundled-tools/clis/maggie_icon_glyph_check.py +382 -0
  72. package/bundled-tools/clis/maggie_icon_release_gate.py +28 -1
  73. package/bundled-tools/clis/maggie_localization.py +5 -0
  74. package/bundled-tools/clis/maggie_marketing_run.py +272 -0
  75. package/bundled-tools/clis/maggie_marketplace.py +199 -5
  76. package/bundled-tools/clis/maggie_notifications.py +528 -0
  77. package/bundled-tools/clis/maggie_ops.py +87 -0
  78. package/bundled-tools/clis/maggie_palette.py +280 -0
  79. package/bundled-tools/clis/maggie_qa_workflow.py +156 -1
  80. package/bundled-tools/clis/maggie_schedule.py +12 -2
  81. package/bundled-tools/clis/maggie_service_import.py +520 -0
  82. package/bundled-tools/clis/maggie_social_queue.py +442 -0
  83. package/bundled-tools/clis/maggie_social_share.py +46 -9
  84. package/bundled-tools/clis/maggie_template_package.py +1141 -0
  85. package/bundled-tools/runtime/google_ads.py +306 -0
  86. package/bundled-tools/runtime/google_capabilities.py +18 -2
  87. package/bundled-tools/runtime/google_remediation.py +152 -0
  88. package/package.json +1 -1
  89. package/references/browser-inspection.md +25 -0
  90. package/references/google-integrations-runbook.md +54 -0
  91. package/references/provider-adapter-contract.md +33 -0
@@ -45,6 +45,19 @@ allocation is rejected inside a rolled-back transaction. It also verifies the
45
45
  normalized payment-event columns, availability snapshot table, and a
46
46
  PostgreSQL advisory-lock round trip.
47
47
 
48
+ Canonical browser evidence capture treats both network-level request failures
49
+ and HTTP responses with status 400 or higher as failed requests. Failure
50
+ records retain viewport, method, status (for HTTP failures), and origin, but
51
+ omit URL paths and query strings so customer identifiers and bearer-like URL
52
+ values are not copied into the evidence artifact. Console and capture errors
53
+ are recorded as route-level codes without raw browser or exception text. The
54
+ GitHub Actions artifact allowlist includes only `evidence.json` and screenshots;
55
+ the protected `storage-state.json` is excluded even when a workflow step fails. Run
56
+ `npm run booking:browser:evidence:test` to check those cases and the 51-screen
57
+ validator contract. Runtime and browser capture commands also avoid printing
58
+ raw plan/exception contents to workflow logs; only allowlisted target error
59
+ codes are emitted, and all other capture errors use a generic code.
60
+
48
61
  The worker repository boundary has a separate source gate:
49
62
 
50
63
  ```bash
@@ -140,6 +153,9 @@ provider payment attempts for one client action.
140
153
 
141
154
  For desktop and mobile:
142
155
 
156
+ - On the public customer booking page, select a slot, change the native date,
157
+ verify availability reloads for the new date, and ensure the prior slot is
158
+ cleared before checkout can be submitted.
143
159
  - login redirect and return path;
144
160
  - sidebar/workspace navigation;
145
161
  - overview empty/loading/error/provider-outage states;
@@ -171,13 +187,28 @@ release-gate.json
171
187
  ```
172
188
 
173
189
  The protected workflow
174
- `.github/workflows/booking-browser-evidence.yml` captures the 15 Booking
190
+ `.github/workflows/booking-browser-evidence.yml` captures all 17 Booking
175
191
  routes at 390x844, 768x1024, and 1440x1000, with a host session supplied by an
176
- environment-scoped secret. `validate-booking-browser-evidence.mjs` fails on a
177
- missing route, non-2xx response, login redirect, missing screenshot, console
178
- error, failed network request, or horizontal overflow reported in
179
- `layoutErrors`. Browser evidence must come from a dedicated test tenant and
180
- must never include committed cookies or customer exports.
192
+ environment-scoped secret. The v2 contract maps every route to its expected
193
+ primary heading. Capture records the final pathname and visible `main h1`;
194
+ `validate-booking-browser-evidence.mjs` rejects a route redirect, the wrong
195
+ screen heading, missing routes or screenshots, non-2xx responses, login
196
+ redirects, console errors, failed network requests, and horizontal overflow
197
+ reported in `layoutErrors`. Browser evidence must come from a dedicated test
198
+ tenant and must never include committed cookies or customer exports.
199
+ Existing v1 artifacts do not satisfy the current v2 gate and must be recaptured;
200
+ do not relabel older evidence because it lacks the route-specific observations.
201
+
202
+ The canonical MaggieDash workflows, the ORA repository's root workflows, and
203
+ both capture commands validate `base_url` against the selected GitHub
204
+ environment's exact-host
205
+ `BOOKING_TEST_HOST_ALLOWLIST` variable. The value is a comma- or
206
+ whitespace-separated list of hostnames; wildcards, non-HTTPS URLs, URLs with
207
+ paths/credentials, and unlisted hosts are rejected. The workflows run this
208
+ preflight before writing session-state or runtime-plan material, then pass the
209
+ allowlist into the capture command for an independent second check. Configure
210
+ only dedicated Booking test hosts in this variable; do not add the production
211
+ host.
181
212
 
182
213
  The protected workflow
183
214
  `.github/workflows/booking-runtime-evidence.yml` captures all 47 host adapter
@@ -97,6 +97,8 @@ This repository currently provides:
97
97
  the host still supplies the concrete official SDK adapter;
98
98
  - a manager Reports screen and tenant-scoped `/reports.json` read model for
99
99
  period totals plus day, service, staff, and location breakdowns;
100
+ - venue-time manager booking displays and wall-clock inputs, with DST-gap
101
+ rejection and explicit choices for repeated fall-back times;
100
102
  - an idempotent 24-hour reminder worker job that queues confirmed-booking
101
103
  reminders into the existing Resend notification outbox;
102
104
  - service-level payment policies (`full`, `deposit`, `pay_later`, and
@@ -120,8 +122,10 @@ customer-flow boundary are implemented locally. A secret-free reference host
120
122
  and an Astro host scaffold are also available for contract/browser work. A host
121
123
  must still apply the schema, prove PostgreSQL transactions, verify a real
122
124
  payment account and webhook, enable notification delivery and tenant locking,
123
- and capture authenticated production browser/runtime/ops evidence before real
124
- bookings can be enabled.
125
+ and capture authenticated browser/runtime/ops evidence against a dedicated
126
+ HTTPS test tenant before real bookings can be enabled. Test evidence workflows
127
+ must not target production; any production observation needs its own approved,
128
+ read-only plan.
125
129
  Resend is the server-side notification and account-email transport. Staff
126
130
  invitation, first-login setup, password reset, one-time token expiry, and
127
131
  session revocation are implemented in the Astro host scaffold; real delivery
@@ -136,18 +140,31 @@ charges/payouts enablement, and a webhook secret. Raw Stripe credentials are
136
140
  never returned by the API or stored as plaintext Booking data. Deployment
137
141
  secrets take precedence over dashboard-managed credentials.
138
142
 
139
- ## Current verification snapshot — 2026-09-21
143
+ ## Verification snapshot — 2026-09-28
144
+
145
+ This dated snapshot records the earlier 0.7.48 candidate review and 15-route
146
+ local browser smoke. It is historical; for the current task count, browser
147
+ contract, and release blockers, use [`CURRENT-STATE.md`](./CURRENT-STATE.md).
148
+
149
+ | Item | Current evidence |
150
+ |---|---|
151
+ | MaggieDash and ai-cmo source | MaggieDash package `0.2.11`; ai-cmo `0.7.48` (published) |
152
+ | Email-template boundary | Ten events, including `payment.no_show_fee`; confirmed bookings allow a host-supplied, escaped `arrivalNote` |
153
+ | ORA source CLI check | Local ai-cmo source `email-templates-contract` and `inspect --project` pass; the installed global package still carries the old nine-event contract and requires a package release/install readback |
154
+ | Regression evidence | MaggieDash `npm test`, 25 targeted ai-cmo Booking Python tests, and ORA email-template/customer validators pass; ORA Astro build passes |
155
+
156
+ ## Historical verification snapshot — 2026-09-21
140
157
 
141
158
  | Item | Current evidence |
142
159
  |---|---|
143
160
  | MaggieDash source | Package `0.2.8`, `HEAD`/`origin/main` [`9d99de7`](https://github.com/TOPY-AI-LTD/MaggieDash/commit/9d99de7); the working tree contains newer uncommitted Booking changes |
144
- | Delivery board | 84 implementation tasks passed and 3 real-host evidence tasks pending (BK-030, BK-031, BK-032); Reports, reminders, payment-policy projection, cancellation policy snapshots/cutoff/refund settlement, consented Stripe no-show fee charging with explicit manager/finance approval, venue-local calendar day/week ranges, manager/customer history, editable schedule rules, catalogue, treatment package catalogue plus customer entitlement balances/redemption, public package checkout/payment return and public customer package redemption, transactional package-credit restoration on cancellation, Stripe package fulfillment/refunds, package confirmation/refund Resend notifications, locations, staff/resource management, live-config booking creation, manager and public multi-treatment appointments, segment-safe rescheduling, strict first-run setup checks, secure dashboard-managed Stripe connection, tenant-scoped Stripe Customer identity mapping, secret-safe Stripe readiness, installed-workspace validator coverage, explicit schema bootstrap, bootstrap secret provisioning, transactional schema dry-run, compatible Resend sender keys, token-bound rescheduling, customer-manage links/history, transactional waitlist conversion, priority/FIFO waitlist slot matching, synchronized install contracts, npm bundled-contract path resolution, tenant-scoped notification inspection/dead-letter replay, first-owner registration hardening, access defaults, complete server-enforced capability permissions, worker migration preflight, complete browser evidence route coverage, installable administrator-managed Booking access contracts, reference-host Team access CRUD/denial evidence, dependency-complete fresh Astro installation, tenant-scoped Resend email template management, and complete tenant booking defaults are covered by the manager/runtime and public-customer contracts |
161
+ | Delivery board | 101 implementation tasks passed and 3 real-host evidence tasks pending (BK-030, BK-031, BK-032). The current browser contract requires all 17 manager routes across three viewports (51 screens), including Packages and Email templates; prior 45-screen captures are historical subset evidence. |
145
162
  | Local code gates | MaggieDash `npm test`, contract/UI/security/customer/runtime validators, and Python task-board/link checks passed |
146
163
  | Installer projection | The default public GitHub source installed 139 source artifacts plus 23 Astro host files in a fresh disposable project; dependency completion added the missing SSR adapter, and the installed host bootstrap validator, `maggie booking inspect`, and `astro build` all passed. Existing host deployment configs are preserved |
147
164
  | Published npm parity | Local CLI source is `0.7.39`; npm still serves `@topy-ai/maggie@0.7.38`, which has the older Booking contract and needs a release/published-tarball verification |
148
165
  | Access boundary | Standard Booking schema owns `maggiedash_booking_user_roles`; host access API, explicit permissions, linked `staff_id`, and repository data-scope checks passed |
149
166
  | Reference host | 47 manager endpoint checks plus public customer-flow checks passed, including explicit no-show fee route coverage, location setup, package catalogue management, customer package grant/balance/redemption, public package redemption from hold to zero-price booking, package checkout/payment-return, Stripe connection verification, notification replay, and multi-treatment hold/checkout/reschedule |
150
- | Local browser smoke | The browser contract now covers all 15 manager routes (`45` route/viewport screens) across 390/768/1440. A fresh authenticated host capture is still required; the earlier 33/33 result covered only the former 11-route surface and is not reused as production evidence |
167
+ | Local browser smoke | At this historical snapshot the browser contract covered 15 manager routes (`45` route/viewport screens). The current v2 contract now covers 17 routes and requires route-specific path/heading evidence; the earlier artifact is not reused as complete evidence. |
151
168
  | Production proof | Not yet complete; reference-host and fixture artifacts are explicitly not production evidence |
152
169
 
153
170
  ## Current product limits
@@ -231,7 +248,7 @@ only.
231
248
  5. Enable one worker scheduler with lock, alert, retry, and dead-letter proof;
232
249
  verify Resend invitation, reset, reminder, waitlist, refund, package, and
233
250
  no-show delivery.
234
- 6. Capture the 47-endpoint runtime, 45-screen browser, and ops evidence bundle;
251
+ 6. Capture the 47-endpoint runtime, 51-screen browser, and ops evidence bundle;
235
252
  run the final release gate before a one-location canary.
236
253
 
237
254
  The detailed execution board is maintained by
@@ -13,7 +13,8 @@ provider adapters, email/SMS, secrets, tenant scope, and deployment.
13
13
  | Payment webhook | `payment_attempts`, `webhook_events`, `events`, `audit_events` | `payment-webhook.mjs`, `booking.provider.webhook` | host server route |
14
14
  | Payment reconciliation | `payment_attempts`, `refunds`, `webhook_events` | `reconcilePaymentEvents` and `booking.payment.*` endpoints | host worker/provider adapter |
15
15
  | Notifications | `outbox`, `notifications`, `events`, `audit_events` | `notifications.mjs`, `claimNotifications`, `scheduleNotification` | host email/SMS adapter |
16
- | Browser evidence | no business tables; artifact storage only | `booking-browser-evidence-v1.json` and capture/validate scripts | protected CI environment |
16
+ | Browser evidence | no business tables; artifact storage only | `booking-browser-evidence-v2.json` and capture/validate scripts | protected CI environment |
17
+ | Worker freshness | `maggiedash_booking_worker_status` | successful write-cycle timestamp, read by the next cycle's `worker.stale` health check | host worker + scheduler |
17
18
 
18
19
  ## Worker sequence
19
20
 
@@ -31,16 +32,46 @@ lock tenant
31
32
  unlock tenant
32
33
  ```
33
34
 
35
+ Sanitized ops evidence uses UTC timestamps and must preserve the sequence
36
+ `backupVerifiedAt <= restoreVerifiedAt <= generatedAt`. Validators reject a
37
+ restore before its backup, a report generated before restore verification, and
38
+ non-object evidence roots. Direct CLI validation reports a bounded
39
+ `BOOKING_CHECK_FAILED` input error for a non-object JSON file; `release-gate`
40
+ continues and returns a structured `blocked` result with ops status `failed`.
41
+
34
42
  The database exclusion constraints remain the final double-booking guard. A
35
43
  distributed lock reduces duplicate work but is not a correctness substitute.
36
44
 
45
+ Each worker acquires its tenant lock before loading worker state. If another
46
+ cycle holds the lock, the runner exits with `status: "skipped"`,
47
+ `worker.lock_contention` at warning severity, and `stateChanged: false`. It
48
+ does not read worker state, write rows, dispatch providers, or mark the cycle
49
+ as a failure. Database/lock acquisition errors still produce a failed worker
50
+ report and must be monitored by the scheduler.
51
+
37
52
  Every installed PostgreSQL worker performs a read-only schema preflight before
38
- acquiring the tenant lock. It checks the core, Booking, and access tables. If a
39
- migration is missing, it exits with code 1 and emits bounded JSON with
53
+ acquiring the tenant lock. It checks the core, Booking, access, and persisted
54
+ worker-status tables. If a migration is missing, it exits with code 1 and emits bounded JSON with
40
55
  `status: "needs-migration"`; it does not load worker state, acquire the lock,
41
56
  or write business rows. Operators should run the schema command's `--dry-run`
42
57
  before an explicitly approved `--apply --confirm` migration.
43
58
 
59
+ The repository reads `last_success_at` for the selected tenant before the cycle
60
+ and upserts it only when a write-mode cycle passes. That timestamp is persisted
61
+ in the same transaction as the worker state and is supplied to the next
62
+ cycle's `worker.stale` evaluation. A successful write returns the committed
63
+ status timestamp and uses it in that cycle's health report, so the report does
64
+ not retain a stale pre-write value. Preview runs do not advance it and continue
65
+ to evaluate the persisted timestamp. If an adapter write fails after state is
66
+ loaded, the structured error output retains that prior timestamp for stale
67
+ health evaluation. An external scheduler monitor is still required to detect
68
+ a worker that never starts, because no in-process health report can be emitted
69
+ while the process is down.
70
+ The additive status table is now present in ORA staging; the six-job preview
71
+ there passed with `write=false`, zero alerts, and no provider dispatch. The
72
+ preview intentionally left `last_success_at` empty. Production still needs the
73
+ schema migration before the updated worker can run.
74
+
44
75
  Notification delivery is intentionally after booking/payment truth is committed.
45
76
  `notifications.mjs` stores only a recipient hash and allowlisted template
46
77
  variables, leases rows before dispatch, retries with exponential backoff, moves
@@ -66,6 +97,28 @@ payment signal.
66
97
 
67
98
  ## Host adapter module
68
99
 
100
+ The worker supports `--help`, which exits before loading environment values or
101
+ connecting to PostgreSQL. The worker defaults to preview mode. A preview reports eligible outbox rows as
102
+ `previewed` and never invokes `dispatchNotification`; it does not write the
103
+ claim or delivery result. `--write` performs database writes and invokes the
104
+ host provider for each claimed notification. Reconcile staging outbox/provider
105
+ activity before any write-mode run.
106
+
107
+ The generic Astro PostgreSQL worker and ORA host worker include the
108
+ schema-versioned `health` summary in successful cycle output and caught
109
+ schema/lock/runtime failures. It carries stable alert codes, severity, a
110
+ correlation ID, and counts only; the worker does not send an alert itself.
111
+ Route critical reports from the host's structured log pipeline to its chosen
112
+ alert destination. Configuration and database connection failures that occur
113
+ before worker startup remain process-level errors and must also be monitored by
114
+ the scheduler. Structured startup and runtime errors pass through the shared
115
+ redactor, which removes known secret environment values, connection URIs,
116
+ bearer/API tokens, customer email and phone numbers, and sensitive key/value
117
+ fragments before writing JSON.
118
+ When the provider accepts a notification, its opaque `providerRef` is retained
119
+ on the sent outbox row for provider activity reconciliation; it is not exposed
120
+ through customer-facing DTOs.
121
+
69
122
  The production command accepts a host module:
70
123
 
71
124
  ```bash
@@ -117,10 +170,12 @@ state write.
117
170
 
118
171
  The protected workflow in
119
172
  `.github/workflows/booking-browser-evidence.yml` requires an HTTPS base URL and
120
- an environment-scoped, short-lived storage state. It captures 15 manager
121
- screens at mobile/tablet/desktop widths, records console/request failures, uploads
122
- artifacts for 14 days, and fails validation when any route is missing, not
123
- ready, non-2xx, or has a browser/network error.
173
+ an environment-scoped, short-lived storage state. The v2 contract captures all
174
+ 17 manager screens at mobile/tablet/desktop widths and binds each route to its
175
+ expected primary heading. Evidence records the final pathname and rendered
176
+ heading; validation rejects wrong-route redirects, a wrong screen rendered at
177
+ the requested URL, missing screens, non-2xx responses, and browser/network
178
+ errors. Artifacts are retained for 14 days.
124
179
 
125
180
  Never commit storage state, cookies, screenshots with customer data, or raw
126
181
  provider payloads. Use a dedicated test tenant and redact artifacts before
@@ -138,7 +193,8 @@ must never be used as production evidence.
138
193
 
139
194
  Alert on:
140
195
 
141
- - worker lock contention or two missed minute ticks;
196
+ - worker lock contention, a stale last successful write cycle, or two missed
197
+ minute ticks;
142
198
  - availability read model older than five minutes;
143
199
  - holds expiring above baseline;
144
200
  - payment webhook verification/quarantine spikes or reconciliation lag;
@@ -210,6 +210,12 @@ present it reports `dashboard-or-host-secret-pending` and points the signed-in
210
210
  owner/manager to the secure Booking Overview connection form. A partial
211
211
  deployment pair remains `degraded` because the dashboard form is intentionally
212
212
  not allowed to override deployment-managed credentials.
213
+ For compatibility with the existing ORA host, `setup` also recognizes
214
+ `ST_SECRECT_KEY` as a legacy alias for `STRIPE_SECRET_KEY`; a complete alias
215
+ plus `STRIPE_WEBHOOK_SECRET` pair is still only
216
+ `online-payments-pending-verification`. New deployments should use the
217
+ canonical name, and only the authenticated Booking connection check can verify
218
+ that the credentials connect to the intended Stripe account.
213
219
  `contract` accepts both the source contract JSON Schema and the compact
214
220
  ai-cmo-skills contract representation. It never reads secrets or customer data.
215
221
 
@@ -445,8 +451,11 @@ maggie booking release-gate --project . --require-runtime \
445
451
  --require-board
446
452
  ```
447
453
 
448
- The browser gate checks all 15 screens at mobile/tablet/desktop widths, safe
449
- screenshot paths, ready state, no console errors, and no failed requests.
454
+ The browser gate checks all 17 screens at mobile/tablet/desktop widths, safe
455
+ screenshot paths, PNG/JPEG content matching the file extension, exact viewport
456
+ width and at least viewport height (host captures use `fullPage`), ready state,
457
+ no console errors, and no failed requests. Screenshot artifacts are capped at
458
+ 25 MiB each.
450
459
  The board gate additionally fails closed until every task in
451
460
  `docs/maggiedash-booking/EXECUTION-BOARD.json` is `passed`; use `--board` to
452
461
  inspect a different board.
@@ -59,7 +59,8 @@ states (`requires_action`, `pending`, `failed`, `succeeded`, `cancelled`, and
59
59
  The first adapter should subscribe only to events the configured capabilities
60
60
  need:
61
61
 
62
- - `checkout.session.completed`, `checkout.session.async_payment_succeeded`,
62
+ - `checkout.session.completed`, `checkout.session.expired`,
63
+ `checkout.session.async_payment_succeeded`,
63
64
  and `checkout.session.async_payment_failed`;
64
65
  - `payment_intent.processing`, `payment_intent.payment_failed`,
65
66
  `payment_intent.succeeded`, `payment_intent.requires_action`, and
@@ -104,6 +105,47 @@ accounting, CRM, support, analytics, marketing, and workflow automation. It is
104
105
  an integration surface, not a reason to add third-party credentials to the
105
106
  MaggieDash browser bundle.
106
107
 
108
+ ## Live setup runbook (read-only verification)
109
+
110
+ Switching a host to live mode is the step most likely to create real objects
111
+ by accident. A probe that was expected to fail has created a real live object,
112
+ so the live checklist is strictly read-only from the agent side:
113
+
114
+ 1. **Verify with GET only.** Use list/retrieve calls (`GET /v1/account`,
115
+ `GET /v1/webhook_endpoints`, `GET /v2/core/event_destinations` or the
116
+ SDK equivalents, `GET /v1/products?limit=…`) to confirm account mode,
117
+ enabled capabilities, endpoint URLs, and subscribed events. Never use a
118
+ `POST`/create call as a probe "to see whether it fails"; in live mode it may
119
+ succeed. If a write is genuinely required, show the exact request to the
120
+ owner and run it only after explicit approval.
121
+ 2. **Install signing secrets through a user-run, no-echo command.** The agent
122
+ must not see, print, or paste webhook or Connect event-destination signing
123
+ secrets. Give the owner a command they run themselves, for example:
124
+
125
+ ```bash
126
+ read -rs STRIPE_WEBHOOK_SECRET && printf '%s' "$STRIPE_WEBHOOK_SECRET" \
127
+ | wrangler secret put STRIPE_WEBHOOK_SECRET # or the host's secret store
128
+ unset STRIPE_WEBHOOK_SECRET
129
+ ```
130
+
131
+ Then verify presence only (secret name listed, value never read back).
132
+ 3. **Thin-event destination secrets are not retrievable via the API.** A
133
+ Connect/thin-event destination's signing secret is shown once in the
134
+ Dashboard when the destination is created or rolled. If it was not
135
+ captured, roll it in the Dashboard and install the new value with step 2;
136
+ do not try to fetch it programmatically.
137
+ 4. **Hand Dashboard steps to the owner.** The Stripe Dashboard can be unusable
138
+ under browser automation (bot challenges, 2FA, session prompts). Treat
139
+ Dashboard-only steps — activating live mode, creating or rolling event
140
+ destinations, revealing secrets, Connect onboarding — as owner tasks with a
141
+ written checklist, then confirm the result with the read-only calls above.
142
+ 5. **Record evidence, not values.** Capture account mode, endpoint IDs, event
143
+ lists, and secret *presence* in the release evidence; never key material.
144
+
145
+ `maggie booking setup` and `maggie booking stripe-audit` do not call Stripe:
146
+ they read local configuration and the versioned capability contract only.
147
+ Any host-side live readiness check must likewise issue `GET` requests only.
148
+
107
149
  ## Recommended rollout order
108
150
 
109
151
  1. Stripe Customers + Checkout Sessions or PaymentIntents.
@@ -114,7 +156,8 @@ MaggieDash browser bundle.
114
156
  6. Billing/Portal for memberships; Terminal for in-person operations; Connect
115
157
  only for a true platform model.
116
158
  7. Gift-card partner or local ledger after accounting and redemption rules are
117
- approved.
159
+ approved. The local-ledger option is fixed by the
160
+ [voucher lifecycle contract](./VOUCHERS.md).
118
161
 
119
162
  Run the local contract gate with:
120
163
 
@@ -127,3 +170,24 @@ maggie booking stripe-audit --contract /path/to/MaggieDash/contracts/stripe-book
127
170
  No production payment, refund, gift-card issue, or referral reward is enabled
128
171
  by this document. The host must add its adapter, integration tests, secret
129
172
  configuration, and runtime evidence first.
173
+
174
+
175
+ Public customer booking payments explicitly request the hosted Checkout flow.
176
+ The PostgreSQL payment adapter preserves `hosted` in the normalized request,
177
+ its idempotency hash, and provider call; the Stripe adapter then creates one
178
+ Checkout Session for that payment attempt. Package purchases already use the
179
+ same hosted flow.
180
+
181
+
182
+ Hosted Checkout Sessions request a 31-minute expiry, above Stripe's 30-minute
183
+ minimum. Reconciliation recognizes `cs_` references and retrieves the Checkout
184
+ Session; open sessions remain pending, paid sessions succeed and adopt the
185
+ PaymentIntent reference when Stripe provides one, and expired sessions map to
186
+ the provider-neutral cancelled state.
187
+
188
+
189
+ For Checkout's asynchronous payment methods, supported `checkout.session.*`
190
+ webhooks retain the Session's PaymentIntent reference when Stripe provides one.
191
+ The Session ID is the fallback for events without a PaymentIntent, such as an
192
+ expired unpaid Checkout. This keeps later reconciliation and refund requests
193
+ on the provider object they expect.
@@ -79,7 +79,7 @@ maggie booking release-gate --project . --require-runtime \
79
79
  --require-ops --ops-evidence .maggie/booking/ops-evidence.json
80
80
  ```
81
81
 
82
- `--require-browser` applies the same 15-screen × 3-viewport checks as the
82
+ `--require-browser` applies the same 17-screen × 3-viewport checks (51 screens) as the
83
83
  browser evidence validator, including safe screenshot paths, ready state,
84
84
  empty console errors, and empty failed-request reports.
85
85
 
@@ -40,8 +40,8 @@ or evidence gate. The detailed leaf-task board is
40
40
  | BK-027 | Finish Booking UI data loading, navigation, forms, and action feedback | MaggieDash | BK-018, BK-022, BK-023 | typed route loading, pagination, dialogs, forms, feedback | UI source gate + esbuild + reference-host Chrome smoke | passed |
41
41
  | BK-028 | Finish manager daily operations journeys | MaggieDash | BK-021, BK-023, BK-027 | calendar modes, lifecycle/reschedule, payment operations, audit views | UI source gate + reference-host Chrome interaction smoke | passed |
42
42
  | BK-029 | Verify authentication, tenancy, roles, and privacy boundaries | both | BK-019, BK-022, BK-027 | session/role/project checks, staff lifecycle-only mutations, payment/customer denial, and redaction scan | security validator + contract gate | passed |
43
- | BK-030 | Wire the production worker and operational controls | both | BK-020, BK-021, BK-024, BK-026 | injected PostgreSQL worker repository/adapter, tenant lock, correlation/health report, dead-letter policy, ops evidence contract, production fixture guard, executable backup/restore rehearsal, and reviewed systemd/cron schedule generation | adapter/repository/health/ops evidence tests + `maggie booking worker-schedule` + real disposable worker cycle/schema/lock + `npm run booking:postgres-backup-restore:integration -- --source-database-url <source> --restore-database-url <empty-target> --pg-bin-dir <matching-postgres-bin-dir> --confirm`; host connection/alert routing/backup/recovery evidence pending | needs-evidence |
44
- | BK-031 | Capture real host conformance and browser evidence | both | BK-019, BK-022, BK-028, BK-029, BK-030 | 47-manager-endpoint runtime plan/evidence and 15-screen Playwright evidence with concrete route/query validation, console/request/layout overflow checks | `npm run booking:runtime:plan:test` + protected runtime/browser workflows | needs-evidence |
43
+ | BK-030 | Wire the production worker and operational controls | both | BK-020, BK-021, BK-024, BK-026 | injected PostgreSQL worker adapter, serialized tenant-scoped reads, no-provider dry-run, credential-free `--help`, tenant lock, correlation/health report with a persisted tenant-scoped last-success timestamp, dead-letter policy, ops evidence contract, production fixture guard, executable backup/restore rehearsal, and reviewed systemd/cron schedule generation | adapter/repository/health/ops evidence tests + safe installed `--help` checks + `maggie booking worker-schedule` + real disposable worker cycle/schema/lock + staging no-dispatch preview + backup/restore integration; lock contention skips before state load and provider dispatch; `worker.stale` reads the persisted prior success and the status table is preflighted; ORA staging migration, six-job preview, and real PostgreSQL integration passed; redaction covers customer email and phone numbers; ORA staging tools now enforce normalized production/staging database separation and provide a read-only cleanup audit; local backup/restore rehearsal passed; ORA production timer observed active and write-capable; provider activity review, alert routing, and host recovery evidence pending | needs-evidence |
44
+ | BK-031 | Capture real host conformance and browser evidence | both | BK-019, BK-022, BK-028, BK-029, BK-030 | ORA local Chrome v2 QA now checks all 17 manager routes at 3 viewports (51/51 normalized route/heading/layout passes, zero captured console errors, no horizontal overflow). A post-BK-141 localhost smoke also confirms Calendar venue-zone rendering and the Bookings direct route/New booking dialog after fixing a missing dirty-state hook and SSR hydration mismatch. Failed network requests were not observable and screenshot bitmap dimensions vary, so local artifacts remain supplemental only. The ORA repo `.env` has no dedicated HTTPS staging base URL; protected workflow secrets were not inspected. Canonical MaggieDash and ORA root workflows now run the exact environment host-allowlist preflight before protected state writes and pass the allowlist to capture for a second check; regression and contract checks cover workflow ordering. Authenticated HTTPS-host evidence for all 47 endpoints and the canonical 51-screen browser artifact remain open | `npm run booking:runtime:plan:test` + MaggieDash `npm test` + ORA `booking:evidence-target:test`, `contract:check`, Astro check/build + protected-workflow order/allowlist regression + canonical/ORA helper byte parity + ORA local Chrome QA (supplemental only) | needs-evidence |
45
45
  | BK-032 | Run release gate, canary, documentation, and feedback closure | both | BK-025, BK-030, BK-031, BK-033, BK-034, BK-035, BK-036, BK-037, BK-038 | final release report, browser artifact parity/layout rejection, and docs | `maggie booking release-gate --require-runtime --require-browser --require-ops --require-board` | needs-evidence |
46
46
  | BK-033 | Freeze and validate the public customer booking boundary | both | BK-021, BK-024, BK-026 | public-noindex catalog/availability/hold/checkout/payment-return/cancel contract, redacted DTOs, notification intents, and host safety boundary | `npm run booking:customer-flow:test` + `npm test` | passed |
47
47
  | BK-034 | Ship the public customer booking page and pending-payment recovery UI | MaggieDash | BK-033 | installable customer page source, Astro route starter, catalog/availability/hold/checkout/pending-return UI, and noindex/public request checks | `npm run booking:customer-ui:test` + manifest/install validation | passed |
@@ -94,7 +94,7 @@ or evidence gate. The detailed leaf-task board is
94
94
  | BK-081 | Harden first-owner registration | both | BK-058, BK-071 | Serialize first-owner registration, verify existing passwords, and prevent password overwrite or disabled-account reactivation | MaggieDash bootstrap validator + `npm test` + ORA `contract:check`/build + `git diff --check` | passed |
95
95
  | BK-082 | Harden Booking access defaults and disabled-account boundary | both | BK-026, BK-081 | Give invited staff/finance accounts safe role defaults, preserve granular permissions, and reject disabled accounts instead of re-enabling them | MaggieDash bootstrap validator + `npm test` + ORA `contract:check`/build + `git diff --check` | passed |
96
96
  | BK-083 | Add worker migration preflight | both | BK-030, BK-070 | Check core, Booking, and access tables before worker lock/repository reads and return bounded `needs-migration` JSON without writes or stack traces | worker `node --check` + Astro bootstrap validator + unmigrated ORA worker run + `git diff --check` | passed |
97
- | BK-084 | Synchronize browser evidence with the complete manager workspace | both | BK-080, BK-083 | Cover all 15 manager routes at mobile, tablet, and desktop viewports and keep installed UI markers aligned with the evidence contract | MaggieDash `npm test` + ORA contract/build + ai-cmo Booking tests + packaged task validation + `git diff --check` | passed |
97
+ | BK-084 | Synchronize browser evidence with the complete manager workspace | both | BK-080, BK-083 | Covered the then-current 15 manager routes across mobile, tablet, and desktop; BK-120 extends the evidence set to all 17 current routes | MaggieDash `npm test` + ORA contract/build + ai-cmo Booking tests + packaged task validation + `git diff --check` | passed |
98
98
  | BK-085 | Make cancellation and refund policy tenant-configurable and booking-scoped | both | BK-064, BK-084 | Configure cutoff/refund/no-show policy, snapshot it on every booking creation path, and enforce customer cancellation cutoff without pretending provider refunds are automatic | MaggieDash `npm test` + ORA contract/build + policy validators + `git diff --check` | passed |
99
99
  | BK-086 | Make calendar day and week views honor their requested venue-local range | both | BK-084, BK-085 | Filter Day/Week queries by the correct venue-local range, keep staff scope, and align reference host/UI behavior with the PostgreSQL contract | MaggieDash `npm test` + calendar/repository validators + ORA contract/build + `git diff --check` | passed |
100
100
  | BK-087 | Execute cancellation refunds through the provider boundary and Resend outbox | both | BK-080, BK-085, BK-086 | Allocate policy-safe refunds across captured attempts, call the injected provider after cancellation, expose bounded settlement status, queue payment.refunded only for accepted/pending refunds, and keep generic/ORA Resend workers behaviorally aligned | MaggieDash `npm test` + cancellation/customer settlement validators + Astro bootstrap validator + ORA contract/build + `git diff --check` | passed |
@@ -115,9 +115,20 @@ or evidence gate. The detailed leaf-task board is
115
115
  | BK-101 | Complete server-enforced Booking capability permissions | both | BK-089, BK-100 | Reconcile every route capability with the administrator registry, enforce safe role defaults for legacy rows, honor explicitly granted staff reads, and synchronize generic/ORA/reference-host/CLI contracts | MaggieDash npm/access/route-handler gates, ORA contract/build, ai-cmo Booking tests, and `git diff --check` | passed |
116
116
  | BK-102 | Persist provider customer identity for real Stripe payments | both | BK-025, BK-100 | Resolve local tenant customer UUIDs to idempotent Stripe Customer objects, persist only the provider reference, and use it for Checkout/PaymentIntent/SetupIntent without leaking credentials or cross-tenant data | Stripe adapter conformance with customer resolver, central/ORA schema validators, ORA contract/build, MaggieDash `npm test`, and `git diff --check` | passed |
117
117
  | BK-103 | Add consented Stripe no-show fee charging | both | BK-088, BK-102 | Add an explicit manager/finance action that charges only a policy-derived no-show fee when the customer consented, a saved payment method is available, and Stripe off-session capability is verified; persist adjustment payment/audit state and queue the Resend payment notification | Stripe adapter, payment adapter, route/reference-host, email, UI, central `npm test`, ORA contract/build, and `git diff --check` | passed |
118
+ | BK-104 | Gate public booking exposure on host readiness | both | BK-033, BK-034 | Shared fail-closed readiness gate and test override; gate Astro customer page and new customer creation routes while preserving customer continuations; install the source manifest and reuse route policy in ORA | MaggieDash `npm test` + Astro host-bootstrap gate + direct route guard tests + ORA public-gate/build + source CLI install parity | passed |
119
+ | BK-105 | Synchronize ORA Booking CLI gates with current contracts | both | BK-097, BK-100 | Sync ORA-local inspect/setup validator and source contract with the canonical ten-event template contract, `arrivalNote`, and Stripe key alias behavior while preserving pending-verification semantics | ORA-local inspect/setup/email-template contract + canonical Booking CLI unit tests + byte-parity + whitespace checks | passed |
120
+ | BK-106 | Explain Stripe connection checks in the Booking setup checklist | MaggieDash | BK-100, BK-105 | Show API, webhook, charge and payout check results, with a clear action when the account cannot accept payments | Booking UI validator + MaggieDash `npm test` + task-board validation + `git diff --check` | passed |
121
+ | BK-107 | Derive online-payment capability from verified Stripe charge availability | both | BK-100, BK-104, BK-106 | Keep online/off-session payment disabled until the credential is verified and Stripe reports charges enabled; mirror the rule into ORA | Stripe readiness regression + host-bootstrap + MaggieDash `npm test` + ORA contract/build + byte parity | passed |
122
+ | BK-108 | Fail closed when online-payment capability is missing | both | BK-107 | Missing payment capability in stored settings must not make manager Overview or payment-health report payments ready | PostgreSQL core repository regression + MaggieDash `npm test` + ORA contract/build + source parity | passed |
118
123
 
119
124
  ## Execution rule
120
125
 
126
+ | BK-109 | Require explicit online-payment capability in shared payment flows | both | BK-108 | Shared payment starts and reference-host readiness must fail closed unless onlinePayment is an explicit boolean true | focused gateway/reference-host regressions + MaggieDash `npm test` + ORA contract/build + task board | passed |
127
+
128
+ | BK-110 | Verify current Booking install parity in a disposable Astro host | both | BK-109 | Exercise the current manifest through canonical CLI install; compare every projected file and run installed inspect/bootstrap validators without DB or dependency writes | disposable Astro install + exact parity + inspect + installed validators + source host-bootstrap + board | passed |
129
+
130
+ | BK-111 | Bind Stripe gateway capabilities to verified account state | both | BK-107, BK-109, BK-110 | Runtime Stripe gateway must use account-verification state, not credential presence or hardcoded true values | readiness matrix + adapter regressions + MaggieDash tests + ORA contract/build + 207-file install parity | passed |
131
+
121
132
  For each leaf task: select it with `maggie booking tasks`, write the plan and
122
133
  acceptance checks, implement the smallest complete slice, run its gate, update
123
134
  the relevant docs, then append a dated entry to [`PROGRESS.md`](./PROGRESS.md).
@@ -135,3 +146,33 @@ invent a production provider integration, notification transport, or live
135
146
  database migration runner. Those remain explicit Phase 2–6 host work in
136
147
  [`CURRENT-STATE.md`](./CURRENT-STATE.md) and are represented by contracts and
137
148
  readiness states where the host must own the runtime behavior.
149
+ | BK-112 | Require verified online-payment capability for public exposure | both | BK-104, BK-107, BK-111 | Keep the natural public entry closed unless Stripe is connected in live mode with an explicit onlinePayment capability and verified secret fingerprint; preserve parity with generic Astro | ORA exposure/contract/readiness validators + Astro build + generic host-bootstrap parity + task-board validation | passed |
150
+ | BK-113 | Restrict public force-open override to non-production hosts | both | BK-104, BK-112 | Deny force-open by default; generic Astro and ORA may opt in only outside production, while production force-off remains available and force-on falls back to natural readiness | shared and ORA gate regressions + host-bootstrap parity + ORA contract/build + staging-backed production preview + fresh install parity + task-board validation | passed |
151
+ | BK-114 | Show verified Stripe account reference in Booking setup | both | BK-100, BK-102, BK-111 | Return the tenant-scoped persisted Stripe account ID and show it in the manager checklist to support intended-account confirmation, with no secret/provider payload exposure | PostgreSQL/reference-host/UI validators + MaggieDash npm test + ORA validators/build + fresh install checks + task-board validation | passed |
152
+ | BK-115 | Complete customer payment-return handoff and guest details | both | BK-107, BK-114 | Use the long-lived manage token after verified payment, expose safe guest/pricing details to the customer DTO, and preserve only the suitability-cleared marker in ORA holds | MaggieDash/ORA customer-flow and UI validators + staging PostgreSQL integration + build + install parity + board validation | passed |
153
+ | BK-116 | Fail fast before staging checkout writes when Stripe test charges are disabled | ORA host harness | BK-114, BK-115 | Run a read-only Stripe test-account capability preflight before staging writes; reject disabled charges and live keys without exposing credentials | ORA preflight unit tests + checkout suite fail-fast check + task-board validation | passed |
154
+ | BK-117 | Validate browser screenshot image contents and viewport dimensions | both | BK-031 | Require PNG/JPEG bytes to match the extension and named viewport width, allow full-page height, and reject malformed or oversized artifacts across the canonical gate and ORA mirrors | Python browser-evidence unit tests + MaggieDash npm test + canonical/ORA JS valid and invalid fixture parity + mirror parity + task-board validation | passed |
155
+ | BK-118 | Keep packaged Booking status references link-safe | ai-cmo-skills | BK-091 | Replace a workspace-only relative link in canonical Booking status docs and rebuild the standalone CLI reference bundle | bundled-reference markdown-link test + full AI-CMO Python suite + task-board validation | passed |
156
+ | BK-119 | Verify customer date changes refresh availability and clear stale slots | ORA host harness | BK-115 | Change the date after selecting a public customer slot; prove the new-date availability request and response render, the old selection clears, and the browser submits no hold/checkout | ORA local-staging Playwright UI journey + contract/build + task-board validation + `git diff --check` | passed |
157
+ | BK-120 | Cover every current manager screen in browser evidence | both | BK-117 | Align the evidence contract/capture/validator and ORA mirrors with all 17 current screens, including Packages and Email templates, across three viewports (51 screens) | canonical/ORA accept and missing-route regressions + MaggieDash `npm test` + ORA contract/build + mirror parity + packaged-contract test + task-board validation | passed |
158
+ | BK-121 | Reject browser evidence captured from the wrong manager screen | both | BK-120 | Version the evidence contract to v2 and require each screen’s final pathname and primary heading to match its manager route | canonical/ORA path-heading regressions + MaggieDash `npm test` + AI-CMO browser-evidence tests + ORA contract/build + mirror parity + task-board validation | passed |
159
+ | BK-122 | Test browser capture readiness without requiring a live host | both | BK-121 | Extract and package the pure pathname/readiness helper; cover successful and rejected capture states deterministically | helper condition regressions + MaggieDash `npm test`/manifest + AI-CMO Booking tests + ORA contract/build + mirror parity + task-board validation | passed |
160
+ | BK-123 | Keep Booking inventory and release status docs aligned with contracts | ai-cmo-skills | BK-122 | Align public inventory/current-state docs with v2 routes and latest Stripe/staging evidence; test task counts against the board | docs inventory/status regression + AI-CMO Booking tests + task-board validation + ORA doc checks | passed |
161
+ | BK-124 | Honor scheduled location closures in customer availability | both | BK-052, BK-123 | Load location closure intervals into the shared planner and reject overlapping public slots and holds while preserving exact boundaries | pure planner + PostgreSQL customer-adapter closure regressions + ORA contract/build + task-board validation | passed |
162
+ | BK-125 | Apply dated staff shifts to customer availability | both | BK-052, BK-124 | Load date-scoped shifts and constrain assigned staff to shifts plus recurring venue/staff hours, preserving fallback on dates without shifts | pure planner + PostgreSQL customer-adapter shift regressions + ORA contract/build + task-board validation | passed |
163
+ | BK-126 | Enforce configured availability on manager-created bookings | both | BK-042, BK-052, BK-125 | Apply the shared venue/staff/resource planner to direct manager creation and waitlist conversion; keep active manager-only services bookable; reject schedule-ineligible explicit assignments before booking/queue writes | Canonical and ORA repository regressions + fresh local-source install projection + customer/availability validators + ORA contract/build + docs/board validation | passed |
164
+ | BK-127 | Enforce configured availability on booking reschedules | both | BK-052, BK-125, BK-126 | Apply the shared planner to proposed manager/customer reschedules while excluding the current booking's old allocations | Canonical and ORA repository regressions + fresh local-source install projection + customer/availability validators + ORA contract/build + docs/board validation | passed |
165
+ | BK-128 | Synchronize expired Stripe Checkout reconciliation across hosts | both | BK-025, BK-030 | Normalize `checkout.session.expired` as a cancelled attempt, cancel its pending booking and release its reserved allocation; sync contract/CLI/host mirrors | Runtime regression + PostgreSQL 16 disposable worker integration + MaggieDash npm test + ORA validators/contract + AI-CMO contract/task validation | passed |
166
+ | BK-129 | Route package purchase reads through the payment repository seam | both | BK-096, BK-097 | Keep the payment-owned manager read on the composed payment repository, outside the core-only transaction callback | service regression + MaggieDash npm test + board validation + `git diff --check` | passed |
167
+ | BK-130 | Persist provider references returned by payment reconciliation | both | BK-025, BK-030 | Save a refreshed provider payment reference during payment-attempt or package-purchase reconciliation, preserving the prior reference when omitted | PostgreSQL payment-adapter regression + MaggieDash npm test + board validation + `git diff --check` | passed |
168
+ | BK-131 | Carry hosted Checkout intent through public booking payments | both | BK-107, BK-130 | Preserve hosted intent from customer checkout through payment adapter and include it in request identity so Stripe creates a Checkout Session | customer/payment adapter regressions + Stripe adapter validator + MaggieDash npm test + board validation + `git diff --check` | passed |
169
+ | BK-132 | Reconcile Stripe Checkout Sessions through the generic adapter | both | BK-128, BK-130, BK-131 | Create bounded-lifetime Checkout Sessions and retrieve `cs_` references through Stripe Checkout, mapping open/paid/expired states and provider references | Stripe adapter regressions + MaggieDash npm test + board validation + Booking Python tests + `git diff --check` | passed |
170
+ | BK-133 | Preserve PaymentIntent references from asynchronous Checkout webhooks | both | BK-130, BK-132 | Normalize `checkout.session.async_payment_succeeded/failed` with the PaymentIntent reference when available, retaining the Session ID only as fallback | canonical/ORA runtime projection regression + disposable PostgreSQL 16 worker persistence integration + MaggieDash npm test + ORA contract check + board validation + Booking Python tests + `git diff --check` | passed |
171
+ | BK-134 | Fulfill captured package purchases after sales are disabled | both | BK-096, BK-097 | Do not gate paid package webhook fulfillment on current sale availability; preserve active checks when starting new purchases | canonical Astro bootstrap + ORA contract regression + builds + board validation + Booking Python tests + `git diff --check` | passed |
172
+ | BK-135 | Retry incomplete package fulfillment on duplicate webhooks | both | BK-134 | Re-run idempotent package settlement when a verified provider event is redelivered; only mark package events processed after fulfillment, and propagate failure so the provider retries | canonical/ORA duplicate retry runtime regression + host contract checks + MaggieDash `npm test` + ORA runtime/contract + board/Python validation + `git diff --check` | passed |
173
+ | BK-136 | Require a validated manage token for closed-gate reschedule availability | both | BK-033, BK-113 | Remove raw query-token gate exemptions; permit closed-gate availability only after host validation of a bearer manage token for a reschedulable booking; keep the token out of the URL | canonical/ORA gate, customer-adapter and UI regressions + MaggieDash `npm test` + ORA `contract:check`, Astro check/build + task-board validation + `git diff --check` | passed |
174
+ | BK-137 | Require validated tokens to render the closed-gate customer page | both | BK-104, BK-136 | Remove the raw query-token page exception; when the public gate is closed, render customer continuations only after validating one unexpired, unrevoked booking payment/manage token or package purchase token | canonical/ORA customer-adapter and route checks + MaggieDash `npm test` and host bootstrap + ORA `contract:check`, Astro check/build + task-board validation + `git diff --check` | passed |
175
+ | BK-138 | Require manage-purpose tokens for customer cancellation and rescheduling | both | BK-060, BK-137 | Require an unexpired, unrevoked manage token scoped to the requested booking before cancel/reschedule mutations and before returning an idempotent replay | canonical/ORA customer-adapter regressions for payment, expired, revoked, wrong-booking and revoked replay denial + MaggieDash `npm test` + ORA `contract:check`, Astro check/build + task-board validation + `git diff --check` | passed |
176
+ | BK-139 | Align the reference customer host with payment/manage token boundaries | MaggieDash | BK-035, BK-138 | Issue separate short-lived payment and 30-day manage tokens; expose manage access only after a valid payment return; validate manage purpose, expiry, revocation, and booking scope before mutation replay | reference-host journey covers token purpose/lifetimes, payment-token and wrong-booking denial, revoked replay denial + MaggieDash `npm test` + task-board validation + `git diff --check` | passed |
177
+ | BK-140 | Fail closed on expired package return tokens in reference hosts | both | BK-035, BK-137 | Reject missing, expired, or malformed-expiry package return tokens before purchase reads/reconciliation, and synchronize canonical/ORA manifest-projected fixture host and validator | canonical and ORA customer-reference-host revoked/expiry regressions + byte parity + MaggieDash `npm test` + ORA `contract:check` + AI-CMO Booking tests + task-board validation + `git diff --check` | passed |
178
+ | BK-141 | Use venue-local time throughout manager booking workflows | both | BK-021, BK-028 | Render appointment instants and interpret manager create, waitlist conversion, reschedule, and dated shift/time-off/closure datetime-local fields in each selected location timezone; reject DST gaps, expose fold choices, disable nonexistent calendar slots, and order dated schedule intervals by UTC instant | Venue-time conversion and schedule UI regressions + MaggieDash `npm test` + ORA Booking UI/contract/build + Booking Python tests + board validation + source parity + `git diff --check` | passed |
@@ -0,0 +1,47 @@
1
+ # Gift voucher lifecycle
2
+
3
+ **Status:** contract only — MaggieDash ships no voucher runtime in this release.
4
+ **Contract:** `contracts/maggiedash/booking-voucher-lifecycle-v1.json`
5
+ **Validator:** `maggie booking voucher-contract [--ledger FIXTURE]`
6
+
7
+ Stripe has no native gift-card resource (see
8
+ [Stripe integration](./STRIPE-INTEGRATION.md#gift-cards-credits-and-referrals)).
9
+ A host that sells vouchers therefore owns a local, append-only ledger, and a
10
+ Stripe payment only *funds* an online voucher. This contract fixes the
11
+ provider-neutral lifecycle so every host implements the same rules instead of
12
+ designing them from scratch.
13
+
14
+ ## Lifecycle
15
+
16
+ | Concern | Rule |
17
+ |---|---|
18
+ | Sale online | Checkout/PaymentIntent funds the voucher; it stays `pending_payment` until the verified payment webhook, then the `issue` entry records `paymentRef`. |
19
+ | Sale in shop (till) | Staff with `vouchers.sell` record the in-shop payment method (`cash`, `card-terminal`, `external`); the voucher is active immediately. |
20
+ | Code format | Online: `PREFIX-XXXX-XXXX-XXXX` from an unambiguous alphabet, last segment a truncated HMAC under a server-only secret, checked in constant time before any lookup. Till: prefix + digits with a Luhn check digit. Store only `codeHash` and `codeLast4`; the full code appears only in the delivery email. |
21
+ | Partial redemption | Any positive amount up to the remaining balance; the remainder stays redeemable. |
22
+ | Undo | `undo_redeem` reverses one earlier `redeem` by id, same amount, at most once, never after void. |
23
+ | Void | Requires a reason; blocks every later redemption, undo, and refund. |
24
+ | Expiry | No redemption at or after `expiresAt`; an `expire` entry records the unused balance. The expiry policy is declared by the host for its jurisdiction. |
25
+ | Refund | Capped by the remaining balance and by the funded amount minus earlier refunds. Online refunds reference the original provider payment (a Stripe Refund); till refunds record `refundMethod`. A full refund before any redemption moves the voucher to `refunded`. |
26
+ | Emails | `voucher.purchase.confirmed` (buyer), `voucher.delivered` (recipient), `voucher.redeemed`, `voucher.refunded`, `voucher.expiry_reminder`, delivered through the host outbox. |
27
+ | Merchant ledger | Append-only `issue`, `redeem`, `undo_redeem`, `void`, `expire`, `refund` entries with actor, timestamp, and idempotency key; every mutation is audited and tenant-scoped. |
28
+
29
+ States: `pending_payment`, `active`, `exhausted`, `expired`, `voided`,
30
+ `refunded`. Money is integer minor units, one currency per voucher.
31
+
32
+ ## Proving a host implementation
33
+
34
+ Export a sanitized `maggiedash-booking-voucher-ledger.v1` fixture (no full
35
+ codes, secrets, or customer PII) and replay it:
36
+
37
+ ```bash
38
+ maggie booking voucher-contract
39
+ maggie booking voucher-contract --ledger path/to/voucher-ledger.json
40
+ ```
41
+
42
+ The replay rejects a negative balance, over-redemption, redemption after void
43
+ or expiry or before payment, a second undo of the same redemption, refunds
44
+ above the balance or funded amount, online refunds without a payment
45
+ reference, and declared `status`/`balance` values that disagree with the
46
+ ledger. `fixtures/maggiedash/booking-voucher-ledger.v1.json` in the source
47
+ repository is a passing example.
@@ -150,6 +150,39 @@ image-processing contract: optimisation may use Cloudflare Images
150
150
  transformations, Astro build tooling or a provider-specific implementation
151
151
  behind the same interface.
152
152
 
153
+ ## OAuth connections
154
+
155
+ A provider connection is only as reliable as its weakest connect path:
156
+
157
+ - Each adapter declares one canonical OAuth scope set. Every client that
158
+ starts the flow (dashboard, mobile app, CLI) requests exactly that set.
159
+ LinkedIn invalidates a member's earlier tokens when a later sign-in asks for
160
+ a different scope set, so a mobile app that omits `email` silently revokes
161
+ the dashboard's token while the database still says `active`.
162
+ - Prefer one OAuth client per product. When a client ID is shared with other
163
+ products or callbacks, record it as `client_shared_with`; their sign-ins can
164
+ revoke this product's tokens unless they use the identical scope set.
165
+ - Treat stored connection status as a cache. A token that the provider has
166
+ revoked, or that the serving host cannot decrypt, is `needs_reconnect`
167
+ before anything is scheduled on it — not when a post fails.
168
+ - Provider media URLs (for example `media.licdn.com` with an `e=` expiry) are
169
+ signed and expire. Cache the bytes in owned storage or refresh on readback.
170
+
171
+ `maggie tool maggie_social_share.py adapters` and `connections` check these
172
+ rules from a redacted JSON manifest; see the Social Share skill for shapes.
173
+
174
+ ## Structured model output
175
+
176
+ Keep structured-output schemas small. Gemini rejected a JSON schema whose enum
177
+ had 125 values with `400 INVALID_ARGUMENT`, and the caller silently fell back
178
+ for every request. For a large vocabulary (styles, categories, catalogue IDs):
179
+
180
+ 1. ask for a free string (optionally with a short list of examples in the
181
+ prompt) instead of a large `enum`;
182
+ 2. validate the returned value server-side against the authoritative list;
183
+ 3. treat a schema rejection or an unknown value as a visible, counted failure —
184
+ never a silent fallback to a default.
185
+
153
186
  ## Adding a provider
154
187
 
155
188
  1. Implement the relevant interface in `src/lib/providers/`.
@@ -373,6 +373,14 @@ node scripts/maggie-booking-schema.mjs --apply --confirm
373
373
  node scripts/maggie-booking-worker.mjs --write --confirm
374
374
  ```
375
375
 
376
+ Before switching Stripe to live mode, follow the read-only live setup runbook
377
+ in `docs/maggiedash-booking/STRIPE-INTEGRATION.md`: verify with list/retrieve
378
+ calls only, never use a create call as a probe, have the owner install
379
+ webhook and event-destination signing secrets with a no-echo command, and hand
380
+ Dashboard-only steps to the owner. Gift vouchers follow the host-owned
381
+ `booking-voucher-lifecycle-v1.json` contract; validate a host ledger with
382
+ `maggie booking voucher-contract --ledger FIXTURE`.
383
+
376
384
  The dry-run executes the complete additive migration in a transaction and
377
385
  rolls it back, which verifies PostgreSQL permissions without changing data.
378
386
  The apply command commits the migration as one transaction.