@topy-ai/maggie 0.7.47 → 0.7.48

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 (58) hide show
  1. package/README-zh-TW.md +2 -2
  2. package/README.md +49 -15
  3. package/bin/maggie.js +6 -2
  4. package/bundled-contracts/maggie-design/palette-roles-v1.schema.json +47 -0
  5. package/bundled-contracts/maggie-marketplace/template-content-v1.schema.json +103 -0
  6. package/bundled-contracts/maggiedash/booking-browser-evidence-v1.json +21 -0
  7. package/bundled-contracts/maggiedash/booking-browser-evidence-v2.json +191 -0
  8. package/bundled-contracts/maggiedash/booking-email-templates-v1.json +3 -1
  9. package/bundled-contracts/maggiedash/booking-voucher-lifecycle-v1.json +85 -0
  10. package/bundled-contracts/maggiedash/execution-board.json +4629 -1553
  11. package/bundled-contracts/maggiedash/stripe-booking-capabilities-v1.json +1 -0
  12. package/bundled-marketplace/README.md +17 -0
  13. package/bundled-marketplace/catalog.json +56 -7
  14. package/bundled-references/browser-inspection.md +25 -0
  15. package/bundled-references/maggiedash-booking/CURRENT-STATE.md +128 -10
  16. package/bundled-references/maggiedash-booking/EXECUTION-BOARD.json +4629 -1553
  17. package/bundled-references/maggiedash-booking/HOST-ADAPTER.md +5 -0
  18. package/bundled-references/maggiedash-booking/ORAWELLNESS-INTEGRATION-AUDIT.md +64 -21
  19. package/bundled-references/maggiedash-booking/PRD.md +9 -1
  20. package/bundled-references/maggiedash-booking/PROGRESS.md +244 -2399
  21. package/bundled-references/maggiedash-booking/QA-TEST-PLAN.md +37 -6
  22. package/bundled-references/maggiedash-booking/README.md +23 -6
  23. package/bundled-references/maggiedash-booking/RUNTIME-OPERATIONS.md +64 -8
  24. package/bundled-references/maggiedash-booking/SKILLS-AND-CLI.md +11 -2
  25. package/bundled-references/maggiedash-booking/STRIPE-INTEGRATION.md +66 -2
  26. package/bundled-references/maggiedash-booking/TASK-RUNBOOK.md +1 -1
  27. package/bundled-references/maggiedash-booking/TASKS.md +44 -3
  28. package/bundled-references/maggiedash-booking/VOUCHERS.md +47 -0
  29. package/bundled-references/provider-adapter-contract.md +33 -0
  30. package/bundled-skills/maggie-booking/SKILL.md +8 -0
  31. package/bundled-skills/maggie-clone-to-template/SKILL.md +26 -0
  32. package/bundled-skills/maggie-deployment/SKILL.md +53 -1
  33. package/bundled-skills/maggie-deployment/references/vps.md +41 -0
  34. package/bundled-skills/maggie-design/SKILL.md +99 -0
  35. package/bundled-skills/maggie-feedback/SKILL.md +38 -1
  36. package/bundled-skills/maggie-marketplace/SKILL.md +91 -0
  37. package/bundled-skills/maggie-qa-workflow/SKILL.md +41 -1
  38. package/bundled-skills/maggie-service-booking/SKILL.md +23 -0
  39. package/bundled-skills/maggie-social-share/SKILL.md +37 -5
  40. package/bundled-skills/maggie-social-share/references/queue-and-connections.md +101 -0
  41. package/bundled-skills/maggie-template/SKILL.md +57 -3
  42. package/bundled-skills/maggie-template/references/template-content-v1.example.json +34 -0
  43. package/bundled-tools/clis/maggie_booking.py +199 -26
  44. package/bundled-tools/clis/maggie_booking_vouchers.py +185 -0
  45. package/bundled-tools/clis/maggie_clone_to_template.py +14 -0
  46. package/bundled-tools/clis/maggie_deployment.py +249 -1
  47. package/bundled-tools/clis/maggie_design.py +9 -0
  48. package/bundled-tools/clis/maggie_design_lint.py +277 -0
  49. package/bundled-tools/clis/maggie_feedback.py +106 -3
  50. package/bundled-tools/clis/maggie_marketplace.py +199 -5
  51. package/bundled-tools/clis/maggie_palette.py +280 -0
  52. package/bundled-tools/clis/maggie_qa_workflow.py +156 -1
  53. package/bundled-tools/clis/maggie_social_queue.py +338 -0
  54. package/bundled-tools/clis/maggie_social_share.py +42 -9
  55. package/bundled-tools/clis/maggie_template_package.py +1141 -0
  56. package/package.json +1 -1
  57. package/references/browser-inspection.md +25 -0
  58. package/references/provider-adapter-contract.md +33 -0
