@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
@@ -2,7 +2,7 @@
2
2
  name: maggie-feedback
3
3
  description: Collect, review, and explicitly submit privacy-safe feedback about a Maggie skill run, workflow result, bug, or feature request.
4
4
  metadata:
5
- version: 1.1.0
5
+ version: 1.2.0
6
6
  ---
7
7
 
8
8
  # Maggie Feedback
@@ -70,6 +70,15 @@ with one shared correlation ID instead of losing their relationship:
70
70
 
71
71
  maggie feedback batch --project . --batch-file ./feedback-batch.json
72
72
 
73
+ For long cross-feature reviews, prefer the batch file over repeated `collect`
74
+ calls: JSON strings carry multiline text, backticks, and command names without
75
+ shell escaping. `--batch-file -` reads the same JSON from stdin, so a quoted
76
+ heredoc (`<<'EOF'`) never interpolates command substitutions:
77
+
78
+ maggie feedback batch --project . --batch-file - <<'EOF'
79
+ {"batchId": "review-2026-10", "skill": "maggie-deployment", "items": [...]}
80
+ EOF
81
+
73
82
  The batch file contains 1–50 items and may provide shared `skill`, `runId`,
74
83
  `phase`, `priority`, and `affectedCli` values. An item can override those
75
84
  fields and supplies the normal `type`, `summary`, `expected`, `actual`,
@@ -118,6 +127,63 @@ Example:
118
127
  ]
119
128
  }
120
129
 
130
+ ## Feedback types
131
+
132
+ - `bug`: the skill or CLI did something wrong.
133
+ - `quality`: the result works but falls short (unclear output, weak defaults).
134
+ - `feature`: a missing capability.
135
+ - `improvement`: a concrete proposal to change an existing skill or CLI
136
+ (a new flag, a better default, a guidance section).
137
+ - `general`: anything else.
138
+
139
+ The hosted endpoint accepts `bug`, `feature`, `quality`, and `general`. An
140
+ `improvement` draft keeps its type locally and is submitted as `feature` with
141
+ `subtype: "improvement"`, so maintainers can still filter it.
142
+
143
+ ## Draft a batch from a working session
144
+
145
+ After a long session, draft batch items from the commits made since a known
146
+ point instead of writing them by hand:
147
+
148
+ ```bash
149
+ maggie feedback session-summary --project . \
150
+ --repo . --since v1.4.0 \
151
+ --batch-id social-session-2026-10 --skill maggie-social-share
152
+ ```
153
+
154
+ The helper reads commit subjects only (no diffs, paths, or file contents) and
155
+ redacts secrets and local paths. `fix:` commits become fixed `bug` items with a
156
+ `commit:<sha>` evidence reference; `feat:`, `perf:` and `refactor:` commits
157
+ become `improvement` candidates; other commits are skipped and counted. It also
158
+ adds one placeholder for an open ask. It writes a draft batch file under
159
+ `.maggie/feedback/batches/` and does not create or submit feedback.
160
+
161
+ Review the file: delete items that concern the project rather than a Maggie
162
+ skill or CLI, and replace every `REVIEW:` field (expected, actual, validation).
163
+ `maggie feedback batch` rejects a file that still contains `REVIEW:`
164
+ placeholders. Then continue with `batch`, `batch-review`, and explicit
165
+ `submit` as usual.
166
+
167
+ ## Check release and rollout claims before reporting "fixed"
168
+
169
+ A fixed report is only as good as the release state it points to. Two
170
+ read-only checks catch the drift that previous reports had to find by hand:
171
+
172
+ python3 scripts/validate_docs_freshness.py --release-metadata
173
+ maggie docs rollout-status --project .
174
+
175
+ The first (Maggie source repository) fails when `VERSION`, the CLI package
176
+ version, the newest `CHANGELOG.md` heading, and the README current-version text
177
+ disagree, so a published version cannot ship without its release notes. The
178
+ second scans `docs/` for rollout item IDs (default pattern `ABC-12`, override
179
+ with `--id-pattern`) and fails when one document says an item is complete while
180
+ another says it is pending or in progress. When `docs/rollout-status.json`
181
+ (`maggie-rollout-status.v1`: `items[]` with `id`, `status` of `planned`,
182
+ `in_progress`, `blocked`, or `complete`, and `evidence` for complete items)
183
+ exists, it is canonical and every document must agree with it. Mark superseded
184
+ documents with `<!-- documentation-status: historical-snapshot -->` instead of
185
+ leaving contradictory claims current.
186
+
121
187
  ## Submit explicitly
122
188
 
123
189
  The CLI never submits automatically. After reviewing the draft:
