@nextcommerce/campaigns-os 1.59.0 → 1.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/CHANGELOG.md +242 -0
  2. package/README.md +11 -10
  3. package/agents/claude/CLAUDE.md +15 -0
  4. package/agents/codex/AGENTS.md +15 -0
  5. package/agents/copilot/copilot-instructions.md +15 -0
  6. package/agents/cursor/campaigns-os.mdc +15 -0
  7. package/compatibility.json +1 -1
  8. package/contracts/brand-theme-target-tokens.next-core.v0.json +95 -25
  9. package/contracts/campaign-cart-sdk-support-policy.v0.json +2 -2
  10. package/contracts/commerce-surface-catalog.json +27 -26
  11. package/contracts/release-ledger.json +1311 -0
  12. package/contracts/supported-surface.json +4 -4
  13. package/contracts/template-brand-contract.shared-commerce.v0.json +1 -1
  14. package/docs/access-model.md +20 -0
  15. package/docs/brand-theme-bridge.md +62 -3
  16. package/docs/build-packet.md +42 -13
  17. package/docs/campaign-build-brief.md +17 -1
  18. package/docs/campaigns-os-build-flow.md +62 -3
  19. package/docs/campaignspec-authoring-examples.md +116 -0
  20. package/docs/design-source-package.md +46 -2
  21. package/docs/entry-points.md +188 -0
  22. package/docs/local-setup.md +1 -1
  23. package/docs/orientation-contract-reference.md +1 -1
  24. package/docs/polish-evidence.md +41 -3
  25. package/docs/qa-and-test-orders.md +50 -2
  26. package/docs/quickstart.md +438 -0
  27. package/docs/readback.md +119 -6
  28. package/docs/runtime-readiness.md +1 -1
  29. package/docs/sdk-storage-compatibility.md +3 -1
  30. package/docs/skills-revision.md +10 -10
  31. package/docs/source-adapters.md +213 -0
  32. package/package.json +10 -3
  33. package/schemas/campaign-design-source-package.v0.schema.json +8 -0
  34. package/schemas/campaigns-os-readback.v2.schema.json +177 -1
  35. package/schemas/source-html-manifest.v0.schema.json +3 -0
  36. package/skills/campaign-lifecycle-orientation/SKILL.md +3 -3
  37. package/skills/campaign-readback-classification/SKILL.md +3 -3
  38. package/skills/campaign-run-evidence/SKILL.md +3 -3
  39. package/skills/contribution-intake/SKILL.md +3 -3
  40. package/skills/next-campaigns-build/SKILL.md +5 -5
  41. package/skills/next-campaigns-os/SKILL.md +4 -3
  42. package/skills/next-campaigns-os-setup/SKILL.md +3 -3
  43. package/skills/next-campaigns-polish/SKILL.md +12 -16
  44. package/skills/next-campaigns-qa/SKILL.md +3 -3
  45. package/skills/next-campaigns-sdk-bump/SKILL.md +286 -0
  46. package/skills.json +18 -10
  47. package/src/brand-theme.mjs +413 -8
  48. package/src/brief-summary.mjs +6 -2
  49. package/src/browser-launch.mjs +2 -1
  50. package/src/build-brief.mjs +9 -2
  51. package/src/built-site-scope.mjs +7 -14
  52. package/src/campaign-identity.mjs +6 -4
  53. package/src/cli.mjs +89 -73
  54. package/src/design-file-reference.mjs +93 -0
  55. package/src/design-source-package.mjs +55 -1
  56. package/src/doctor/checks.mjs +14 -77
  57. package/src/doctor/ci.mjs +112 -0
  58. package/src/doctor/inspect.mjs +20 -8
  59. package/src/doctor/next-step.mjs +6 -3
  60. package/src/doctor/source-provenance.mjs +74 -0
  61. package/src/evidence-debt.mjs +119 -0
  62. package/src/orchestration-stage-contract.mjs +6 -3
  63. package/src/page-kit-build-summary.mjs +21 -1
  64. package/src/page-kit-campaign-config.mjs +19 -0
  65. package/src/parity/compare.mjs +316 -0
  66. package/src/parity/design-access.mjs +54 -0
  67. package/src/parity/element-parity-record.mjs +569 -0
  68. package/src/parity/probe.mjs +205 -0
  69. package/src/parity/snapshot.mjs +110 -0
  70. package/src/png-header.mjs +87 -0
  71. package/src/polish-browser.mjs +186 -9
  72. package/src/polish-captures-record.mjs +52 -0
  73. package/src/polish-deadline.mjs +14 -0
  74. package/src/polish-gate.mjs +26 -11
  75. package/src/polish-node.mjs +81 -7
  76. package/src/polish-visual-fixtures.mjs +74 -0
  77. package/src/polish-visual.mjs +606 -0
  78. package/src/progress-node.mjs +2 -1
  79. package/src/qa-analytics-correctness.mjs +14 -2
  80. package/src/qa-analytics-parity.mjs +94 -5
  81. package/src/qa-node.mjs +39 -6
  82. package/src/qc-accept.mjs +148 -6
  83. package/src/qc-check-registry.mjs +37 -1
  84. package/src/qc-results.mjs +404 -16
  85. package/src/readback.mjs +57 -13
  86. package/src/sdk-attribute-index.mjs +11 -11
  87. package/src/sdk-markup.mjs +77 -2
  88. package/src/sdk-storage-compatibility.mjs +94 -4
  89. package/src/source-html-manifest.mjs +7 -0
  90. package/src/source-html-server.mjs +129 -0
  91. package/src/spec-derive.mjs +24 -9
  92. package/src/stage-ledger.mjs +27 -1
  93. package/src/stage-record.mjs +63 -9
  94. package/src/theme-gate.mjs +2 -2
  95. package/src/visual-diff.mjs +296 -0
  96. package/src/visual-reference.mjs +126 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,248 @@
2
2
 
3
3
  Notable supported-surface changes are recorded here.
4
4
 