@@ -67,6 +67,32 @@ then stores the prompt as
67
67
  `CUSTOMIZATION_PROMPT.md` beside the package. It creates a resumable job under
68
68
  `marketplace/.maggie/clone-to-template-jobs/`.
69
69
 
70
+ ### Neutral display identity
71
+
72
+ A package's customer-facing identity is separate from its source evidence.
73
+ `template.json` `name` and `id` are internal; `sourceMetadata` records the
74
+ source title only as provenance. Pass a designed, neutral style name and a short
75
+ description when planning:
76
+
77
+ ```bash
78
+ maggie tool maggie_clone_to_template.py plan <url> "<approved brief>" --rename <template-id> \
79
+ --display-name "Olive Atelier" \
80
+ --display-description "A light editorial beauty homepage with olive accents."
81
+ ```
82
+
83
+ Packaging forwards both to the marketplace importer. Without them, completion
84
+ derives a name from the measured design (accent hue, display typeface,
85
+ industry). The validator rejects a name that repeats a distinctive source-title
86
+ word, looks like a counter (`Beauty Studio 20 001`), or duplicates another
87
+ catalogue entry. Change it later with `maggie_marketplace.py identity <id>
88
+ --display-name …`. Template pickers must show `displayName` and
89
+ `displayDescription`, never the source business name.
90
+
91
+ Packaging also measures `DESIGN.md` from the rendered CSS, records
92
+ `screenshotReview`, and lists every asset with its provenance. Review captures
93
+ stay at viewport height; tile any full-page capture as described in the
94
+ `maggie-marketplace` package quality gates.
95
+
70
96
  If the full clone run fails or cannot reach `verified`, stop and report the
71
97
  clone checkpoint. Do not invoke the marketplace importer as a fallback. If the
72
98
  Maggie design review fails, stop before declaring the template ready.
@@ -2,7 +2,7 @@
2
2
  name: maggie-deployment
3
3
  description: Deploy and operate Maggie blog projects with Cloudflare Workers as the default target, while preserving an adapter boundary for VPS, GCP, and AWS.
4
4
  metadata:
5
- version: 1.4.0
5
+ version: 1.5.0
6
6
  ---
7
7
 
8
8
  # Maggie Deployment
@@ -239,6 +239,58 @@ maggie tool maggie_deployment.py --retention-plan \
239
239
  The CLI never deletes release directories and never permits fewer than two
240
240
  retained releases.
241
241
 
