@nextcommerce/campaigns-os 1.61.0 → 1.63.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 (129) hide show
  1. package/AGENTS.md +2 -1
  2. package/CHANGELOG.md +127 -0
  3. package/README.md +86 -438
  4. package/agents/claude/CLAUDE.md +9 -4
  5. package/agents/codex/AGENTS.md +8 -4
  6. package/agents/copilot/copilot-instructions.md +8 -4
  7. package/agents/cursor/campaigns-os.mdc +10 -4
  8. package/campaign-spec/README.md +7 -0
  9. package/campaign-spec/dist/analytics-vendors.d.ts +40 -0
  10. package/campaign-spec/dist/analytics-vendors.js +44 -0
  11. package/campaign-spec/dist/checkout-flow.d.ts +18 -0
  12. package/campaign-spec/dist/checkout-flow.js +28 -0
  13. package/campaign-spec/dist/index.d.ts +4 -2
  14. package/campaign-spec/dist/index.js +5 -1
  15. package/campaign-spec/dist/rules/analytics-contract-shape.d.ts +8 -0
  16. package/campaign-spec/dist/rules/analytics-contract-shape.js +39 -0
  17. package/campaign-spec/dist/rules/campaign-currencies.d.ts +30 -0
  18. package/campaign-spec/dist/rules/campaign-currencies.js +130 -0
  19. package/campaign-spec/dist/rules/checkout-path-has-packages.d.ts +31 -0
  20. package/campaign-spec/dist/rules/checkout-path-has-packages.js +79 -0
  21. package/campaign-spec/dist/rules/index.d.ts +3 -0
  22. package/campaign-spec/dist/rules/index.js +9 -0
  23. package/campaign-spec/dist/rules/package-currency-prices.d.ts +29 -0
  24. package/campaign-spec/dist/rules/package-currency-prices.js +137 -0
  25. package/campaign-spec/dist/types.d.ts +59 -9
  26. package/compatibility.json +1 -1
  27. package/contracts/commerce-surface-catalog.json +59 -53
  28. package/contracts/effects.v1.json +549 -165
  29. package/contracts/fixtures/runtime-recipe/accept/current.json +4 -0
  30. package/contracts/fixtures/runtime-recipe/accept/minimal.json +4 -0
  31. package/contracts/fixtures/runtime-recipe/dist-states.json +1 -1
  32. package/contracts/fixtures/runtime-recipe/reject/advisory-enforcement.json +4 -0
  33. package/contracts/fixtures/runtime-recipe/reject/allowlist-without-hosts.json +4 -0
  34. package/contracts/fixtures/runtime-recipe/reject/committed-output-claim.json +4 -0
  35. package/contracts/fixtures/runtime-recipe/reject/engines-disagreement-warns.json +4 -0
  36. package/contracts/fixtures/runtime-recipe/reject/lifecycle-scripts-enabled.json +4 -0
  37. package/contracts/fixtures/runtime-recipe/reject/unknown-kind.json +4 -0
  38. package/contracts/fixtures/runtime-recipe/reject/unknown-network-policy.json +4 -0
  39. package/contracts/fixtures/runtime-recipe/reject/unknown-output-check.json +4 -0
  40. package/contracts/fixtures/runtime-recipe/reject/unknown-revision.json +4 -0
  41. package/contracts/fixtures/runtime-recipe/reject/unknown-step-id.json +4 -0
  42. package/contracts/fixtures/runtime-recipe/reject/unperformable-check-skipped.json +4 -0
  43. package/contracts/fixtures/runtime-recipe/reject/unpinned-lockfile.json +4 -0
  44. package/contracts/release-ledger.json +1260 -0
  45. package/contracts/runtime-recipe.campaigns-os-node-v1.json +4 -0
  46. package/contracts/supported-surface.json +8 -8
  47. package/contracts/template-brand-contract.shared-commerce.v0.json +23 -1
  48. package/docs/build-packet.md +430 -37
  49. package/docs/campaign-standardization-report.md +4 -4
  50. package/docs/campaigns-os-build-flow.md +54 -3
  51. package/docs/campaignspec-authoring-examples.md +59 -4
  52. package/docs/design-source-package.md +18 -6
  53. package/docs/effects.md +17 -9
  54. package/docs/local-setup.md +1 -1
  55. package/docs/orientation-contract-reference.md +1 -1
  56. package/docs/polish-evidence.md +2 -0
  57. package/docs/progress-snapshots.md +7 -4
  58. package/docs/qa-and-test-orders.md +147 -1
  59. package/docs/readback.md +40 -5
  60. package/docs/runtime-readiness.md +7 -3
  61. package/docs/sdk-storage-compatibility.md +1 -1
  62. package/docs/skills-revision.md +10 -10
  63. package/package.json +1 -1
  64. package/schemas/campaign-runtime-build-context.v0.schema.json +9 -0
  65. package/schemas/campaign-runtime-build-packet.v0.schema.json +9 -0
  66. package/schemas/campaign-spec.v4.schema.json +34 -3
  67. package/schemas/campaign-spec.v5.schema.json +34 -3
  68. package/schemas/campaigns-os-readback.v2.schema.json +62 -1
  69. package/skills/campaign-lifecycle-orientation/SKILL.md +3 -3
  70. package/skills/campaign-readback-classification/SKILL.md +3 -3
  71. package/skills/campaign-run-evidence/SKILL.md +3 -3
  72. package/skills/contribution-intake/SKILL.md +3 -3
  73. package/skills/next-campaigns-build/SKILL.md +4 -3
  74. package/skills/next-campaigns-os/SKILL.md +6 -4
  75. package/skills/next-campaigns-os-setup/SKILL.md +5 -3
  76. package/skills/next-campaigns-polish/SKILL.md +5 -4
  77. package/skills/next-campaigns-qa/SKILL.md +7 -4
  78. package/skills/next-campaigns-sdk-bump/SKILL.md +42 -9
  79. package/skills.json +11 -11
  80. package/src/brand-theme.mjs +2 -1
  81. package/src/build-brief.mjs +4 -1
  82. package/src/campaign-workspace.mjs +288 -15
  83. package/src/change-scope.mjs +284 -0
  84. package/src/cli.mjs +308 -86
  85. package/src/commercial-journey.mjs +16 -3
  86. package/src/commercial-parity.mjs +15 -7
  87. package/src/content-residue.mjs +4 -2
  88. package/src/design-source-package.mjs +36 -0
  89. package/src/design-source-publication.mjs +9 -6
  90. package/src/directory-lock.mjs +73 -19
  91. package/src/doctor/checks.mjs +79 -7
  92. package/src/doctor/ci.mjs +75 -10
  93. package/src/doctor/inspect.mjs +23 -6
  94. package/src/doctor/next-step.mjs +7 -0
  95. package/src/doctor-sidecar.mjs +3 -2
  96. package/src/evidence-debt.mjs +47 -7
  97. package/src/finding-cause.mjs +12 -11
  98. package/src/input-refresh.mjs +339 -32
  99. package/src/invocation.mjs +7 -1
  100. package/src/live-campaign-refs.mjs +7 -2
  101. package/src/local-preview-policy.mjs +35 -2
  102. package/src/page-kit-analytics-vendors.mjs +132 -0
  103. package/src/polish-browser.mjs +3 -1
  104. package/src/polish-readability.mjs +221 -9
  105. package/src/polish-visual.mjs +9 -2
  106. package/src/progress-node.mjs +3 -2
  107. package/src/qa-analytics-parity.mjs +17 -1
  108. package/src/qa-browser.mjs +40 -4
  109. package/src/qa-commercial-parity.mjs +50 -3
  110. package/src/qa-node.mjs +196 -16
  111. package/src/qa-publish.mjs +9 -8
  112. package/src/qa-sidecar.mjs +16 -4
  113. package/src/qa-vendor-beacons.mjs +232 -0
  114. package/src/qa-vendor-endpoints.mjs +306 -0
  115. package/src/qc-accept.mjs +29 -1
  116. package/src/qc-check-registry.mjs +5 -1
  117. package/src/qc-results.mjs +73 -26
  118. package/src/readback.mjs +58 -10
  119. package/src/route-identity.mjs +10 -0
  120. package/src/run-record.mjs +18 -10
  121. package/src/runtime-state-ignore.mjs +6 -2
  122. package/src/sdk-storage-compatibility.mjs +21 -2
  123. package/src/source-html-intake.mjs +15 -1
  124. package/src/spec-derive-campaign.mjs +216 -0
  125. package/src/spec-derive.mjs +473 -53
  126. package/src/spec-identity.mjs +14 -0
  127. package/src/stage-ledger.mjs +40 -1
  128. package/src/stage-record.mjs +58 -13
  129. package/src/target-lock.mjs +11 -1