@@ -52,6 +52,18 @@ maggie tool maggie_marketplace.py apply \
52
52
  --id medical-spa-landing-30 --project /path/to/astro-project
53
53
  ```
54
54
 
55
+ Package-quality commands (read-only unless `--write`/`--record`/`--approve`):
56
+
57
+ ```bash
58
+ maggie tool maggie_marketplace.py audit-package <id> # all package-quality gates, JSON report
59
+ maggie tool maggie_marketplace.py measure-design <id> --write # palette roles + fonts from homepage CSS
60
+ maggie tool maggie_marketplace.py repair-assets <id> --write # list unlisted assets honestly; add file extensions
61
+ maggie tool maggie_marketplace.py identity <id> --display-name "Olive Atelier" \
62
+ --display-description "A light editorial beauty homepage with olive accents."
63
+ maggie tool maggie_marketplace.py image-plan <id> --unit-cost 0.04 --currency USD
64
+ maggie tool maggie_marketplace.py image-review <id> [--approve --reviewer NAME | --flag assets/x.png]
65
+ ```
66
+
55
67
  The native installer exposes the same operation as
56
68
  `maggie marketplace add <template-url> clone <preview-url> --rename <id>`.
57
69
 
@@ -95,6 +107,55 @@ validator before it is reported complete. If the validator has changed or the
95
107
  artifact drifted, the job becomes `STALE` and must be resumed or rebuilt; do
96
108
  not treat an old readiness flag as proof of current validity.
97
109
 
110
+ ## Package quality gates
111
+
112
+ `validate` and the completion checkpoint include five package-quality gates.
113
+ `audit-package` runs only these, without the mutating cleanup that `validate`
114
+ performs, so it is safe on any checkout.
115
+
116
+ 1. **Screenshots decode and fit a pixel budget.** Every file in
117
+ `screenshots/` must fully decode (PNG chunk CRCs and inflated size, JPEG
118
+ frame/end markers, WebP header; Pillow is used too when installed). A
119
+ corrupt capture shows as glitch noise and is reported as
120
+ `recapture-required`; recapture it with `maggie_clone_to_template.py
121
+ review` — never hand-edit or keep it. The budget is 40 MP per image and
122
+ 16383 px per edge, well under sharp's default `limitInputPixels`
123
+ (268,402,689 px) and Pillow's decompression-bomb guard, so consumers never
124
+ need to disable those limits. Ship full-page captures as tiles no taller
125
+ than 4096 px (`desktop-full-01.png`, `desktop-full-02.png`, …) or as a
126
+ compressed WebP preview; keep `desktop.png`/`tablet.png`/`mobile.png` at
127
+ viewport height. `audit-package --record` stores the per-file result in
128
+ `template.json` `screenshotReview`.
129
+ 2. **`DESIGN.md` palette is measured, not inherited.** The palette and fonts
130
+ come from the template's own CSS: Tailwind config colours and fonts,
131
+ arbitrary utilities (`bg-[#…]`), the Tailwind neutral scales, body rules,
132
+ inline and stylesheet declarations, and Google Fonts links.
133
+ `measure-design --write` rewrites the `### Reference palette` and
134
+ typography lines, stores `designTokens` (the nine
135
+ `maggie-palette-roles-v1` roles plus fonts and missing font links) in
136
+ `template.json`, and fills empty `styleTags` with measured tags
137
+ (`light-canvas`, `serif-display`, `warm-neutral`, …). Every declared colour
138
+ must exist in the page CSS and Background/Text primary must match the
139
+ measured canvas/text; derived contrast-safe roles are labelled `derived`.
140
+ Check the result against the screenshots before overriding anything.
141
+ 3. **Every asset has provenance.** Every image under `assets/` must be listed
142
+ in `generated-asset-manifest.json` with a provider and role. Captured
143
+ source images are listed as `provider: captured-source`, `reuse: false`,
144
+ `replacementRequired: true`; files without a generation record are
145
+ `provider: unrecorded`, `reuse: false`, `provenanceReview: required`. Both
146
+ block publishing. Files without an extension are rejected;
147
+ `repair-assets --write` sniffs the type, renames the file, and rewrites
148
+ `homepage.html` and `image-inventory.json`.
149
+ 4. **Neutral display identity.** `template.json` carries a customer-facing
150
+ `displayName` and `displayDescription` that are separate from the ID,
151
+ `name`, and `sourceMetadata`. The name must not repeat a distinctive word
152
+ from the source title, must not be a counter such as `Beauty Studio 20
153
+ 001`, and must be unique in the catalogue. Completion derives one from the
154
+ measured design (accent hue, display typeface, industry) when none is
155
+ given; prefer a reviewed, designed name. `list`, `suggest`, and the catalogue
156
+ show `displayName`; source titles never appear in customer-facing pickers.
157
+ 5. **Generated images pass a no-text review.** See step 4 below.
158
+
98
159
  Each import also creates `tasks.json`. It is the workflow ledger: it stores
99
160
  source/output inventories for logos, icons, images, headings, links, buttons,
100
161
  visible copy, and Tailwind, plus evidence and status for source analysis,
@@ -222,6 +283,32 @@ role, provider, date, and prompt in `generated-asset-manifest.json`. Validate
222
283
  that every PNG/JPEG decodes. Never apply text replacement tools to binary
223
284
  assets.
224
285
 
286
+ Report cost before and after every generation run, and review every output
287
+ for text. A "no text, no labels" prompt is not a guarantee: product bottles,
288
+ signage, and packaging routinely come back with readable words.
289
+
290
+ ```bash
291
+ # before generating: planned image count and estimated cost
292
+ maggie tool maggie_marketplace.py image-plan <id> --unit-cost <price-per-image> --currency USD
293
+ # after generating: actual count/cost, contact sheet, and text review
294
+ maggie tool maggie_marketplace.py image-review <id>
295
+ # a person checked image-review/contact-sheet.html and found no text
296
+ maggie tool maggie_marketplace.py image-review <id> --approve --reviewer <name>
297
+ # or record a failure, regenerate that asset, and review again
298
+ maggie tool maggie_marketplace.py image-review <id> --flag assets/maggie-hero.png
299
+ ```
300
+
301
+ `image-plan` counts inventory occurrences marked `needs-generation`, pending
302
+ roles, and captured-source assets awaiting replacement. Take the unit cost from
303
+ the provider's current price list; when omitted, the estimate is recorded as
304
+ unknown rather than guessed. `image-review` writes the post-run count and cost,
305
+ `image-review/contact-sheet.html`, and a per-image `textReview` in
306
+ `image-generation-report.json`. When `tesseract` is installed, OCR flags any
307
+ image with readable words; otherwise the review stays `pending-human-review`
308
+ until `--approve`. Completion and `validate` block until the review is
309
+ `passed` and covers every generated asset. These commands make no model or
310
+ paid API calls themselves.
311
+
225
312
  Before generating anything, create `image-inventory.json` from the final
226
313
  section structure. Include one record for every logo and image occurrence:
227
314
  `id`, source occurrence/line, semantic role, composition, dimensions/aspect
@@ -315,6 +402,10 @@ image references. It also verifies the generated asset roles used by the
315
402
  sample. A mismatch blocks `apply` and publish until the template is repaired
316
403
  or an explicitly approved `--sample` contract is selected.
317
404
 
405
+ The validator also runs the package quality gates above (screenshot
406
+ integrity and budget, measured palette, asset provenance, neutral display
407
+ identity, generated-image text review).
408
+
318
409
  Also parse all JSON and JSON-LD, require exactly one canonical, verify `en-GB`,
319
410
  decode every local image, scan for source brand/person/place/phone/social URL
320
411
  remnants, confirm no Iconify/platform runtime remains, and inspect desktop,
@@ -96,10 +96,47 @@ prints these safe identifiers and scopes before any separate provider adapter
96
96
  is allowed to perform a write. A v1 report is rejected because it cannot prove
97
97
  that the browser/session is on the intended Google account and property.
98
98
 
99
+ When a check fails, add an optional `failure` (`code`, `reason`, `httpStatus`;
100
+ never a token or payload) to the row. The validator maps it to one failed
101
+ prerequisite and one safe next action under `remediation`. For a single error,
102
+ `maggie ops google-diagnose --code SERVICE_DISABLED --http-status 403` prints the
103
+ same mapping.
104
+
105
+ For Google Ads, run the read-only adapter before any keyword research:
106
+
107
+ ```bash
108
+ maggie ops google-ads-preflight --customer-id 123-456-7890 \
109
+ [--login-customer-id 999-888-7777] [--probe-keyword-planner]
110
+ maggie ops google-ads-keyword-ideas --customer-id 123-456-7890 \
111
+ --keyword "day spa" --language 1000 --geo-target 2826 --currency GBP
112
+ ```
113
+
114
+ Credentials come from `GOOGLE_ADS_ACCESS_TOKEN` and
115
+ `GOOGLE_ADS_DEVELOPER_TOKEN` (names overridable); values are never printed.
116
+ The adapter only allows `listAccessibleCustomers`, `googleAds:search`, and
117
+ `generateKeywordIdeas`, so it cannot mutate Ads state.
118
+
99
119
  The result separates `read`, `report`, `edit`, and `publish` for each
100
120
  provider/resource. Write and publish remain `not_tested` until the operator
101
121
  explicitly confirms the exact mutation and a successful read-back is captured.
102
122
 
123
+ ## Website notifications
124
+
125
+ For website email, in-app, and SMS operations, follow
126
+ [Website notification operations](references/notifications-operations.md):
127
+ a catalogue with consent, retention, and delivery rules, template drift
128
+ against a paginated provider export, a Resend preflight by variable name
129
+ only, aggregate queue health with operator alerts, and a dry-run retention
130
+ plan. All `maggie ops notifications` commands are offline and read-only, and
131
+ none of them sends a message.
132
+
133
+ ```bash
134
+ maggie ops notifications catalogue validate --project . --catalogue docs/notifications/catalogue.json
135
+ maggie ops notifications templates drift --project . --catalogue docs/notifications/catalogue.json --local src/emails --provider-export exports/page-1.json
136
+ maggie ops notifications preflight --project . --env-file .env.production --catalogue docs/notifications/catalogue.json
137
+ maggie ops notifications health --project . --snapshot .maggie/notifications-health.json
138
+ ```
139
+
103
140
  ## Required preflight
104
141
 
105
142
  1. Inspect `.maggie/analysis.json` and `.maggie/bootstrap-state.json`.
@@ -0,0 +1,154 @@
1
+ # Website notification operations
2
+
3
+ A provider-neutral operating contract for website email, in-app, and SMS
4
+ notifications: what each message is, which consent it needs, how templates
5
+ stay in sync with the provider, how delivery is kept durable, how the queue is
6
+ watched, and how notification data expires. Every command below is offline and
7
+ read-only. None of them call a provider API, send a message, or print secret
8
+ values or recipient addresses.
9
+
10
+ ## 1. Catalogue every message
11
+
12
+ Keep one machine-readable catalogue in the project (for example
13
+ `docs/notifications/catalogue.json`) using
14
+ `contracts/maggie-ops/notification-catalogue-v1.schema.json`. The packaged
15
+ example `contracts/maggie-ops/notification-catalogue-example-v1.json` covers the
16
+ seven sections a website normally needs:
17
+
18
+ | Section | Typical entries |
19
+ |---|---|
20
+ | `identity-security` | email verification, password reset (often provider-owned), sign-in alert, credential/2FA/passkey change, account deletion |
21
+ | `account` | welcome, onboarding reminder, preference update, saved-item digest |
22
+ | `business` | listing/claim status, verification, team invite/approval, import or sync result, publish/domain readiness |
23
+ | `billing` | checkout/subscription active, payment failed, receipt (often provider-owned), plan change, cancellation, trial ending |
24
+ | `support` | contact/waitlist receipt, team copy of a contact, case reply/closure, feedback request |
25
+ | `marketing` | opt-in confirmation, newsletter welcome, content digest, recommendation, gift/voucher interest follow-up, merchant lead digest, re-engagement |
26
+ | `deliverability-ops` | bounce/complaint, suppression, worker failure, dead-letter growth, template drift, sender-domain health, queue health |
27
+
28
+ Each entry records trigger, audience, category (`transactional`, `support`,
29
+ `marketing`), consent boundary, locales and markets, variables, CTA route,
30
+ idempotency-key template, retention days, provider, channels, delivery mode
31
+ (`outbox`, `direct`, `provider`), queue, and status (`implemented`,
32
+ `provider-owned`, `reserved`, `missing`). The status column turns the
33
+ catalogue into a planning asset: `missing` lists what the site still lacks.
34
+
35
+ ```bash
36
+ maggie ops notifications catalogue validate --project . --catalogue docs/notifications/catalogue.json
37
+ ```
38
+
39
+ The validator enforces the cross-field rules a schema cannot:
40
+
41
+ - Marketing messages require `consent: opt-in-required`, `unsubscribe: true`
42
+ (preference-centre and unsubscribe links), and the `marketing` queue.
43
+ - `deliverability-ops` alerts use the `operations` queue. An alert about a
44
+ failing provider or queue must not travel through that same queue.
45
+ - External-recipient lead email (`lead: true`: contact, waitlist, gift or
46
+ voucher interest) must use durable `outbox` delivery. A direct send that
47
+ only logs a failure can silently lose a business lead.
48
+ - CTA routes are site paths or `https://` URLs with a fixed host.
49
+
50
+ ## 2. Durable delivery for lead email
51
+
52
+ Contact, waitlist, and interest messages are acquisition signals. Route them
53
+ through the same outbox as transactional mail: an idempotency key per
54
+ submission, lease-based claiming, bounded retries, a dead-letter state with
55
+ recorded-reason replay, and provider webhook reconciliation. The visitor's
56
+ request succeeds once the outbox row is committed; delivery failure is an
57
+ operations alert, not a visitor-facing error.
58
+
59
+ ## 3. Template lifecycle and drift
60
+
61
+ Template work moves through these stages, each producing reviewable evidence:
62
+
63
+ 1. **Discover/scaffold**: derive the template matrix (alias × locale) from the
64
+ catalogue's `implemented` email entries.
65
+ 2. **Preview**: render HTML and plain text from fixtures only, never live
66
+ customer data.
67
+ 3. **Lint**: every placeholder is a declared variable; CTA routes resolve.
68
+ 4. **Localize**: every catalogue locale exists in HTML and plain text, with
69
+ the same variables (see `maggie-content-localization`).
70
+ 5. **Approve**: record who approved which template version.
71
+ 6. **Sync dry run**: compute the provider diff without writing.
72
+ 7. **Publish**: apply the reviewed diff with an explicit confirmation.
73
+ 8. **Rollback**: keep the previous provider version ID to restore.
74
+ 9. **Verify**: re-run drift; any real send uses a provider test mode or an
75
+ allow-listed internal recipient, behind an explicit confirmation.
76
+
77
+ Before every deploy, compare the catalogue, local templates, and a provider
78
+ export. Export **every** page of the provider's template list to JSON first
79
+ (list endpoints paginate; a single call with a page limit can miss templates):
80
+
81
+ ```bash
82
+ maggie ops notifications templates drift --project . \
83
+ --catalogue docs/notifications/catalogue.json \
84
+ --local src/emails/templates \
85
+ --provider-export exports/templates-page-1.json \
86
+ --provider-export exports/templates-page-2.json
87
+ ```
88
+
89
+ `--local` accepts a directory of `<alias>.<locale>.<ext>` files (placeholders
90
+ `{{ name }}` are extracted) or a `maggie-notification-templates.v1` manifest.
91
+ The report lists missing local/provider templates, extra provider or local
92
+ aliases, locale gaps, undeclared or unused variables, and local/provider
93
+ version drift. It exits non-zero on drift, and when the last export page still
94
+ reports `has_more: true`. A runtime fallback to locally rendered email protects
95
+ delivery but hides drift, so treat drift as a deploy blocker.
96
+
97
+ ## 4. Provider preflight (Resend)
98
+
99
+ ```bash
100
+ maggie ops notifications preflight --project . --env-file .env.production \
101
+ --catalogue docs/notifications/catalogue.json
102
+ ```
103
+
104
+ Checks, by variable name only: API key, sender (`RESEND_EMAIL`, `RESEND_FROM`,
105
+ or `RESEND_SENDER`), worker secret, support recipients, webhook secret, and
106
+ the template map. Template IDs are not printed. Only the map's alias keys are
107
+ compared with implemented Resend catalogue entries. Add project-specific names
108
+ with `--require NAME`. Presence is not proof of delivery: after deploy, the
109
+ release still needs sender-domain verification, webhook reachability, timer
110
+ health, and an authenticated synthetic delivery recorded as redacted evidence.
111
+
112
+ ## 5. Queue health and alerts
113
+
114
+ Have the host worker or a read-only SQL job write an aggregate snapshot
115
+ (`maggie-notification-queue-snapshot.v1`) with counts (`pending`,
116
+ `processing`, `deadLetter`, `awaitingWebhook`), `oldestPendingAt`,
117
+ `expiredLeases`, `lastWebhookAt`, `lastSuccessfulRunAt`, optional `rates`
118
+ (`bounce`, `complaint`), and `senderDomainVerified`. Snapshots must not contain
119
+ addresses; the check rejects them if they do.
120
+
121
+ ```bash
122
+ maggie ops notifications health --project . --snapshot .maggie/notifications-health.json \
123
+ --max-oldest-pending-minutes 30 --max-dead-letter 0
124
+ maggie ops notifications alerts
125
+ ```
126
+
127
+ `health` exits non-zero when any threshold is exceeded, so it can run from a
128
+ systemd timer or CI after the worker. A timer can be active while the worker
129
+ never succeeds, so `lastSuccessfulRunAt` is required. `alerts` prints the
130
+ operator alert templates (severity, owner, recovery action, escalation). Send
131
+ alerts through an operations channel that is independent of the notification
132
+ queue and provider being monitored.
133
+
134
+ ## 6. Privacy, retention, and suppression
135
+
136
+ The catalogue's `retention` block sets days for `webhook-payload`,
137
+ `delivery-record`, `rendered-snapshot`, and `template-variables`. Store
138
+ minimized webhook fields (event type, provider message ID, status, time), not
139
+ the full raw payload. Keep suppression entries as a hashed address with
140
+ reason and time. Recovery from suppression (for example, a fixed mailbox)
141
+ needs an explicit operator action with a recorded reason.
142
+
143
+ Plan purges from aggregate counts only:
144
+
145
+ ```bash
146
+ maggie ops notifications retention plan --project . \
147
+ --catalogue docs/notifications/catalogue.json \
148
+ --inventory .maggie/notifications-inventory.json
149
+ ```
150
+
151
+ The plan is always a dry run. Rows tied to an open support case or legal hold
152
+ are reported as held. Apply purges through the host's reviewed job or
153
+ migration, and handle account deletion by purging that user's delivery
154
+ records and snapshots and keeping only the hashed suppression entry.
@@ -2,7 +2,7 @@
2
2
  name: maggie-qa-workflow
3
3
  description: Run scenario-based browser QA with explicit evidence, fix/retest lifecycle, and release-gate decisions for web projects.
4
4
  metadata:
5
- version: 1.2.0
5
+ version: 1.3.0
6
6
  ---
7
7
 
8
8
  # Maggie QA Workflow
@@ -74,6 +74,46 @@ the host browser adapter. The adapter owns console, network, authentication,
74
74
  URL, viewport, and screenshot capture; this skill stores only a relative path,
75
75
  URL reference, and hash when a local file exists.
76
76
 
77
+ ## Protect production data
78
+
79
+ Declare which API the build under test talks to, and mark scenarios that
80
+ write data with `"mutates": true` in the scenario manifest:
81
+
82
+ ```bash
83
+ maggie qa start --project . --run-id local-qa-002 \
84
+ --environment local --base-url http://localhost:4321 \
85
+ --api-base https://api.example.com \
86
+ --production-api https://api.example.com
87
+ ```
88
+
89
+ When the API base is a production API, mutating scenarios start as `blocked`
90
+ and `record` refuses a pass or fail result for them. Run those scenarios
91
+ against a non-production API, or start a run with `--allow-production-writes`
92
+ only after the user explicitly consents and a restore path exists. Overriding
93
+ `window.fetch` from the page does not stop a bundled API client from sending
94
+ requests; use network-layer interception as described in the
95
+ [browser inspection contract](../../references/browser-inspection.md).
96
+
97
+ ## Check CORS for every method the client uses
98
+
99
+ Before a release that adds or changes API calls from a browser or webview,
100
+ preflight every HTTP method the client sends through the public edge, not only
101
+ the origin server:
102
+
103
+ ```bash
104
+ maggie qa cors-preflight --project . \
105
+ --url https://api.example.com/v1/setup \
106
+ --origin https://app.example.com \
107
+ --method GET,POST,PUT,PATCH,DELETE \
108
+ --request-header content-type,authorization \
109
+ --output .maggie/qa-runs/cors-preflight.json
110
+ ```
111
+
112
+ The command sends only `OPTIONS` requests and fails when a method, origin, or
113
+ request header is not allowed. A method missing from the edge allow-list
114
+ fails in the browser with a generic network error (Safari: "Load failed") and
115
+ leaves no request in server logs, so it is easy to misdiagnose.
116
+
77
117
  ## Assert the requirement at runtime
78
118
 
79
119
  Do not use a source class, edited markup fragment, or implementation detail as
@@ -231,6 +231,65 @@ The contract is documented in
231
231
  It is provider-neutral and does not accept credentials, provider response
232
232
  bodies, or arbitrary filesystem paths in the poll reference.
233
233
 
234
+ ### Long-running import stages, readiness, and fact provenance
235
+
236
+ Inside the `import` workflow, a provider import runs four stages: `source`,
237
+ then `enrichment` and `research` in parallel, then `verification`. Validate a
238
+ redacted snapshot with:
239
+
240
+ ```bash
241
+ maggie service import-stages-validate --project . \
242
+ --manifest .maggie/booking/import-stages.json --output docs/import-stages.json
243
+ ```
244
+
245
+ The `maggie-service-import-stages.v1` contract
246
+ (`contracts/maggie-service-booking/import-stages-v1.schema.json`) requires a
247
+ stage key per stage prefixed with the import ID and reused on retry, bounded
248
+ attempts, `{done, total}` progress (a succeeded stage is complete), and a
249
+ `heartbeatAt` for running stages. A running stage without a heartbeat for more
250
+ than `staleAfterSeconds` makes the import `stale` with an explicit
251
+ `nextAction`. Parallel stages may complete in any order, but a stage may not
252
+ start before its dependencies finish, and a downstream result built from a
253
+ superseded `source.resultRevision` must be marked `resultDiscarded` instead of
254
+ applied. Cancellation must reach every stage; results completed after
255
+ `cancellation.requestedAt` are discarded. The declared import state must match
256
+ the state derived from its stages (`partial` when retries are exhausted after
257
+ some stages succeeded).
258
+
259
+ Before queuing a long-running provider job, run the worker readiness preflight
260
+ on the worker host. It fails — and the job must not be queued — when a Python
261
+ module is not importable, a browser or matching WebDriver is missing, a crawler
262
+ setting is absent (checked by environment variable name; values are never
263
+ printed), the runtime is not UTF-8, or a country label cannot be normalized to
264
+ ISO 3166 (locale display names and mis-decoded text such as `Königreich` are
265
+ repaired first). A rate-limit probe is a single HEAD request and runs only when
266
+ requested:
267
+
268
+ ```bash
269
+ maggie service import-readiness --project . --python-module selenium \
270
+ --browser --webdriver --env MAPS_CRAWLER_KEY --country "United Kingdom" \
271
+ --output docs/import-readiness.json
272
+ ```
273
+
274
+ Imported business facts keep field-level provenance in
275
+ `maggie-service-fact-provenance.v1`
276
+ (`contracts/maggie-service-booking/fact-provenance-v1.schema.json`). A
277
+ user-entered value is authoritative and always wins; provider values carry a
278
+ source, confidence, and reference. Providers that agree corroborate a value;
279
+ providers that disagree above `minConfidence` produce a `needs-review` conflict
280
+ with the policy's proposed choice (`fieldPrecedence` can, for example, prefer
281
+ the website for `websiteUrl`). A provider error is recorded under
282
+ `unavailableSources` and never blocks other providers or fields:
283
+
284
+ ```bash
285
+ maggie service fact-provenance --project . \
286
+ --facts .maggie/booking/fact-provenance.json --output docs/fact-merge.json
287
+ ```
288
+
289
+ The command exits 1 while conflicts need review; the host review UI reads the
290
+ `maggie-service-fact-merge.v1` artifact and records the reviewer's choice as a
291
+ user-entered value.
292
+
234
293
  `convert-page` imports a normal page as a draft service without inventing