242
+ ### Multi-host secret parity
243
+
244
+ When several hosts serve the same routes, check that each one holds every
245
+ required secret. The check compares key names and SHA-256 fingerprints and
246
+ never prints, stores, or transmits values:
247
+
248
+ ```bash
249
+ # Local env files (one per host):
250
+ maggie deployment secret-parity \
251
+ --host api-1=.secrets/api-1.env --host api-2=.secrets/api-2.env \
252
+ --required SOCIAL_SHARE_ENCRYPTION_KEY
253
+
254
+ # Or fingerprint manifests produced on each host:
255
+ maggie deployment secret-fingerprint --env-file /etc/example.env \
256
+ --host api-1 --output api-1.json
257
+ maggie deployment secret-parity --manifest api-1.json --manifest api-2.json \
258
+ --required SOCIAL_SHARE_ENCRYPTION_KEY
259
+ ```
260
+
261
+ A required key that is missing or differs on any host fails the check. Other
262
+ drifting keys are warnings unless `--strict` is set. A host without Maggie can
263
+ use the no-echo shell snippet in [the VPS reference](references/vps.md); the
264
+ parity command accepts its `KEY <sha256>` output directly. Manifests that
265
+ contain anything other than names and 64-character hex digests are rejected.
266
+
267
+ ### Local and production database isolation
268
+
269
+ ```bash
270
+ maggie deployment env-isolation --project . \
271
+ --production-env .env.production
272
+ # or: --production-db-host db.example.net
273
+ ```
274
+
275
+ The check fails when the local `.env` points at the production database (same
276
+ host, and port/name when known). The same server with a different database is
277
+ a warning. Deployment preflight runs the check automatically, as a non-blocking
278
+ warning, when `.env.production` exists or `MAGGIE_PRODUCTION_DB_HOST` is set.
279
+ Database URLs are reduced to host/port; credentials are never reported.
280
+
281
+ ### Release ordering for workers and notification templates
282
+
283
+ Deploy the worker and its templates before any code path can enqueue an event
284
+ that uses a new template. When local development or a staged app shares a
285
+ queue with production, an event that names a template the running worker does
286
+ not know yet must be held and retried, not dead-lettered: an unknown template
287
+ during a rollout is a release-ordering state, not a permanent failure. Check
288
+ that the outbox worker (MaggieDash Booking or the host's own) does not let
289
+ unknown-template deliveries consume the retry budget, and after the release
290
+ confirm the held deliveries were sent.
291
+ If dead-lettered rows already exist, requeue them only after the worker that
292
+ knows the template is live.
293
+
242
294
  Validate the database release separately before a VPS migration:
243
295
 
244
296
  ```bash
@@ -132,6 +132,47 @@ inspect → plan → backup/migrate → npm ci → npm run build
132
132
  Deploy staging first. A passing build does not prove Nginx, systemd, DNS, TLS,
133
133
  robots, sitemap, or private-route correctness.
134
134
 
135
+ ### Release retention
136
+
137
+ Keep exactly the `current` release plus one previous release as the rollback
138
+ target. Prune after every deploy, and only after the new release passed its
139
+ health checks: an unhealthy release must still have its predecessor on disk.
140
+ The generated release runner does this as its final step; it never removes the
141
+ release `current` points at or the release it replaced. Without pruning,
142
+ `releases/` grows by one full `node_modules` tree per deploy until the disk
143
+ fills. Use `--retention-plan` for a read-only list of prune candidates on hosts
144
+ whose runner predates this step, and review it before deleting anything.
145
+
146
+ ### Multi-host secret parity
147
+
148
+ When more than one host can serve the same routes (failover, load-balanced API
149
+ nodes, workers), every host must hold the same required secrets. A key that
150
+ exists on only one host is invisible until traffic fails over to another and
151
+ returns 5xx. Compare hosts by name and SHA-256 fingerprint, never by value:
152
+
153
+ ```bash
154
+ # On each host (prints names and digests only; values are never echoed):
155
+ for k in SOCIAL_SHARE_ENCRYPTION_KEY DATABASE_URL; do
156
+ v=$(sed -n "s/^$k=//p" /etc/example.env | head -1)
157
+ printf '%s %s\n' "$k" "$(printf %s "$v" | sha256sum | cut -c1-64)"
158
+ done > /tmp/api-1.fingerprints
159
+
160
+ # Locally, after copying each host's fingerprint file:
161
+ maggie deployment secret-parity \
162
+ --manifest api-1.fingerprints --manifest api-2.fingerprints \
163
+ --manifest api-3.fingerprints \
164
+ --required SOCIAL_SHARE_ENCRYPTION_KEY --required DATABASE_URL
165
+ ```
166
+
167
+ Run it after adding a secret and before enabling a host in a pool.
168
+
169
+ ### Environment isolation
170
+
171
+ A local `.env` must never point at the production database. Shared databases
172
+ let local test records (vouchers, palettes, emails) appear on live pages and be
173
+ picked up by production workers. `maggie deployment env-isolation` fails when
174
+ the local database host, port, and name match production.
175
+
135
176
  ## Verification and rollback
136
177
 
137
178
  Verify the homepage, changed service routes, `/robots.txt`, `/sitemap.xml`,
@@ -285,6 +285,57 @@ all required camera states, and valid PNGs at 390px, 768px, and desktop
285
285
  widths. The machine-readable contract is
286
286
  [mobile-app-surface-v1.schema.json](../../bundled-contracts/maggie-design/mobile-app-surface-v1.schema.json).
287
287
 
288
+ ### Onboarding wizards
289
+
290
+ Use one pattern for multi-step setup (brand, logo, voice, posting hours, and
291
+ similar first-run flows) instead of designing each flow ad hoc:
292
+
293
+ - A segmented progress bar with one segment per step; the current step is
294
+ visibly distinct and completed steps are tappable.
295
+ - Each step shows Maggie (or the product guide) with exactly one headline and,
296
+ at most, one supporting line. Put help in the control, not in paragraphs.
297
+ - Record step state on the server (`pending`, `done`, `skipped`) after every
298
+ step, and resume from the first unfinished step on any device. Local state
299
+ alone loses progress on reinstall or a second device.
300
+ - Every optional step offers **Later**. A skipped step reopens on the next
301
+ sign-in until it is done or explicitly dismissed; never block the app on it.
302
+ - Completed steps keep a redo action (for example "Retrain voice" or
303
+ "Choose another logo") that reopens that step with the saved value
304
+ preselected, without restarting the wizard.
305
+ - The primary action stays in the fixed footer; Back never discards saved
306
+ server state.
307
+
308
+ ### Pickers with previews
309
+
310
+ For choices that need to be seen (logo styles, templates, palettes, voices):
311
+
312
+ - The list sheet shows a thumbnail, name, and selection state per row; the
313
+ row itself selects, and a separate preview control opens a larger view.
314
+ - The large preview opens as a sheet nested in the list sheet, so dismissing
315
+ it returns to the same scroll position in the list. It offers **Use this**
316
+ and close; it never replaces the list route.
317
+ - Thumbnails are generated or cached assets, not live renders of every option.
318
+
319
+ ### React Native Web pressables
320
+
321
+ React Native Web renders `Pressable` and the `Touchable*` family as button-like
322
+ DOM elements. A chip with a nested remove control becomes `<button>` inside
323
+ `<button>`: the DOM is invalid, browsers repair it differently, and taps land
324
+ on the wrong control (for example, removing a tag opens its preview). Render
325
+ the chip body and its remove control as **sibling** pressables inside a plain
326
+ `View`, each with its own accessible label. The same rule applies to `<a>`
327
+ and `<button>` on the web.
328
+
329
+ Run the static check before browser QA; it scans `.tsx`/`.jsx`, skips build
330
+ and dependency folders, and treats `asChild` wrappers (such as an expo-router
331
+ `Link`) as a pass-through:
332
+
333
+ maggie design pressable-check --project . [--pressable Chip --pressable IconButton]
334
+
335
+ Pass `--pressable` for project components that render a pressable. A rare,
336
+ reviewed exception can carry `maggie-allow-nested-pressable` in a comment on
337
+ the inner element's line.
338
+
288
339
  ## Explicit homepage rebrand mode
289
340
 
290
341
  The homepage `review` mode only compares screenshots. It does not rebrand a
@@ -543,6 +594,54 @@ collapsed-rail, mobile-drawer, and modal evidence. Sample plans require
543
594
  noindex, sitemap exclusion, a visible sample banner, placeholders, and a
544
595
  finish checklist.
545
596
 
597
+ ### Tailwind v4 cascade layers
598
+
599
+ Tailwind v4 emits utilities inside `@layer utilities`. An unlayered rule beats
600
+ every layered rule regardless of specificity, so an unlayered
601
+ `h1, h2, h3 { font-family: … }` silently defeats template `font-*` utilities,
602
+ and an unlayered icon runtime rule such as `.ph { display: inline-block }`
603
+ defeats `hidden` and `group-open:inline` (a mobile menu then shows both the
604
+ open and close icons). Static class checks pass; only a browser shows it.
605
+
606
+ - Put app-wide element rules (headings, links, body copy) in `@layer base`.
607
+ - Put icon-font runtime rules and component classes in `@layer components`,
608
+ or import the icon stylesheet with `@import "./icons.css" layer(components);`.
609
+ - Keep `@theme`, `@utility`, and `@font-face` as they are; they are not
610
+ competing rules.
611
+
612
+ Run the static check whenever CSS or the icon package changes:
613
+
614
+ maggie design layer-check --project .
615
+
616
+ It runs only when an `@import "tailwindcss"` entry exists (or with
617
+ `--tailwind-v4`), honours `@layer` blocks and `layer(...)` imports, and fails on
618
+ unlayered element or icon rules that set utility-competing properties.
619
+ Unlayered `html`/`body` rules and class rules that set `display` are reported
620
+ as warnings. Keep `css-cascade-check` for the rendered-browser proof.
621
+
622
+ ### Palette role contract
623
+
624
+ A template that offers brand colour choices exposes semantic roles instead of
625
+ raw hex values in markup: `canvas`, `panel`, `soft`, `text`, `accent`,
626
+ `accentText`, `onAccent`, `dark`, and `deep`. Bind them to CSS variables (for
627
+ example `--color-canvas`) so a palette swap never edits markup. The generator
628
+ keeps the signature palette and derives named variants by moving hue while
629
+ keeping lightness; neutrals never gain chroma, accent saturation is capped
630
+ (uncapped variants turn garish), `accentText` is forced to 4.5:1 on canvas,
631
+ and `onAccent` is the most legible of white, deep, text, and canvas:
632
+
633
+ maggie design palette generate --template <template-id> \
634
+ --canvas '#F7F3EE' --text '#1F1B16' --accent '#B5651D' \
635
+ [--roles roles.json] [--count 17] [--max-saturation 0.65] \
636
+ --output design/palettes.json
637
+ maggie design palette validate --palette design/palettes.json
638
+
639
+ Measure the signature roles from the template's rendered CSS, not from a
640
+ reference palette. Generation stops if the signature itself fails the
641
+ contrast rules; fix the signature rather than lowering the threshold. The
642
+ contract is
643
+ [palette-roles-v1.schema.json](../../bundled-contracts/maggie-design/palette-roles-v1.schema.json).
644
+
546
645
  For generated or converted pages, run the markup gate before handing the page
547
646
  to a host editor:
548
647
 
@@ -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
@@ -118,6 +118,43 @@ Example:
118
118
  ]
119
119
  }
120
120
 
121
+ ## Feedback types
122
+
123
+ - `bug`: the skill or CLI did something wrong.
124
+ - `quality`: the result works but falls short (unclear output, weak defaults).
125
+ - `feature`: a missing capability.
126
+ - `improvement`: a concrete proposal to change an existing skill or CLI
127
+ (a new flag, a better default, a guidance section).
128
+ - `general`: anything else.
129
+
130
+ The hosted endpoint accepts `bug`, `feature`, `quality`, and `general`. An
131
+ `improvement` draft keeps its type locally and is submitted as `feature` with
132
+ `subtype: "improvement"`, so maintainers can still filter it.
133
+
134
+ ## Draft a batch from a working session
135
+
136
+ After a long session, draft batch items from the commits made since a known
137
+ point instead of writing them by hand:
138
+
139
+ ```bash
140
+ maggie feedback session-summary --project . \
141
+ --repo . --since v1.4.0 \
142
+ --batch-id social-session-2026-10 --skill maggie-social-share
143
+ ```
144
+
145
+ The helper reads commit subjects only (no diffs, paths, or file contents) and
146
+ redacts secrets and local paths. `fix:` commits become fixed `bug` items with a
147
+ `commit:<sha>` evidence reference; `feat:`, `perf:` and `refactor:` commits
148
+ become `improvement` candidates; other commits are skipped and counted. It also
149
+ adds one placeholder for an open ask. It writes a draft batch file under
150
+ `.maggie/feedback/batches/` and does not create or submit feedback.
151
+
152
+ Review the file: delete items that concern the project rather than a Maggie
153
+ skill or CLI, and replace every `REVIEW:` field (expected, actual, validation).
154
+ `maggie feedback batch` rejects a file that still contains `REVIEW:`
155
+ placeholders. Then continue with `batch`, `batch-review`, and explicit
156
+ `submit` as usual.
157
+
121
158
  ## Submit explicitly
122
159
 
123
160
  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,
@@ -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
@@ -427,6 +427,29 @@ FAQ helper from the first category implementation; it is a known gap and must
427
427
  remain marked incomplete until each FAQ record is independently AI-authored and
428
428
  reviewed.
429
429
 
430
+ ## Payments: Stripe live setup and gift vouchers
431
+
432
+ Service pages often lead to first-party payments. When the host takes money
433
+ through MaggieDash Booking (rather than the external provider), follow the
434
+ read-only live setup runbook in `docs/maggiedash-booking/STRIPE-INTEGRATION.md`:
435
+
436
+ - verify live state with list/retrieve (`GET`) calls only; never use a create
437
+ call as a probe — a probe expected to fail can create a real live object;
438
+ - the owner installs webhook and Connect event-destination signing secrets
439
+ with a no-echo command (`read -rs … | <secret store>`); the agent never sees
440
+ them;
441
+ - thin-event destination signing secrets cannot be retrieved via the API;
442
+ roll them in the Dashboard if they were not captured;
443
+ - the Stripe Dashboard may be unusable under browser automation, so hand
444
+ Dashboard-only steps to the owner and confirm them with read-only calls.
445
+
446
+ Gift vouchers (online and at the till, partial redemption, undo, void, expiry,
447
+ refunds, buyer/recipient emails, merchant ledger) follow the host-owned
448
+ `contracts/maggiedash/booking-voucher-lifecycle-v1.json` contract described in
449
+ `docs/maggiedash-booking/VOUCHERS.md`. Do not invent a separate voucher model;
450
+ replay the host's sanitized ledger with
451
+ `maggie booking voucher-contract --ledger FIXTURE`.
452
+
430
453
  ## Gates
431
454
 
432
455
  The workflow stops when any gate fails:
@@ -30,6 +30,17 @@ 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
+ ```
43
+
33
44
  1. Select an approved or explicitly shareable source article/content asset.
34
45
  2. Read Project Context and the selected social tone/template.
35
46
  3. Extract one clear content atom: insight, statistic, process, story, or
@@ -37,8 +48,11 @@ URL, channel limits, UTM links, approval state, and provider post state.
37
48
  4. Create platform-native variants with the platform's current limits and a
38
49
  clear CTA. Preserve the source canonical URL and apply the configured UTM
39
50
  policy.
40
- 5. Store drafts as calendar items with source ID, platform, version, approval,
41
- scheduled time, and local/remote status.
51
+ 5. Store drafts as queue items with source ID, platform, version, approval,
52
+ optional `not_before`, and local/remote status. Posting hours are slots;
53
+ do not persist a fixed `scheduled_at` per post (it goes stale and strands
54
+ overdue posts). Campaign ideas stay in the idea stage until written, and a
55
+ campaign starts only through the Start gate.
42
56
  6. Publish only after the required approval and entitlement checks. Record the
43
57
  publication attempt and provider ID; retry only with bounded idempotency.
44
58
  7. Read back clicks, engagement, assisted conversions, and failures separately
@@ -48,12 +62,30 @@ URL, channel limits, UTM links, approval state, and provider post state.
48
62
 
49
63
  ```text
50
64
  source_content_id, canonical_url, platform, format, hook, body, cta,
51
- hashtags_or_mentions, scheduled_at, approval_state, tracking_url
65
+ hashtags_or_mentions, not_before, queue_position, campaign_id, approval_state,
66
+ tracking_url
52
67
  ```
53
68
 
69
+ `not_before` is optional and only a lower bound; the slot planner assigns the
70
+ actual publish slot.
71
+
54
72
  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.
73
+ adapter can declare limits, one canonical auth scope set, media requirements,
74
+ idempotency, and delete/republish behavior.
75
+
76
+ ## Connections
77
+
78
+ - Every connect path (dashboard, mobile, CLI) requests the adapter's canonical
79
+ scope set. LinkedIn revokes a member's earlier tokens when a sign-in asks
80
+ for a different set; a shared OAuth client used by other products can do
81
+ the same. `adapters` fails on scope drift and warns on shared clients.
82
+ - A connection whose token the provider revoked, or that a serving host cannot
83
+ decrypt, shows **Reconnect** before anything is scheduled on it. Run the
84
+ decrypt check on every host that serves social routes.
85
+ - Provider avatar URLs are signed and expire; cache the bytes or refresh on
86
+ readback.
87
+ - Keep model structured-output enums small and validate large vocabularies
88
+ server-side; see [provider adapter contract](../../references/provider-adapter-contract.md#structured-model-output).
57
89
 
58
90
  ## Safety and commercial boundary
59
91