@nextcommerce/campaigns-os 1.53.0 → 1.54.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 +61 -0
- package/README.md +1 -0
- package/compatibility.json +1 -1
- package/contracts/campaign-cart-checkout-field-contract.v0.json +10 -0
- package/contracts/campaign-cart-sdk-support-policy.v0.json +2 -2
- package/contracts/commerce-surface-catalog.json +27 -27
- package/contracts/effects.v1.json +96 -37
- package/contracts/release-ledger.json +333 -0
- package/contracts/supported-surface.json +3 -3
- package/contracts/template-brand-contract.shared-commerce.v0.json +1 -1
- package/docs/build-packet.md +11 -4
- package/docs/campaign-standardization-report.md +32 -0
- package/docs/design-source-package.md +7 -3
- package/docs/effects.md +2 -1
- package/docs/local-setup.md +1 -1
- package/docs/orientation-contract-reference.md +1 -1
- package/docs/progress-snapshots.md +3 -1
- package/docs/qa-and-test-orders.md +28 -3
- package/docs/runtime-readiness.md +1 -1
- package/docs/sdk-storage-compatibility.md +15 -0
- package/docs/skills-revision.md +10 -10
- package/docs/supported-surface.md +1 -0
- package/package.json +1 -1
- package/schemas/campaign-runtime-assembly-report.v0.schema.json +5 -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 +3 -3
- 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 +3 -3
- package/skills/next-campaigns-qa/SKILL.md +3 -3
- package/skills.json +10 -10
- package/src/campaign-ecosystem.mjs +153 -31
- package/src/cli.mjs +22 -3
- package/src/directory-lock.mjs +79 -7
- package/src/doctor/checks.mjs +12 -2
- package/src/doctor/inspect.mjs +13 -0
- package/src/invocation.mjs +3 -1
- package/src/progress-node.mjs +3 -2
- package/src/qa-browser.mjs +80 -9
- package/src/qa-node.mjs +33 -4
- package/src/sdk-attribute-index.mjs +111 -23
- package/src/sdk-markup.mjs +49 -10
- package/src/sdk-repin.mjs +282 -0
- package/src/stage-ledger.mjs +1 -1
- package/src/stage-record.mjs +37 -6
- package/src/standardization-report.mjs +26 -1
- package/src/target-lock.mjs +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,67 @@
|
|
|
2
2
|
|
|
3
3
|
Notable supported-surface changes are recorded here.
|
|
4
4
|
|
|
5
|
+
## [1.54.0] - 2026-10-07
|
|
6
|
+
|
|
7
|
+
Ships the same-surface changes 1.53.0+agent.1 through +agent.11 (+agent.6 and +agent.8 were never used), including the `qa run --test-order` fix for Campaign Cart SDK 0.4.41 card fields (+agent.5) and the starter catalog, SDK attribute index and support policy at 0.4.41 (+agent.10, +agent.11).
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
`campaigns-os sdk repin --target <repo> [--target-sdk <x.y.z>] [--apply] [--json]` updates the Campaign Cart SDK pins written into a static campaign repo's HTML, the `loader.js` and `campaign-cart.css` URLs that `standardize` already lists with path and line. It rewrites only a semver pin (`@vX.Y.Z` or `@X.Y.Z`) below the target version, and only the version part of the URL. `@latest`, `@main`, commit and prerelease refs, and pins already at or above the target, are listed and left alone. Without `--target-sdk` the target is the SDK support policy's `preferred_minimum`. By default it only previews, printing each path and line with the old and new URL. `--apply` writes the files and a change record at `.campaign-runtime/sdk-repin.json` with the files touched, the reference count and the from and to versions, which a Run Record can cite. A second run finds nothing to change and writes nothing. A repo with `_data/campaigns.json` is refused with exit 2, because page-kit owns that pin; use `page-kit sync` there. This replaces the hand-run `sed` step in the SDK bump for static repos.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
`qa run` no longer publishes a verdict to the QA portal by default when the base URL is a local address (`localhost` or any `*.localhost` name, any `127.x.x.x` address, `0.0.0.0`, `[::1]` or an IPv4-mapped loopback), whether the spec came from a saved Map or a local file. The verdict stays local, and the output names the destination plus `qa publish` and `--post-verdict`. Pass `--post-verdict` to publish a local-address run. `publish_decision.reason` reads `loopback_base_url` when this default applied. Runs against a remote base URL publish exactly as before. The `--post-verdict` help line now names the IPv4-mapped loopback too.
|
|
16
|
+
|
|
17
|
+
`record deploy` now stamps `stages.deploy.source_build_fingerprint` with the recorded build it probed. When a later `record build` records different output, a deploy stamped with the old build becomes `required` (`required_by` build, `required_for` qa), its old probe (`outputs` and `evidence`) leaves the live stage and the prior record is kept in `stages.deploy.history`, and `next` routes back to `record deploy` before QA. A rebuild with byte-identical output keeps the deploy current. A deploy recorded before this change carries no stamp and is kept as recorded. The Assembly Report schema describes the field.
|
|
18
|
+
|
|
19
|
+
The effects contract declares the `sdk repin` and `sdk repin --apply` rows, and its `record deploy` and `record build` rows say a deploy is stamped with the build it probed and owed again after a build of other output. On the eight `qa run` rows, the verdict send to `{proxy-base}/api/qa/verdicts` now names the local-address default in its condition, and the offline fixture no longer observes it because it serves the campaign from 127.0.0.1; `qa publish` proves that send.
|
|
20
|
+
|
|
21
|
+
## [1.53.0+agent.11] - 2026-10-07
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
The bundled Campaign Cart SDK support policy records 0.4.41 as the latest known release (`provenance.latest_known_release`, was 0.4.38). With the starter catalog verified against 0.4.41 (1.53.0+agent.10), template freshness already took 0.4.41 as the current SDK, so no family's freshness changes; the policy now agrees with the catalog instead of naming a release three behind it, and "current SDK" is reported from the policy. `minimum_supported` (0.4.20) and `preferred_minimum` (0.4.30) are unchanged.
|
|
26
|
+
|
|
27
|
+
## [1.53.0+agent.10] - 2026-10-07
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- The vendored starter-template catalog is re-synced to campaign-cart-starter-templates `7833290` (was `2c61894`). Every certified family now records Campaign Cart SDK 0.4.41 verification evidence (`sdk-0.4.41-2026-10-06.5`, a `lint-sdk` pass), and the eight agent CampaignSpec fixtures pin `sdk_version` 0.4.41. Doctor's missing-SDK-pin message therefore names 0.4.41 as the version a family was verified against. The certified-family render fixtures are regenerated at the new pin: the loader moves to 0.4.41, and the checkout and receipt pages pick up the starters' SDK address blocks (`data-next-address`) and the savings badge drawn from the summary token. The payment-chrome `asset_pin` moves to the same commit; the five hashed assets are byte-identical there.
|
|
32
|
+
- The SDK attribute index (`src/sdk-attribute-index.mjs`) moves from v0.4.38 to v0.4.41. v0.4.41 removed the generated `docs/attribute-index.md` the old recipe read, and the SDK's hand-written attribute docs leave out names its source still reads. The list is now regenerated from the SDK source at the tag (every `data-next-*` string and `dataset.next*` property in non-test TypeScript), and that recipe is in the file. It keeps all 135 names of the v0.4.38 list and adds 14: the address block (`data-next-address`, `-lang`, `-api`, `-field`, `-row`, `-state`), `data-next-i18n`, `data-next-phone-e164`, `data-next-phone-country`, `data-next-bump-section`, `data-next-button-text`, and the variant option state (`data-next-variant-name`, `-value`, `data-next-unavailable`). `built_output.sdk_markup` no longer reports these as unknown, and its findings now name `sdk_attribute_index_version` 0.4.41. The checkout field names are unchanged at v0.4.41.
|
|
33
|
+
- The raw cart placeholder check (`built_output.cart_placeholders`) accepts pages pinned to 0.4.41: all ten renderer files it was generated from have the same git blob ids at v0.4.38 and v0.4.41. Before, every 0.4.41 page reported `unexercised` (`sdk_pin_unverified`).
|
|
34
|
+
|
|
35
|
+
## [1.53.0+agent.9] - 2026-10-06
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
The per-target lock now tells an ownerless lock apart from something at the lock path that is not a lock. When the wait ends on an ordinary file, a symbolic link, or a directory with no owner record that holds other entries, the refusal names what is there and says it is never removed automatically; before, it read as a busy or ownerless lock. An empty ownerless lock directory is still refused as before. The holder of a lock also clears the staging, recovery-staging and released directories that a crashed process or a failed release left beside the lock, but only those whose recorded owner process no longer exists; a sibling with a live or unreadable owner is left alone.
|
|
40
|
+
|
|
41
|
+
## [1.53.0+agent.7] - 2026-10-06
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
`doctor --built --base-url <url>` now says that it checked the local built files only. The URL is not fetched: it fills `deploy.preview_url` in the minimal Build Packet. The output names `qa run --site <repo> --base-url <url> --family <family> --browser` as the command that loads the served pages, and `--json` carries `derived.base_url` with `fetched: false`. The checks themselves are unchanged.
|
|
46
|
+
|
|
47
|
+
## [1.53.0+agent.5] - 2026-10-06
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
|
|
51
|
+
- `qa run --test-order` types the test card on pages running Campaign Cart SDK 0.4.41. That release draws the card number and CVV with the fields NEXT's `payments.29next.com` script mounts, whose iframes are named `spreedly-hosted-number-…` and `spreedly-hosted-cvv-…`; the runner looked only for the `spreedly-number-frame-…` and `spreedly-cvv-frame-…` iframes of 0.4.40 and earlier, so on a 0.4.41 checkout it timed out before submitting. It now finds either, and nothing changes on pages pinned to 0.4.40 or earlier. A checkout carrying both kinds of card iframe, or two of either, fails at `card_fields_filled` with the iframe ids it found instead of typing into whichever comes first, and the step's evidence records which iframes it typed into.
|
|
52
|
+
- `qa run --test-order` no longer loses card digits typed before the card fields are ready. On SDK 0.4.41 the hosted number input appears before its script has loaded, and digits typed in that window are dropped. The SDK then refuses the shortened number without tokenizing, so the run timed out at `order_submitted` 45 seconds later with no order created. This happened about once in 33 live runs, usually when the card fields loaded slowly. The runner now waits up to 15 seconds for the checkout form to drop its `next-loading-spreedly` class (SDK 0.4.38 to 0.4.41 set it until the card fields are ready); if it is still there, `card_fields_filled` fails and says the card script never finished loading. It then reads the card number and CVV back, and retypes up to three attempts in all. If the fields still don't hold the card, `card_fields_filled` fails and names what the fields held, instead of the run timing out at submit.
|
|
53
|
+
|
|
54
|
+
## [1.53.0+agent.4] - 2026-10-06
|
|
55
|
+
|
|
56
|
+
### Fixed
|
|
57
|
+
|
|
58
|
+
- The checkout field-name checks now read the SDK version of the page they judge. `first_name` and `last_name` pass on Campaign Cart SDK 0.4.39 and later, and `phone_number` passes on 0.4.41 and later; `fname`, `lname` and `phone` still pass on every version. Earlier releases blocked `first_name` and `last_name` (`built_output.sdk_markup` `WRONG_FIELD_NAME`, and `checkout.unsupported_field_binding` in `standardize`) and flagged `phone_number` on every SDK, so a page written to the 0.4.41 field names failed doctor although the SDK maps them. Doctor reads the page's own exact loader pin, then the campaign's `sdk_version` in `_data/campaigns.json`. `standardize` reads the file's own loader pin, then the lowest exact pin the campaign declares (for a bundled `campaign-cart` dependency, an exact pin or the floor of a `^`, `~` or `>=` range). When neither gives an exact released version, the checks keep their earlier behaviour, because `fname`, `lname` and `phone` work on every version. Below a name's version the result is also unchanged, and the message names the version the name needs. Findings and bindings now record the SDK version they were judged against.
|
|
59
|
+
|
|
60
|
+
## [1.53.0+agent.3] - 2026-10-06
|
|
61
|
+
|
|
62
|
+
### Fixed
|
|
63
|
+
|
|
64
|
+
- `standardize` now judges a bundled `campaign-cart` dependency against the SDK support policy by the lowest version its `package.json` spec allows. Earlier releases took the version written in the spec, so `<0.4.39` was evaluated as 0.4.39 and `0.4.41 || 0.4.10` as 0.4.41, and both could pass the minimum although npm may install an older SDK. An exact pin or one `^`, `~` or `>=` range on a released version is evaluated by that version, as before. Any other spec gets no policy evaluation and raises the new warning `version.sdk_dependency_floor_unknown`. The lowest version is recorded as `sdk_loader.bundled_dependency.floor_version`.
|
|
65
|
+
|
|
5
66
|
## [1.53.0+agent.2] - 2026-10-05
|
|
6
67
|
|
|
7
68
|
### Changed
|
package/README.md
CHANGED
|
@@ -290,6 +290,7 @@ npm run campaigns-os -- doctor --packet <page-kit-repo>/campaign-runtime.build.j
|
|
|
290
290
|
npm run campaigns-os -- page-kit sync --packet <page-kit-repo>/campaign-runtime.build.json --dry-run
|
|
291
291
|
npm run campaigns-os -- checkpoint waive --packet <packet.json> --gate source_html.producer_provenance --page <page_id> --reason "<why>" --waived-by "<named human>" --review-condition "<trigger>" --dry-run
|
|
292
292
|
npm run campaigns-os -- sdk storage-check --target <campaign-git-root> --target-sdk 0.4.38 --manifest <sdk-storage-manifest.json> --scope <campaign,shared> --json
|
|
293
|
+
npm run campaigns-os -- sdk repin --target <static-campaign-repo> --target-sdk 0.4.38
|
|
293
294
|
npm run campaigns-os -- standardize --target <page-kit-repo-or-cpk-repo> --json
|
|
294
295
|
npm run campaigns-os -- theme inspect --packet <page-kit-repo>/campaign-runtime.build.json --json
|
|
295
296
|
npm run campaigns-os -- theme generate --packet <page-kit-repo>/campaign-runtime.build.json --json
|
package/compatibility.json
CHANGED
|
@@ -31,6 +31,16 @@
|
|
|
31
31
|
"cc-year": "exp-year"
|
|
32
32
|
},
|
|
33
33
|
"prefixes": ["billing-"],
|
|
34
|
+
"version_gated_aliases": {
|
|
35
|
+
"first_name": { "canonical": "fname", "since": "0.4.39" },
|
|
36
|
+
"last_name": { "canonical": "lname", "since": "0.4.39" },
|
|
37
|
+
"phone_number": { "canonical": "phone", "since": "0.4.41" }
|
|
38
|
+
},
|
|
39
|
+
"version_gated_provenance": {
|
|
40
|
+
"source": "NextCommerceCo/campaign-cart src/utils/checkout-field-names.ts at v0.4.39 (first_name, last_name; v0.4.40 is the same SDK) and v0.4.41 (phone_number), and v0.4.41 docs/guides/reference/data-attributes.md (Field names)",
|
|
41
|
+
"rule": "A version-gated alias is supported when the binding's SDK version is an exact release at or after since. Below since, or when the version is unknown, the alias is judged as on an earlier SDK: a name also listed in stale_aliases is a stale alias, any other is unknown. The canonical name is supported on every version.",
|
|
42
|
+
"captured_at": "2026-10-06"
|
|
43
|
+
},
|
|
34
44
|
"stale_aliases": {
|
|
35
45
|
"state": "province",
|
|
36
46
|
"region": "province",
|
|
@@ -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-
|
|
5
|
+
"latest_known_release": "0.4.41",
|
|
6
|
+
"captured_at": "2026-10-07"
|
|
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.41",
|
|
852
|
+
"verified_at": "2026-10-06T23:03:41Z",
|
|
853
|
+
"evidence": "sdk-0.4.41-2026-10-06.5",
|
|
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": "1a3bf7218e7f10ef5733ceba84d2856eeca2cfbd",
|
|
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.41",
|
|
1276
|
+
"verified_at": "2026-10-06T23:03:41Z",
|
|
1277
|
+
"evidence": "sdk-0.4.41-2026-10-06.5",
|
|
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.41",
|
|
1587
|
+
"verified_at": "2026-10-06T23:03:41Z",
|
|
1588
|
+
"evidence": "sdk-0.4.41-2026-10-06.5",
|
|
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.41",
|
|
1890
|
+
"verified_at": "2026-10-06T23:03:41Z",
|
|
1891
|
+
"evidence": "sdk-0.4.41-2026-10-06.5",
|
|
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.41",
|
|
2231
|
+
"verified_at": "2026-10-06T23:03:41Z",
|
|
2232
|
+
"evidence": "sdk-0.4.41-2026-10-06.5",
|
|
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.41",
|
|
2670
|
+
"verified_at": "2026-10-06T23:03:41Z",
|
|
2671
|
+
"evidence": "sdk-0.4.41-2026-10-06.5",
|
|
2672
2672
|
"status": "certified",
|
|
2673
2673
|
"source": "template-verification.json"
|
|
2674
2674
|
}
|
|
@@ -3023,9 +3023,9 @@
|
|
|
3023
3023
|
}
|
|
3024
3024
|
},
|
|
3025
3025
|
"verification": {
|
|
3026
|
-
"sdk_version": "0.4.
|
|
3027
|
-
"verified_at": "2026-10-
|
|
3028
|
-
"evidence": "sdk-0.4.
|
|
3026
|
+
"sdk_version": "0.4.41",
|
|
3027
|
+
"verified_at": "2026-10-06T23:03:41Z",
|
|
3028
|
+
"evidence": "sdk-0.4.41-2026-10-06.5",
|
|
3029
3029
|
"status": "certified",
|
|
3030
3030
|
"source": "template-verification.json"
|
|
3031
3031
|
}
|
|
@@ -3313,9 +3313,9 @@
|
|
|
3313
3313
|
}
|
|
3314
3314
|
},
|
|
3315
3315
|
"verification": {
|
|
3316
|
-
"sdk_version": "0.4.
|
|
3317
|
-
"verified_at": "2026-10-
|
|
3318
|
-
"evidence": "sdk-0.4.
|
|
3316
|
+
"sdk_version": "0.4.41",
|
|
3317
|
+
"verified_at": "2026-10-06T23:03:41Z",
|
|
3318
|
+
"evidence": "sdk-0.4.41-2026-10-06.5",
|
|
3319
3319
|
"status": "certified",
|
|
3320
3320
|
"source": "template-verification.json"
|
|
3321
3321
|
}
|
|
@@ -3504,6 +3504,6 @@
|
|
|
3504
3504
|
}
|
|
3505
3505
|
},
|
|
3506
3506
|
"_synced_from_repo": "NextCommerceCo/campaign-cart-starter-templates",
|
|
3507
|
-
"_synced_from_ref": "
|
|
3508
|
-
"_synced_from_sha": "
|
|
3507
|
+
"_synced_from_ref": "783329017c6994a94d11e46580c33bd052aabdb0",
|
|
3508
|
+
"_synced_from_sha": "783329017c6994a94d11e46580c33bd052aabdb0"
|
|
3509
3509
|
}
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"observed_in": "The conditions in which the effect test must SEE this write or send. An empty list declares an effect the offline fixture cannot reach; it then requires a not_observed_reason, and check-effects refuses the row without one. The test always refuses an effect that is NOT declared, in every condition.",
|
|
43
43
|
"effect_changing_flags": [
|
|
44
|
+
"--apply",
|
|
44
45
|
"--browser",
|
|
45
46
|
"--built",
|
|
46
47
|
"--dry-run",
|
|
@@ -233,6 +234,72 @@
|
|
|
233
234
|
"test_scope": "full",
|
|
234
235
|
"notes": "A static scan of tracked source in a Git checkout. Exempted from lifecycle capture by name in persistLifecycleIfRequested, and it bypasses the stale-session sweep."
|
|
235
236
|
},
|
|
237
|
+
{
|
|
238
|
+
"command": "sdk",
|
|
239
|
+
"subcommand": "repin",
|
|
240
|
+
"flags": [],
|
|
241
|
+
"annotations": {
|
|
242
|
+
"readOnlyHint": true,
|
|
243
|
+
"destructiveHint": false,
|
|
244
|
+
"openWorldHint": false,
|
|
245
|
+
"idempotentHint": true
|
|
246
|
+
},
|
|
247
|
+
"tier": "none",
|
|
248
|
+
"writes": [],
|
|
249
|
+
"sends": [],
|
|
250
|
+
"effect_test": "effects: sdk repin",
|
|
251
|
+
"test_scope": "full",
|
|
252
|
+
"notes": "The preview: it reads the target's HTML and script files and prints each semver-pinned Campaign Cart loader.js / campaign-cart.css reference below the target version with its rewrite, and the references it leaves alone. It writes nothing, appends no lifecycle entry (only --apply journals; the subcommand is declared journal-exempt without it in src/invocation.mjs), runs no stale-session closeout and sends nothing. A target holding _data/campaigns.json is refused (exit 2) with the same result: nothing written."
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"command": "sdk",
|
|
256
|
+
"subcommand": "repin",
|
|
257
|
+
"flags": [
|
|
258
|
+
"--apply"
|
|
259
|
+
],
|
|
260
|
+
"annotations": {
|
|
261
|
+
"readOnlyHint": false,
|
|
262
|
+
"destructiveHint": false,
|
|
263
|
+
"openWorldHint": false,
|
|
264
|
+
"idempotentHint": true
|
|
265
|
+
},
|
|
266
|
+
"tier": "B",
|
|
267
|
+
"writes": [
|
|
268
|
+
{
|
|
269
|
+
"path": "{target}/**",
|
|
270
|
+
"when": "an HTML or script file under the target holds a semver-pinned Campaign Cart loader.js / campaign-cart.css URL below the target version; only the version segment of each such URL changes",
|
|
271
|
+
"observed_in": [
|
|
272
|
+
"no_session",
|
|
273
|
+
"ambient_session",
|
|
274
|
+
"stale_session",
|
|
275
|
+
"lifecycle_log",
|
|
276
|
+
"persisted_consent"
|
|
277
|
+
]
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
"path": "{target}/.campaign-runtime/sdk-repin.json",
|
|
281
|
+
"when": "at least one reference was rewritten: the change record (campaigns-os-sdk-repin/v0) is (re)written",
|
|
282
|
+
"observed_in": [
|
|
283
|
+
"no_session",
|
|
284
|
+
"ambient_session",
|
|
285
|
+
"stale_session",
|
|
286
|
+
"lifecycle_log",
|
|
287
|
+
"persisted_consent"
|
|
288
|
+
]
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"path": "{lifecycle-journal}",
|
|
292
|
+
"when": "a lifecycle journal is selected for the invocation — an active run session, --lifecycle-journal, or CAMPAIGNS_OS_LIFECYCLE_LOG",
|
|
293
|
+
"observed_in": [
|
|
294
|
+
"lifecycle_log"
|
|
295
|
+
]
|
|
296
|
+
}
|
|
297
|
+
],
|
|
298
|
+
"sends": [],
|
|
299
|
+
"effect_test": "effects: sdk repin --apply",
|
|
300
|
+
"test_scope": "full",
|
|
301
|
+
"notes": "Rewrites the version segment of each semver-pinned reference below the target and writes the change record; @latest, @main, commit and prerelease refs and pins at or above the target are left alone. A second run with the same target finds nothing to change and writes nothing. `sdk repin --target <repo>` names no packet, so an ambient session bound to a packet elsewhere is not resolved for it and no entry is appended under that session. A target holding _data/campaigns.json is refused (exit 2) and nothing is written."
|
|
302
|
+
},
|
|
236
303
|
{
|
|
237
304
|
"command": "tooling",
|
|
238
305
|
"subcommand": "diagnose",
|
|
@@ -2202,11 +2269,10 @@
|
|
|
2202
2269
|
{
|
|
2203
2270
|
"destination": "{proxy-base}/api/qa/verdicts",
|
|
2204
2271
|
"what": "the QA verdict for the attempt, published to the QA portal",
|
|
2205
|
-
"when": "
|
|
2272
|
+
"when": "--post-verdict is given; or, by default (no --no-post-verdict), the base URL is not a local address (localhost, *.localhost, 127.x.x.x, 0.0.0.0, [::1], an IPv4-mapped loopback) and the consent seam allows it — Run Telemetry consent on for the endpoint, or a portal-managed campaign; never for a local-spec packet",
|
|
2206
2273
|
"requires_consent": true,
|
|
2207
|
-
"observed_in": [
|
|
2208
|
-
|
|
2209
|
-
]
|
|
2274
|
+
"observed_in": [],
|
|
2275
|
+
"not_observed_reason": "the offline fixture serves the campaign from a 127.0.0.1 base URL, a local address, so the default keeps the verdict local (#486); qa publish proves this send"
|
|
2210
2276
|
},
|
|
2211
2277
|
{
|
|
2212
2278
|
"destination": "{base-url}",
|
|
@@ -2244,7 +2310,7 @@
|
|
|
2244
2310
|
],
|
|
2245
2311
|
"effect_test": "effects: qa run",
|
|
2246
2312
|
"test_scope": "full",
|
|
2247
|
-
"notes": "Destructive and not idempotent: each attempt overwrites the committed verdict sidecar and the report's QA stage, and a ready verdict clears the ambient run session. It SENDS on a blocked attempt too: the
|
|
2313
|
+
"notes": "Destructive and not idempotent: each attempt overwrites the committed verdict sidecar and the report's QA stage, and a ready verdict clears the ambient run session. It SENDS on a blocked attempt too: the QA stage progress observation to {proxy-base}/api/progress under persisted consent for the endpoint, and the verdict to {proxy-base}/api/qa/verdicts under the same consent unless the base URL is a local address, which keeps the verdict local by default (#486; --post-verdict still sends it). Publishing rides the telemetry consent seam rather than a flag of its own, so the four consent-off conditions saw neither request. Local-spec packets retain verdicts in the repository and never send a QA verdict or progress to the Map portal, even with --post-verdict. When a served page was read and a public Campaigns API key resolves, it also makes one read-only GET of {proxy-base}/api/campaign under X-Campaign-Key to check the served pages' shipping and package refs against the live campaign (#533); without a key or a page, or on a failed read, the verdict records the check as not_run with its reason. --no-live-refs skips that read (its own row)."
|
|
2248
2314
|
},
|
|
2249
2315
|
{
|
|
2250
2316
|
"command": "qa",
|
|
@@ -2335,11 +2401,10 @@
|
|
|
2335
2401
|
{
|
|
2336
2402
|
"destination": "{proxy-base}/api/qa/verdicts",
|
|
2337
2403
|
"what": "the QA verdict for the attempt, published to the QA portal",
|
|
2338
|
-
"when": "
|
|
2404
|
+
"when": "--post-verdict is given; or, by default (no --no-post-verdict), the base URL is not a local address (localhost, *.localhost, 127.x.x.x, 0.0.0.0, [::1], an IPv4-mapped loopback) and the consent seam allows it — Run Telemetry consent on for the endpoint, or a portal-managed campaign; never for a local-spec packet",
|
|
2339
2405
|
"requires_consent": true,
|
|
2340
|
-
"observed_in": [
|
|
2341
|
-
|
|
2342
|
-
]
|
|
2406
|
+
"observed_in": [],
|
|
2407
|
+
"not_observed_reason": "the offline fixture serves the campaign from a 127.0.0.1 base URL, a local address, so the default keeps the verdict local (#486); qa publish proves this send"
|
|
2343
2408
|
},
|
|
2344
2409
|
{
|
|
2345
2410
|
"destination": "{base-url}",
|
|
@@ -2583,11 +2648,10 @@
|
|
|
2583
2648
|
{
|
|
2584
2649
|
"destination": "{proxy-base}/api/qa/verdicts",
|
|
2585
2650
|
"what": "the QA verdict for the attempt, published to the QA portal",
|
|
2586
|
-
"when": "
|
|
2651
|
+
"when": "--post-verdict is given; or, by default (no --no-post-verdict), the base URL is not a local address (localhost, *.localhost, 127.x.x.x, 0.0.0.0, [::1], an IPv4-mapped loopback) and the consent seam allows it — Run Telemetry consent on for the endpoint, or a portal-managed campaign; never for a local-spec packet",
|
|
2587
2652
|
"requires_consent": true,
|
|
2588
|
-
"observed_in": [
|
|
2589
|
-
|
|
2590
|
-
]
|
|
2653
|
+
"observed_in": [],
|
|
2654
|
+
"not_observed_reason": "the offline fixture serves the campaign from a 127.0.0.1 base URL, a local address, so the default keeps the verdict local (#486); qa publish proves this send"
|
|
2591
2655
|
},
|
|
2592
2656
|
{
|
|
2593
2657
|
"destination": "{base-url}",
|
|
@@ -2625,7 +2689,7 @@
|
|
|
2625
2689
|
],
|
|
2626
2690
|
"effect_test": "effects: qa run --test-order",
|
|
2627
2691
|
"test_scope": "full",
|
|
2628
|
-
"notes": "The most consequential row in the file: --test-order places REAL orders against the store under test. Destructive, open-world, not idempotent. It SENDS on a blocked attempt too: the
|
|
2692
|
+
"notes": "The most consequential row in the file: --test-order places REAL orders against the store under test. Destructive, open-world, not idempotent. It SENDS on a blocked attempt too: the QA stage progress observation to {proxy-base}/api/progress under persisted consent for the endpoint, and the verdict to {proxy-base}/api/qa/verdicts under the same consent unless the base URL is a local address, which keeps the verdict local by default (#486; --post-verdict still sends it). Publishing rides the telemetry consent seam rather than a flag of its own, so the four consent-off conditions saw neither request. Local-spec packets retain verdicts in the repository and never send a QA verdict or progress to the Map portal, even with --post-verdict. When a served page was read and a public Campaigns API key resolves, it also makes one read-only GET of {proxy-base}/api/campaign under X-Campaign-Key to check the served pages' shipping and package refs against the live campaign (#533); without a key or a page, or on a failed read, the verdict records the check as not_run with its reason. --no-live-refs skips that read (its own row)."
|
|
2629
2693
|
},
|
|
2630
2694
|
{
|
|
2631
2695
|
"command": "qa",
|
|
@@ -2716,11 +2780,10 @@
|
|
|
2716
2780
|
{
|
|
2717
2781
|
"destination": "{proxy-base}/api/qa/verdicts",
|
|
2718
2782
|
"what": "the QA verdict for the attempt, published to the QA portal",
|
|
2719
|
-
"when": "
|
|
2783
|
+
"when": "--post-verdict is given; or, by default (no --no-post-verdict), the base URL is not a local address (localhost, *.localhost, 127.x.x.x, 0.0.0.0, [::1], an IPv4-mapped loopback) and the consent seam allows it — Run Telemetry consent on for the endpoint, or a portal-managed campaign; never for a local-spec packet",
|
|
2720
2784
|
"requires_consent": true,
|
|
2721
|
-
"observed_in": [
|
|
2722
|
-
|
|
2723
|
-
]
|
|
2785
|
+
"observed_in": [],
|
|
2786
|
+
"not_observed_reason": "the offline fixture serves the campaign from a 127.0.0.1 base URL, a local address, so the default keeps the verdict local (#486); qa publish proves this send"
|
|
2724
2787
|
},
|
|
2725
2788
|
{
|
|
2726
2789
|
"destination": "{base-url}",
|
|
@@ -2766,7 +2829,7 @@
|
|
|
2766
2829
|
],
|
|
2767
2830
|
"effect_test": "effects: qa run --browser (preflight)",
|
|
2768
2831
|
"test_scope": "preflight",
|
|
2769
|
-
"notes": "PREFLIGHT-PROVED: --browser needs an installed Chromium and a reachable campaign, neither of which exists offline. The case proves the attempt is blocked at the same gate as the node run and writes exactly the blocked-attempt evidence. It SENDS on a blocked attempt too: the
|
|
2832
|
+
"notes": "PREFLIGHT-PROVED: --browser needs an installed Chromium and a reachable campaign, neither of which exists offline. The case proves the attempt is blocked at the same gate as the node run and writes exactly the blocked-attempt evidence. It SENDS on a blocked attempt too: the QA stage progress observation to {proxy-base}/api/progress under persisted consent for the endpoint, and the verdict to {proxy-base}/api/qa/verdicts under the same consent unless the base URL is a local address, which keeps the verdict local by default (#486; --post-verdict still sends it). Publishing rides the telemetry consent seam rather than a flag of its own, so the four consent-off conditions saw neither request. Local-spec packets retain verdicts in the repository and never send a QA verdict or progress to the Map portal, even with --post-verdict. When a served page was read and a public Campaigns API key resolves, it also makes one read-only GET of {proxy-base}/api/campaign under X-Campaign-Key to check the served pages' shipping and package refs against the live campaign (#533); without a key or a page, or on a failed read, the verdict records the check as not_run with its reason. --no-live-refs skips that read (its own row). Once the page checks run, it also sends the header-only GETs to the configured http(s) store policy URLs (their own row) to check the served pages' policy links; offline the run is blocked at the gate before any page is checked, so none is sent.",
|
|
2770
2833
|
"preflight": {
|
|
2771
2834
|
"may_write": [
|
|
2772
2835
|
"{target}/qa-output/**",
|
|
@@ -2872,11 +2935,10 @@
|
|
|
2872
2935
|
{
|
|
2873
2936
|
"destination": "{proxy-base}/api/qa/verdicts",
|
|
2874
2937
|
"what": "the QA verdict for the attempt, published to the QA portal",
|
|
2875
|
-
"when": "
|
|
2938
|
+
"when": "--post-verdict is given; or, by default (no --no-post-verdict), the base URL is not a local address (localhost, *.localhost, 127.x.x.x, 0.0.0.0, [::1], an IPv4-mapped loopback) and the consent seam allows it — Run Telemetry consent on for the endpoint, or a portal-managed campaign; never for a local-spec packet",
|
|
2876
2939
|
"requires_consent": true,
|
|
2877
|
-
"observed_in": [
|
|
2878
|
-
|
|
2879
|
-
]
|
|
2940
|
+
"observed_in": [],
|
|
2941
|
+
"not_observed_reason": "the offline fixture serves the campaign from a 127.0.0.1 base URL, a local address, so the default keeps the verdict local (#486); qa publish proves this send"
|
|
2880
2942
|
},
|
|
2881
2943
|
{
|
|
2882
2944
|
"destination": "{base-url}",
|
|
@@ -2998,11 +3060,10 @@
|
|
|
2998
3060
|
{
|
|
2999
3061
|
"destination": "{proxy-base}/api/qa/verdicts",
|
|
3000
3062
|
"what": "the QA verdict for the attempt, published to the QA portal",
|
|
3001
|
-
"when": "
|
|
3063
|
+
"when": "--post-verdict is given; or, by default (no --no-post-verdict), the base URL is not a local address (localhost, *.localhost, 127.x.x.x, 0.0.0.0, [::1], an IPv4-mapped loopback) and the consent seam allows it — Run Telemetry consent on for the endpoint, or a portal-managed campaign; never for a local-spec packet",
|
|
3002
3064
|
"requires_consent": true,
|
|
3003
|
-
"observed_in": [
|
|
3004
|
-
|
|
3005
|
-
]
|
|
3065
|
+
"observed_in": [],
|
|
3066
|
+
"not_observed_reason": "the offline fixture serves the campaign from a 127.0.0.1 base URL, a local address, so the default keeps the verdict local (#486); qa publish proves this send"
|
|
3006
3067
|
},
|
|
3007
3068
|
{
|
|
3008
3069
|
"destination": "{base-url}",
|
|
@@ -3232,11 +3293,10 @@
|
|
|
3232
3293
|
{
|
|
3233
3294
|
"destination": "{proxy-base}/api/qa/verdicts",
|
|
3234
3295
|
"what": "the QA verdict for the attempt, published to the QA portal",
|
|
3235
|
-
"when": "
|
|
3296
|
+
"when": "--post-verdict is given; or, by default (no --no-post-verdict), the base URL is not a local address (localhost, *.localhost, 127.x.x.x, 0.0.0.0, [::1], an IPv4-mapped loopback) and the consent seam allows it — Run Telemetry consent on for the endpoint, or a portal-managed campaign; never for a local-spec packet",
|
|
3236
3297
|
"requires_consent": true,
|
|
3237
|
-
"observed_in": [
|
|
3238
|
-
|
|
3239
|
-
]
|
|
3298
|
+
"observed_in": [],
|
|
3299
|
+
"not_observed_reason": "the offline fixture serves the campaign from a 127.0.0.1 base URL, a local address, so the default keeps the verdict local (#486); qa publish proves this send"
|
|
3240
3300
|
},
|
|
3241
3301
|
{
|
|
3242
3302
|
"destination": "{base-url}",
|
|
@@ -3358,11 +3418,10 @@
|
|
|
3358
3418
|
{
|
|
3359
3419
|
"destination": "{proxy-base}/api/qa/verdicts",
|
|
3360
3420
|
"what": "the QA verdict for the attempt, published to the QA portal",
|
|
3361
|
-
"when": "
|
|
3421
|
+
"when": "--post-verdict is given; or, by default (no --no-post-verdict), the base URL is not a local address (localhost, *.localhost, 127.x.x.x, 0.0.0.0, [::1], an IPv4-mapped loopback) and the consent seam allows it — Run Telemetry consent on for the endpoint, or a portal-managed campaign; never for a local-spec packet",
|
|
3362
3422
|
"requires_consent": true,
|
|
3363
|
-
"observed_in": [
|
|
3364
|
-
|
|
3365
|
-
]
|
|
3423
|
+
"observed_in": [],
|
|
3424
|
+
"not_observed_reason": "the offline fixture serves the campaign from a 127.0.0.1 base URL, a local address, so the default keeps the verdict local (#486); qa publish proves this send"
|
|
3366
3425
|
},
|
|
3367
3426
|
{
|
|
3368
3427
|
"destination": "{base-url}",
|
|
@@ -5996,7 +6055,7 @@
|
|
|
5996
6055
|
"sends": [],
|
|
5997
6056
|
"effect_test": "effects: record build",
|
|
5998
6057
|
"test_scope": "full",
|
|
5999
|
-
"notes": "Destructive: it replaces stages.assembly (the replaced record is kept in its history) and, when the output changed, resets stages.polish to required. When it detects a brief or CampaignSpec change since the replaced record, it writes input_change and also makes Polish and QA required. Re-recording output identical to the build an input change superseded keeps the build owed unless --deviation-reason records the operator's reason. The fingerprint is doctor's, never typed. Refused, writing nothing but the lifecycle entry, when next answers prepare-build, when doctor cannot compute the fingerprint (no built output), when setup is still required or stages.setup is not terminal, or when the report would fail its schema. The Build Context is read, not written."
|
|
6058
|
+
"notes": "Destructive: it replaces stages.assembly (the replaced record is kept in its history) and, when the output changed, resets stages.polish to required, and a completed stages.deploy stamped with other output to required, its prior record kept in its history (a deploy with no stamped build is kept). When it detects a brief or CampaignSpec change since the replaced record, it writes input_change and also makes Polish and QA required. Re-recording output identical to the build an input change superseded keeps the build owed unless --deviation-reason records the operator's reason. The fingerprint is doctor's, never typed. Refused, writing nothing but the lifecycle entry, when next answers prepare-build, when doctor cannot compute the fingerprint (no built output), when setup is still required or stages.setup is not terminal, or when the report would fail its schema. The Build Context is read, not written."
|
|
6000
6059
|
},
|
|
6001
6060
|
{
|
|
6002
6061
|
"command": "record",
|
|
@@ -6222,7 +6281,7 @@
|
|
|
6222
6281
|
],
|
|
6223
6282
|
"effect_test": "effects: record deploy",
|
|
6224
6283
|
"test_scope": "full",
|
|
6225
|
-
"notes": "Destructive: it replaces stages.deploy and the packet's deploy.preview_url. The requests stay on this machine: --base-url must be a loopback origin. Refused, writing nothing but the lifecycle entry, when the packet is not local-serve, the URL is not loopback or not the campaign's route root, a built page does not answer 2xx, 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 the theme gate is blocked. The Build Context is read, not written."
|
|
6284
|
+
"notes": "Destructive: it replaces stages.deploy, stamped with the build fingerprint it probed, and the packet's deploy.preview_url. The requests stay on this machine: --base-url must be a loopback origin. Refused, writing nothing but the lifecycle entry, when the packet is not local-serve, the URL is not loopback or not the campaign's route root, a built page does not answer 2xx, 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 the theme gate is blocked. The Build Context is read, not written."
|
|
6226
6285
|
},
|
|
6227
6286
|
{
|
|
6228
6287
|
"command": "record",
|