235
294
  booking facts. `match-pages` reads filesystem pages plus `docs/pages.json` and
236
295
  `docs/page-content.json`, writes candidate evidence to both `.maggie/booking`
@@ -427,6 +486,29 @@ FAQ helper from the first category implementation; it is a known gap and must
427
486
  remain marked incomplete until each FAQ record is independently AI-authored and
428
487
  reviewed.
429
488
 
489
+ ## Payments: Stripe live setup and gift vouchers
490
+
491
+ Service pages often lead to first-party payments. When the host takes money
492
+ through MaggieDash Booking (rather than the external provider), follow the
493
+ read-only live setup runbook in `docs/maggiedash-booking/STRIPE-INTEGRATION.md`:
494
+
495
+ - verify live state with list/retrieve (`GET`) calls only; never use a create
496
+ call as a probe — a probe expected to fail can create a real live object;
497
+ - the owner installs webhook and Connect event-destination signing secrets
498
+ with a no-echo command (`read -rs … | <secret store>`); the agent never sees
499
+ them;
500
+ - thin-event destination signing secrets cannot be retrieved via the API;
501
+ roll them in the Dashboard if they were not captured;
502
+ - the Stripe Dashboard may be unusable under browser automation, so hand
503
+ Dashboard-only steps to the owner and confirm them with read-only calls.
504
+
505
+ Gift vouchers (online and at the till, partial redemption, undo, void, expiry,
506
+ refunds, buyer/recipient emails, merchant ledger) follow the host-owned
507
+ `contracts/maggiedash/booking-voucher-lifecycle-v1.json` contract described in
508
+ `docs/maggiedash-booking/VOUCHERS.md`. Do not invent a separate voucher model;
509
+ replay the host's sanitized ledger with
510
+ `maggie booking voucher-contract --ledger FIXTURE`.
511
+
430
512
  ## Gates