5
+ ## [1.61.0] - 2026-10-23
6
+
7
+ ### Changed
8
+
9
+ - Publishes `1.60.0+agent.7`: installed users receive the quickstart, access, source-adapter and CampaignSpec authoring guides, and the package check verifies documentation links and headings inside the installed package.
10
+ - Publishes `1.60.0+agent.8`: readback reports when a changed build requires Polish or QA again, and `doctor --ci` reports that evidence debt for campaign pull requests. Installed agent context describes revising a live campaign and renewing its evidence (campaigns-os#695, campaigns-os#699).
11
+ - Publishes `1.60.0+agent.9`: completed Polish requires current package captures, with a captured build screenshot for every planned route; source renders are captured beside them for comparison. The review handoff includes visual reference warnings and image differences for operator review; pixel scores do not decide fidelity (campaigns-os#696).
12
+ - Publishes `1.60.0+agent.10`: the brand theme carries the design source's fonts and button radius onto commerce pages. `theme generate` writes `brand-fonts.css` beside `brand-theme.css`, and `record theme` refuses a styled commerce page that doesn't load it (campaigns-os#703).
13
+ - Intake records a manifest `design_file` as the page's authority and its HTML export as derived from that file; a Figma spec `design_source` records that lineage only with figma-sections-export provenance that passes doctor's `source_html.producer_provenance` check without a waiver. This version cannot read design files, so `design.access` reports `unexercised` with `design_access_missing` for a recorded file and explains how to continue or compare the export and file by hand; a changed design file or conflicting declaration is listed for review; an absent declaration reports `design_reference_missing`, with recovery by restoring it or rerunning intake with `--force` to drop the recorded file (campaigns-os#697).
14
+ - Polish probes the source and built renders and reports element-level differences in geometry, typography, colour and copy as warnings an operator can review and accept; they never block Polish or change readiness (campaigns-os#697).
15
+ - The readback schema now describes the optional `evidence_debt` field, its `current`, `owed` and `unknown` stage statuses, reasons and changes against the retained assembly manifest. Any owed Polish or QA stage makes `clean` false; unknown debt still needs review when `clean` is true.
16
+ - Bundled skills advance to `1.61.0+skills.1`.
17
+
18
+ ## [1.60.0+agent.10] - 2026-10-23
19
+
20
+ ### Changed
21
+
22
+ Brand theme carries the design source's type onto commerce pages, not only its colours:
23
+
24
+ - `theme inspect` / `theme generate` read the `@font-face` rules the source ships and the families its headings, body copy and buttons use, plus the button `border-radius`. `var()` references resolve through custom properties on `:root`, `html`, `body` and the class a stylesheet scopes itself under (the importer's `.cc-import`). They map to next-core's `--_text---font-family--heading`, `--_text---font-family--primary` and `--radius-size--buttons` (new `typography` block in `contracts/brand-theme-target-tokens.next-core.v0.json`). Each family is followed directly by the generic the source declared for it. A family is mapped only when the source ships a face for it; one that can't ship is a `theme.typography.face_unavailable` warning and is listed in the report's `typography.unavailable`. The radius takes `0` or one to four lengths or percentages, lists any other button radius in `typography.radius_rejected`, and is mapped only alongside a family, so a source without brand faces generates the same CSS as before.
25
+ - The font-family tokens are emitted in a `:root, body` block, because next-core re-declares them on `body` at its 991, 767 and 479px breakpoints and a `:root`-only value held on desktop alone. `validateGeneratedCss` accepts that block.
26
+ - `theme generate` writes `.campaign-runtime/theme/brand-fonts.css` beside `brand-theme.css`: only `@font-face` rules for the mapped families, always with `font-display: swap`, every format of a face kept, and URLs relative to `assets/css/`. Remote, `data:`, root-relative, missing, or outside-root face files (checked on real paths, so symlinks out are caught) are left out with `theme.typography.face_src_dropped`. The theme report gains `typography`, and `generated.fonts_css_path` names the file.
27
+ - `record theme` refuses a styled commerce page that doesn't load a copy of the generated `brand-fonts.css` (found through the Build Context's `theme.generated.fonts_css_path`) from inside the built site, identical to the generated file, naming the page. The theme gate's generate/apply actions, the build guidance, `docs/brand-theme-bridge.md`, and the build (1.0.50) and polish (1.1.50) skills say to copy and load it. Polish now checks font parity at a mobile width as well as desktop.
28
+ - The skills bundle revision advances to `1.60.0+skills.5`, and every bundled skill moves one patch version.
29
+
30
+ ## [1.60.0+agent.9] - 2026-10-23
31
+
32
+ ### Changed
33
+
34
+ `polish capture` now takes its own full-page captures of each mapped page and of the page's source HTML at desktop and mobile widths, verifies the source screenshots recorded in the Design Source Package, and compares compatible pairs section by section as a review diagnostic with a heatmap. `record polish` now requires these package captures for a completed Polish, including at least one rendered build cell with a captured actual shot for every planned route. Agent-written screenshot paths no longer satisfy the screenshot check for a new record, so run `polish capture` again after upgrading. Polish records written before this version are read as before. The source HTML render runs offline: it reaches only a local read-only server, and requests, WebSocket connections and host-name lookups to anything else are blocked. Source screenshots or pages that are the build's own output are reported as self-referential warnings. Width or pixel-ratio mismatches are reported as unsupported, never resized. The comparison never passes, fails or blocks anything. `pngjs` and `pixelmatch` are new optional dependencies; without them captures are still taken and the comparison is listed as unavailable. Capture images are kept out of the repository by a `.gitignore` inside each capture folder.
35
+
36
+ The Polish skill is 1.1.49, bundle `1.60.0+skills.4`.
37
+
38
+ ## [1.60.0+agent.8] - 2026-10-23
39
+
40
+ ### Added
41
+
42
+ Readback's additive `evidence_debt` field and text section show whether Polish and QA bind to the build on disk: `current`, `owed`, or `unknown`. Changed pages and other changed files are listed against the retained assembly manifest. An empty page list does not clear an owed stage. Missing or unreadable output or a missing assembly fingerprint leaves stage debt unknown. Otherwise a lifecycle-recorded `required` stage is owed (reason `stage_required_by_build`, `stage_required_by_brief`, or `stage_required_by_spec` from `required_by`, and `stage_required` for an absent or unrecognized source), even without a stage fingerprint; other missing stage fingerprints leave debt unknown. A missing or unusable manifest leaves only page changes unknown; matching stage bindings remain current unless required, and differing bindings remain owed. This build comparison is independent of readback's time-based staleness. Either owed stage makes `clean` false (campaigns-os#699).
43
+
44
+ `doctor --ci --packet <packet> --no-live-refs` reports the same evidence debt as Markdown for a PR comment, or under `ci` with `--json`. It exits 0 when both stages are current, 3 when either is owed, 4 when debt cannot be determined, and 2 when the packet is missing or unreadable. Other doctor findings remain visible without changing the CI exit code. The check does not renew evidence or deploy (campaigns-os#695).
45
+
46
+ The workflow example at `docs/examples/campaign-repo-evidence-check.yml` installs locked dependencies, builds the campaign, runs the check and posts or updates one PR comment. Evidence findings are report-only by default; set the repository Actions variable `CAMPAIGNS_OS_EVIDENCE_CHECK` to `fail` to enforce them. Install and build failures still fail normally and replace the comment with a fixed "build failed; evidence not evaluated" message when doctor did not run. A comment-permission failure leaves the report in the job log (campaigns-os#695).
47
+
48
+ ### Changed
49
+
50
+ The installed agent context for all four supported harnesses gains a live-campaign revision section: read readback and `next` before editing, follow the Design Source Package, rebuild and record the build before capturing and recording Polish, run QA when owed, and show each changed page's design reference beside its preview in the PR. `install-agent-context --dry-run` previews each destination and its full content without writing files; `--json` carries the same preview (campaigns-os#699).
51
+
52
+ ## [1.60.0+agent.7] - 2026-10-22
53
+
54
+ ### Fixed
55
+
56
+ The installed package now includes the existing quickstart, access model, entry-point, source-adapter and CampaignSpec authoring guides. Links from the Build Packet and README continue inside the package; repository-only evaluation, architecture and case-study references point to GitHub. The authoring guide links the shipped v5 schema and public multi-step examples, which remain repository test data.
57
+
58
+ The package check follows relative documentation links and checks destination headings against the extracted tarball, so a source-only guide or renamed anchor cannot leave installed users at a dead end. It ignores illustrative code and does not fetch external links. Runtime requirements and campaign behavior are unchanged.
59
+
60
+ ## [1.60.0+agent.6] - 2026-10-22
61
+
62
+ ### Changed
63
+
64
+ `sdk storage-check` output, from Sam's findings on campaigns-os#683:
65
+
66
+ - When `--target-sdk` is outside the manifest's supported range, the human report's first line reads `checked against SDK <range>, not the requested target <x.y.z>`, the next line says the report does not speak for that target, and the count line repeats it. The result is still `unknown` and the exit status still 2. `--json` adds `targetCovered`.
67
+ - An unknown `dynamic-key`, `unsupported-storage-method` or `storage-object-escape` line inside a loop that matches the keys it reads from storage by a scoped SDK key's prefix (`k.indexOf('next-cart-state') === 0`, `k.startsWith(...)`) ends in `[prefix loop: <prefix>]`, and `--json` adds `prefixScan` to the finding. A key read from storage is a `k = sessionStorage.key(i)` variable, a for-of over `Object.keys(sessionStorage)` or for-in over `sessionStorage`, or the element parameter (the second for `reduce`) of a callback chained on `Object.keys(sessionStorage)`. Only the line where that key came from, or a line that reads that key by name, is marked; other storage use in the loop, such as passing `sessionStorage` to a function, is not. One note under the findings explains them: the loop survives the scope suffix, but on a shared origin the prefix also matches another campaign's copy, so the lines stay unknown. Where the manifest names a public store for the key, the note names it.
68
+
69
+ ## [1.60.0+agent.5] - 2026-10-22
70
+
71
+ ### Changed
72
+
73
+ `qa run`'s test customer and shipping address flags are now documented and supported (campaigns-os#683 review). The order runner has always read them; none was in the usage text or the QA docs. `--test-first-name`, `--test-last-name`, `--test-phone`, `--test-country`, `--test-address1`, `--test-city`, `--test-province` and `--test-postal` are listed in `qa help` with their defaults (a US address in Mountain View, CA), and `docs/qa-and-test-orders.md` gains a "Test customer and shipping address" section with a non-US example. The province select is a required step, so a checkout with no province select for the chosen country fails at that field; those orders are placed by hand.
74
+
75
+ A non-USD `--currency` on a `qa run` that places orders, with no `--test-country`, now prints a warning on stderr naming the address flags. The run is not refused. Only the missing flag is checked, since a currency such as EUR has many markets.
76
+
77
+ `qa run --site` lists `--currency <code>` in its usage line, and a test now proves it: the slug's entry page is fetched with `?currency=<CODE>` and the verdict records `evidence.currency` on that page's `http:` row.
78
+
79
+ The `next-campaigns-sdk-bump` skill (1.0.3, bundle `1.60.0+skills.3`) names the address flags in step 6 as the way to run non-US orders through the runner, with ordering by hand as the fallback.
80
+
81
+ ## [1.60.0+agent.4] - 2026-10-22
82
+
83
+ ### Changed
84
+
85
+ The `next-campaigns-sdk-bump` skill (1.0.2, bundle `1.60.0+skills.2`) takes the second-run findings on campaigns-os#683 and a review of them:
86
+
87
+ - Step 1 reads each slug's live or retired status from the target repository's `CLAUDE.md`, root first. A missing or unclear status is never read as live or retired: the skill lists those slugs and asks. Before any order, it shows the developer the live slugs and the orders planned on each, and orders only on the list they confirm.
88
+ - The reload bar in step 6 is one fresh load and five cached reloads of every SDK page, upsells included, with the counts in the hand-back. The receipt, and any page with a hand-wired purchase push or `order:completed` listener, is left out of the cached reloads, because upsell pages reload the order and can resend a real purchase on each load; purchase events are counted across the run.
89
+ - The first page carries `?currency=<main>&country=<main>`. The SDK picks the market by IP and never reads browser geolocation, so the geolocation step is gone. The skill says `?country=` needs `currencyBehavior: auto`, and that an unsupported value falls back without failing, so the shown market is confirmed before the first order. `qa run` takes `--currency <main>`, which pins only each funnel's entry page.
90
+ - `qa run`'s own test orders use a US shipping address by default, so for a non-US main market the orders are placed by hand, with both parameters on the first page of every new tab.
91
+ - Test orders send real purchase events to every analytics vendor the campaign configures unless beacons are blocked at the network, and `qa run` does not block them yet. The vendors, read from the slug's `_data/campaigns.json` ids and `config.js` on Page Kit or the page's inline config on a static funnel, are named in the test-order question, with a note that GTM-fired tags, hand-wired pixels and server-side conversions may also receive them, and again in the hand-back. `?ignore=true` is ruled out: it turns off the SDK's analytics, `dl_*` included, for the rest of the session.
92
+ - The install-browser, `--browser` and local-only answers are asked up front, so a no-packet bump does not skip the `qa run --browser` pass by default. `doctor --built` runs once per bumped slug and `qa run --site` once per live slug. `--family` must exactly match a template brand contract shipped in the package or a private family in `contracts/private-template-sources.json` (which needs its repository checked out or `PRIVATE_TEMPLATE_SOURCES_ROOT`), and `--slug` a key in `_data/campaigns.json`; otherwise the skill asks.
93
+ - Step 3 lists payment and express methods the range adds (0.4.43 adds Shop Pay), and step 6 starts and cancels each one the campaign offers.
94
+ - The skill asks before the first project-local install, pins a reviewed version whose bundle revision matches the skill, and says to expect and commit the `devDependencies` and `package-lock.json` change. In a static repo it never installs into the publish root. `tooling status` only reads the pin.
95
+
96
+ Doctor's SDK attribute index now names Campaign Cart v0.4.43 (`docs/build-packet.md` says so). Regenerated from the source at that tag, it has the same 149 `data-next-*` names as v0.4.42. The cart placeholder renderers are unchanged too, so pages pinned to 0.4.43 pass the placeholder check instead of reading unexercised.
97
+
98
+ ## [1.60.0+agent.3] - 2026-10-21
99
+
100
+ ### Added
101
+
102
+ Doctor's SDK markup check gains two advisories about the page type (campaigns-os#683), on both `doctor --built` and packet doctor:
103
+
104
+ - `PAGE_TYPE_ATTRIBUTE`: a page sets `data-next-page-type` but has no `<meta name="next-page-type">`. The SDK never reads the attribute, so the page runs as the default `product` step, and an upsell page records no upsell page view. The message names the meta value to add, `upsell` on a page with an upsell offer, and never a page type the SDK does not have. Before, the attribute only appeared in the list of `data-next-*` names the SDK does not read.
105
+ - `UPSELL_PAGE_TYPE_MISSING`: a page with a `data-next-upsell` offer whose `next-page-type` meta is missing or is not `upsell`. The SDK records the upsell page view only from `<meta name="next-page-type" content="upsell">` and has no `downsell` page type, so reports showed the purchase with no upsell view before it.
106
+
107
+ Both are warnings; neither blocks. The certified templates raise neither.
108
+
109
+ ### Changed
110
+
111
+ When `tooling status` asks for a skills refresh on some installed harnesses only, the action now names them (for example "for Codex and Shared agent skills; not needed in a session that uses another harness"), so a session in another harness does not take it as its own step (campaigns-os#683).
112
+
113
+ ## [1.60.0+agent.2] - 2026-10-21
114
+
115
+ ### Fixed
116
+
117
+ `analytics-correctness:tag:meta` now passes when the declared Meta pixel initialises and tracks in the page, even if the browser never requests `facebook.com/tr` (campaigns-os#686). Headless Chromium can run `fbq('init')` and `fbq('track')` with fbevents.js loaded and still send no pixel request, so `qa run --browser` blocked campaigns whose pixel works in real browsers. QA now also watches `fbq` calls in the page: a pixel id counts once it is initialised and a track call follows on the same page.
118
+
119
+ If page code replaces `window.fbq` so QA can no longer see its calls, and no matching pixel request was seen, the row still fails but now says `unmeasured` and carries `evidence.reason: fbq_observer_disarmed`, instead of reporting a clean absence.
120
+
121
+ These are unchanged:
122
+ - A pixel that initialises but never tracks, or a different pixel id, still fails the row.
123
+ - An in-page `fbq('track', 'Purchase')` is not a Meta Purchase fire and supplies no CAPI dedup key; both still need the pixel request.
124
+
125
+ ## [1.60.0+agent.1] - 2026-10-20
126
+
127
+ ### Fixed
128
+
129
+ `qa run --site <repo> --base-url <site origin> --slug <slug>` now requests the campaign's pages under `/<slug>/` (campaigns-os#683). Before, it joined each page route straight onto `--base-url`, so it requested `/checkout/` rather than `/<slug>/checkout/` and every page returned 404. The slug is added the same way packet QA adds it: a base URL that already ends in the slug is used as given, and a slug found from the single campaign under `_site/` is added too.
130
+
131
+ ## [1.60.0] - 2026-10-20
132
+
133
+ ### Changed
134
+
135
+ - Publishes `1.59.0+agent.4`: the build-flow doc and quickstart describe the Campaigns App's offer-first setup.
136
+ - Publishes `1.59.0+agent.5`: hosted all-template guidance names `record deploy --base-url <route root>` for both deploy targets.
137
+ - Publishes `1.59.0+agent.6`: the progress snapshot binds QA to its build through `qc_build_fingerprint`, and the polish gate reads the recorded build only from `stages.assembly.build_fingerprint` (campaigns-os#672).
138
+ - Publishes `1.59.0+agent.7`: `run status` always names `next` as the next command (campaigns-os#673).
139
+ - Publishes `1.59.0+agent.8`: Campaigns OS adopts next-campaign-page-kit 0.3.0, keeps 0.2.x targets working, and doctor reports page-kit's `assetWarnings`. The first 0.3.0 build can change the build fingerprint; run `record build` again.
140
+ - Publishes `1.59.0+agent.9`: the starter catalog is re-synced to campaign-cart-starter-templates `3987b18` (build-time promo banner, `next_step` prefetch).
141
+ - Publishes `1.59.0+agent.10` and `1.59.0+agent.11`: the Playwright 1.64.1 / acorn 8.19.0 lockfile bump and repository workflow action bumps (campaigns-os#675, campaigns-os#679).
142
+ - Publishes `1.59.0+agent.12`: `install-skills` installs `next-campaigns-sdk-bump`, the 0.4.x Campaign Cart bump procedure (campaigns-os#677).
143
+ - Publishes `1.59.0+agent.13`: a CampaignSpec-only change keeps the Polish review of the kept output (campaigns-os#668).
144
+ - The `next-campaigns-sdk-bump` skill takes the feedback from its first live bump (campaigns-os#683). When the release range removes a feature the campaign uses, the skill now looks for a documented replacement and stops to ask rather than deleting the call. It guards every `next:initialized` listener for cached reloads, which 0.4.42 no longer replays, and proves them on fresh and cached loads. It judges a legacy page by what drives its cart and checkout, not by the Campaigns analytics script the 0.4.x SDK loads itself, and it explains a storage manifest whose range stops below the target tag. It also names the QA portal post and `--local-only`, keeps `qa-output/` out of commits, mentions `qa install-browser`, and triggers on bump requests in repositories that have their own BUMP.md.
145
+ - Bundled skills advance to `1.60.0+skills.1`.
146
+
147
+ ## [1.59.0+agent.13] - 2026-10-19
148
+
149
+ ### Fixed
150
+
151
+ A CampaignSpec-only change no longer throws away a Polish review of pages it did not change (campaigns-os#668). Before, `record build --deviation-reason` recorded the build, but Polish stayed owed after the re-intake (or `record spec`). The next `qa run` then stopped on `polish.evidence_missing`, and the agent had to retake the same screenshots and re-record the same findings.
152
+
153
+ Now `record build --deviation-reason` restores the Polish record that the change moved to history, stamped with the current inputs, when all of the following hold:
154
+ - the build records the exact output that Polish reviewed (same build fingerprint and source package);
155
+ - the record was a completed Polish;
156
+ - only the CampaignSpec changed, not the brief's presentation.
157
+
158
+ These are unchanged:
159
+ - QA stays owed, because the CampaignSpec changed.
160
+ - A presentation change, a different build, or a build recorded without the deviation reason still owes a new Polish.
161
+ - The build is still recorded with a warning and the operator's reason.
162
+
163
+ ## [1.59.0+agent.12] - 2026-10-19
164
+
165
+ ### Added
166
+
167
+ `install-skills` now installs `next-campaigns-sdk-bump`, so an agent told "bump this campaign to SDK 0.4.x" has a shipped procedure to follow instead of one written into the ticket (campaigns-os#677). It covers a 0.4.x to later 0.4.x Campaign Cart bump on page-kit and static repos, and it stops at a 0.3.x pin or the legacy Campaigns script, because moving those is migration work. The steps:
168
+
169
+ - Find every pin: `_data/campaigns.json` and loaders that hard-code their version on page-kit repos, or `sdk repin` scoped to the funnel folder on static repos.
170
+ - Read the release diff against the campaign's own code, including where its purchase event comes from.
171
+ - Run `sdk storage-check` with the target tag's manifest.
172
+ - Run `doctor --built`, or `doctor --packet` when there is a Build Packet.
173
+ - Prove the bump on a preview, with the browser pinned to the store's main market and each test order approved.
174
+ - Hand back what is not proven, on the ticket or the pull request, never in the served tree.
175
+
176
+ It adds no write, send or order capability. Bundled skills advance to `1.59.0+skills.4`.
177
+
178
+ ## [1.59.0+agent.11] - 2026-10-19
179
+
180
+ ### Changed
181
+
182
+ Repository workflows move `actions/create-github-app-token` from 3.2.0 to 3.3.0, `actions/upload-artifact` from 7.0.1 to 7.0.2 and `actions/download-artifact` from 8.0.1 to 8.0.2 (campaigns-os#679). This changes repository CI only, and the published package is unchanged.
183
+
184
+ ## [1.59.0+agent.10] - 2026-10-19
185
+
186
+ ### Changed
187
+
188
+ The lockfile moves Playwright from 1.63.0 to 1.64.1 and acorn from 8.18.0 to 8.19.0 (campaigns-os#675). Both stay within the ranges `package.json` already declares, so an installed toolkit resolves the same versions on a fresh install. Playwright drives `qa run --browser` and polish capture. acorn parses page scripts for doctor's `built_output.script_syntax` check, and 8.19.0 now rejects additional subscripts before the arrow in async arrow functions.
189
+
190
+ ## [1.59.0+agent.9] - 2026-10-19
191
+
192
+ ### Changed
193
+
194
+ The vendored starter catalog is re-synced to campaign-cart-starter-templates `3987b18` (was `d5ff501`). That range carries:
195
+ - campaign-cart-starter-templates#229: step and select pages prefetch `next_step` rather than the post-payment `next_url`.
196
+ - campaign-cart-starter-templates#234: every family renders the promo banner at build time from `promo_banner` frontmatter. The `<promo-banner>` web component and `promo-banner.js` are gone, along with the layout shift they caused.
197
+ - #228, #230, #235 and #237: the 5.0 multi-step fixture specs and recertified SDK 0.4.42 evidence. Each certified family now records `sdk-0.4.42-2026-10-16.2`.
198
+
199
+ The certified-family fixtures are regenerated at the pin with page-kit 0.2.0, which is what the starter repository still pins. The payment-chrome `asset_pin` moves to `3987b18`. Its five images have the same bytes there, so no hash changed. The SDK pin (0.4.42), the support policy and the CampaignSpec fixtures do not change.
200
+
201
+ ## [1.59.0+agent.8] - 2026-10-19
202
+
203
+ ### Changed
204
+
205
+ Campaigns OS adopts next-campaign-page-kit 0.3.0 and keeps 0.2.x targets working. The new-folder installs in `docs/local-setup.md`, the quickstart and the README pin `next-campaign-page-kit@0.3.0`; the quickstart and README installed it unpinned, and `docs/local-setup.md` pinned 0.2.0. The example target declares page-kit as a runtime dependency at that pin.
206
+
207
+ Doctor's build summary check reads the top-level `assetWarnings` array that page-kit 0.3.0 adds to `campaign-build --json`. 0.3.0 neither builds nor copies `.html` files under a campaign's `assets/`, and lists each one there as `ASSET_IGNORED`, never in `pages[].warnings`. Doctor read only `pages`, so such a build printed "no build errors or shape warnings". Each entry for the campaign is now a non-blocking `built_output.build_asset_warning` naming the file, because a link or iframe to it 404s on the built site, and the ready line prints only when there are neither page nor asset warnings. The build prompt and the Campaign Build skill name `assetWarnings` and `ASSET_IGNORED`.
208
+
209
+ `spec derive` and doctor's built-page lookup follow the target's installed page-kit, read from `node_modules/next-campaign-page-kit/package.json`, when they discover source pages. On 0.3.0 and later they skip `.html` files under the campaign's top-level `assets/`, so a page is no longer bound to a file page-kit does not build. A target on 0.2.x, or with no readable install, keeps the 0.2.x rule. The stray-file text in `docs/build-packet.md` and in the campaign identity gate's message now says that unpruned `_site/` output and an `assets/` `index.html` built as a page are page-kit 0.2.x behaviour; the `stray_files` gate is unchanged. Bundled skills advance to `1.59.0+skills.3`.
210
+
211
+ ### Migration
212
+
213
+ The first build on page-kit 0.3.0 can change the build fingerprint with unchanged source: 0.3.0 removes `_site/<slug>/` before it builds, so output left by earlier builds disappears, and it no longer copies `.html` files under `assets/` into `_site/`. Run `record build` again after that build and expect polish, deploy and QA to be owed again. That is the fingerprint doing its job.
214
+
215
+ ## [1.59.0+agent.7] - 2026-10-15
216
+
217
+ ### Fixed
218
+
219
+ `run status` now always names `next` as the next command: `progress.next_command` is `campaigns-os next --packet <packet> --json`. Before, once every stage status the Assembly Report records read completed or skipped, it named `run end` even when `next` had not reached done: after a CampaignSpec edit with no `record spec` (`next` answers build), on a report written before input stamps existed, and after a rebuild with no `record build`. `next` decides whether the campaign is done, and once it is, with a run session active, it names `run end` as a required action. `run status` stays read-only, and `progress.incomplete_stages` still lists the recorded statuses (campaigns-os#673).
220
+
221
+ ### Changed
222
+
223
+ `next` returns a blocked or unavailable prepare-build gate's recovery-only answer from one branch, whether the stage was named or picked; `requested_stage` still appears only when a stage was named. Doctor's status, `next`'s status and doctor's `next` block read one readiness ladder (`blocked`, then `ready_with_waivers`, `ready_with_warnings`, `ready`), each over its own errors and warnings. The output of `next` and doctor is unchanged.
224
+
225
+ ## [1.59.0+agent.6] - 2026-10-15
226
+
227
+ ### Fixed
228
+
229
+ The progress snapshot binds a QA record to its build through the field `next`, the QA gate and the Run Record already read: `stages.qa.evidence.qc_build_fingerprint`, falling back to `source_build_fingerprint`. It used to read only `source_build_fingerprint`, which QA writes only when the placeholder-text gate records an outcome. A `qa run` without `--browser`, or with that gate skipped, therefore showed `qa.binding: "unconfirmed"` and a qa stage row with `build_binding: "unconfirmed"` and no fingerprint, although QA was recorded for the current build. Records that bind no build, or a different one, still read `unconfirmed`.
230
+
231
+ The polish gate reads the recorded build only from `stages.assembly.build_fingerprint`. It no longer falls back to `stages.assembly.artifact_fingerprint`, a top-level `build_fingerprint` or a top-level `artifact_fingerprint`, which no toolkit version writes. A report carrying only one of those used to make doctor print "Build output fingerprint matches stages.assembly.build_fingerprint" and report `polish.evidence_missing`, while `record polish`, `record theme`, `record deploy` and `polish capture` refused the same report as having no recorded build. Doctor now reports `polish.build_fingerprint_missing` for it, as they do.
232
+
233
+ `npm run smoke:polish-capture` passes again. It wrote its page outside `_site/<slug>/` with a placeholder build fingerprint, which `polish capture` refuses; it now writes `_site/runtime-packet-demo/landing/` and records that tree's real fingerprint. A failed capture prints the underlying error after the smoke's failure message (campaigns-os#672).
234
+
235
+ ## [1.59.0+agent.5] - 2026-10-15
236
+
237
+ ### Fixed
238
+
239
+ The hosted all-template guidance now matches what `next` has done since 1.59.0, where a hosted preview records its deploy with `record deploy` before QA. The Campaign Polish skill, `docs/build-packet.md` and the README no longer say that the hosted preview URL satisfies the deploy stage or that `record deploy` takes only a loopback route root; they name `record deploy --base-url <route root>` for both deploy targets and leave the order to `next`. A forced `next deploy` or `next qa` on an all-template hosted packet whose preview URL is loopback or the production page now prompts for `qa policy set --preview-url`, as its next actions and doctor already did and as an unset preview URL already did, instead of the generic deploy prompt or a QA command against that URL; the QA prompt then sends the agent to `next`, which records the deploy before QA. The done prompt names `record deploy` for both deploy targets in place of an instruction to record the hosted URL by hand. Bundled skills advance to `1.59.0+skills.2`.
240
+
241
+ ## [1.59.0+agent.4] - 2026-10-14
242
+
243
+ ### Changed
244
+
245
+ The build-flow doc and the quickstart describe the Campaigns App's offer-first setup: Create Campaign, then Add Offer on the campaign's Offers tab. Selecting store products in an Offer creates one campaign product (a package in the API) per variant at its store price when the Offer is saved, and later Offers reuse it. The dashboard's Packages tab is now Products. The rule against separate `1x` / `2x` / `3x` packages for tier pricing is unchanged, and campaigns set up over the Admin API still create packages before Offers.
246
+
5
247
  ## [1.59.0] - 2026-10-09
6
248
 
7
249
  ### Changed
package/README.md CHANGED
@@ -13,7 +13,7 @@ This toolkit gives campaign developers and AI coding tools a clear path for asse
13
13
  7. Hand off to `next-campaigns-build`.
14
14
  8. Run build/lint and record the build with `campaigns-os record build`, then install the Campaigns OS Playwright browser once with `campaigns-os qa install-browser`.
15
15
  9. Run `next-campaigns-polish`, serve the current build, run the mandatory `campaigns-os polish capture` producer, then record Polish with `campaigns-os record polish --evidence <file>`.
16
- 10. Deploy a preview. For a local preview (`--deploy-target local-serve`), serve the current build and record it with `campaigns-os record deploy --base-url <loopback route root>`; a later `record build` of different output makes the deploy owed again. `record deploy` takes only a loopback route root; for a hosted preview, deploy through your host and follow `next` for what to record.
16
+ 10. Deploy a preview and record it with `campaigns-os record deploy --base-url <route root>`: for a local preview (`--deploy-target local-serve`), serve the current build and pass its loopback route root; for a hosted preview, deploy through your host and pass the https route root. A later `record build` of different output makes the deploy owed again.
17
17
  11. Run `next-campaigns-qa` against the tested URL.
18
18
  12. Record launch blockers and follow-up work.
19
19
 
@@ -45,7 +45,7 @@ steps, in this order:
45
45
 
46
46
  ```bash
47
47
  mkdir "<route>" && cd "<route>"
48
- npm init -y && npm i --save-exact next-campaign-page-kit
48
+ npm init -y && npm i --save-exact next-campaign-page-kit@0.3.0
49
49
  npx campaign-init --non-interactive --template <family> --slug "<route>" --name "<campaign name>"
50
50
  npm install --save-dev --save-exact @nextcommerce/campaigns-os@<version>
51
51
  npx --no-install campaigns-os tooling status --platform claude
@@ -303,7 +303,7 @@ npm run campaigns-os -- next polish --packet <packet.json> --report <assembly-re
303
303
  npm run campaigns-os -- polish capture --packet <packet.json> --base-url <served-current-build-url>
304
304
  npm run campaigns-os -- record polish --packet <packet.json> --evidence <polish-evidence.json>
305
305
  npm run campaigns-os -- record theme --packet <packet.json>
306
- npm run campaigns-os -- record deploy --packet <packet.json> --base-url <loopback-route-root>
306
+ npm run campaigns-os -- record deploy --packet <packet.json> --base-url <route-root>
307
307
  npm run campaigns-os -- record brief --packet <packet.json> --brief <campaign-build-brief.yaml>
308
308
  npm run campaigns-os -- record spec --packet <packet.json>
309
309
  npm run campaigns-os -- next qa --packet <packet.json> --report <assembly-report.json>
@@ -325,8 +325,9 @@ commands continue to record their own stages.
325
325
 
326
326
  Record a stage's completion with `record setup`, `record build` (after every
327
327
  rebuild), `record polish --evidence <file>`, `record theme` (once the brand layer
328
- is linked) and, for a local preview, `record deploy --base-url <loopback route
329
- root>`, rather than hand-editing `.campaign-runtime/build-context.json` or
328
+ is linked) and `record deploy --base-url <route root>` (a loopback URL for a
329
+ local preview, https for a hosted one), rather than hand-editing
330
+ `.campaign-runtime/build-context.json` or
330
331
  `.campaign-runtime/assembly-report.json`. A recorded deploy is bound to the
331
332
  build it probed, so a later `record build` of different output makes it owed
332
333
  again. When the brief or the CampaignSpec changes after stages are recorded, save
@@ -422,17 +423,17 @@ See [`campaign-spec/README.md`](campaign-spec/README.md).
422
423
  - [Campaign Standardization Report](docs/campaign-standardization-report.md)
423
424
  - [Entry Points](docs/entry-points.md) — five intake shapes (template-stock, Figma-driven, AI-generated, hand-authored, mixed) and which producer / manifest each one ships with
424
425
  - [Source Adapters](docs/source-adapters.md)
425
- - [Setup Profile Parity](docs/setup-profile-parity.md)
426
- - [Developer Evaluation](docs/developer-evaluation.md)
426
+ - [Setup Profile Parity](https://github.com/NextCommerceCo/campaigns-os/blob/main/docs/setup-profile-parity.md)
427
+ - [Developer Evaluation](https://github.com/NextCommerceCo/campaigns-os/blob/main/docs/developer-evaluation.md)
427
428
  - [QA And Test Orders](docs/qa-and-test-orders.md)
428
429
  - [Run-Artifact Readback](docs/readback.md) — `campaigns-os readback`: a read-only projection of one run's emitted artifacts, with per-artifact freshness against the checkout and a versioned JSON contract to gate on
429
430
  - [Declared Command Effects](docs/effects.md) — what every supported invocation writes and sends, one row per command and effect-changing flag, each row proved by a test that runs the real CLI in a disposable target
430
431
  - [Legacy Migration Contract](docs/legacy-migration.md) — pure inventory, preview-plan, receipt, Offer request/readback, and token-free evidence helpers for bounded SDK 0.3.x shadow migrations
431
- - [Template Family vs Figma-extraction vs Hybrid](docs/template-vs-extraction-decision.md) — when to mint a template family, when to extract a bespoke design, and when to do both
432
- - [Small PR Review Path](docs/small-pr-review-path.md)
432
+ - [Template Family vs Figma-extraction vs Hybrid](https://github.com/NextCommerceCo/campaigns-os/blob/main/docs/template-vs-extraction-decision.md) — when to mint a template family, when to extract a bespoke design, and when to do both
433
+ - [Small PR Review Path](https://github.com/NextCommerceCo/campaigns-os/blob/main/docs/small-pr-review-path.md)
433
434
  - [Run Telemetry](docs/workflow-findings-sidecar.md) — per-run Run Record (system signal + workflow findings) tagged by improvement surface; captured locally always, remitted to Next Commerce only with up-front opt-out consent
434
435
  - [Versioning](docs/versioning.md)
435
- - [ADR 0002: One shipping path](docs/adr/0002-one-shipping-path-campaigns-agent-fold.md) — decides that the agent surface (skills, charter, declared effects, readback) lives in this repository; Campaigns Agent folds in
436
+ - [ADR 0002: One shipping path](https://github.com/NextCommerceCo/campaigns-os/blob/main/docs/adr/0002-one-shipping-path-campaigns-agent-fold.md) — decides that the agent surface (skills, charter, declared effects, readback) lives in this repository; Campaigns Agent folds in
436
437
 
437
438
  ## Status
438
439
 
@@ -39,3 +39,18 @@ Core rules:
39
39
  - Campaigns OS proof is not merchant launch readiness. Before launch, confirm production storefront URL, live payment methods, shipping markets, legal/support URLs, analytics expectations, and merchant-side configuration.
40
40
 
41
41
  Current source adapter: prepared HTML/assets (`html_funnel`).
42
+
43
+ ## Revising a live campaign
44
+
45
+ 1. Before editing, run `npx --no-install campaigns-os readback .` and
46
+ `npx --no-install campaigns-os next --packet campaign-runtime.build.json`.
47
+ Readback's `evidence_debt` compares the build on disk with the builds Polish and QA were recorded for.
48
+ Changed pages are listed against the recorded assembly build manifest; an owed stage with an empty page list still means evidence is owed.
49
+ 2. For pages built from a provided design, the Design Source Package is the authority, not the punch list's wording.
50
+ 3. Before opening the pull request, after the final edit, rebuild, then run `npx --no-install campaigns-os record build --packet campaign-runtime.build.json`,
51
+ `npx --no-install campaigns-os polish capture --packet campaign-runtime.build.json --base-url <served-current-build-url>` for the whole route,
52
+ and `npx --no-install campaigns-os record polish --packet campaign-runtime.build.json --evidence <polish-evidence.json>`, in that order.
53
+ When QA is owed, run `npx --no-install campaigns-os qa run --packet campaign-runtime.build.json` against that build.
54
+ 4. In the pull request body, put the design reference and the preview of each changed page side by side.
55
+
56
+ The standing pull-request check is `npx --no-install campaigns-os doctor --ci --packet campaign-runtime.build.json --no-live-refs`, report-only unless the repo opts in.
@@ -29,3 +29,18 @@ A NEXT campaign is one connected commerce journey: the pages the CampaignSpec de
29
29
  - Do not use `next.getCartData().cartLines` as cart-populated proof; use typed-card order read-back, `cart:updated` payload `items` / `summary.lines`, and rendered bundle DOM evidence.
30
30
  - Campaigns OS proof is not merchant launch readiness. Before launch, confirm production storefront URL, live payment methods, shipping markets, legal/support URLs, analytics expectations, and merchant-side configuration.
31
31
  - This is not full automated readiness. QA remains a separate gate.
32
+
33
+ ## Revising a live campaign
34
+
35
+ 1. Before editing, run `npx --no-install campaigns-os readback .` and
36
+ `npx --no-install campaigns-os next --packet campaign-runtime.build.json`.
37
+ Readback's `evidence_debt` compares the build on disk with the builds Polish and QA were recorded for.
38
+ Changed pages are listed against the recorded assembly build manifest; an owed stage with an empty page list still means evidence is owed.
39
+ 2. For pages built from a provided design, the Design Source Package is the authority, not the punch list's wording.
40
+ 3. Before opening the pull request, after the final edit, rebuild, then run `npx --no-install campaigns-os record build --packet campaign-runtime.build.json`,
41
+ `npx --no-install campaigns-os polish capture --packet campaign-runtime.build.json --base-url <served-current-build-url>` for the whole route,
42
+ and `npx --no-install campaigns-os record polish --packet campaign-runtime.build.json --evidence <polish-evidence.json>`, in that order.
43
+ When QA is owed, run `npx --no-install campaigns-os qa run --packet campaign-runtime.build.json` against that build.
44
+ 4. In the pull request body, put the design reference and the preview of each changed page side by side.
45
+
46
+ The standing pull-request check is `npx --no-install campaigns-os doctor --ci --packet campaign-runtime.build.json --no-live-refs`, report-only unless the repo opts in.
@@ -15,3 +15,18 @@ CampaignSpec validation is owned by the public `@nextcommerce/campaigns-os/campa
15
15
  Preserve Campaign Cart SDK-owned commerce surfaces. Replace starter demo refs from CampaignSpec/API. Prepared AI/exported HTML must be converted into page-kit-ready source first: keep page-owned body markup, strip document wrappers, add YAML frontmatter, move shared CSS/assets into the campaign structure, and use Liquid helpers only for page-kit links/assets/includes. Landing/presell pages can preserve source design; checkout/upsell/downsell/receipt should use starter-template commerce surfaces as SDK contract references while campaign/source owns visual chrome. Reproduce the source design's own proof and urgency elements as designed (reviews, ratings, stock counters, countdowns, guarantees). They are the merchant's content; Campaigns OS does not review them, so do not remove, soften or flag them. Copy starter template families atomically with dependent pages, `_includes/`, `_layouts/`, `assets/css/`, and `assets/js/`; do not copy only checkout/receipt pages. Do not claim launch readiness until build, polish, deploy, and QA evidence are recorded.
16
16
 
17
17
  Before Polish becomes terminal or hands off to deploy/QA, install the package-owned Playwright browser with `npm run qa:install-browser`, serve the current build, and run `npx --no-install campaigns-os polish capture --packet campaign-runtime.build.json --base-url <served-current-build-url>`. After that checkpoint clears, QA must use the Campaigns OS Node/npm runner: run `npx --no-install campaigns-os qa resolve`, then run `npx --no-install campaigns-os qa run --browser --test-order common` against the tested URL. Typed-card test-order proof must use `npx --no-install campaigns-os qa run --test-order <common|checkout|decline|accept|both|full|explicit-path>` through the tested checkout and rendered upsell controls. `qa run` has no permission flag: coverage is its only control. Test orders still land in the store as real orders (global test cards: no charge, no transaction) that someone may have to cancel. Unless the operator has already said test orders are fine for this campaign, ask once, up front in your first turn with your other setup questions, so the answer covers the whole build and QA and neither stops for it later. `common` runs every actual terminal path when they fit under the flood cap (`--max-test-orders`, 6 by default); above the cap it runs the checkout baseline, first-offer accept and decline, and a deduplicated shortest real receipt path, then adds one decline path per offer or downsell page not yet declined, up to the cap, and names any page left out. A page counts as covered only when an order clicks its decline; the `browser-test-order:upsell-action-coverage` verdict row warns naming each page whose decline no order clicked. `full` walks every actual terminal path in the selected checkout topology; cycles, missing routes, and reachable nonterminals block exhaustive proof before browser launch. The accidental-flood cap remains `6`, and an overflow names the exact explicit `--max-test-orders` raise. Analytics correctness is two-phase: the campaign-root visit inventories declared providers/tags only, and the same canonical typed-card run proves Purchase only from the topology-recognized final receipt document after `--analytics-settle`. Missing/unrecognized receipts are manual-review warnings; recognized receipt no-signal and capture/settle errors block. Only the genuine recognized-receipt/no-signal failure is waivable; capture/settle errors are not. Checkout/upsell signals remain whole-journey parity evidence and cannot satisfy a silent receipt. Do not use `next.getCartData().cartLines` as cart-populated proof; use typed-card order read-back, `cart:updated` payload `items` / `summary.lines`, and rendered bundle DOM evidence. Localhost on any port is a Campaigns App Development domain for SDK QA with analytics suppressed; non-localhost preview/production origins still need SDK origin allowlist confirmation. Do not use external browser skills, SDK test-mode events, or direct backend orders as launch proof. Campaigns OS proof is not merchant launch readiness; before launch, confirm production storefront URL, live payment methods, shipping markets, legal/support URLs, analytics expectations, and merchant-side configuration.
18
+
19
+ ## Revising a live campaign
20
+
21
+ 1. Before editing, run `npx --no-install campaigns-os readback .` and
22
+ `npx --no-install campaigns-os next --packet campaign-runtime.build.json`.
23
+ Readback's `evidence_debt` compares the build on disk with the builds Polish and QA were recorded for.
24
+ Changed pages are listed against the recorded assembly build manifest; an owed stage with an empty page list still means evidence is owed.
25
+ 2. For pages built from a provided design, the Design Source Package is the authority, not the punch list's wording.
26
+ 3. Before opening the pull request, after the final edit, rebuild, then run `npx --no-install campaigns-os record build --packet campaign-runtime.build.json`,
27
+ `npx --no-install campaigns-os polish capture --packet campaign-runtime.build.json --base-url <served-current-build-url>` for the whole route,
28
+ and `npx --no-install campaigns-os record polish --packet campaign-runtime.build.json --evidence <polish-evidence.json>`, in that order.
29
+ When QA is owed, run `npx --no-install campaigns-os qa run --packet campaign-runtime.build.json` against that build.
30
+ 4. In the pull request body, put the design reference and the preview of each changed page side by side.
31
+
32
+ The standing pull-request check is `npx --no-install campaigns-os doctor --ci --packet campaign-runtime.build.json --no-live-refs`, report-only unless the repo opts in.
@@ -13,3 +13,18 @@ A NEXT campaign is one connected commerce journey: the pages the CampaignSpec de
13
13
  Do not carry over demo package, shipping, voucher, payment, tracking, footer, or SEO values. Prepared AI/exported HTML must be converted into page-kit-ready source first: keep page-owned body markup, strip document wrappers, add YAML frontmatter, move shared CSS/assets into the campaign structure, and use Liquid helpers only for page-kit links/assets/includes. Preserve prepared landing/presell source HTML when it is a real standalone design. For checkout/upsell/downsell/receipt, use starter-template commerce surfaces as SDK contract references while campaign/source owns visual chrome. Reproduce the source design's own proof and urgency elements as designed (reviews, ratings, stock counters, countdowns, guarantees). They are the merchant's content; Campaigns OS does not review them, so do not remove, soften or flag them. Copy starter template families atomically with dependent pages, `_includes/`, `_layouts/`, `assets/css/`, and `assets/js/`; do not copy only checkout/receipt pages. Emit SDK routing meta tags as campaign-root paths such as `/campaign-slug/upsell/`. Preserve SDK-owned checkout/cart/upsell/receipt surfaces. For `shop-three-step`, shipping is dynamic via `window.next.getShippingMethods()`.
14
14
 
15
15
  Before Polish becomes terminal or hands off to deploy/QA, install the package-owned Playwright browser with `npm run qa:install-browser`, serve the current build, and run `npx --no-install campaigns-os polish capture --packet campaign-runtime.build.json --base-url <served-current-build-url>`. After that checkpoint clears, QA uses the Campaigns OS Node/npm runner: `npx --no-install campaigns-os qa resolve`, then `npx --no-install campaigns-os qa run --browser --test-order common` against the tested URL. Test-order proof uses `npx --no-install campaigns-os qa run --test-order <common|checkout|decline|accept|both|full|explicit-path>` through the tested checkout and rendered upsell controls. `qa run` has no permission flag: coverage is its only control. Test orders still land in the store as real orders (global test cards: no charge, no transaction) that someone may have to cancel. Unless the operator has already said test orders are fine for this campaign, ask once, up front in your first turn with your other setup questions, so the answer covers the whole build and QA and neither stops for it later. `common` runs every actual terminal path when they fit under the flood cap (`--max-test-orders`, 6 by default); above the cap it runs the checkout baseline, first-offer accept and decline, and a deduplicated shortest real receipt path, then adds one decline path per offer or downsell page not yet declined, up to the cap, and names any page left out. A page counts as covered only when an order clicks its decline; the `browser-test-order:upsell-action-coverage` verdict row warns naming each page whose decline no order clicked. `full` walks every actual terminal path in the selected checkout topology; cycles, missing routes, and reachable nonterminals block exhaustive proof before browser launch. The accidental-flood cap remains `6`, and an overflow names the exact explicit `--max-test-orders` raise. Analytics correctness is two-phase: the campaign-root visit inventories declared providers/tags only, and the same canonical typed-card run proves Purchase only from the topology-recognized final receipt document after `--analytics-settle`. Missing/unrecognized receipts are manual-review warnings; recognized receipt no-signal and capture/settle errors block. Only the genuine recognized-receipt/no-signal failure is waivable; capture/settle errors are not. Checkout/upsell signals remain whole-journey parity evidence and cannot satisfy a silent receipt. Do not use `next.getCartData().cartLines` as cart-populated proof; use typed-card order read-back, `cart:updated` payload `items` / `summary.lines`, and rendered bundle DOM evidence. Localhost on any port is a Campaigns App Development domain for SDK QA with analytics suppressed; non-localhost preview/production origins still need SDK origin allowlist confirmation. External browser skills, SDK test-mode events, and direct backend orders are not launch proof. Campaigns OS proof is not merchant launch readiness; before launch, confirm production storefront URL, live payment methods, shipping markets, legal/support URLs, analytics expectations, and merchant-side configuration.
16
+
17
+ ## Revising a live campaign
18
+
19
+ 1. Before editing, run `npx --no-install campaigns-os readback .` and
20
+ `npx --no-install campaigns-os next --packet campaign-runtime.build.json`.
21
+ Readback's `evidence_debt` compares the build on disk with the builds Polish and QA were recorded for.
22
+ Changed pages are listed against the recorded assembly build manifest; an owed stage with an empty page list still means evidence is owed.
23
+ 2. For pages built from a provided design, the Design Source Package is the authority, not the punch list's wording.
24
+ 3. Before opening the pull request, after the final edit, rebuild, then run `npx --no-install campaigns-os record build --packet campaign-runtime.build.json`,
25
+ `npx --no-install campaigns-os polish capture --packet campaign-runtime.build.json --base-url <served-current-build-url>` for the whole route,
26
+ and `npx --no-install campaigns-os record polish --packet campaign-runtime.build.json --evidence <polish-evidence.json>`, in that order.
27
+ When QA is owed, run `npx --no-install campaigns-os qa run --packet campaign-runtime.build.json` against that build.
28
+ 4. In the pull request body, put the design reference and the preview of each changed page side by side.
29
+
30
+ The standing pull-request check is `npx --no-install campaigns-os doctor --ci --packet campaign-runtime.build.json --no-live-refs`, report-only unless the repo opts in.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "@nextcommerce/campaigns-os",
3
- "version": "1.59.0",
3
+ "version": "1.61.0",
4
4
  "status": "developer-preview",
5
5
  "contracts": {
6
6
  "campaign_spec": "4.2-5.0",
@@ -24,42 +24,112 @@
24
24
  "--brand--color--rating-star",
25
25
  "--component--color--outline",
26
26
  "--system-colors--success",
27
- "--system-colors--destructive"
27
+ "--system-colors--destructive",
28
+ "--_text---font-family--heading",
29
+ "--_text---font-family--primary",
30
+ "--radius-size--buttons"
28
31
  ],
29
32
  "source_mappings": {
30
- "--brand-primary": ["--brand--color--primary"],
31
- "--brand-accent": ["--brand--color--accent"],
32
- "--brand-secondary": ["--brand--color--secondary"],
33
- "--surface-bg": ["--brand--color--background"],
34
- "--surface-card": ["--brand--color--surface"],
35
- "--text-primary": ["--brand--color--text-primary", "--brand--color--foreground"],
36
- "--text-secondary": ["--brand--color--text-secondary"],
37
- "--border-default": ["--brand--color--border", "--component--color--outline"],
38
- "--rating-star": ["--brand--color--rating-star"],
39
- "--state-success": ["--system-colors--success"],
40
- "--ui-success": ["--system-colors--success"],
41
- "--state-error": ["--system-colors--destructive"],
42
- "--ui-danger": ["--system-colors--destructive"],
43
- "--brand-cta": ["--brand--color--cta-primary"],
44
- "--cta-primary": ["--brand--color--cta-primary"],
45
- "--button-primary-bg": ["--brand--color--cta-primary"]
33
+ "--brand-primary": [
34
+ "--brand--color--primary"
35
+ ],
36
+ "--brand-accent": [
37
+ "--brand--color--accent"
38
+ ],
39
+ "--brand-secondary": [
40
+ "--brand--color--secondary"
41
+ ],
42
+ "--surface-bg": [
43
+ "--brand--color--background"
44
+ ],
45
+ "--surface-card": [
46
+ "--brand--color--surface"
47
+ ],
48
+ "--text-primary": [
49
+ "--brand--color--text-primary",
50
+ "--brand--color--foreground"
51
+ ],
52
+ "--text-secondary": [
53
+ "--brand--color--text-secondary"
54
+ ],
55
+ "--border-default": [
56
+ "--brand--color--border",
57
+ "--component--color--outline"
58
+ ],
59
+ "--rating-star": [
60
+ "--brand--color--rating-star"
61
+ ],
62
+ "--state-success": [
63
+ "--system-colors--success"
64
+ ],
65
+ "--ui-success": [
66
+ "--system-colors--success"
67
+ ],
68
+ "--state-error": [
69
+ "--system-colors--destructive"
70
+ ],
71
+ "--ui-danger": [
72
+ "--system-colors--destructive"
73
+ ],
74
+ "--brand-cta": [
75
+ "--brand--color--cta-primary"
76
+ ],
77
+ "--cta-primary": [
78
+ "--brand--color--cta-primary"
79
+ ],
80
+ "--button-primary-bg": [
81
+ "--brand--color--cta-primary"
82
+ ]
46
83
  },
47
84
  "derived_mappings": {
48
85
  "--brand-primary": {
49
- "--brand--color--primary-dark": { "method": "mix-black", "amount": 0.18 },
50
- "--brand--color--primary-light": { "method": "mix-white", "amount": 0.2 },
51
- "--brand--color--primary-lighter": { "method": "mix-white", "amount": 0.86 }
86
+ "--brand--color--primary-dark": {
87
+ "method": "mix-black",
88
+ "amount": 0.18
89
+ },
90
+ "--brand--color--primary-light": {
91
+ "method": "mix-white",
92
+ "amount": 0.2
93
+ },
94
+ "--brand--color--primary-lighter": {
95
+ "method": "mix-white",
96
+ "amount": 0.86
97
+ }
52
98
  }
53
99
  },
54
100
  "foreground_derivations": {
55
101
  "description": "Foreground/on-color tokens are derived from the luminance of the background they sit on, never copied blindly from a source --text-inverse token (which defaults to white and renders illegible on a light brand, e.g. white-on-yellow CTAs). Each foreground target picks the first paired background that was mapped and emits the readable choice from foreground_choices. next-core .button/.submit-button render their label with --brand--color--text-inverse, so text-inverse pairs with the CTA background first.",
56
- "foreground_choices": { "dark": "#0a0a0a", "light": "#ffffff" },
102
+ "foreground_choices": {
103
+ "dark": "#0a0a0a",
104
+ "light": "#ffffff"
105
+ },
57
106
  "min_contrast_ratio": 4.5,
58
107
  "derivations": {
59
- "--brand--color--cta-foreground": ["--brand--color--cta-primary"],
60
- "--brand--color--text-inverse": ["--brand--color--cta-primary", "--brand--color--primary"],
61
- "--brand--color--primary-foreground": ["--brand--color--primary"],
62
- "--brand--color--accent-foreground": ["--brand--color--accent"]
108
+ "--brand--color--cta-foreground": [
109
+ "--brand--color--cta-primary"
110
+ ],
111
+ "--brand--color--text-inverse": [
112
+ "--brand--color--cta-primary",
113
+ "--brand--color--primary"
114
+ ],
115
+ "--brand--color--primary-foreground": [
116
+ "--brand--color--primary"
117
+ ],
118
+ "--brand--color--accent-foreground": [
119
+ "--brand--color--accent"
120
+ ]
63
121
  }
122
+ },
123
+ "typography": {
124
+ "description": "Typography targets. Font families are mapped only when the design source ships an @font-face for the family; the faces are written to brand-fonts.css beside brand-theme.css. next-core re-declares the font-family tokens on body inside its 991px, 767px and 479px media queries, so those tokens are emitted on `:root, body` to hold at every width.",
125
+ "targets": {
126
+ "heading_family": "--_text---font-family--heading",
127
+ "body_family": "--_text---font-family--primary",
128
+ "button_radius": "--radius-size--buttons"
129
+ },
130
+ "body_scoped_tokens": [
131
+ "--_text---font-family--heading",
132
+ "--_text---font-family--primary"
133
+ ]
64
134
  }
65
135
  }
@@ -2,8 +2,8 @@
2
2
  "schema_version": "campaign-cart-sdk-support-policy/v0",
3
3
  "provenance": {
4
4
  "source": "NextCommerceCo/campaign-cart release tags",
5
- "latest_known_release": "0.4.42",
6
- "captured_at": "2026-10-09"
5
+ "latest_known_release": "0.4.43",
6
+ "captured_at": "2026-10-22"
7
7
  },
8
8
  "source": "contracts/campaign-cart-sdk-support-policy.v0.json",
9
9
  "minimum_supported": "0.4.20",