@nextcommerce/campaigns-os 1.37.3 → 1.43.1

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 (76) hide show
  1. package/AGENTS.md +114 -10
  2. package/CHANGELOG.md +708 -0
  3. package/README.md +44 -31
  4. package/agents/claude/CLAUDE.md +5 -1
  5. package/campaign-spec/dist/types.d.ts +2 -0
  6. package/contracts/agent-relevant-change-policy.v1.json +11 -1
  7. package/contracts/effects.v1.json +4887 -0
  8. package/contracts/migration-sidecar-bundle.v0.json +9 -0
  9. package/contracts/release-ledger.json +1541 -0
  10. package/contracts/supported-surface.json +33 -12
  11. package/docs/build-packet.md +83 -22
  12. package/docs/campaigns-os-build-flow.md +2 -2
  13. package/docs/demo-preview.md +1 -1
  14. package/docs/diagnostics.md +7 -4
  15. package/docs/effects.md +350 -0
  16. package/docs/gateway-login.md +113 -0
  17. package/docs/local-setup.md +51 -0
  18. package/docs/migration-sidecar-bundle.md +6 -1
  19. package/docs/orientation-contract-reference.md +4 -1
  20. package/docs/progress-snapshots.md +9 -3
  21. package/docs/qa-and-test-orders.md +29 -13
  22. package/docs/readback.md +523 -0
  23. package/docs/runtime-readiness.md +1 -1
  24. package/docs/sdk-storage-compatibility.md +1 -1
  25. package/docs/skills-revision.md +364 -0
  26. package/docs/supported-surface.md +11 -3
  27. package/docs/versioning.md +8 -4
  28. package/package.json +10 -4
  29. package/schemas/campaign-runtime-assembly-report.v0.schema.json +6 -1
  30. package/schemas/campaign-runtime-build-packet.v0.schema.json +11 -1
  31. package/schemas/campaign-spec.v4.schema.json +4 -0
  32. package/schemas/campaigns-os-effects.v1.schema.json +211 -0
  33. package/schemas/campaigns-os-progress-snapshot.v0.schema.json +1 -0
  34. package/schemas/campaigns-os-qa-verdict-sidecar.v0.schema.json +1 -0
  35. package/schemas/campaigns-os-qa-verdict.v0.schema.json +1 -0
  36. package/schemas/campaigns-os-readback.v2.schema.json +267 -0
  37. package/schemas/campaigns-os-run-record.v0.schema.json +1 -0
  38. package/skills/campaign-lifecycle-orientation/SKILL.md +179 -0
  39. package/skills/campaign-readback-classification/SKILL.md +230 -0
  40. package/skills/campaign-run-evidence/SKILL.md +142 -0
  41. package/skills/contribution-intake/SKILL.md +85 -0
  42. package/skills/next-campaigns-build/SKILL.md +33 -12
  43. package/skills/next-campaigns-os/SKILL.md +59 -22
  44. package/skills/next-campaigns-os/references/session-intake.md +4 -4
  45. package/skills/next-campaigns-os-setup/SKILL.md +35 -14
  46. package/skills/next-campaigns-polish/SKILL.md +43 -17
  47. package/skills/next-campaigns-qa/SKILL.md +53 -28
  48. package/skills.json +40 -7
  49. package/src/admin-transport.mjs +123 -0
  50. package/src/cli.mjs +1178 -270
  51. package/src/credential-store.mjs +183 -0
  52. package/src/deviation.mjs +3 -2
  53. package/src/diagnostic.mjs +4 -1
  54. package/src/finding-cause.mjs +14 -10
  55. package/src/gate-actions.mjs +2 -2
  56. package/src/install-mode.mjs +17 -9
  57. package/src/lifecycle.mjs +96 -0
  58. package/src/login.mjs +152 -0
  59. package/src/package-install-fixture.mjs +3 -2
  60. package/src/polish-node.mjs +5 -2
  61. package/src/progress-node.mjs +3 -2
  62. package/src/progress.mjs +5 -3
  63. package/src/qa-node.mjs +105 -36
  64. package/src/qa-publish.mjs +112 -2
  65. package/src/qa-sidecar.mjs +2 -0
  66. package/src/qa-verdict-discovery.mjs +11 -0
  67. package/src/qa-verdict-publish.mjs +1 -0
  68. package/src/qa-verdict.mjs +8 -1
  69. package/src/readback.mjs +1937 -0
  70. package/src/remit.mjs +17 -3
  71. package/src/run-record-closeout.mjs +3 -4
  72. package/src/run-record.mjs +4 -0
  73. package/src/sidecar-bundle.mjs +21 -0
  74. package/src/spec-source-identity.mjs +44 -0
  75. package/src/stage-ledger.mjs +4 -1
  76. package/src/tooling-setup.mjs +160 -0
@@ -1,25 +1,46 @@
1
1
  ---
2
2
  name: next-campaigns-build
3
- version: 1.0.3
3
+ version: 1.0.12
4
4
  description: Assemble a NEXT campaign from a doctor-cleared Build Packet, CampaignSpec/API values, prepared HTML/assets, page-kit, and starter-template contracts.
5
5
  ---
6
6
 
7
+ Bundle revision: 1.43.1+skills.1
8
+ Run `npx --no-install campaigns-os tooling status --skills-revision 1.43.1+skills.1`
9
+ from the campaign's Page Kit folder, where it runs the project's pinned copy and
10
+ never installs one, at the start of each task. Start a fresh session if it
11
+ reports `mismatch`: this text is already in your context and is never re-read
12
+ while the CLI on disk can move under it. If the output has no `Skills revision:`
13
+ line (no `revision_check` under `--json`), a campaigns-os older than this check
14
+ answered; follow none of its actions and run the pinned copy.
15
+
7
16
  # Next Campaigns Build
8
17
 
9
18
  ## Installed toolkit commands
10
19
 
11
20
  Run from the campaign folder with an exact project-local devDependency and
12
21
  committed lockfile. Orient on reviewed source before installation; check release
13
- provenance or pin the full reviewed Git SHA. Preflight with `npx campaigns-os
14
- tooling status --platform <claude|codex>` and refresh bundled skills for the same
15
- profile. Use the invocation printed by status and `next` to avoid PATH shadowing.
22
+ provenance or pin the full reviewed Git SHA. Preflight with `npx --no-install
23
+ campaigns-os tooling status --platform <claude|codex>` (tier `B`: its only write
24
+ is the command-lifecycle journal) and refresh bundled skills for the same
25
+ profile with `install-skills` (tier `B`: writes the shared skill directories;
26
+ nothing leaves the machine). Use the invocation printed by status and `next` to
27
+ avoid PATH shadowing.
28
+
29
+ In the instructions below, bare `campaigns-os …` means `npx --no-install
30
+ campaigns-os …` from that campaign folder. Keep `--no-install`: `campaigns-os`
31
+ is only the bin name of `@nextcommerce/campaigns-os`, so where no pinned copy is
32
+ installed a plain `npx` looks that name up on the registry and, with no terminal
33
+ to ask, installs what it finds. Global-only users substitute the global copy's
34
+ printed invocation for each `npx --no-install campaigns-os` example; toolkit
35
+ contributors translate to `npm run campaigns-os -- …` in the toolkit checkout.
36
+ Browser installation is `npx --no-install campaigns-os qa install-browser`, not
37
+ a campaign npm script. `tooling diagnose --packet <p> --json` (tier `none`:
38
+ read-only, and exempt from lifecycle capture) provides a redacted support export
39
+ without changing retained evidence.
16
40
 
17
- In the instructions below, bare `campaigns-os …` means `npx campaigns-os …`
18
- from that campaign folder. Global-only users substitute the global copy's printed invocation for
19
- each `npx campaigns-os` example; toolkit contributors translate to `npm run campaigns-os -- …` in
20
- the toolkit checkout. Browser installation is `npx campaigns-os qa
21
- install-browser`, not a campaign npm script. `tooling diagnose --packet <p>
22
- --json` provides a redacted support export without changing retained evidence.
41
+ The effect class in each parenthetical below is the declared row of
42
+ `contracts/effects.v1.json` (`none` < `B` writes < `A` sends < `C` destructive).
43
+ Read that file, not this text, when an exact path or endpoint matters.
23
44
 