431
513
 
432
514
  The workflow stops when any gate fails:
@@ -2,7 +2,7 @@
2
2
  name: maggie-social-share
3
3
  description: Turn approved AI CMO articles and content assets into platform-native social drafts, scheduled posts, and measured distribution. Use for Social Share planning, LinkedIn/Facebook copy, CTA mapping, calendars, approvals, publish retries, or social performance readback.
4
4
  metadata:
5
- version: 1.0.0
5
+ version: 1.1.0
6
6
  ---
7
7
 
8
8
  # Maggie Social Share
@@ -30,6 +30,33 @@ maggie tool maggie_social_share.py validate .maggie/social-share-plan.json
30
30
  The CLI does not generate copy or publish. It validates identity, canonical
31
31
  URL, channel limits, UTM links, approval state, and provider post state.
32
32
 
33
+ Before connecting providers or scheduling, check the adapter, connection,
34
+ campaign, and queue contracts (shapes and rules in
35
+ [queue and connections](references/queue-and-connections.md)):
36
+
37
+ ```bash
38
+ maggie tool maggie_social_share.py adapters .maggie/social-adapters.json
39
+ maggie tool maggie_social_share.py connections .maggie/social-connections.json
40
+ maggie tool maggie_social_share.py campaigns .maggie/social-campaigns.json
41
+ maggie tool maggie_social_share.py queue .maggie/social-queue.json --slots 14
42
+ maggie tool maggie_social_share.py reconcile .maggie/social-attempts.json
43
+ ```
44
+
45
+ A publishing adapter also declares limits, media rules, pending behaviour,
46
+ retry classes (a timeout is an unknown outcome, never retryable), idempotency,
47
+ and readback. `reconcile` turns the attempt log plus provider readback into
48
+ adopt / await / retry-with-the-same-key / fail decisions, so a
49
+ timeout-after-success never creates a duplicate post.
50
+
51
+ When social work is part of a wider campaign, record it in a
52
+ [marketing run](references/marketing-run.md) with named schedule layers
53
+ (infrastructure, content calendar, campaign flight, measurement window) and,
54
+ for regulated content, a review that gates only external publication:
55
+
56
+ ```bash
57
+ maggie tool maggie_marketing_run.py validate .maggie/marketing-runs/<runId>.json
58
+ ```
59
+
33
60
  1. Select an approved or explicitly shareable source article/content asset.
