@nextcommerce/campaigns-os 1.57.0 → 1.60.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.
- package/CHANGELOG.md +176 -0
- package/README.md +6 -5
- package/campaign-spec/dist/checkout-flow.d.ts +7 -0
- package/campaign-spec/dist/checkout-flow.js +17 -1
- package/compatibility.json +1 -1
- package/contracts/campaign-cart-sdk-support-policy.v0.json +2 -2
- package/contracts/commerce-surface-catalog.json +27 -28
- package/contracts/effects.v1.json +5 -5
- package/contracts/release-ledger.json +975 -0
- package/contracts/supported-surface.json +4 -4
- package/contracts/template-brand-contract.shared-commerce.v0.json +1 -1
- package/docs/build-packet.md +35 -19
- package/docs/campaign-build-brief.md +1 -1
- package/docs/campaigns-os-build-flow.md +1 -1
- package/docs/local-setup.md +1 -1
- package/docs/orientation-contract-reference.md +1 -1
- package/docs/polish-evidence.md +1 -1
- package/docs/qa-and-test-orders.md +54 -12
- package/docs/runtime-readiness.md +1 -1
- package/docs/skills-revision.md +10 -10
- package/package.json +1 -1
- package/schemas/campaign-runtime-build-context.v0.schema.json +2 -1
- package/schemas/campaign-runtime-build-packet.v0.schema.json +2 -1
- package/skills/campaign-lifecycle-orientation/SKILL.md +3 -3
- package/skills/campaign-readback-classification/SKILL.md +3 -3
- package/skills/campaign-run-evidence/SKILL.md +3 -3
- package/skills/contribution-intake/SKILL.md +3 -3
- package/skills/next-campaigns-build/SKILL.md +7 -7
- package/skills/next-campaigns-os/SKILL.md +3 -3
- package/skills/next-campaigns-os-setup/SKILL.md +3 -3
- package/skills/next-campaigns-polish/SKILL.md +9 -10
- package/skills/next-campaigns-qa/SKILL.md +3 -3
- package/skills/next-campaigns-sdk-bump/SKILL.md +193 -0
- package/skills.json +18 -10
- package/src/built-site-scope.mjs +96 -12
- package/src/campaign-identity.mjs +6 -4
- package/src/cli.mjs +50 -81
- package/src/doctor/checks.mjs +79 -6
- package/src/doctor/inspect.mjs +2 -8
- package/src/doctor/next-step.mjs +9 -17
- package/src/orchestration-stage-contract.mjs +6 -3
- package/src/page-kit-build-summary.mjs +21 -1
- package/src/page-kit-campaign-config.mjs +19 -0
- package/src/polish-gate.mjs +1 -5
- package/src/polish-node.mjs +5 -4
- package/src/progress-node.mjs +2 -1
- package/src/qa-browser.mjs +137 -2
- package/src/qa-cart-entry.mjs +105 -0
- package/src/qa-node.mjs +3 -1
- package/src/qa-verdict.mjs +24 -1
- package/src/sdk-attribute-index.mjs +8 -7
- package/src/source-html-intake.mjs +27 -18
- package/src/spec-derive.mjs +24 -9
- package/src/stage-ledger.mjs +27 -1
- package/src/stage-record.mjs +218 -35
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,182 @@
|
|
|
2
2
|
|
|
3
3
|
Notable supported-surface changes are recorded here.
|
|
4
4
|
|
|
5
|
+
## [1.60.0] - 2026-10-20
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Publishes `1.59.0+agent.4`: the build-flow doc and quickstart describe the Campaigns App's offer-first setup.
|
|
10
|
+
- Publishes `1.59.0+agent.5`: hosted all-template guidance names `record deploy --base-url <route root>` for both deploy targets.
|
|
11
|
+
- 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).
|
|
12
|
+
- Publishes `1.59.0+agent.7`: `run status` always names `next` as the next command (campaigns-os#673).
|
|
13
|
+
- 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.
|
|
14
|
+
- 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).
|
|
15
|
+
- 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).
|
|
16
|
+
- Publishes `1.59.0+agent.12`: `install-skills` installs `next-campaigns-sdk-bump`, the 0.4.x Campaign Cart bump procedure (campaigns-os#677).
|
|
17
|
+
- Publishes `1.59.0+agent.13`: a CampaignSpec-only change keeps the Polish review of the kept output (campaigns-os#668).
|
|
18
|
+
- 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.
|
|
19
|
+
- Bundled skills advance to `1.60.0+skills.1`.
|
|
20
|
+
|
|
21
|
+
## [1.59.0+agent.13] - 2026-10-19
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
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.
|
|
26
|
+
|
|
27
|
+
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:
|
|
28
|
+
- the build records the exact output that Polish reviewed (same build fingerprint and source package);
|
|
29
|
+
- the record was a completed Polish;
|
|
30
|
+
- only the CampaignSpec changed, not the brief's presentation.
|
|
31
|
+
|
|
32
|
+
These are unchanged:
|
|
33
|
+
- QA stays owed, because the CampaignSpec changed.
|
|
34
|
+
- A presentation change, a different build, or a build recorded without the deviation reason still owes a new Polish.
|
|
35
|
+
- The build is still recorded with a warning and the operator's reason.
|
|
36
|
+
|
|
37
|
+
## [1.59.0+agent.12] - 2026-10-19
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
`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:
|
|
42
|
+
|
|
43
|
+
- 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.
|
|
44
|
+
- Read the release diff against the campaign's own code, including where its purchase event comes from.
|
|
45
|
+
- Run `sdk storage-check` with the target tag's manifest.
|
|
46
|
+
- Run `doctor --built`, or `doctor --packet` when there is a Build Packet.
|
|
47
|
+
- Prove the bump on a preview, with the browser pinned to the store's main market and each test order approved.
|
|
48
|
+
- Hand back what is not proven, on the ticket or the pull request, never in the served tree.
|
|
49
|
+
|
|
50
|
+
It adds no write, send or order capability. Bundled skills advance to `1.59.0+skills.4`.
|
|
51
|
+
|
|
52
|
+
## [1.59.0+agent.11] - 2026-10-19
|
|
53
|
+
|
|
54
|
+
### Changed
|
|
55
|
+
|
|
56
|
+
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.
|
|
57
|
+
|
|
58
|
+
## [1.59.0+agent.10] - 2026-10-19
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
|
|
62
|
+
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.
|
|
63
|
+
|
|
64
|
+
## [1.59.0+agent.9] - 2026-10-19
|
|
65
|
+
|
|
66
|
+
### Changed
|
|
67
|
+
|
|
68
|
+
The vendored starter catalog is re-synced to campaign-cart-starter-templates `3987b18` (was `d5ff501`). That range carries:
|
|
69
|
+
- campaign-cart-starter-templates#229: step and select pages prefetch `next_step` rather than the post-payment `next_url`.
|
|
70
|
+
- 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.
|
|
71
|
+
- #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`.
|
|
72
|
+
|
|
73
|
+
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.
|
|
74
|
+
|
|
75
|
+
## [1.59.0+agent.8] - 2026-10-19
|
|
76
|
+
|
|
77
|
+
### Changed
|
|
78
|
+
|
|
79
|
+
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.
|
|
80
|
+
|
|
81
|
+
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`.
|
|
82
|
+
|
|
83
|
+
`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`.
|
|
84
|
+
|
|
85
|
+
### Migration
|
|
86
|
+
|
|
87
|
+
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.
|
|
88
|
+
|
|
89
|
+
## [1.59.0+agent.7] - 2026-10-15
|
|
90
|
+
|
|
91
|
+
### Fixed
|
|
92
|
+
|
|
93
|
+
`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).
|
|
94
|
+
|
|
95
|
+
### Changed
|
|
96
|
+
|
|
97
|
+
`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.
|
|
98
|
+
|
|
99
|
+
## [1.59.0+agent.6] - 2026-10-15
|
|
100
|
+
|
|
101
|
+
### Fixed
|
|
102
|
+
|
|
103
|
+
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`.
|
|
104
|
+
|
|
105
|
+
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.
|
|
106
|
+
|
|
107
|
+
`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).
|
|
108
|
+
|
|
109
|
+
## [1.59.0+agent.5] - 2026-10-15
|
|
110
|
+
|
|
111
|
+
### Fixed
|
|
112
|
+
|
|
113
|
+
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`.
|
|
114
|
+
|
|
115
|
+
## [1.59.0+agent.4] - 2026-10-14
|
|
116
|
+
|
|
117
|
+
### Changed
|
|
118
|
+
|
|
119
|
+
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.
|
|
120
|
+
|
|
121
|
+
## [1.59.0] - 2026-10-09
|
|
122
|
+
|
|
123
|
+
### Changed
|
|
124
|
+
|
|
125
|
+
- Publishes the untagged `1.58.0` change: multi-step checkout frontmatter follows the starter-template `next_step` contract (campaigns-os#641).
|
|
126
|
+
- Publishes `1.58.0+agent.2`: doctor warns `template_contract.select_step_missing` for a two-step family with no select page before checkout, and the phone scan skips comments and `<style>` content (campaigns-os#658, campaigns-os#660).
|
|
127
|
+
- Publishes `1.58.0+agent.3`: a stale build fingerprint names the extra, missing and changed files and flags sync conflict copies (campaigns-os#659).
|
|
128
|
+
- Publishes `1.58.0+agent.4`: QA verdicts separate planned order paths from retry attempts (campaigns-os#661).
|
|
129
|
+
- Publishes `1.58.0+agent.6`: QA cart entry chooses each slot's variant on a select page before Next (campaigns-os#667).
|
|
130
|
+
- Publishes `1.58.0+agent.7`: the starter catalog is re-synced to campaign-cart-starter-templates `d5ff501` (campaign-cart-starter-templates#223, SDK 0.4.42).
|
|
131
|
+
- Bundled skills advance to `1.59.0+skills.1`.
|
|
132
|
+
|
|
133
|
+
### Added
|
|
134
|
+
|
|
135
|
+
`record deploy` records a hosted deploy. On a packet whose `deploy.target` is not `local-serve` it takes an https `--base-url` naming the campaign's route root (plain http only on a loopback host), requests every built page there, and requires each to answer HTTP 200. It then requests every script and stylesheet the built pages load from that origin and compares each one's sha256 with the file in the built output, following redirects only within that origin and reading no more bytes than the built file holds; a missing, larger or different asset refuses the record, naming the URL and the built file. A `record build` of other output between the probe and the write refuses the record, on a `local-serve` packet too. A response with no readable body refuses as a transport failure, not as a byte mismatch. HTML is not compared, because hosts inject toolbars and other markup. A passing probe writes what the loopback path writes: `deploy.preview_url` on the packet, and `stages.deploy` completed with the URL in `outputs`, one evidence line per page and per matched asset, and the build fingerprint it probed, so a later `record build` of other output makes deploy owed again. `local-serve` packets keep the loopback-only rules. The hosted all-template preview no longer skips the deploy stage: `next` hands off `record deploy` for the recorded preview URL and then QA, and the hosted deploy prompt names `record deploy` in place of hand-editing `stages.deploy` (campaigns-os#657).
|
|
136
|
+
|
|
137
|
+
## [1.58.0+agent.7] - 2026-10-09
|
|
138
|
+
|
|
139
|
+
### Changed
|
|
140
|
+
|
|
141
|
+
The vendored starter catalog is re-synced to campaign-cart-starter-templates `d5ff501`, which carries the multi-step checkout contract from campaign-cart-starter-templates#223 and the Campaign Cart SDK 0.4.42 pin. Builds made with 1.58.0's `next_step` frontmatter now take templates whose step forms and select links read `next_step` and whose `next-success-url` is the Checkout's post-payment destination. Every certified family records 0.4.42 verification evidence (`sdk-0.4.42-2026-10-09`), and the eight agent CampaignSpec fixtures pin `sdk_version` 0.4.42. The certified-family fixtures are regenerated at the pin, and the payment-chrome asset pin moves to `d5ff501`; the five asset hashes are unchanged.
|
|
142
|
+
|
|
143
|
+
The SDK attribute index moves to v0.4.42 with the same recipe; it returns the same 149 names as at v0.4.41. 0.4.42 joins the cart-placeholder verified pins: the ten renderer and enhancer files the placeholder lists come from have the same git blob ids at v0.4.38 and v0.4.42. The checkout field-name mapping is unchanged at v0.4.42. The SDK support policy names 0.4.42 as `latest_known_release`; `minimum_supported` and `preferred_minimum` are unchanged.
|
|
144
|
+
|
|
145
|
+
## [1.58.0+agent.6] - 2026-10-09
|
|
146
|
+
|
|
147
|
+
### Fixed
|
|
148
|
+
|
|
149
|
+
On a select page whose bundle slots each need a variant (size, colour) before Next, `qa run --test-order` now chooses one per slot before clicking the checkout control. It does this after revealing the second step and after any bundle card click, one field at a time, over the visible, enabled slot variant selects (`[data-next-variant-selectors] select` or `.next-slot-variant-field select`, counted visible when the field is). When a field shows a dropdown UI (`os-dropdown` with a `.os-card__variant-dropdown-toggle` and `os-dropdown-item` rows, as the olympus-mv-two-step starter renders), the runner clicks the toggle and a row like a shopper, even when the SDK has already filled the select, because a page may count a field as chosen only when a row was clicked. It clicks the row matching the select's current value when that row is in stock, so the cart stays what the SDK chose, and otherwise the first in-stock row. After the toggle click it finds the field again by slot identity and the row again by its value, and waits up to 2 seconds for that row to show. A field with no dropdown UI gets its first in-stock option only when its select is empty, with `input` and `change` dispatched. Each choice is recorded on the `entered_via_landing` evidence as `variant_selections: [{ bundle_id, slot, variant_code, value, via }]`, with `via` set to `dropdown` or `select`, so the ordered variants can be checked against the cart lines. A field with no in-stock row or option, or a row that does not show or cannot be clicked, fails the path before Next with the new code `cart_entry_variant_unfilled`, naming the slot, instead of `cart_entry_no_navigation` after the navigation timeout. It classifies as `not_created` like the other cart-entry codes. A page whose filled selects have no dropdown UI is left untouched and `variant_selections` is omitted. Before this, every path on a page that blocks Next until a variant is picked failed with `cart_entry_no_navigation` (campaigns-os#667).
|
|
150
|
+
## [1.58.0+agent.4] - 2026-10-09
|
|
151
|
+
|
|
152
|
+
### Fixed
|
|
153
|
+
|
|
154
|
+
A QA run that re-ran failed order paths no longer reads as more paths than it planned. Each `test_orders[]` entry in the verdict now carries `attempt` (1 for the first try, 2 for the re-run) beside the `plan_id` of the planned path it belongs to, and `qa run` prints a summary line that keeps paths, attempts and created orders apart, such as `Test orders: 5 paths, 10 attempts, 0 orders created`. Before this, a run capped at five paths where every path was re-run once showed ten entries and nothing to say which were retries. The Assembly Report's `stages.qa.purchase_proof` gains `test_order_attempts`, and `order_paths_executed` now counts planned paths rather than attempts. Verdicts written before `attempt` existed count each entry as a path, as they did before. The array keeps one entry per attempt and no existing field changed shape.
|
|
155
|
+
|
|
156
|
+
## [1.58.0+agent.3] - 2026-10-09
|
|
157
|
+
|
|
158
|
+
### Fixed
|
|
159
|
+
|
|
160
|
+
When the built output no longer matches the recorded build fingerprint, doctor's `built_output.fingerprint_stale` and the `polish capture` refusal now name the paths that are extra, missing, or changed, at most 20 per list followed by `(+N more)`. Before, both reported only the recorded and current hashes, so finding the files behind a mismatch took a manual diff of `_site/`. `record build` keeps the path and SHA-256 list behind the fingerprint on `stages.assembly.build_manifest` to make the comparison possible; the field is additive and the fingerprint value is unchanged. A file or folder named like a macOS or iCloud sync conflict copy (`<name> 2.<ext>` beside `<name>.<ext>`) is marked as one, with a hint to remove the copies and rebuild. A build recorded before this change carries no manifest: the refusal is unchanged and says to run `record build` again to record one (campaigns-os#659).
|
|
161
|
+
|
|
162
|
+
## [1.58.0+agent.2] - 2026-10-09
|
|
163
|
+
|
|
164
|
+
### Fixed
|
|
165
|
+
|
|
166
|
+
- Doctor, and so `start` and `build`, warns `template_contract.select_step_missing` before build when the selected template family puts package selection on its own `select` page and its checkout carries no selector, but no enabled `select` page in the Map leads to a Checkout. The certified family affected today is `olympus-mv-two-step`. Without the select page, QA resolves the landing as the entry page, finds no add-to-cart control, and every order path fails after build, polish and deploy. The warning names the Checkout and funnel and the fix: add a Select page between the entry page and checkout in Map Builder. It stays silent when a `select` page routes to that Checkout, when the family's checkout carries its own selector, and for a Checkout pinned to another family through `sdk_hints.template_family`. The family's shape is read from the commerce surface catalog's `selectStep` and `mainSelector` surfaces. The warning does not block intake (campaigns-os#658).
|
|
167
|
+
- `copy.hardcoded_phone` no longer reads digit runs inside HTML comments, `<style>` blocks or CSS comments as phone numbers, such as a design-export frame name like `Group 1000003339`. Visible phone numbers still warn, at their original line numbers (campaigns-os#660).
|
|
168
|
+
|
|
169
|
+
## [1.58.0] - 2026-10-09
|
|
170
|
+
|
|
171
|
+
### Changed
|
|
172
|
+
|
|
173
|
+
Page Kit frontmatter for multi-step checkout paths follows the starter-template contract adopted in NextCommerceCo/campaign-cart-starter-templates#223. On a `select` or `checkout_step` page on a path to a Checkout, `next_url` is now the Checkout's post-payment destination, the meaning `next_url` has on every checkout page; the layouts render it as `next-success-url`, which the SDK reads for express orders. The page's forward link moves to the new `next_step` key, which the templates render as the step form's `data-next-checkout-step` and the select page's checkout link. `step_number` is unchanged. `success_url` is no longer emitted as a frontmatter key; it stays a CampaignSpec field on `checkout` pages, and the Build Context and Build Packet schemas still accept it so packets written by 1.56.0 and 1.57.0 validate. A landing page that feeds a Checkout keeps `next_url` as its call-to-action target, because every certified family's landing call-to-action reads it; it no longer carries `success_url`, and the build prompt takes an express landing page's `next-success-url` from the Checkout's own `next_url`. The build prompt and the `next-campaigns-build` skill describe the new keys. Bundled skills advance to `1.58.0+skills.1` (campaigns-os#641).
|
|
174
|
+
|
|
175
|
+
## [1.57.0+agent.1] - 2026-10-08
|
|
176
|
+
|
|
177
|
+
### Fixed
|
|
178
|
+
|
|
179
|
+
Reading a 4.2 or 4.3 spec no longer turns a `checkout → checkout` chain linked through `success_url` into Checkout Steps with no way forward. A page retyped `checkout_step` keeps the link it followed as a checkout: the resolved forward target is written to `next_page` and `success_url` is dropped, because routing ignores `success_url` on a step. Before this, the upgraded spec failed `CheckoutStepReachesCheckout` and warned `RouteFieldIgnoredForPageType` on every step. A `next_page` the checkout never took (shadowed by `success_url`) is replaced by the followed link. Chains already linked through `next_page`, and 5.x specs, read as before.
|
|
180
|
+
|
|
5
181
|
## [1.57.0] - 2026-10-08
|
|
6
182
|
|
|
7
183
|
### 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
|
|
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 <
|
|
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
|
|
329
|
-
|
|
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
|
|
@@ -86,5 +86,12 @@ export declare function paymentPagesForFunnel(funnel: Funnel | null | undefined)
|
|
|
86
86
|
* "this form moves on without taking payment". A supported v4 `schema_version`
|
|
87
87
|
* becomes `5.0`; a missing or unsupported one is left for SchemaVersion to
|
|
88
88
|
* report.
|
|
89
|
+
*
|
|
90
|
+
* A retyped page keeps the link it followed as a checkout. A `checkout_step`
|
|
91
|
+
* moves on through `next_page` only (routing.ts ignores `success_url` on it),
|
|
92
|
+
* so a v4 chain linked through `success_url` would otherwise upgrade into a
|
|
93
|
+
* step with no way forward and fail CheckoutStepReachesCheckout. The resolved
|
|
94
|
+
* forward target is written to `next_page` and `success_url` is dropped; a
|
|
95
|
+
* `next_page` the checkout shadowed (never taken) is replaced by it.
|
|
89
96
|
*/
|
|
90
97
|
export declare function upgradeCampaignSpec<T>(input: T): T;
|
|
@@ -189,6 +189,13 @@ export function paymentPagesForFunnel(funnel) {
|
|
|
189
189
|
* "this form moves on without taking payment". A supported v4 `schema_version`
|
|
190
190
|
* becomes `5.0`; a missing or unsupported one is left for SchemaVersion to
|
|
191
191
|
* report.
|
|
192
|
+
*
|
|
193
|
+
* A retyped page keeps the link it followed as a checkout. A `checkout_step`
|
|
194
|
+
* moves on through `next_page` only (routing.ts ignores `success_url` on it),
|
|
195
|
+
* so a v4 chain linked through `success_url` would otherwise upgrade into a
|
|
196
|
+
* step with no way forward and fail CheckoutStepReachesCheckout. The resolved
|
|
197
|
+
* forward target is written to `next_page` and `success_url` is dropped; a
|
|
198
|
+
* `next_page` the checkout shadowed (never taken) is replaced by it.
|
|
192
199
|
*/
|
|
193
200
|
export function upgradeCampaignSpec(input) {
|
|
194
201
|
if (input == null || typeof input !== 'object' || Array.isArray(input))
|
|
@@ -216,7 +223,16 @@ export function upgradeCampaignSpec(input) {
|
|
|
216
223
|
changed = true;
|
|
217
224
|
return {
|
|
218
225
|
...funnel,
|
|
219
|
-
pages: pages.map((page) =>
|
|
226
|
+
pages: pages.map((page) => {
|
|
227
|
+
if (!retype.has(page))
|
|
228
|
+
return page;
|
|
229
|
+
const step = { ...page, type: CHECKOUT_STEP_PAGE_TYPE };
|
|
230
|
+
const forward = forwardRouteTarget(page);
|
|
231
|
+
if (forward === null)
|
|
232
|
+
return step;
|
|
233
|
+
const { success_url: _ignoredOnStep, ...rest } = step;
|
|
234
|
+
return forward === page.next_page ? rest : { ...rest, next_page: forward };
|
|
235
|
+
}),
|
|
220
236
|
};
|
|
221
237
|
});
|
|
222
238
|
const upgradeVersion = version === '4.2' || version === '4.3';
|
package/compatibility.json
CHANGED
|
@@ -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.
|
|
6
|
-
"captured_at": "2026-10-
|
|
5
|
+
"latest_known_release": "0.4.42",
|
|
6
|
+
"captured_at": "2026-10-09"
|
|
7
7
|
},
|
|
8
8
|
"source": "contracts/campaign-cart-sdk-support-policy.v0.json",
|
|
9
9
|
"minimum_supported": "0.4.20",
|
|
@@ -848,9 +848,9 @@
|
|
|
848
848
|
}
|
|
849
849
|
},
|
|
850
850
|
"verification": {
|
|
851
|
-
"sdk_version": "0.4.
|
|
852
|
-
"verified_at": "2026-10-
|
|
853
|
-
"evidence": "sdk-0.4.
|
|
851
|
+
"sdk_version": "0.4.42",
|
|
852
|
+
"verified_at": "2026-10-16T23:13:26Z",
|
|
853
|
+
"evidence": "sdk-0.4.42-2026-10-16.2",
|
|
854
854
|
"status": "certified",
|
|
855
855
|
"source": "template-verification.json"
|
|
856
856
|
}
|
|
@@ -861,7 +861,7 @@
|
|
|
861
861
|
"id": "template-reference-apollo",
|
|
862
862
|
"family": "apollo",
|
|
863
863
|
"version": "sdk-0.4.38-composable-upsells-2026-09-25",
|
|
864
|
-
"source_commit": "
|
|
864
|
+
"source_commit": "ac529485f0a728cf9c6ac8dbcde81041bd1c6ba8",
|
|
865
865
|
"provenance_url": "https://raw.githubusercontent.com/NextCommerceCo/campaign-cart-starter-templates/main/docs/template-references/apollo/README.md",
|
|
866
866
|
"contract_path": "contracts/commerce-surface-catalog.json",
|
|
867
867
|
"standard_viewport_refs": [
|
|
@@ -1272,9 +1272,9 @@
|
|
|
1272
1272
|
}
|
|
1273
1273
|
},
|
|
1274
1274
|
"verification": {
|
|
1275
|
-
"sdk_version": "0.4.
|
|
1276
|
-
"verified_at": "2026-10-
|
|
1277
|
-
"evidence": "sdk-0.4.
|
|
1275
|
+
"sdk_version": "0.4.42",
|
|
1276
|
+
"verified_at": "2026-10-16T23:13:26Z",
|
|
1277
|
+
"evidence": "sdk-0.4.42-2026-10-16.2",
|
|
1278
1278
|
"status": "certified",
|
|
1279
1279
|
"source": "template-verification.json"
|
|
1280
1280
|
}
|
|
@@ -1583,9 +1583,9 @@
|
|
|
1583
1583
|
}
|
|
1584
1584
|
},
|
|
1585
1585
|
"verification": {
|
|
1586
|
-
"sdk_version": "0.4.
|
|
1587
|
-
"verified_at": "2026-10-
|
|
1588
|
-
"evidence": "sdk-0.4.
|
|
1586
|
+
"sdk_version": "0.4.42",
|
|
1587
|
+
"verified_at": "2026-10-16T23:13:26Z",
|
|
1588
|
+
"evidence": "sdk-0.4.42-2026-10-16.2",
|
|
1589
1589
|
"status": "certified",
|
|
1590
1590
|
"source": "template-verification.json"
|
|
1591
1591
|
}
|
|
@@ -1886,9 +1886,9 @@
|
|
|
1886
1886
|
}
|
|
1887
1887
|
},
|
|
1888
1888
|
"verification": {
|
|
1889
|
-
"sdk_version": "0.4.
|
|
1890
|
-
"verified_at": "2026-10-
|
|
1891
|
-
"evidence": "sdk-0.4.
|
|
1889
|
+
"sdk_version": "0.4.42",
|
|
1890
|
+
"verified_at": "2026-10-16T23:13:26Z",
|
|
1891
|
+
"evidence": "sdk-0.4.42-2026-10-16.2",
|
|
1892
1892
|
"status": "certified",
|
|
1893
1893
|
"source": "template-verification.json"
|
|
1894
1894
|
}
|
|
@@ -2227,9 +2227,9 @@
|
|
|
2227
2227
|
}
|
|
2228
2228
|
},
|
|
2229
2229
|
"verification": {
|
|
2230
|
-
"sdk_version": "0.4.
|
|
2231
|
-
"verified_at": "2026-10-
|
|
2232
|
-
"evidence": "sdk-0.4.
|
|
2230
|
+
"sdk_version": "0.4.42",
|
|
2231
|
+
"verified_at": "2026-10-16T23:13:26Z",
|
|
2232
|
+
"evidence": "sdk-0.4.42-2026-10-16.2",
|
|
2233
2233
|
"status": "certified",
|
|
2234
2234
|
"source": "template-verification.json"
|
|
2235
2235
|
}
|
|
@@ -2666,9 +2666,9 @@
|
|
|
2666
2666
|
}
|
|
2667
2667
|
},
|
|
2668
2668
|
"verification": {
|
|
2669
|
-
"sdk_version": "0.4.
|
|
2670
|
-
"verified_at": "2026-10-
|
|
2671
|
-
"evidence": "sdk-0.4.
|
|
2669
|
+
"sdk_version": "0.4.42",
|
|
2670
|
+
"verified_at": "2026-10-16T23:13:26Z",
|
|
2671
|
+
"evidence": "sdk-0.4.42-2026-10-16.2",
|
|
2672
2672
|
"status": "certified",
|
|
2673
2673
|
"source": "template-verification.json"
|
|
2674
2674
|
}
|
|
@@ -2686,7 +2686,6 @@
|
|
|
2686
2686
|
],
|
|
2687
2687
|
"canonicalSurfaces": {
|
|
2688
2688
|
"selectStep": "mv-selection-step",
|
|
2689
|
-
"checkoutSelector": "mv-selected-bundle-review",
|
|
2690
2689
|
"variantSlots": "bundle-slot-selector",
|
|
2691
2690
|
"personalization": "per-slot picker (data-next-property per slot, toggled by slot_personalization); order-wide default via personalization-field (ships unwired)",
|
|
2692
2691
|
"orderSummary": "cart-summary03|cart-summary04",
|
|
@@ -3023,9 +3022,9 @@
|
|
|
3023
3022
|
}
|
|
3024
3023
|
},
|
|
3025
3024
|
"verification": {
|
|
3026
|
-
"sdk_version": "0.4.
|
|
3027
|
-
"verified_at": "2026-10-
|
|
3028
|
-
"evidence": "sdk-0.4.
|
|
3025
|
+
"sdk_version": "0.4.42",
|
|
3026
|
+
"verified_at": "2026-10-16T23:13:26Z",
|
|
3027
|
+
"evidence": "sdk-0.4.42-2026-10-16.2",
|
|
3029
3028
|
"status": "certified",
|
|
3030
3029
|
"source": "template-verification.json"
|
|
3031
3030
|
}
|
|
@@ -3313,9 +3312,9 @@
|
|
|
3313
3312
|
}
|
|
3314
3313
|
},
|
|
3315
3314
|
"verification": {
|
|
3316
|
-
"sdk_version": "0.4.
|
|
3317
|
-
"verified_at": "2026-10-
|
|
3318
|
-
"evidence": "sdk-0.4.
|
|
3315
|
+
"sdk_version": "0.4.42",
|
|
3316
|
+
"verified_at": "2026-10-16T23:13:26Z",
|
|
3317
|
+
"evidence": "sdk-0.4.42-2026-10-16.2",
|
|
3319
3318
|
"status": "certified",
|
|
3320
3319
|
"source": "template-verification.json"
|
|
3321
3320
|
}
|
|
@@ -3504,6 +3503,6 @@
|
|
|
3504
3503
|
}
|
|
3505
3504
|
},
|
|
3506
3505
|
"_synced_from_repo": "NextCommerceCo/campaign-cart-starter-templates",
|
|
3507
|
-
"_synced_from_ref": "
|
|
3508
|
-
"_synced_from_sha": "
|
|
3506
|
+
"_synced_from_ref": "main",
|
|
3507
|
+
"_synced_from_sha": "3987b18a356cb961b06c94b2035622bafe938316"
|
|
3509
3508
|
}
|
|
@@ -6267,8 +6267,8 @@
|
|
|
6267
6267
|
"sends": [
|
|
6268
6268
|
{
|
|
6269
6269
|
"destination": "{base-url}",
|
|
6270
|
-
"what": "a GET for each built page under the served URL, to prove the
|
|
6271
|
-
"when": "the
|
|
6270
|
+
"what": "a GET for each built page under the served URL, to prove the preview answers before it is recorded, and on a hosted target a GET for each script and stylesheet the built pages load from that origin, to compare its bytes with the built output",
|
|
6271
|
+
"when": "--base-url names the campaign's route root on a loopback origin (deploy target local-serve) or an https origin (any other deploy target; plain http only on a loopback host)",
|
|
6272
6272
|
"requires_consent": false,
|
|
6273
6273
|
"observed_in": [
|
|
6274
6274
|
"no_session",
|
|
@@ -6281,7 +6281,7 @@
|
|
|
6281
6281
|
],
|
|
6282
6282
|
"effect_test": "effects: record deploy",
|
|
6283
6283
|
"test_scope": "full",
|
|
6284
|
-
"notes": "Destructive: it replaces stages.deploy, stamped with the build fingerprint it probed, and the packet's deploy.preview_url.
|
|
6284
|
+
"notes": "Destructive: it replaces stages.deploy, stamped with the build fingerprint it probed, and the packet's deploy.preview_url. On a local-serve packet the requests stay on this machine: --base-url must be a loopback origin. On any other deploy target --base-url is an https origin and the served scripts and stylesheets are compared by sha256 with the built output (HTML is not compared). Refused, writing nothing but the lifecycle entry, when the URL breaks those rules or is not the campaign's route root, a built page does not answer (2xx locally, 200 hosted), a served asset is missing or differs, polish is not recorded, build or Polish is owed again after a brief or CampaignSpec change or its record does not say which content it was made against, the built output changed since build was recorded or a record build of other output lands between the probe and the write (on either deploy target), or the theme gate is blocked. The Build Context is read, not written."
|
|
6285
6285
|
},
|
|
6286
6286
|
{
|
|
6287
6287
|
"command": "record",
|
|
@@ -6300,8 +6300,8 @@
|
|
|
6300
6300
|
"sends": [
|
|
6301
6301
|
{
|
|
6302
6302
|
"destination": "{base-url}",
|
|
6303
|
-
"what": "a GET for each built page under the served URL, to prove the
|
|
6304
|
-
"when": "the
|
|
6303
|
+
"what": "a GET for each built page under the served URL, to prove the preview answers before it is recorded, and on a hosted target a GET for each script and stylesheet the built pages load from that origin, to compare its bytes with the built output",
|
|
6304
|
+
"when": "--base-url names the campaign's route root on a loopback origin (deploy target local-serve) or an https origin (any other deploy target; plain http only on a loopback host)",
|
|
6305
6305
|
"requires_consent": false,
|
|
6306
6306
|
"observed_in": [
|
|
6307
6307
|
"no_session",
|