24
45
 
25
46
  ## Recommended Build Loop
@@ -63,11 +84,11 @@ Build rules:
63
84
  - Replace values named by `frontmatter.replaceFromSpecOrApi`.
64
85
  - Remove unsupported surfaces named by `frontmatter.removeWhenUnsupported`.
65
86
  - Preserve SDK-owned checkout/cart/upsell/receipt/payment/address/totals/submit surfaces.
66
- - If `doctor` reports `derived.scope.mode = "partial"`, build the pages listed in `derived.scope.built_pages` from their prepared source. A page in `derived.scope.out_of_scope_pages` whose assembly-report decision `dec_page_scope_<page>` carries `template_stock: true` is template stock: materialise it from the locked family's own page for that role (`decision.template_family`; the `next build` prompt lists them), copied atomically with its dependent `_includes/`, `_layouts/`, and assets, and wired from CampaignSpec — a pre-checkout `select` step first, because it seeds the cart the runtime pages read. Do not look for prepared source HTML for it, and do not attest a screenshot of it as a design source. Once its built HTML exists at the page's route, doctor lists it among the previewable routes and lifts the runtime-QA block for it. An out-of-scope page without that marker stays unbuilt: carry its `skip_reason` into the assembly report and label the preview as route/visual-testable rather than full-funnel launch-ready.
87
+ - If `doctor` (tier `none`: read-only inspection; `--write`/`--built` are tier `B`) reports `derived.scope.mode = "partial"`, build the pages listed in `derived.scope.built_pages` from their prepared source. A page in `derived.scope.out_of_scope_pages` whose assembly-report decision `dec_page_scope_<page>` carries `template_stock: true` is template stock: materialise it from the locked family's own page for that role (`decision.template_family`; the `next build` prompt lists them), copied atomically with its dependent `_includes/`, `_layouts/`, and assets, and wired from CampaignSpec — a pre-checkout `select` step first, because it seeds the cart the runtime pages read. Do not look for prepared source HTML for it, and do not attest a screenshot of it as a design source. Once its built HTML exists at the page's route, doctor lists it among the previewable routes and lifts the runtime-QA block for it. An out-of-scope page without that marker stays unbuilt: carry its `skip_reason` into the assembly report and label the preview as route/visual-testable rather than full-funnel launch-ready.
67
88
  - For `landing` and `presell` pages, prefer the prepared source HTML when `source_html.pages[].path` points at a real standalone page. Preserve the design/content through a passthrough page-kit layout, inject the SDK loader/config as needed, and repoint CTAs into the CampaignSpec flow. Treat `source_html.pages[].path` and `context.page_map[].source_path` as source provenance. Treat `source_html.pages[].page_kit`, `context.page_map[].page_kit`, and `context.page_map[].output_path` as the Page Kit target file, route, CPK `page_type`, and frontmatter projection.
68
89
  - Prepared source HTML means page-kit-ready markup, not a wholesale Liquid rewrite. Standalone AI/exported HTML should keep page-owned body markup, remove document wrappers, add YAML frontmatter, move shared CSS/assets into the campaign structure, and use Liquid helpers only where page-kit needs campaign-rooted links/assets/includes.
69
90
  - For `checkout`, `upsell`, `downsell`, and `receipt` pages, treat the selected starter-template commerce surface as the SDK contract reference: preserve required `data-next-*` controls, hidden fields, payment/address/totals/submit wiring, and `next_dont_touch` regions. The surrounding HTML wrapper, page composition, imagery, copy hierarchy, and brand layer are campaign/source-owned. Do not carry starter visual chrome forward when prepared source design should own that surface.
70
- - Read `context.theme` and `.campaign-runtime/theme/theme-report.json` when present. If a fresh `brand-theme.css` artifact exists, copy it into the campaign asset tree and load it after `next-core.css` on checkout, upsell, downsell, and receipt pages. If policy is `inspect_only`, either run `campaigns-os theme generate` or record an explicit skipped reason before applying a new brand layer.
91
+ - Read `context.theme` and `.campaign-runtime/theme/theme-report.json` when present. If a fresh `brand-theme.css` artifact exists, copy it into the campaign asset tree and load it after `next-core.css` on checkout, upsell, downsell, and receipt pages. If policy is `inspect_only`, either run `campaigns-os theme generate` (tier `B`: writes the theme artifacts and doctor output under the target; `--force` is tier `C`) or record an explicit skipped reason before applying a new brand layer.
71
92
  - Generated brand-theme v0 is root-variable-only. It may skin commerce pages through next-core custom properties, but it is not permission to edit SDK-owned selectors, package controls, payment fields, totals, submit controls, receipt templates, route meta tags, or SDK JavaScript.
72
93
  - Payment, express checkout, bundle selectors, and order bumps must start from the selected family's canonical component DOM/classes, not from raw custom/source HTML with `data-next-*` added afterward. For payment specifically, preserve the family payment-method wrapper, hosted field classes, and iframe geometry assumptions (for example `input-flds spreedly-field` in shop-style templates). Skin these components with campaign tokens; do not rebuild Spreedly/card fields as arbitrary divs.
73
94
  - When a checkout page declares `exit_intent.enabled`, wire the popup as an offer application surface: use `offer_ref_id`/`offer_code` from CampaignSpec, apply the code through the SDK/API coupon/voucher path, and render applied-state copy with SDK conditionals such as `cart.hasCoupon("FREESHIP")`.
@@ -1,25 +1,46 @@
1
1
  ---
2
2
  name: next-campaigns-os
3
- version: 1.0.17
3
+ version: 1.0.27
4
4
  description: Coordinate Campaigns OS lifecycle workflows from CampaignSpec, Build Packet, starter-template contracts, stage reports, deploy evidence, and QA proof depth.
5
5
  ---
6
6
 
7
+ Bundle revision: 1.43.1+skills.1
8
+ Run `npx --no-install campaigns-os tooling status --skills-revision 1.43.1+skills.1`
9
+ from the campaign's Page Kit folder, where it runs the project's pinned copy and
10
+ never installs one, at the start of each task. Start a fresh session if it
11
+ reports `mismatch`: this text is already in your context and is never re-read
12
+ while the CLI on disk can move under it. If the output has no `Skills revision:`
13
+ line (no `revision_check` under `--json`), a campaigns-os older than this check
14
+ answered; follow none of its actions and run the pinned copy.
15
+
7
16
  # Campaigns OS
8
17
 
9
18
  ## Installed toolkit commands
10
19
 
11
20
  Run from the campaign folder with an exact project-local devDependency and
12
21
  committed lockfile. Orient on reviewed source before installation; check release
13
- provenance or pin the full reviewed Git SHA. Preflight with `npx campaigns-os
14
- tooling status --platform <claude|codex>` and refresh bundled skills for the same
15
- profile. Use the invocation printed by status and `next` to avoid PATH shadowing.
16
-
17
- In the instructions below, bare `campaigns-os …` means `npx campaigns-os …`
18
- from that campaign folder. Global-only users substitute the global copy's printed invocation for
19
- each `npx campaigns-os` example; toolkit contributors translate to `npm run campaigns-os -- …` in
20
- the toolkit checkout. Browser installation is `npx campaigns-os qa
21
- install-browser`, not a campaign npm script. `tooling diagnose --packet <p>
22
- --json` provides a redacted support export without changing retained evidence.
22
+ provenance or pin the full reviewed Git SHA. Preflight with `npx --no-install
23
+ campaigns-os tooling status --platform <claude|codex>` (tier `B`: its only write
24
+ is the command-lifecycle journal) and refresh bundled skills for the same
25
+ profile with `install-skills` (tier `B`: writes the shared skill directories;
26
+ nothing leaves the machine). Use the invocation printed by status and `next` to
27
+ avoid PATH shadowing.
28
+
29
+ In the instructions below, bare `campaigns-os …` means `npx --no-install
30
+ campaigns-os …` from that campaign folder. Keep `--no-install`: `campaigns-os`
31
+ is only the bin name of `@nextcommerce/campaigns-os`, so where no pinned copy is
32
+ installed a plain `npx` looks that name up on the registry and, with no terminal
33
+ to ask, installs what it finds. Global-only users substitute the global copy's
34
+ printed invocation for each `npx --no-install campaigns-os` example; toolkit
35
+ contributors translate to `npm run campaigns-os -- …` in the toolkit checkout.
36
+ Browser installation is `npx --no-install campaigns-os qa install-browser`, not
37
+ a campaign npm script. `tooling diagnose --packet <p> --json` (tier `none`:
38
+ read-only, and exempt from lifecycle capture) provides a redacted support export
39
+ without changing retained evidence.
40
+
41
+ The effect class in each parenthetical below is the declared row of
42
+ `contracts/effects.v1.json` (`none` < `B` writes < `A` sends < `C` destructive).
43
+ Read that file, not this text, when an exact path or endpoint matters.
23
44
 