package/AGENTS.md CHANGED
@@ -124,7 +124,8 @@ precede argument refusal: `start`, `prepare-build`, `build`, `run start` and
124
124
  before argv is refused, which is a declared effect of those commands and is
125
125
  suppressed by `--no-write`. Commands implementing `--dry-run` also suppress
126
126
  that closeout whenever the flag is present, including a value that will be
127
- refused (such as `run end --dry-run yes`). Every remitting command's effect
127
+ refused (such as `run end --dry-run yes`), and any `--flag=value` token, which
128
+ every command refuses, skips it too. Every remitting command's effect
128
129
  declaration, when published, names its destination as open-world, and the agent onboarding skill
129
130
  records an explicit telemetry choice before the first remitting command.
130
131
 
package/CHANGELOG.md CHANGED
@@ -2,10 +2,93 @@
2
2
 
3
3
  Notable supported-surface changes are recorded here.
4
4
 
5
+ ## [1.63.0] - 2026-10-31
6
+
7
+ CampaignSpec can carry a page package's price in each currency the campaign sells in, and validation warns when a package has no price in one of them. To take it, pin `@nextcommerce/campaigns-os@1.63.0` and refresh the installed skills to `1.63.0+skills.1`; the skill text changes only in its stated revision.
8
+
9
+ ### Added
10
+
11
+ - **`prices[]` on a page package (#714).** A row in `funnels[].pages[].packages[]` may carry `prices: [{ currency, price, price_retail?, price_recurring? }]`, one entry per currency the Campaigns App prices the package in, read from the Campaigns API in that currency (`GET /campaigns/?currency=<code>`). `price` and `price_retail` stay the default currency's. The field is optional and additive in schemas v4 and v5 and in the `PagePackage` type (with `PackageCurrencyPrice`), and the authoring guide's Campaign Currencies section shows it.
12
+ - **`PackageCurrencyPrices` rule (#714).** A warning, tagged `fast` and `spec-only`, so `doctor` and Map Builder both run it. For a row that carries `prices[]`, it reports a currency in `campaign.available_currencies` or `campaign.currency` with no entry, since the Campaigns API leaves an unpriced package out of the campaign in that currency; an entry without an ISO 4217 `currency` and a non-negative decimal `price`, or with a malformed `price_retail` or `price_recurring`; and a currency listed twice. A row without `prices[]` (absent or null) is not checked, and malformed campaign currency codes stay with `CampaignCurrencies`.
13
+
14
+ ## [1.62.0] - 2026-10-30
15
+
16
+ This release makes the path from a Map to a working campaign shorter to start and cheaper to maintain. CampaignSpec validation catches a checkout nothing sells into and malformed currencies, and it carries the starter templates' analytics vendors. One project can hold several funnels. After handoff, `spec derive` keeps the spec in step with the repo's pages and the live campaign. A change to some pages' copy owes QA on those pages only. `qa run --test-order` holds test purchases back from the analytics vendors it can intercept (all of the template vendors except Northbeam), and `qa run --currency` blocks when the currency did not take. To take it, pin `@nextcommerce/campaigns-os@1.62.0` and refresh the installed skills to `1.62.0+skills.1`.
17
+
18
+ ### Changed
19
+
20
+ - **Several funnels in one project (#719).** The first funnel set up in a Page Kit project keeps `campaign-runtime.build.json` and `.campaign-runtime/`. Each later funnel gets `campaign-runtime-<route>.build.json` and keeps its Build Context, Assembly Report, doctor output, theme output, inputs, QA verdict sidecar and Run Records under `.campaign-runtime/funnels/<route>/`, which the packet records as `assembly.runtime_dir`. Every `--packet` command reads and writes that funnel's records.
21
+ - `readback` without `--packet` refuses, naming each packet and its route, when the project holds more than one funnel. `tooling status` then reads no packet pin.
22
+ - `prepare-build` no longer replaces another funnel's Build Packet, including one named with `--out`. `--force` replaces it on purpose: `prepare-build --out campaign-runtime.build.json --force` renames the route of a project's first funnel and keeps its records where they are. When a new route is set up beside an existing funnel, prepare-build prints a `Funnel:` line with the rename steps.
23
+ - Two funnels set up at the same moment no longer collide: the run that waited for the target lock stops and asks to be run again.
24
+ - Existing single-funnel projects read their records where they already are, with no setup rerun. The managed `.gitignore` block gains `.campaign-runtime/funnels/*/run-records/`.
25
+ - **`spec derive` after handoff (#721, #531).** A campaign is handed off once its deploy or its QA has completed. From then on derive adds a page the page tree builds that no spec page binds (id from the file name, type from its page-kit `page_type`; a checkout file with `next_step` is added as a `checkout_step` when it has a `step_number`, as a `checkout` that forwards to the Checkout in a v4 spec, and as a `select` page when it has none), removes a page whose built file is gone (matched by page id), and sets the routing on the edges that name those pages from the page files' `next_url` / `decline_url` / `next_step` frontmatter, rewriting the matching `sdk_hints.meta_tags` routing hint. A page file that is gone while a new file of the same page-kit `page_type` appears is read as a rename: neither change is applied and derive reports `page_renamed`, so the page's authored packages and offers are kept. Page order is reported as not derived, and so are an added page's packages (`page_packages_not_derived`): they are authored, and doctor blocks on `CheckoutPathHasPackages` or `UpsellHasPackages` until they are set.
26
+ - Once the campaign is built, derive makes the same read-only `GET /api/campaign` doctor makes and refreshes the fields the spec mirrors from the Campaigns App: each page package's name, price, recurring price, product, variant and availability, the offer records, and each page's offer copies. Which packages and offers a page carries stays authored, and a price never comes from the repo. `--no-live-refs` sends nothing; `--proxy-base` names the proxy. The effects contract declares the read on both `spec derive` rows and advances its `contract_version` to 1.3.0, because an existing row's declared effect changed.
27
+ - `record spec` binds a move of page routes: it re-projects every page's page-kit target in the packet and the Build Context and rewrites the Design Source Package's page surfaces and references. On a handed-off campaign it also binds a page added or removed, without intake. A respelling that projects to the same targets keeps the build, Polish and QA. A `record spec` that stopped part way is finished by the next one. It refuses a change that moves the route root or slug, leaves a routing hint stale, puts two pages on one target, or would rewrite a Design Source Package that prepare-build did not synthesize or that was edited since.
28
+ - Doctor blocks when a routing hint (`next-success-url`, `next-upsell-accept-url`, `next-upsell-decline-url`) names a route its page no longer has (`spec.routing_hint_stale`). `spec derive` and `record spec` use the same check.
29
+ - **Small changes owe small checks (#720).** After launch, a change that touches only some pages' HTML and leaves checkout pages, commerce markup, routes, scripts and the campaign's Page Kit config entry alone owes QA on those pages only, and Polish is advisory for it. Any other change still owes the full Polish and QA. A page-only change extends only a review that completed and that no brief or spec change has made owed since.
30
+ - `record build` keeps `stages.assembly.commerce_signature` (one hash per page over its commerce-bearing markup, plus the config entry) and `stages.assembly.build_changes`, each rebuild classified `page_only`, `commerce_affecting` or `unknown`.
31
+ - Readback's `evidence_debt` gives each owed stage a `change` object; Polish gains `advisory`, QA gains `scope` and `owed_pages`, and `clean` ignores advisory Polish. `doctor --ci` names the change it found and what each stage owes.
32
+ - New `qa run --packet <packet> --page <page_id>` (repeatable) checks only the named pages and places no test orders. It pays the page-only debt and keeps the purchase proof of the full run it extends. It refuses a commerce-affecting change, an unrecorded rebuild, a changed page left out, a last QA that did not complete, QA that a `qa_policy` or CampaignSpec change owes, and `--test-order` or `--vendor-beacons`.
33
+ - **Analytics vendors in the spec (#689).** The CampaignSpec types and both schemas add `analytics.vendors.<vendor>` for the starter templates' adapters (GA4, AppLovin Axon, Taboola, Triple Whale, TikTok, Northbeam, Snapchat, Pinterest) in the shape Map Builder saves: `enabled`, `id`, `platform`, `identityEnabled`, `allowedEvents`, `blockedEvents`. `AnalyticsContractShape` warns on an unknown vendor, an enabled vendor without an id, and event lists that are not arrays. `spec derive` copies each vendor's `_data/campaigns.json` id key (`ga4_id`, `triplewhale_name` and the rest) into `analytics.vendors.<vendor>.id` with the same empty-value and placeholder rules as GTM and Meta. The new advisory doctor check `page_kit.analytics_vendors` warns when the spec and `campaigns.json` disagree about a vendor or its id.
34
+ - **Test orders stay out of vendor reporting (#689).** `qa run --test-order` answers requests to the known beacon endpoints of GA4, Meta, TikTok, Snap, Pinterest, Taboola, Triple Whale and AppLovin Axon with a local empty response in every browser context it opens. Loader scripts still load, and those contexts block service workers. The new `browser-test-order:vendor-beacons` row records per vendor how many requests the page sent, whether one named a purchase, and the ids and events, and it lists configured vendors that sent nothing, that it cannot observe, or that are not intercepted (Northbeam, whose beacon host is unconfirmed). The row is evidence that the page sent them, never purchase proof, and it never blocks. `--vendor-beacons live` sends them to the vendors; it is refused without `--test-order`. `qa parity` orders are not intercepted.
35
+ - **`qa run --currency` checks the currency took (#713).** Each test order gets a `browser-order-currency:<path>` row that blocks when the order came out in another currency or recorded none. Commercial parity asks for expected totals in the run currency, and a calculate response in another currency is a `commercial-currency:<RUN>:<ANSWERED>` blocker. When the run currency is not the Map's, the fallback prices in the page source are left unresolved instead of compared. Runs without `--currency` are unchanged.
36
+ - **Polish layout conventions (#700).** At the mobile width, Polish warns (`layout.conventions`, acceptable with `checkpoint accept`) when a fixed or sticky CTA bar holds more than its one link or button (`floating_cta`), and when a purchase, accept or submit label is under 16px (`cta_label_size`). The thresholds live in a new `layout_conventions` block in the shared commerce brand contract. Readability records captured before this release show the check as not captured until the next `polish capture`.
37
+ - Skills: `next-campaigns-qa` covers default beacon interception, the `--currency` blockers and page-scoped QA; `next-campaigns-sdk-bump` the beacon default and the currency blockers; `next-campaigns-os` per-funnel records, `spec derive` after handoff and the page-only exception to full Polish and QA; `next-campaigns-os-setup` and `next-campaigns-build` setting up and building a later funnel; `next-campaigns-polish` the layout warnings. The QA and Polish skills read a later funnel's brief and report under its runtime directory. The installed agent context names the page-scoped QA path. Bundled skills advance to `1.62.0+skills.1`.
38
+
39
+ ### Added
40
+
41
+ - **A checkout something sells into (#711, #206).** New CampaignSpec rule `CheckoutPathHasPackages`: every path from an entry page to a Checkout must pass a page with a main-cart package entry (one marked neither `is_upsell` nor `is_order_bump`). Bump rows alone, and packages on upsell, downsell or thank-you pages, do not count. Paths follow routing fields, never page order or names. It is an error, or a warning when `build_scope.mode` is `partial`, and doctor reports it as `spec.validation`. The main-cart entry contract is in `docs/template-family-contracts.md`.
42
+ - **Currency codes (#714).** New CampaignSpec rule `CampaignCurrencies`: `campaign.currency` and every `campaign.available_currencies` entry must be a three-letter upper-case ISO 4217 code (an error, with the code to write for a near miss such as `"usd"`). A default currency missing from a non-empty `available_currencies` is a warning. The schemas and authoring guide say the spec owns `available_currencies`, listing every currency including the default; the Campaigns App's `additional_currencies` is not a spec field.
43
+ - The CampaignSpec schemas and authoring guide say that on an upsell or downsell page every package row is that page's offer, never an order bump, whatever `is_upsell` says (#710). Campaigns OS already read it this way, and tests now hold it.
44
+
45
+ ### Fixed
46
+
47
+ - Directory locks (#514): a command that finds the target lock or the progress allocation lock held by a live process of another Campaigns OS release refuses at once and names that process (`ELOCKFORMAT`), instead of racing it. Lock owner records carry `lock_format: 2`, so a holder from an earlier release is refused too; dead holders are still recovered. Two releases that start in the same instant are still not detected, so run one release against a target at a time. The holder also removes `.abandoned-<token>` directories left by an interrupted recovery, and an unreadable directory at the lock path is named as such.
48
+ - Every command refuses a `--flag=value` token, as it refuses any flag up front, and says to write the flag alone (an on/off flag) or `--flag value`; the message names the flag, never the value. Such a command does nothing first: the stale-session closeout that otherwise precedes argument refusal is skipped, as it is for a valued `--dry-run`, because the token's value (a `--packet`, `--target` or `--proxy-base`) is not read. Under `doctor --ci` the refusal is a usage error (`doctor.ci.usage`, exit 2). The shared parser read the token as an unknown key and dropped it, so `qa run --page=upsell1` ran a full QA and `--test-order=common` placed no orders. `standardize`, `page-kit sync` and `spec derive` already refused it as an unknown flag.
49
+ - 1.61.0 residuals (#707): the changed-page list survives `record build`; a reference refused for its location keeps its `location` on a stale-bound row; the readability reader passes an undefined `buildOutput` through unchanged.
50
+
51
+ ## [1.61.0+agent.2] - 2026-10-29
52
+
53
+ The `next-campaigns-sdk-bump` skill (1.0.7) takes the findings from its third live run, the first on a static repository. Step 3 now has a table of known changes a bump can cross, and step 6 names the 3-D Secure test card. `sdk storage-check` no longer fails on large repositories, and its inventory error now says why. Refresh installed skills with `install-skills` to get it.
54
+
55
+ ### Changed
56
+
57
+ The `next-campaigns-sdk-bump` skill (1.0.7, bundle `1.61.0+skills.2`) takes the third-run findings on campaigns-os#683:
58
+
59
+ - Step 3 has a table of known changes by version. 0.4.32: the checkout page no longer emits `order:completed` when it creates an order. The skill prefers the SDK's `dl_purchase`, which fires once per order; a capture that stays hand-wired moves to the first page after checkout, reads the order by the order's `?ref_id=`, and sends once per order, and step 6 reloads that page once with beacons blocked to prove it. 0.4.41: the card fields are Spreedly's hosted fields loaded by NEXT's payment script, so a page's own Spreedly `iframe-v1.min.js` tag, calls on the `Spreedly` global and CSS aimed at the v1 frame ids are removed or ported in the same commit as the pin move, after confirming the campaign has a payment key. 0.4.42 points at the `next:initialized` guard and 0.4.43 at the Shop Pay check. A page with a hand-written `modulepreload` list of SDK files rebuilds it from the target tag's `dist/` or removes it.
60
+ - Step 6 names the 3-D Secure test card from `docs/qa-and-test-orders.md`, links the platform's testing page, and asks the developer to confirm the gateway is in test mode before placing the order.
61
+ - Step 4 says that the old storage-check failure below means the pinned Campaigns OS is npm 1.61.0 or earlier, to update the pin, and not to run the check on a copied repository, which can lose tracked files.
62
+
63
+ ### Fixed
64
+
65
+ - `sdk storage-check` lists only the tracked files under `--scope` (`git ls-files -- <scope>`), so a large repository no longer passes Node's 1 MiB default buffer. Before this, a repository with more than about 25,000 tracked paths stopped with `Cannot inventory tracked Git source files.` (#717)
66
+ - That error now reads `Cannot inventory tracked Git source files: <reason>`, with Git's first stderr line as the reason, or, when Git printed nothing, how it ended (its exit status, the signal that stopped it, or a spawn error code), or a request to narrow a scope whose list passes 256 MiB. `docs/sdk-storage-compatibility.md` says so.
67
+
68
+ ## [1.61.0+agent.1] - 2026-10-24
69
+
70
+ ### Changed
71
+
72
+ The vendored starter catalog is re-synced to campaign-cart-starter-templates `5711e22` (was `b38343e`). That range carries:
73
+ - campaign-cart-starter-templates#246: tiered offers use one shipping method plus a free-shipping card coupon, in place of a separate free-shipping method. The CampaignSpec fixtures follow.
74
+ - campaign-cart-starter-templates#248: the Apollo Template Reference is re-stamped `sdk-0.4.43-shipping-coupon-tiers-2026-10-23`.
75
+ - campaign-cart-starter-templates#250: the MV families' `removeWhenUnsupported` names `variant_slots[].vouchers` for the tier coupon, as the bundle families do, in place of the removed free-shipping row.
76
+ - #247, #249 and #251: recorded SDK 0.4.43 verification evidence.
77
+
78
+ The certified-family fixtures are regenerated at the pin with page-kit 0.3.0, which is what the starter repository now pins. They were last rendered at `3987b18` with page-kit 0.2.0. The payment-chrome `asset_pin` moves to `5711e22`. Its five images have the same bytes there, so no hash changed. Two test files no longer depend on starter data that moved: the live-campaign drift tests give their saved Map its own second shipping method, and the Apollo Template Reference test reads the expected stamp from the catalog. The two payment-chrome tests pass again because the pin moved. The SDK pin and the support policy do not change.
79
+
5
80
  ## [1.61.0] - 2026-10-23
6
81
 
82
+ This release gathers the whole 1.60.0 line into one installable version and adds two things of its own. Intake now records a declared design file as the authority for a page, and Polish reports element-level differences between the source render and the built page as warnings an operator can review. To take it, pin `@nextcommerce/campaigns-os@1.61.0`, refresh the installed skills to `1.61.0+skills.1`, and run `polish capture` again before the next completed Polish record. Doctor cannot open design files yet, so a recorded file reads `unexercised` rather than verified.
83
+
7
84
  ### Changed
8
85
 
86
+ - Publishes `1.60.0+agent.1`: `qa run --site` requests the campaign's pages under `/<slug>/` instead of joining each route straight onto `--base-url` (campaigns-os#683).
87
+ - Publishes `1.60.0+agent.2`: `analytics-correctness:tag:meta` passes when the declared Meta pixel initialises and tracks in the page even if no `facebook.com/tr` request is seen; a replaced `fbq` reads `unmeasured` (campaigns-os#686).
88
+ - Publishes `1.60.0+agent.3`: doctor's SDK markup check gains the `PAGE_TYPE_ATTRIBUTE` and `UPSELL_PAGE_TYPE_MISSING` advisories, because the SDK reads the page type only from `<meta name="next-page-type">` (campaigns-os#683).
89
+ - Publishes `1.60.0+agent.4`: the `next-campaigns-sdk-bump` skill takes the second-run findings on campaigns-os#683 (per-slug live status, the reload bar, the market pin, vendor beacon disclosure, up-front gate answers), and doctor's SDK attribute index moves to Campaign Cart v0.4.43.
90
+ - Publishes `1.60.0+agent.5`: `qa run`'s test customer and shipping address flags are documented and supported, and a non-USD `--currency` with no `--test-country` warns (campaigns-os#683).
91
+ - Publishes `1.60.0+agent.6`: `sdk storage-check` names an out-of-range `--target-sdk` up front and marks SDK prefix loops in its report (campaigns-os#683).
9
92
  - 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
93
  - 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
94
  - 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).
@@ -17,6 +100,8 @@ Notable supported-surface changes are recorded here.
17
100
 
18
101
  ## [1.60.0+agent.10] - 2026-10-23
19
102
 
103
+ The generated brand theme now carries the design source's fonts and button radius onto the commerce pages, where before it carried only the colours. `theme generate` writes a second file, `brand-fonts.css`, beside `brand-theme.css`. Copy it into the campaign's `assets/css/` and load it on the same pages, because `record theme` refuses a styled commerce page that does not load it. A source that ships no font files of its own gets the same CSS as before.
104
+
20
105
  ### Changed
21
106
 
22
107
  Brand theme carries the design source's type onto commerce pages, not only its colours:
@@ -29,6 +114,8 @@ Brand theme carries the design source's type onto commerce pages, not only its c
29
114
 
30
115
  ## [1.60.0+agent.9] - 2026-10-23
31
116
 
117
+ `polish capture` now takes its own screenshots of every mapped page and of its source HTML, at desktop and mobile widths, and compares the pairs section by section as a review aid. A completed Polish record needs those captures, so after upgrading run `polish capture` again before `record polish`; screenshot paths written by hand no longer count. The comparison is a diagnostic only. It never passes, fails or blocks anything, and older Polish records are read as before.
118
+
32
119
  ### Changed
33
120
 
34
121
  `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.
@@ -37,6 +124,8 @@ The Polish skill is 1.1.49, bundle `1.60.0+skills.4`.
37
124
 
38
125
  ## [1.60.0+agent.8] - 2026-10-23
39
126
 
127
+ Readback now tells you whether the Polish and QA records still match the build on disk, in a new `evidence_debt` field: `current`, `owed` or `unknown`. `doctor --ci` reports the same debt as Markdown or JSON for a pull request check, with an example workflow under `docs/examples/`, and exits 3 when a stage is owed. Before revising a live campaign, read readback and renew any owed stage; the installed agent context now describes that procedure.
128
+
40
129
  ### Added
41
130
 
42
131
  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).
@@ -51,6 +140,8 @@ The installed agent context for all four supported harnesses gains a live-campai
51
140
 
52
141
  ## [1.60.0+agent.7] - 2026-10-22
53
142
 
143
+ The npm package now ships the quickstart, access model, entry-point, source-adapter and CampaignSpec authoring guides, so links from the Build Packet and the README resolve inside an installed copy instead of pointing at files that are not there. The package check follows those links and their headings, so a guide missing from the package now fails the check. Runtime behaviour is unchanged.
144
+
54
145
  ### Fixed
55
146
 
56
147
  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.
@@ -59,6 +150,8 @@ The package check follows relative documentation links and checks destination he
59
150
 
60
151
  ## [1.60.0+agent.6] - 2026-10-22
61
152
 
153
+ `sdk storage-check` is clearer about two things. When the `--target-sdk` you ask about is outside the manifest's supported range, the report says so in its first line and the result stays `unknown`, so you know the scan did not speak for that version. Unknown findings inside a loop that scans storage keys by an SDK prefix are marked `[prefix loop: <prefix>]`, with one note explaining why they stay unknown. Exit codes and the commands you run are unchanged.
154
+
62
155
  ### Changed
63
156
 
64
157
  `sdk storage-check` output, from Sam's findings on campaigns-os#683:
@@ -68,6 +161,8 @@ The package check follows relative documentation links and checks destination he
68
161
 
69
162
  ## [1.60.0+agent.5] - 2026-10-22
70
163
 
164
+ `qa run` has always accepted flags for the test customer and shipping address; they are now in `qa help` and the QA docs. Use `--test-country`, `--test-address1`, `--test-city`, `--test-province` and `--test-postal`, plus the name and phone flags, to place test orders against a non-US market; the default is a US address. A non-USD `--currency` with no `--test-country` now warns on stderr but still runs. A checkout with no province select for the chosen country still fails at that field, so those orders are placed by hand.
165
+
71
166
  ### Changed
72
167
 
73
168
  `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.
@@ -80,6 +175,8 @@ The `next-campaigns-sdk-bump` skill (1.0.3, bundle `1.60.0+skills.3`) names the
80
175
 
81
176
  ## [1.60.0+agent.4] - 2026-10-22
82
177
 
178
+ The `next-campaigns-sdk-bump` skill (1.0.2) takes the findings from its second live run. It now reads each slug's live or retired status from the target's `CLAUDE.md` and asks when that is unclear, confirms the market before the first order, names the analytics vendors that will receive real purchase events from test orders, and asks its browser and install questions up front. Refresh installed skills with `install-skills` to get it. Doctor's SDK attribute index moves to Campaign Cart 0.4.43, which has the same `data-next-*` names as 0.4.42, so pages pinned to 0.4.43 pass the placeholder check.
179
+
83
180
  ### Changed
84
181
 
85
182
  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:
@@ -97,6 +194,8 @@ Doctor's SDK attribute index now names Campaign Cart v0.4.43 (`docs/build-packet
97
194
 
98
195
  ## [1.60.0+agent.3] - 2026-10-21
99
196
 
197
+ Doctor now warns when a page sets `data-next-page-type` but has no `<meta name="next-page-type">`, and when an upsell page's meta is missing or is not `upsell`. The SDK reads the page type only from the meta tag, so without it an upsell page runs as a product page and records no upsell page view. Both are warnings and block nothing; add the meta tag the message names. `tooling status` also names which harnesses a skills refresh is for.
198
+
100
199
  ### Added
101
200
 
102
201
  Doctor's SDK markup check gains two advisories about the page type (campaigns-os#683), on both `doctor --built` and packet doctor:
@@ -112,6 +211,8 @@ When `tooling status` asks for a skills refresh on some installed harnesses only
112
211
 
113
212
  ## [1.60.0+agent.2] - 2026-10-21
114
213
 
214
+ `qa run --browser` no longer fails a working Meta pixel. Headless Chromium can run `fbq('init')` and `fbq('track')` without ever sending the `facebook.com/tr` request, so QA now also watches the `fbq` calls in the page and passes the `analytics-correctness:tag:meta` row when the declared pixel initialises and tracks. If page code replaces `window.fbq` so QA cannot see the calls, the row fails as `unmeasured` instead of reporting a clean absence. A Meta Purchase still needs the real pixel request.
215
+
115
216
  ### Fixed
116
217
 
117
218
  `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.
@@ -124,12 +225,16 @@ These are unchanged:
124
225
 
125
226
  ## [1.60.0+agent.1] - 2026-10-20
126
227
 
228
+ `qa run --site` now requests a campaign's pages under `/<slug>/`, as the deployed site serves them. Before this fix it joined each route straight onto `--base-url`, so every page returned 404. If a site QA run on 1.60.0 showed nothing but 404s, run it again on this version. The flags are unchanged.
229
+
127
230
  ### Fixed
128
231
 
129
232
  `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
233
 
131
234
  ## [1.60.0] - 2026-10-20
132
235
 
236
+ This release packages the ten `1.59.0+agent` sections below. The largest change for a campaign folder is next-campaign-page-kit 0.3.0: the first build on it can change the build fingerprint with no source change, so run `record build` again and expect Polish, deploy and QA to be owed. `install-skills` now also installs `next-campaigns-sdk-bump`, the procedure for moving a campaign to a later 0.4.x Campaign Cart, and that skill takes the lessons from its first live bump. Pin `@nextcommerce/campaigns-os@1.60.0` and refresh skills to `1.60.0+skills.1`.
237
+
133
238
  ### Changed
134
239
 
135
240
  - Publishes `1.59.0+agent.4`: the build-flow doc and quickstart describe the Campaigns App's offer-first setup.
@@ -146,6 +251,8 @@ These are unchanged:
146
251
 
147
252
  ## [1.59.0+agent.13] - 2026-10-19
148
253
 
254
+ A CampaignSpec-only change no longer throws away a Polish review of pages it did not touch. When you re-record the build with `record build --deviation-reason` and the output is identical to what Polish reviewed, the completed Polish record is restored instead of staying owed. QA is still owed, because the spec changed. A presentation change or a different build still owes a new Polish.
255
+
149
256
  ### Fixed
150
257
 
151
258
  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.
@@ -162,6 +269,8 @@ These are unchanged:
162
269
 
163
270
  ## [1.59.0+agent.12] - 2026-10-19
164
271
 
272
+ `install-skills` now installs a new skill, `next-campaigns-sdk-bump`: the procedure for moving a campaign from one 0.4.x Campaign Cart version to a later one, on page-kit and static repos. It finds every pin, reads the release diff against the campaign's code, runs `sdk storage-check` and doctor, and proves the bump on a preview with approved test orders. It stops at a 0.3.x pin or the legacy Campaigns script, because those are migration work. Run `install-skills` to get it; the bundle is `1.59.0+skills.4`.
273
+
165
274
  ### Added
166
275
 
167
276
  `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:
@@ -177,18 +286,24 @@ It adds no write, send or order capability. Bundled skills advance to `1.59.0+sk
177
286
 
178
287
  ## [1.59.0+agent.11] - 2026-10-19
179
288
 
289
+ Repository CI workflows move to newer versions of three GitHub Actions. This changes nothing in the published package, and there is nothing to do.
290
+
180
291
  ### Changed
181
292
 
182
293
  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
294
 
184
295
  ## [1.59.0+agent.10] - 2026-10-19
185
296
 
297
+ The lockfile moves Playwright to 1.64.1 and acorn to 8.19.0, both inside the ranges `package.json` already declared, so a fresh install resolves the same versions. Playwright drives `qa run --browser` and `polish capture`; acorn parses page scripts for doctor's script-syntax check and now rejects one more malformed async arrow-function shape. There is nothing to do unless doctor newly reports a syntax error in a page script.
298
+
186
299
  ### Changed
187
300
 
188
301
  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
302
 
190
303
  ## [1.59.0+agent.9] - 2026-10-19
191
304
 
305
+ The vendored starter-template catalog moves to campaign-cart-starter-templates `3987b18`. Step and select pages prefetch `next_step` instead of the post-payment URL, and the promo banner is rendered at build time from frontmatter, so the `<promo-banner>` web component and its layout shift are gone. The SDK pin stays 0.4.42 and the CampaignSpec fixtures do not change.
306
+
192
307
  ### Changed
193
308
 
194
309
  The vendored starter catalog is re-synced to campaign-cart-starter-templates `3987b18` (was `d5ff501`). That range carries:
@@ -200,6 +315,8 @@ The certified-family fixtures are regenerated at the pin with page-kit 0.2.0, wh
200
315
 
201
316
  ## [1.59.0+agent.8] - 2026-10-19
202
317
 
318
+ Campaigns OS now works with next-campaign-page-kit 0.3.0 and keeps 0.2.x targets working. The setup docs pin `next-campaign-page-kit@0.3.0`, and doctor reads 0.3.0's new `assetWarnings`, so an `.html` file under a campaign's `assets/` that page-kit no longer builds is reported instead of 404ing silently on the built site. The first build on 0.3.0 can change the build fingerprint with unchanged source: run `record build` again afterwards and expect Polish, deploy and QA to be owed.
319
+
203
320
  ### Changed
204
321
 
205
322
  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.
@@ -214,6 +331,8 @@ The first build on page-kit 0.3.0 can change the build fingerprint with unchange
214
331
 
215
332
  ## [1.59.0+agent.7] - 2026-10-15
216
333
 
334
+ `run status` now always points to `next` as the next command, so a finished-looking report no longer sends you to `run end` before `next` has reached done. `next` decides when the campaign is done and names `run end` itself. The output of `next` and doctor is otherwise unchanged.
335
+
217
336
  ### Fixed
218
337
 
219
338
  `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).
@@ -224,6 +343,8 @@ The first build on page-kit 0.3.0 can change the build fingerprint with unchange
224
343
 
225
344
  ## [1.59.0+agent.6] - 2026-10-15
226
345
 
346
+ Two fixes to how the toolkit binds QA and Polish to a build. The progress snapshot now reads the QA record's `qc_build_fingerprint`, so a `qa run` without `--browser` no longer shows `qa.binding: unconfirmed` for a build it did test. The polish gate reads the recorded build only from `stages.assembly.build_fingerprint`, and a report that carries only a legacy fingerprint field now gets a clear `polish.build_fingerprint_missing` from doctor instead of contradictory messages. `npm run smoke:polish-capture` passes again.
347
+
227
348
  ### Fixed
228
349
 
229
350
  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`.
@@ -234,18 +355,24 @@ The polish gate reads the recorded build only from `stages.assembly.build_finger
234
355
 
235
356
  ## [1.59.0+agent.5] - 2026-10-15
236
357
 
358
+ The hosted preview path is now documented the way `next` has run it since 1.59.0: record the hosted deploy with `record deploy --base-url <route root>` before QA, for both deploy targets. The Polish skill, the Build Packet doc and the README no longer say a hosted preview URL satisfies the deploy stage on its own. A forced `next deploy` or `next qa` on a hosted packet whose preview URL is loopback or production now asks for `qa policy set --preview-url` first. Bundled skills advance to `1.59.0+skills.2`.
359
+
237
360
  ### Fixed
238
361
 
239
362
  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
363
 
241
364
  ## [1.59.0+agent.4] - 2026-10-14
242
365
 
366
+ The build-flow doc and the quickstart now describe campaign setup in the Campaigns App the way the dashboard does it: create the campaign, then add Offers on its Offers tab. Selecting store products in an Offer creates the campaign's products (packages in the API) at their store price, and the Packages tab is now called Products. Do not create separate `1x`, `2x` and `3x` packages for tier pricing. This is documentation only.
367
+
243
368
  ### Changed
244
369
 
245
370
  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
371
 
247
372
  ## [1.59.0] - 2026-10-09
248
373
 
374
+ This release publishes the 1.58.0 line and adds hosted deploy recording. `record deploy --base-url <https route root>` now works for a hosted preview: it requests every built page, requires HTTP 200, and checks that every script and stylesheet the pages load is byte-identical to the built output. The hosted all-template path no longer skips the deploy stage; `next` hands you `record deploy` and then QA. Pin `@nextcommerce/campaigns-os@1.59.0` and refresh skills to `1.59.0+skills.1`.
375
+
249
376
  ### Changed
250
377
 
251
378
  - Publishes the untagged `1.58.0` change: multi-step checkout frontmatter follows the starter-template `next_step` contract (campaigns-os#641).