34
61
  2. Read Project Context and the selected social tone/template.
35
62
  3. Extract one clear content atom: insight, statistic, process, story, or
@@ -37,10 +64,14 @@ URL, channel limits, UTM links, approval state, and provider post state.
37
64
  4. Create platform-native variants with the platform's current limits and a
38
65
  clear CTA. Preserve the source canonical URL and apply the configured UTM
39
66
  policy.
40
- 5. Store drafts as calendar items with source ID, platform, version, approval,
41
- scheduled time, and local/remote status.
67
+ 5. Store drafts as queue items with source ID, platform, version, approval,
68
+ optional `not_before`, and local/remote status. Posting hours are slots;
69
+ do not persist a fixed `scheduled_at` per post (it goes stale and strands
70
+ overdue posts). Campaign ideas stay in the idea stage until written, and a
71
+ campaign starts only through the Start gate.
42
72
  6. Publish only after the required approval and entitlement checks. Record the
43
- publication attempt and provider ID; retry only with bounded idempotency.
73
+ publication attempt and provider ID; reconcile unknown outcomes against
74
+ readback and retry only with the original idempotency key.
44
75
  7. Read back clicks, engagement, assisted conversions, and failures separately
45
76
  from article SEO/GEO metrics.
46
77
 
@@ -48,12 +79,30 @@ URL, channel limits, UTM links, approval state, and provider post state.
48
79
 