24
45
 
25
46
  Use this skill to orient a campaign build, run preflight, decide the next stage, and keep the lifecycle honest.
@@ -39,17 +60,33 @@ but those wrappers should not redefine the public contract.
39
60
 
40
61
  Workflow:
41
62
 
42
- 1. Confirm the campaign was configured in Campaigns App and exported from Campaign Map Builder as current CampaignSpec JSON. Current authoring is v4.3+ while preserving the v4.2 `funnels[]` topology as the compatibility shape.
43
- 2. Run `campaigns-os start` or `campaigns-os prepare-build` with a local CampaignSpec, prepared HTML/assets source, target page-kit repo, and explicit template family. The family must be certified (commerce catalog + brand contract; the CLI lists them on rejection) — an uncertified/custom family requires `--allow-uncertified-template "<reason>"` and forfeits deterministic assembly, residue QA, and pricing contracts. The entry point auto-opens the run session in the target repo; do not skip `campaigns-os run end` at the finish. If intake blocks with `DESIGN_SOURCE_PACKAGE_NOT_READY`, the source material carries no desktop/mobile screenshot proof: supply it through `pages[].screenshots[]` in `<source-root>/.campaigns-os/source-html-manifest.json` and follow "Clearing `DESIGN_SOURCE_PACKAGE_NOT_READY`" in `docs/design-source-package.md`, which also gives the recovery for the package a blocked run left behind.
44
- 3. Brand-theme discovery runs in inspect-only mode by default and records `context.theme`. When it proves a brand theme is generatable and the campaign ships commerce pages, the theme gate BLOCKS polish/deploy/QA until the brand layer is applied after `next-core.css` or explicitly waived (`campaigns-os theme waive --packet <p> --reason "<why>" --waived-by "<named human>"`, the same named-human rule as `checkpoint waive`). Run `campaigns-os theme generate` and apply it during build; do not defer the decision.
45
- 4. Run `campaigns-os doctor --packet <packet>`.
46
- 5. Resolve the registered **Page Kit** checkpoints before runtime work. The CampaignSpec is the authority for the target's `_data/campaigns.json` entry, and the reconcile is a command, not a hand edit: `campaigns-os page-kit sync --packet <p>` (add `--dry-run` to see the field-by-field diff first) writes the spec's `campaign.store_*` fields into the entry for the packet's route and seeds the released SDK pin (`global_config.sdk_version` is canonical, `runtime.sdk_version` an accepted alias) while the entry is still in scaffold state or behind the spec; it never moves a configured campaign's pin backwards (on an existing campaign the repo pin moves first and the Map is stale: run `campaigns-os spec derive --packet <p>`, which writes the repo pin — and the page routes and analytics ids the repo carries — into the local CampaignSpec with a field-by-field diff, and add `--write-map` to record the pin in the saved Map's Build hints too (it reads the Map back and moves only the pin, forward or not at all; a Map pin ahead of the repo is refused as a warning), or re-save the Map by hand; a hand edit of the spec is never the answer for a derived field; the `campaign.store_*` fields are derived from the store itself with `spec derive --packet <p> --from-store <subdomain>`, the Admin API read token in `<SUBDOMAIN>_ADMIN_TOKEN`, and a field the store cannot state is reported and left as it is, never emptied), and touches nothing else; doctor and `next` print it as the gate's `repair_target` action, and after it `page_kit.store_profile` and `page_kit.sdk_version` pass without a waiver. Starter demo residue (a demo storefront URL or phone) in that entry is never waivable and must be replaced this way. A `PARTIAL` status means a field could not be made spec-authoritative (a spec value of the wrong type or shape, the demo value itself in the spec, demo residue in a field the spec does not carry, a conflicting or non-released pin, or a gate under an active waiver); the warnings name the spec field to fix, then sync again. Missing/malformed Store Profile or SDK evidence, invalid types or semantic versions, and conflicting dual SDK declarations are not waivable. An exact valid mismatch may be accepted with named-human attribution and a bound: `campaigns-os checkpoint waive --packet <p> --gate <page_kit.store_profile|page_kit.sdk_version> --reason "<why>" --waived-by "<named human>" --review-condition "<trigger>"` (or `--expires-at <future ISO timestamp>`). The package-owned hidden eager-media checkpoint is produced and resolved during Polish in step 9.
63
+ Local-spec runs use packet-based QA and repository evidence. They never post QA
64
+ to the Map portal or claim saved-Map revision alignment. Existing lifecycle
65
+ gates remain in force; use `local-serve` for the first localhost proof.
66
+
67
+ 1. Confirm the selected campaign is configured in Campaigns App. Use its current
68
+ saved Map export when available. For HTML-and-brief intake without a Map, author
69
+ a normal CampaignSpec from the source design, operator's brief and verified
70
+ Campaigns API commerce values. Follow `docs/build-packet.md` "Local-spec entry":
71
+ create one `spec_identity.local_spec_id` (UUID), preserve it through revisions,
72
+ set `public_route_slug`, and omit saved-Map identity/URLs. Do not ask the operator
73
+ to author a spec or fabricate a Map ID. Verify store/campaign binding and real
74
+ package/offer references. Store contact and policy details can come from the
75
+ brief; gateway access is optional. Current authoring is v4.3+ while preserving
76
+ the v4.2 `funnels[]` topology as the compatibility shape.
77
+ 2. Run `campaigns-os start` or `campaigns-os prepare-build` (tier `A`: they write the
78
+ Build Packet, Build Context, assembly report, run session and `.gitignore` under
79
+ the target plus a Run Record under the working directory, and they contact the
80
+ Map and run endpoints) with a local CampaignSpec, prepared HTML/assets source, target page-kit repo, and explicit template family. The family must be certified (commerce catalog + brand contract; the CLI lists them on rejection) — an uncertified/custom family requires `--allow-uncertified-template "<reason>"` and forfeits deterministic assembly, residue QA, and pricing contracts. The entry point auto-opens the run session in the target repo; do not skip `campaigns-os run end` (tier `C`: it clears the active run session — a write that discards prior state — while assembling and remitting the Run Record) at the finish. If intake blocks with `DESIGN_SOURCE_PACKAGE_NOT_READY`, the source material carries no desktop/mobile screenshot proof: supply it through `pages[].screenshots[]` in `<source-root>/.campaigns-os/source-html-manifest.json` and follow "Clearing `DESIGN_SOURCE_PACKAGE_NOT_READY`" in `docs/design-source-package.md`, which also gives the recovery for the package a blocked run left behind.
81
+ 3. Brand-theme discovery runs in inspect-only mode by default and records `context.theme`. When it proves a brand theme is generatable and the campaign ships commerce pages, the theme gate BLOCKS polish/deploy/QA until the brand layer is applied after `next-core.css` or explicitly waived (`campaigns-os theme waive --packet <p> --reason "<why>" --waived-by "<named human>"` — tier `C`: it overwrites the assembly report and doctor output, the same named-human rule as `checkpoint waive`). Run `campaigns-os theme generate` (tier `B`: writes the theme artifacts and doctor output under the target; `--force` is tier `C` because it overwrites an existing theme) and apply it during build; do not defer the decision.
82
+ 4. Run `campaigns-os doctor --packet <packet>` (tier `none`: read-only inspection, exempt from lifecycle capture; `--write`, `--built` and `--built --emit-packet` are tier `B` and write doctor output or the emitted packet under the target).
83
+ 5. Resolve the registered **Page Kit** checkpoints before runtime work. The CampaignSpec is the authority for the target's `_data/campaigns.json` entry, and the reconcile is a command, not a hand edit: `campaigns-os page-kit sync --packet <p>` (tier `B`: writes the target's `_data/campaigns.json` entry and doctor output, nothing off the machine; add `--dry-run`, tier `none` and read-only, to see the field-by-field diff first) writes the spec's `campaign.store_*` fields into the entry for the packet's route and seeds the released SDK pin (`global_config.sdk_version` is canonical, `runtime.sdk_version` an accepted alias) while the entry is still in scaffold state or behind the spec; it never moves a configured campaign's pin backwards (on an existing campaign the repo pin moves first and the Map is stale: run `campaigns-os spec derive --packet <p>` (tier `B`: writes the local CampaignSpec and doctor output), which writes the repo pin — and the page routes and analytics ids the repo carries — into the local CampaignSpec with a field-by-field diff, and add `--write-map` (tier `A`: the same local writes plus a read and a write against the Map endpoints) to record the pin in the saved Map's Build hints too (it reads the Map back and moves only the pin, forward or not at all; a Map pin ahead of the repo is refused as a warning), or re-save the Map by hand; a hand edit of the spec is never the answer for a derived field; the `campaign.store_*` fields are derived from the store itself with `spec derive --packet <p> --from-store <subdomain>` (tier `A`: it contacts the store's Admin API through the login gateway), using gateway credentials saved by `campaigns-os login --store <subdomain>` (tier `A`: it contacts the gateway and writes the credential file under your home directory) by default within the admitted owned-store private pilot; existing direct Admin callers must explicitly add `--store-token-source env:<VAR>` naming their existing environment variable (this warned break-glass path bypasses gateway custody; there is no implicit environment lookup or fallback after gateway failure; see `docs/gateway-login.md`), and a field the store cannot state is reported and left as it is, never emptied), and touches nothing else; doctor and `next` print it as the gate's `repair_target` action, and after it `page_kit.store_profile` and `page_kit.sdk_version` pass without a waiver. Starter demo residue (a demo storefront URL or phone) in that entry is never waivable and must be replaced this way. A `PARTIAL` status means a field could not be made spec-authoritative (a spec value of the wrong type or shape, the demo value itself in the spec, demo residue in a field the spec does not carry, a conflicting or non-released pin, or a gate under an active waiver); the warnings name the spec field to fix, then sync again. Missing/malformed Store Profile or SDK evidence, invalid types or semantic versions, and conflicting dual SDK declarations are not waivable. An exact valid mismatch may be accepted with named-human attribution and a bound: `campaigns-os checkpoint waive` (tier `C`: a waiver overwrites the assembly report and doctor output) `--packet <p> --gate <page_kit.store_profile|page_kit.sdk_version> --reason "<why>" --waived-by "<named human>" --review-condition "<trigger>"` (or `--expires-at <future ISO timestamp>`). The package-owned hidden eager-media checkpoint is produced and resolved during Polish in step 9.
47
84
  6. On any doctor run that sees built output, resolve `built_output.upsell_selector_scope`. A `data-next-bundle-selector` on a page whose funnel role is `upsell` or `downsell` writes to the shopper's LIVE CART unless it carries `data-next-upsell-context`; loading the page then adds that package with no click, and it is charged at the next checkout without appearing in that checkout's rendered order summary. Being hidden does not help — the write happens at init. Fix it by adding `data-next-upsell-context` to the named selector, or by deleting a selector that exists only to display a price. This gate runs on EVERY doctor invocation, not only after assembly, because the defect it was written for was introduced by a later review round. If a cart-scoped selector on a post-purchase page is genuinely intended, record it: `campaigns-os checkpoint waive --packet <p> --gate built_output.upsell_selector_scope --reason "<why>" --waived-by "<named human>" --review-condition "<trigger>"`. On the same runs, resolve `built_output.campaign_identity`: every page must name the same campaign — one API key (`next-api-key` meta or the `config.js` / `window.nextConfig` `apiKey`), one `next-funnel`, and any `setAttribution({ funnel })` call agreeing with the tag of the page that makes it. A page copied from another funnel that still carries the other campaign's key, tag, or call binds and renders without complaint and puts the order on the wrong campaign. Each error names the two files and the two values; make the one-line edit it describes. Not waivable — there is no `checkpoint waive` lane for it. Parked `-backup-` / `-old-` copies are skipped and listed, not scanned. Also resolve `built_output.sdk_markup`: its blockers (`SWAP_WITH_ADD_TO_CART`, `CHECKOUT_NOT_FORM`, `WRONG_FIELD_NAME`, `MISSING_SELECTOR_ID_MATCH`) are markup the SDK binds and then silently no-ops or double-writes on — fix the markup the message names (it gives the SDK spelling for a wrong field name); its warnings (`DOUBLE_SELECTED`, `TEMPLATE_DOUBLE_BRACE`) are advisory. Neither is waivable. A `data-next-*` name the SDK does not read shows up as one advisory line naming the attribute index version, not a warning.
48
85
  7. If doctor's `next` block says `doctor-blocked` or `prepare-build` (it names the same stage `campaigns-os next` would), stop and resolve the named blockers.
49
- 8. If doctor returns `build`, hand off with `campaigns-os next build --packet <packet>` and follow `next-campaigns-build`'s recommended **build → independent review → repair → verification** loop.
86
+ 8. If doctor returns `build`, hand off with `campaigns-os next build --packet <packet>` (tier `A`, like every `next` form: additive writes under `.campaign-runtime/` plus a stage-progress POST once Run Telemetry consent is persisted; `--no-write` and `--no-remit` are each tier `B` and keep the invocation local) and follow `next-campaigns-build`'s recommended **build → independent review → repair → verification** loop.
50
87
  9. After build, require polish and a preview deploy before QA. During Polish,
51
- install the package-owned browser once with `npx campaigns-os qa install-browser`,
52
- serve the current build, and run `campaigns-os polish capture --packet <p> --base-url <served-build-url>` before recording a terminal Polish status.
88
+ install the package-owned browser once with `npx --no-install campaigns-os qa install-browser`,
89
+ serve the current build, and run `campaigns-os polish capture --packet <p> --base-url <served-build-url>` (tier `A`: it writes the polish evidence and assembly report under the target and fetches the served build at `--base-url`) before recording a terminal Polish status.
53
90
  The package-owned producer attaches `visual_review.page_load`; never
54
91
  hand-author it. Nonwaivable incomplete evidence blocks. A complete hidden
55
92
  eager-media finding may receive an exact bound decision through
@@ -57,7 +94,7 @@ Workflow:
57
94
  Doctor/next report `ready_with_waivers`; QA
58
95
  retains each attributed exception as `ready_with_exceptions`, and one
59
96
  exception never suppresses another blocker.
60
- 10. Run the package-owned proof path in sequence: ensure `npx campaigns-os qa install-browser` has completed, run `campaigns-os qa resolve --packet <packet>`, then `campaigns-os qa run --packet <packet> --base-url <url> --browser --test-order common`.
97
+ 10. Run the package-owned proof path in sequence: ensure `npx --no-install campaigns-os qa install-browser` has completed, run `campaigns-os qa resolve --packet <packet>` (tier `A`: it fetches `--base-url`; `--no-probe` is tier `B` and local), then `campaigns-os qa run --packet <packet> --base-url <url> --browser --test-order common` (tier `C`: it overwrites the stored verdict and assembly report, places real typed-card test orders against the campaign, and posts the verdict and progress; `--no-post-verdict` drops the verdict POST and `--no-remit` the Run Record remit, but both stay tier `C`).
61
98
  11. Treat typed-card proof coverage as the control. Global test cards bypass the gateway and create no transactions, so no permission/approval is needed. `common` runs checkout, first-offer accept and decline, and a deduplicated shortest real receipt path when that adds coverage (at most four orders). `full` walks every actual terminal path in the selected checkout topology; cycles, missing routes, and reachable nonterminals block exhaustive proof before browser launch. The accidental-flood cap remains `6`, and an overflow names the exact explicit `--max-test-orders` raise. Localhost on any port is a Campaigns App Development domain for SDK QA with analytics suppressed; non-localhost preview/production origins still need SDK origin allowlist confirmation.
62
99
  12. Discuss launch only from recorded build, polish, deploy, browser QA, and test-order evidence, or from explicit blockers.
63
100
 
@@ -104,7 +141,7 @@ Rules:
104
141
  - Designed source owns visual composition and page-level content.
105
142
  - Brand-theme evidence is workflow-order neutral. Do not assume a Figma export came first; consume `context.theme` and `.campaign-runtime/theme/theme-report.json` when present. A truly missing/ungeneratable theme stays a warning, but a generatable-and-unapplied theme on a commerce-page campaign is a gate: apply it or waive it explicitly before polish/deploy/QA.
106
143
  - Follow `campaigns-os next` literally. Every `next` response carries its applicable Store Profile, SDK, hidden eager-media, theme, and broad Polish gates plus `next_actions` with exact commands — execute those instead of improvising. With an active run session, pipeline-advancing commands that don't match the last `next` recommendation are recorded to `.campaign-runtime/agent-deviations.jsonl`; declare an intentional detour with `--deviation-reason "<why>"`.
107
- - Close the loop: when `next` reports `done` (or QA has published its verdict and the PR is up), finish with `campaigns-os run end` so the Run Record is assembled and the run session clears. `campaigns-os run status` shows incomplete stages and the exact next command at any point.
144
+ - Close the loop: when `next` reports `done` (or QA has published its verdict and the PR is up), finish with `campaigns-os run end` (tier `C`; `--no-write` still clears the session file) so the Run Record is assembled and the run session clears. `campaigns-os run status` (tier `none`: read-only) shows incomplete stages and the exact next command at any point.
108
145
  - Do not copy demo refs or unsupported optional surfaces into the target campaign.
109
146
  - Use SDK conditionals such as `cart.hasCoupon("CODE")` for code-specific presentation; do not mutate visible prices from campaign-specific JavaScript.
110
147
  - Build Packet, Build Context, and Assembly Report paths should be repo-relative when possible so handoff artifacts can be committed without machine-local absolute paths.
@@ -112,6 +149,6 @@ Rules:
112
149
  - Store Profile fields are operator-entered storefront/legal metadata for page-kit `campaigns.json`; they do not come from the Campaigns API and should be collected in the CampaignSpec before build.
113
150
  - Treat `campaigns-os checkpoint waive` as a staged generic registry, not a universal waiver command. This release registers Store Profile, the Page Kit SDK pin, `polish.hidden_eager_media`, and `built_output.upsell_selector_scope`. The broad Polish Source Freshness gate remains on its existing artifact handling, and theme/QA keep their existing `theme waive` / `qa waive` lanes until those gates are explicitly registered. A checkpoint waiver needs a named human, non-empty reason, and at least one future expiry or non-empty review condition; a waiver remains visible, applies only to its exact checkpoint state, and never turns the checkpoint into a clean pass. Hidden eager-media measurement completeness is never waivable.
114
151
  - Keep the lifecycle in a tight sequence. Pause only for missing inputs, doctor blockers, deploy blockers, out-of-scope runtime pages, or merchant-specific uncertainty.
115
- - `campaigns-os standardize` audits the campaign ecosystem read-only: it recognizes Page Kit roots and non-Page-Kit Campaign Cart applications (Vite/React/Express apps, static HTML funnels) via portable evidence, classifies each root (`implementation.kind`), validates checkout field bindings against the Campaign Cart field contract, and evaluates loader versions against the SDK support policy contract. Findings carry `confidence` (`static_contract`, `static_inference`, `runtime_proof_required`); treat `runtime_proof_required` findings as missing proof, never as confirmed defects, and route them to browser QA rather than static repair.
152
+ - `campaigns-os standardize` (tier `B`: it writes no artifact of its own, but the command-lifecycle journal append makes it a write) audits the campaign ecosystem read-only: it recognizes Page Kit roots and non-Page-Kit Campaign Cart applications (Vite/React/Express apps, static HTML funnels) via portable evidence, classifies each root (`implementation.kind`), validates checkout field bindings against the Campaign Cart field contract, and evaluates loader versions against the SDK support policy contract. Findings carry `confidence` (`static_contract`, `static_inference`, `runtime_proof_required`); treat `runtime_proof_required` findings as missing proof, never as confirmed defects, and route them to browser QA rather than static repair.
116
153
  - Launch readiness is separate from Campaigns OS proof. Surface production storefront URL, live payment methods, shipping markets, legal/support URLs, analytics expectations, and merchant-side configuration as real-shopper readiness items, not Campaigns OS build blockers.
117
154
  - Browser QA and test-order proof are owned by Campaigns OS through Playwright. Do not route the core QA path through external browser skills or hand-built backend orders.
@@ -40,7 +40,7 @@ end-to-end campaign.
40
40
 
41
41
  Required before build:
42
42
 
43
- - Map ID or CampaignSpec path/URL.
43
+ - Saved Map ID/export, or the configured store/campaign details, public key, prepared HTML/assets and brief from which the agent authors a local CampaignSpec. Do not make a saved Map a prerequisite; follow `docs/build-packet.md` "Local-spec entry".
44
44
  - Public route slug and target repo/output directory.
45
45
  - Source type and source files: Figma, exported HTML, prepared HTML, existing campaign, or other.
46
46
  - Pages in scope and any pages to preserve.
@@ -101,10 +101,10 @@ Use when the user wants evidence on a deployed campaign and no source edit.
101
101
 
102
102
  Collect:
103
103
 
104
- - Map ID and deployed base URL.
105
- - Build Packet path if local; otherwise enough info to resolve topology.
104
+ - Saved Map ID or local-spec Build Packet, plus the tested base URL.
105
+ - Build Packet path; required for a local spec, otherwise enough info to resolve topology.
106
106
  - Whether browser QA should run.
107
- - Whether verdict should use the default QA portal publish path or stay local-only.
107
+ - For a saved Map, whether the verdict should use the QA portal publish path or stay local-only. Local-spec packet QA always keeps verdicts and progress local, even with `--post-verdict`; `qa publish` refuses it. Run Telemetry retains its consent controls.
108
108
  - Typed-card test-order depth (`common`/explicit/`full`).
109
109
 
110
110
  Route to QA. Do not patch campaign code from the QA-only path.
@@ -1,28 +1,49 @@
1
1
  ---
2
2
  name: next-campaigns-os-setup
3
- version: 2.0.1
3
+ version: 2.0.10
4
4
  description: Bootstrap or prepare a target page-kit campaign repo from a doctor-cleared Campaigns OS Build Packet before full build wiring. Formerly installed as next-campaigns-setup; renamed 2026-08 to stop colliding with the published NextCommerceCo/skills scaffolder of that name.
5
5
  ---
6
6
 
7
+ Bundle revision: 1.43.1+skills.1
8
+ Run `npx --no-install campaigns-os tooling status --skills-revision 1.43.1+skills.1`
9
+ from the campaign's Page Kit folder, where it runs the project's pinned copy and
10
+ never installs one, at the start of each task. Start a fresh session if it
11
+ reports `mismatch`: this text is already in your context and is never re-read
12
+ while the CLI on disk can move under it. If the output has no `Skills revision:`
13
+ line (no `revision_check` under `--json`), a campaigns-os older than this check
14
+ answered; follow none of its actions and run the pinned copy.
15
+
7
16
  # Next Campaigns OS Setup
8
17
 
9
18
  ## Installed toolkit commands
10
19
 
11
20
  Run from the campaign folder with an exact project-local devDependency and
12
21
  committed lockfile. Orient on reviewed source before installation; check release
13
- provenance or pin the full reviewed Git SHA. Preflight with `npx campaigns-os
14
- tooling status --platform <claude|codex>` and refresh bundled skills for the same
15
- profile. Use the invocation printed by status and `next` to avoid PATH shadowing.
16
-
17
- In the instructions below, bare `campaigns-os …` means `npx campaigns-os …`
18
- from that campaign folder. Global-only users substitute the global copy's printed invocation for
19
- each `npx campaigns-os` example; toolkit contributors translate to `npm run campaigns-os -- …` in
20
- the toolkit checkout. Browser installation is `npx campaigns-os qa
21
- install-browser`, not a campaign npm script. `tooling diagnose --packet <p>
22
- --json` provides a redacted support export without changing retained evidence.
23
-
24
-
25
- Use this skill when the Build Packet doctor says setup is required before assembly.
22
+ provenance or pin the full reviewed Git SHA. Preflight with `npx --no-install
23
+ campaigns-os tooling status --platform <claude|codex>` (tier `B`: its only write
24
+ is the command-lifecycle journal) and refresh bundled skills for the same
25
+ profile with `install-skills` (tier `B`: writes the shared skill directories;
26
+ nothing leaves the machine). Use the invocation printed by status and `next` to
27
+ avoid PATH shadowing.
28
+
29
+ In the instructions below, bare `campaigns-os …` means `npx --no-install
30
+ campaigns-os …` from that campaign folder. Keep `--no-install`: `campaigns-os`
31
+ is only the bin name of `@nextcommerce/campaigns-os`, so where no pinned copy is
32
+ installed a plain `npx` looks that name up on the registry and, with no terminal
33
+ to ask, installs what it finds. Global-only users substitute the global copy's
34
+ printed invocation for each `npx --no-install campaigns-os` example; toolkit
35
+ contributors translate to `npm run campaigns-os -- …` in the toolkit checkout.
36
+ Browser installation is `npx --no-install campaigns-os qa install-browser`, not
37
+ a campaign npm script. `tooling diagnose --packet <p> --json` (tier `none`:
38
+ read-only, and exempt from lifecycle capture) provides a redacted support export
39
+ without changing retained evidence.
40
+
41
+ The effect class in each parenthetical below is the declared row of
42
+ `contracts/effects.v1.json` (`none` < `B` writes < `A` sends < `C` destructive).
43
+ Read that file, not this text, when an exact path or endpoint matters.
44
+
45
+
46
+ Use this skill when the Build Packet doctor (tier `none`: read-only inspection) says setup is required before assembly. Setup follows `campaigns-os start` or `campaigns-os prepare-build` (tier `A`: they write the Build Packet, Build Context, assembly report and run session under the target and contact the Map and run endpoints).
26
47
 
27
48
  Responsibilities:
28
49
 
@@ -1,34 +1,55 @@
1
1
  ---
2
2
  name: next-campaigns-polish
3
- version: 1.1.2
3
+ version: 1.1.11
4
4
  description: Run the visual/runtime polish pass after build and before QA for a Campaigns OS campaign.
5
5
  ---
6
6
 
7
+ Bundle revision: 1.43.1+skills.1
8
+ Run `npx --no-install campaigns-os tooling status --skills-revision 1.43.1+skills.1`
9
+ from the campaign's Page Kit folder, where it runs the project's pinned copy and
10
+ never installs one, at the start of each task. Start a fresh session if it
11
+ reports `mismatch`: this text is already in your context and is never re-read
12
+ while the CLI on disk can move under it. If the output has no `Skills revision:`
13
+ line (no `revision_check` under `--json`), a campaigns-os older than this check
14
+ answered; follow none of its actions and run the pinned copy.
15
+
7
16
  # Next Campaigns Polish
8
17
 
9
18
  ## Installed toolkit commands
10
19
 
11
20
  Run from the campaign folder with an exact project-local devDependency and
12
21
  committed lockfile. Orient on reviewed source before installation; check release
13
- provenance or pin the full reviewed Git SHA. Preflight with `npx campaigns-os
14
- tooling status --platform <claude|codex>` and refresh bundled skills for the same
15
- profile. Use the invocation printed by status and `next` to avoid PATH shadowing.
16
-
17
- In the instructions below, bare `campaigns-os …` means `npx campaigns-os …`
18
- from that campaign folder. Global-only users substitute the global copy's printed invocation for
19
- each `npx campaigns-os` example; toolkit contributors translate to `npm run campaigns-os -- …` in
20
- the toolkit checkout. Browser installation is `npx campaigns-os qa
21
- install-browser`, not a campaign npm script. `tooling diagnose --packet <p>
22
- --json` provides a redacted support export without changing retained evidence.
22
+ provenance or pin the full reviewed Git SHA. Preflight with `npx --no-install
23
+ campaigns-os tooling status --platform <claude|codex>` (tier `B`: its only write
24
+ is the command-lifecycle journal) and refresh bundled skills for the same
25
+ profile with `install-skills` (tier `B`: writes the shared skill directories;
26
+ nothing leaves the machine). Use the invocation printed by status and `next` to
27
+ avoid PATH shadowing.
28
+
29
+ In the instructions below, bare `campaigns-os …` means `npx --no-install
30
+ campaigns-os …` from that campaign folder. Keep `--no-install`: `campaigns-os`
31
+ is only the bin name of `@nextcommerce/campaigns-os`, so where no pinned copy is
32
+ installed a plain `npx` looks that name up on the registry and, with no terminal
33
+ to ask, installs what it finds. Global-only users substitute the global copy's
34
+ printed invocation for each `npx --no-install campaigns-os` example; toolkit
35
+ contributors translate to `npm run campaigns-os -- …` in the toolkit checkout.
36
+ Browser installation is `npx --no-install campaigns-os qa install-browser`, not
37
+ a campaign npm script. `tooling diagnose --packet <p> --json` (tier `none`:
38
+ read-only, and exempt from lifecycle capture) provides a redacted support export
39
+ without changing retained evidence.
40
+
41
+ The effect class in each parenthetical below is the declared row of
42
+ `contracts/effects.v1.json` (`none` < `B` writes < `A` sends < `C` destructive).
43
+ Read that file, not this text, when an exact path or endpoint matters.
23
44
 
24
45
 
25
46
  Use this after build has produced a runnable page-kit campaign.
26
47
 
27
- Theme gate: `campaigns-os next polish` blocks when theme inspect found a
48
+ Theme gate: `campaigns-os next polish` (tier `A`, like every `next` form: additive writes under `.campaign-runtime/` plus a stage-progress POST under Run Telemetry consent; `--no-write` and `--no-remit` are each tier `B`) blocks when theme inspect found a
28
49
  generatable brand theme that is not yet applied to commerce pages. Do not work
29
- around the gate — apply the brand layer (`theme generate`, copy into campaign
30
- assets, load after `next-core.css`, record `report.theme`) or record an
31
- explicit waiver (`campaigns-os theme waive --packet <p> --reason "<why>" --waived-by "<named human>"`; placeholders are refused).
50
+ around the gate — apply the brand layer (`theme generate`, tier `B`; copy into
51
+ campaign assets, load after `next-core.css`, record `report.theme`) or record an
52
+ explicit waiver (`campaigns-os theme waive --packet <p> --reason "<why>" --waived-by "<named human>"` — tier `C`, because the waiver overwrites the assembly report and doctor output; placeholders are refused).
32
53
 
33
54
  Responsibilities:
34
55
 
@@ -49,8 +70,10 @@ Responsibilities:
49
70
  - For exit-intent pops and promo-code inputs, polish the wrapper/copy states without breaking SDK coupon/voucher apply hooks or `cart.hasCoupon("CODE")` conditional labels.
50
71
  - If `report.theme` or `context.theme` exists, verify brand-theme load order after `next-core.css`, source-token parity for primary color/CTA/surface/text/font/radius when present, and SDK safety. When the brand layer is missing, stale, low-confidence, or unsafe to apply, record the first repair-loop defect or an explicit skipped reason.
51
72
  - Before recording a terminal Polish status, install the package-owned browser
52
- once with `npx campaigns-os qa install-browser`, serve the current build, and run
53
- `campaigns-os polish capture --packet <packet> --base-url <served-build-url>`.
73
+ once with `npx --no-install campaigns-os qa install-browser`, serve the
74
+ current build, and run `campaigns-os polish capture --packet <packet> --base-url <served-build-url>`
75
+ (tier `A`: it writes the polish evidence and assembly report under the target
76
+ and fetches the served build at `--base-url`).
54
77
  The package captures every mapped route at fixed desktop/mobile viewports and
55
78
  attaches `stages.polish.evidence.visual_review.page_load`. Never hand-author,
56
79
  copy, or repair that object directly.
@@ -105,6 +128,9 @@ exact ASCII-case-insensitive `preload="none"` or `preload="metadata"` content
105
128
  attribute. Repair and recapture first. Only a complete real finding has an exact
106
129
  named-human waiver lane:
107
130
 
131
+ `campaigns-os checkpoint waive` is tier `C`: a waiver overwrites the assembly
132
+ report and doctor output.
133
+
108
134
  ```bash
109
135
  campaigns-os checkpoint waive \
110
136
  --packet <packet> \
@@ -1,48 +1,72 @@
1
1
  ---
2
2
  name: next-campaigns-qa
3
- version: 1.3.2
4
- description: Run spec-aware QA from a Campaign Map ID and tested campaign URL after build, polish, and deploy/local evidence exist, including Playwright typed-card test-order proof.
3
+ version: 1.3.11
4
+ description: Run spec-aware QA from a saved Map or local-spec Build Packet and tested campaign URL after build, polish, and deploy/local evidence exist, including Playwright typed-card test-order proof.
5
5
  ---
6
6
 
7
+ Bundle revision: 1.43.1+skills.1
8
+ Run `npx --no-install campaigns-os tooling status --skills-revision 1.43.1+skills.1`
9
+ from the campaign's Page Kit folder, where it runs the project's pinned copy and
10
+ never installs one, at the start of each task. Start a fresh session if it
11
+ reports `mismatch`: this text is already in your context and is never re-read
12
+ while the CLI on disk can move under it. If the output has no `Skills revision:`
13
+ line (no `revision_check` under `--json`), a campaigns-os older than this check
14
+ answered; follow none of its actions and run the pinned copy.
15
+
7
16
  # Next Campaigns QA
8
17
 
9
18
  ## Installed toolkit commands
10
19
 
11
20
  Run from the campaign folder with an exact project-local devDependency and
12
21
  committed lockfile. Orient on reviewed source before installation; check release
13
- provenance or pin the full reviewed Git SHA. Preflight with `npx campaigns-os
14
- tooling status --platform <claude|codex>` and refresh bundled skills for the same
15
- profile. Use the invocation printed by status and `next` to avoid PATH shadowing.
22
+ provenance or pin the full reviewed Git SHA. Preflight with `npx --no-install
23
+ campaigns-os tooling status --platform <claude|codex>` (tier `B`: its only write
24
+ is the command-lifecycle journal) and refresh bundled skills for the same
25
+ profile with `install-skills` (tier `B`: writes the shared skill directories;
26
+ nothing leaves the machine). Use the invocation printed by status and `next` to
27
+ avoid PATH shadowing.
28
+
29
+ In the instructions below, bare `campaigns-os …` means `npx --no-install
30
+ campaigns-os …` from that campaign folder. Keep `--no-install`: `campaigns-os`
31
+ is only the bin name of `@nextcommerce/campaigns-os`, so where no pinned copy is
32
+ installed a plain `npx` looks that name up on the registry and, with no terminal
33
+ to ask, installs what it finds. Global-only users substitute the global copy's
34
+ printed invocation for each `npx --no-install campaigns-os` example; toolkit
35
+ contributors translate to `npm run campaigns-os -- …` in the toolkit checkout.
36
+ Browser installation is `npx --no-install campaigns-os qa install-browser` (tier
37
+ `A`: it downloads the Chromium build from the Playwright CDN and writes
38
+ Playwright's browser registry on your machine; it touches no campaign file), not
39
+ a campaign npm script. `tooling diagnose --packet <p> --json` (tier `none`:
40
+ read-only, and exempt from lifecycle capture) provides a redacted support export
41
+ without changing retained evidence.
16
42
 
17
- In the instructions below, bare `campaigns-os …` means `npx campaigns-os …`
18
- from that campaign folder. Global-only users substitute the global copy's printed invocation for
19
- each `npx campaigns-os` example; toolkit contributors translate to `npm run campaigns-os -- …` in
20
- the toolkit checkout. Browser installation is `npx campaigns-os qa
21
- install-browser`, not a campaign npm script. `tooling diagnose --packet <p>
22
- --json` provides a redacted support export without changing retained evidence.
43
+ The effect class in each parenthetical below is the declared row of
44
+ `contracts/effects.v1.json` (`none` < `B` writes < `A` sends < `C` destructive).
45
+ Read that file, not this text, when an exact path or endpoint matters.
23
46
 
24
47
 
25
- Use this after the campaign has a preview or production URL and the assembly report records build and polish status. The public v0 runner is Node/npm-based, with an owned Playwright browser pass:
48
+ Use this after the campaign has a tested localhost, preview or production URL and the assembly report records build and polish status. The public v0 runner is Node/npm-based, with an owned Playwright browser pass. `qa resolve` is tier `A` (it fetches `--base-url`; `--no-probe` is tier `B` and local); every `qa run` form is tier `C` — it overwrites the stored verdict and the assembly report, places requested typed-card test orders against the campaign, and can post saved-Map verdicts and progress under their existing controls. Local-spec packet verdicts and progress stay local; `qa parity` is tier `A` (it drives the fixture's scenario through the candidate funnel with real typed-card orders and publishes the verdict, but takes no packet, so it writes only under `qa-output/` — never the packet, the assembly report or the verdict sidecar; `--no-post-verdict` drops the publish and stays tier `A`):
26
49
 
27
50
  ```bash
28
- npx campaigns-os qa install-browser
29
- npx campaigns-os qa resolve --packet campaign-runtime.build.json
30
- npx campaigns-os qa run --packet campaign-runtime.build.json --base-url <preview-url>
51
+ npx --no-install campaigns-os qa install-browser
52
+ npx --no-install campaigns-os qa resolve --packet campaign-runtime.build.json
53
+ npx --no-install campaigns-os qa run --packet campaign-runtime.build.json --base-url <preview-url>
31
54
  # Fixture-driven migration parity proof. Publishes to the QA portal by default.
32
- npx campaigns-os qa parity --fixture <parity-fixture.json> --scenario <scenario-id> --base-url <preview-url>
33
- # Browser QA + typed-card proof. Publishes to the QA portal by default and prints the portal link.
34
- npx campaigns-os qa run --packet campaign-runtime.build.json --base-url <preview-url> --browser --test-order common
35
- # Offline / dev / CI only: keep the verdict local
36
- npx campaigns-os qa run --packet campaign-runtime.build.json --base-url <preview-url> --browser --test-order common --no-post-verdict
55
+ npx --no-install campaigns-os qa parity --fixture <parity-fixture.json> --scenario <scenario-id> --base-url <preview-url>
56
+ # Browser QA + typed-card proof. Saved-Map publishing follows consent; local-spec QA stays local.
57
+ npx --no-install campaigns-os qa run --packet campaign-runtime.build.json --base-url <preview-url> --browser --test-order common
58
+ # Keep a saved-Map verdict local (local-spec verdicts are always local).
59
+ npx --no-install campaigns-os qa run --packet campaign-runtime.build.json --base-url <preview-url> --browser --test-order common --no-post-verdict
37
60
  ```
38
61
 
39
- `npx campaigns-os qa install-browser` is part of the standard QA sequence. Run it once
40
- after install/update before using `--browser` or `--test-order`; do not skip it
41
- unless the local Playwright browser binary is already installed.
62
+ `npx --no-install campaigns-os qa install-browser` is part of the standard QA
63
+ sequence. Run it once after install/update before using `--browser` or
64
+ `--test-order`; do not skip it unless the local Playwright browser binary is
65
+ already installed.
42
66
 
43
67
  Inputs:
44
68
 
45
- - Campaign Map ID from the Build Packet
69
+ - Build Packet with a saved Map ID or `local_spec_id`; local-spec QA requires `--packet`
46
70
  - tested base URL (localhost dev URL, preview URL, or production URL)
47
71
  - assembly report
48
72
  - Test-order coverage choice (`common` default vs explicit paths vs topology-complete `full`) and SDK origin state (localhost is a Development domain; non-localhost origins need allowlist confirmation so the SDK loads)
@@ -55,17 +79,18 @@ Rules:
55
79
  - Parity capture blocking proof is the voucher-adjusted persisted line from typed-card order readback. Browser totals and client state do not replace the persisted-line voucher guard.
56
80
  - Read client purchase values per event. A whole-cart `dl_purchase` must not mask or supply an offer-level upsell purchase expectation.
57
81
  - Live `qa parity` runs publish to the QA portal by default like other QA runs. Pass `--no-post-verdict` for dev, replay, negative-control, and other local proof runs.
58
- - Theme gate: `qa run` refuses to run when a generatable brand theme is not applied to commerce pages and no waiver exists. Apply the brand layer or record a waiver (`campaigns-os theme waive` / `qa run --theme-waive "<reason>"`); do not bypass the gate another way. A waived run still reports template-residue findings at warn severity.
82
+ - Theme gate: `qa run` refuses to run when a generatable brand theme is not applied to commerce pages and no waiver exists. Apply the brand layer or record a waiver (`campaigns-os theme waive`, tier `C`: it overwrites the assembly report and doctor output / `qa run --theme-waive "<reason>"`); do not bypass the gate another way. A waived run still reports template-residue findings at warn severity.
59
83
  - Template residue is a QA dimension, not advice: promoted starter families must have a brand/residue/pricing contract (`contracts/template-brand-contract.<family>.v0.json`). Browser QA inspects computed styles on commerce surfaces and fails pages that still render starter defaults (`#3c7dff`/`#0a265c`, starter `next-logo.png`, paypal/klarna chrome absent from the spec).
60
84
  - Pricing visibility is a blocker: an upsell/downsell offer with zero visible price rows fails QA. Pricing surfaces render via template pricing modes (`full_price`, `compare_at_current`, `unit_price_plus_total`, `savings_badge_amount`, `code_discounted_post_checkout`), never via campaign CSS `display:none` on price wrappers.
61
85
  - Exit-pop widgets are governed offer surfaces. If the selected family ships or copies a default exit-pop and CampaignSpec has no checkout `exit_intent` or `promo_code_input`, QA/doctor must report it as residue; strip it or wire the mapped offer/code through the SDK coupon path.
62
86
  - Typed-card runs emit a per-step ladder (`[qa:test-order] step=... status=...`) with bounded per-step and per-path timeouts, and always produce a verdict — a hung or crashed path is a blocked verdict with the step ladder as evidence, not a silent exit. Read the last completed step before re-running.
63
87
  - A typed-card path that fails is classified by **what it did to the store** before the runner decides what to do about it. A failure the runner can prove happened before submit (`not_created`) is **re-run once, if the creation budget has a slot no still-unrun planned path needs** — so a transient miss is not reported as a defect in the build, without an early path eating budget the last planned paths need. Under the default budget a path whose submit was *rejected* has already spent its own slot, so it is not re-run and records `evidence.order_creation.rerun_skipped` instead. When the re-run does happen, both attempts appear in `test_orders[]` and `evidence.retry` names the first attempt's error and ref id. A failure that happened **after** the order was created (`created` — most often a receipt that did not render) is **never resubmitted**: the runner reloads that order's receipt and re-runs only the read-only checks, and `evidence.recovery` carries the original failure, the checks re-run, and whether it cleared. Read `evidence.order_creation` for two separate counts: `submissions_reserved` (platform-side creation slots charged to this path — reserved before a submit click, or charged for a hosted-checkout redirect where no submit click happens — which stand even when the create then failed) and `orders_confirmed_created` (creates the platform was observed to accept) — a spent slot with no confirmed order is the ambiguous case, not an order to reconcile. Recovery clears only on persisted evidence it re-read on that pass: a failed or absent order read-back stops it honestly rather than re-deciding against the original attempt's numbers. An outcome it cannot prove either way (`ambiguous` — an unusable read-back, a lost create response, a network-failed create, a 4xx after an earlier 2xx) stops the path and names the operator check instead of buying again. A pass that only came back after recovery is never indistinguishable from a first-attempt pass, and a failure that survives recovery still blocks.
64
88
  - Analytics correctness is two-phase in the same run: the campaign-root visit inventories declared providers/tags only, then the one canonical typed-card run proves Purchase for each topology-recognized receipt from the signals emitted across every page the path loaded after checkout, read after the full `--analytics-settle` window. The receipt qualifies the order; the journey is measured, because the SDK fires `dl_purchase` (and the outbound Purchase) on the first `?ref_id=` page — the upsell page when the funnel has one — and dedupes it on the receipt. It never places a second analytics order. The receipt document's own reading stays in evidence (`receipt_signals`, `fired_on`) as the diagnostic of which document fired.
65
- - A missing or topology-unrecognized receipt is `MANUAL_REVIEW`/`WARN`; a recognized receipt with no dataLayer, outbound Meta, or outbound GA4 Purchase is `FAIL`/`BLOCKER`. Capture, unreadable-page, and settle-deadline errors on a recognized receipt are explicit non-waivable blockers. The `analytics-correctness:purchase-fires` waiver applies only to a genuine recognized-receipt/no-signal failure.
89
+ - A missing or topology-unrecognized receipt is `MANUAL_REVIEW`/`WARN`; a recognized receipt with no dataLayer, outbound Meta, or outbound GA4 Purchase is `FAIL`/`BLOCKER`. Capture, unreadable-page, and settle-deadline errors on a recognized receipt are explicit non-waivable blockers. The `analytics-correctness:purchase-fires` waiver applies only to a genuine recognized-receipt/no-signal failure, and is recorded with `campaigns-os qa waive --assertion analytics-correctness:purchase-fires --reason "<why>"` (tier `C`: it overwrites the assembly report and doctor output; the lane is scoped to that one assertion and every other is refused).
66
90
  - Keep QA in a tight sequence: install the Playwright browser, resolve topology, run browser QA plus typed-card proof with `--test-order common` by default. Test orders need no permission step. Pause only for missing inputs, out-of-scope runtime pages that block checkout proof, or merchant-specific uncertainty.
67
91
  - Use `--browser` for rendered browser evidence. Browser QA must use the package-owned Playwright flow, not external agent/browser skills.
68
- - QA runs publish to the QA portal by default, so the QA tab/dashboard carries the full audit log and the run prints its portal link — report that link as the run reference. Pass `--no-post-verdict` (or `--local-only`) only for offline / dev / CI runs; those stay local-only under `qa-output/` and must not be reported as dashboard-visible.
92
+ - Saved-Map QA publishes to the QA portal under the existing consent and flag controls; report the portal link only when publication succeeds. Pass `--no-post-verdict` (or `--local-only`) to keep that verdict local. This stays tier `C`: served-page probes, requested orders, Run Telemetry and progress retain their own controls. See `docs/qa-and-test-orders.md` for the saved-Map publication policy.
93
+ - Local-spec QA always keeps verdicts and progress local. `qa run` suppresses portal publication even with `--post-verdict`; `qa publish` refuses local-spec packets with `local_spec`. Report the local verdict/sidecar as evidence, never a dashboard link. A matching route cannot replace a matching `local_spec_id`, and QA refuses a foreign or stale local Assembly Report. Run Telemetry still follows its consent controls.
69
94
  - Browser QA must include checkout commerce geometry evidence, not just mount counts: express-wallet buttons rendered in the current browser, card/CVV hosted iframe host dimensions, iframe text-path height, and center alignment. Apple Pay is browser/device eligible, so record mounted wallet kinds instead of requiring Apple Pay in Chrome-only QA.
70
95
  - `qa resolve` accepts either the deploy host or the campaign-root URL; when a Build Packet carries `campaign.public_route_slug`, the runner resolves page URLs under that slug.
71
96
  - Routing meta tags must be checked in runtime form. `next-success-url`, `next-upsell-accept-url`, and `next-upsell-decline-url` should point at campaign-root paths such as `/campaign-slug/upsell/`, not source filenames or unrooted spec literals.
@@ -105,4 +130,4 @@ Canonical test-order flow:
105
130
  6. On upsell pages, click the actual accept or decline button for the target path.
106
131
  7. Verify receipt/order evidence and summarize order number, `ref_id`, selected cart, active vouchers/promo codes, discounts, upsell path, and line-item result.
107
132
 
108
- Do not use `campaigns-os qa --legacy-api-test-order` as the canonical proof path. It bypasses the deployed campaign page and the SDK checkout/upsell surfaces; keep it only as a diagnostic fallback when explicitly requested.
133
+ Do not use `campaigns-os qa run --legacy-api-test-order` as the canonical proof path. It bypasses the deployed campaign page and the SDK checkout/upsell surfaces; keep it only as a diagnostic fallback when explicitly requested.