49
80
  ```text
50
81
  source_content_id, canonical_url, platform, format, hook, body, cta,
51
- hashtags_or_mentions, scheduled_at, approval_state, tracking_url
82
+ hashtags_or_mentions, not_before, queue_position, campaign_id, approval_state,
83
+ tracking_url
52
84
  ```
53
85
 
86
+ `not_before` is optional and only a lower bound; the slot planner assigns the
87
+ actual publish slot.
88
+
54
89
  Start with LinkedIn and Facebook adapters. Add other platforms only when the
55
- adapter can declare limits, auth scope, media requirements, idempotency, and
56
- delete/republish behavior.
90
+ adapter can declare limits, one canonical auth scope set, media requirements,
91
+ idempotency, and delete/republish behavior.
92
+
93
+ ## Connections
94
+
95
+ - Every connect path (dashboard, mobile, CLI) requests the adapter's canonical
96
+ scope set. LinkedIn revokes a member's earlier tokens when a sign-in asks
97
+ for a different set; a shared OAuth client used by other products can do
98
+ the same. `adapters` fails on scope drift and warns on shared clients.
99
+ - A connection whose token the provider revoked, or that a serving host cannot
100
+ decrypt, shows **Reconnect** before anything is scheduled on it. Run the
101
+ decrypt check on every host that serves social routes.
102
+ - Provider avatar URLs are signed and expire; cache the bytes or refresh on
103
+ readback.
104
+ - Keep model structured-output enums small and validate large vocabularies
105
+ server-side; see [provider adapter contract](../../references/provider-adapter-contract.md#structured-model-output).
57
106
 
58
107
  ## Safety and commercial boundary
59
108