@nextcommerce/campaigns-os 1.43.1 → 1.46.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/AGENTS.md +9 -2
- package/CHANGELOG.md +1099 -5103
- package/README.md +34 -13
- package/agents/claude/CLAUDE.md +1 -1
- package/agents/codex/AGENTS.md +1 -1
- package/agents/copilot/copilot-instructions.md +1 -1
- package/agents/cursor/campaigns-os.mdc +1 -1
- package/campaign-spec/dist/rules/analytics-contract-shape.d.ts +2 -2
- package/campaign-spec/dist/rules/analytics-contract-shape.js +2 -2
- package/campaign-spec/dist/rules/store-profile-shape.d.ts +5 -1
- package/campaign-spec/dist/rules/store-profile-shape.js +8 -10
- package/campaign-spec/dist/types.d.ts +2 -2
- package/contracts/agent-relevant-change-policy.v1.json +5 -0
- package/contracts/archive/CHANGELOG.2026-09-30.md +5111 -0
- package/contracts/archive/release-ledger.2026-09-30.json +5068 -0
- package/contracts/effects.v1.json +1184 -121
- package/contracts/orientation-reason-codes.v1.json +7 -0
- package/contracts/release-ledger.json +2190 -5260
- package/contracts/supported-surface.json +7 -4
- package/contracts/template-slot-manifest.shared-content-core.v0.json +403 -0
- package/docs/brand-theme-bridge.md +81 -0
- package/docs/build-packet.md +222 -23
- package/docs/campaigns-os-build-flow.md +4 -3
- package/docs/design-source-package.md +162 -15
- package/docs/effects.md +66 -12
- package/docs/gateway-login.md +3 -0
- package/docs/local-setup.md +1 -1
- package/docs/orientation-contract-reference.md +42 -2
- package/docs/polish-evidence.md +74 -0
- package/docs/progress-snapshots.md +10 -6
- package/docs/qa-and-test-orders.md +230 -20
- package/docs/release-ledger-authoring-guide.md +70 -8
- package/docs/runtime-readiness.md +1 -1
- package/docs/sdk-storage-compatibility.md +1 -1
- package/docs/skills-revision.md +10 -10
- package/docs/supported-surface.md +2 -2
- package/docs/versioning.md +4 -1
- package/package.json +1 -1
- package/schemas/campaigns-os-release-ledger.v1.schema.json +32 -2
- package/schemas/campaigns-os-tooling-orientation.v1.schema.json +1 -0
- package/skills/campaign-lifecycle-orientation/SKILL.md +16 -5
- package/skills/campaign-readback-classification/SKILL.md +3 -3
- package/skills/campaign-run-evidence/SKILL.md +7 -6
- package/skills/contribution-intake/SKILL.md +3 -3
- package/skills/next-campaigns-build/SKILL.md +7 -6
- package/skills/next-campaigns-os/SKILL.md +7 -7
- package/skills/next-campaigns-os/references/session-intake.md +9 -3
- package/skills/next-campaigns-os-setup/SKILL.md +5 -5
- package/skills/next-campaigns-polish/SKILL.md +28 -9
- package/skills/next-campaigns-qa/SKILL.md +7 -4
- package/skills.json +10 -10
- package/src/brand-theme.mjs +320 -20
- package/src/build-brief.mjs +6 -4
- package/src/built-script-syntax.mjs +480 -0
- package/src/built-site-scope.mjs +16 -4
- package/src/campaigns-api-key.mjs +99 -0
- package/src/cli-helpers.mjs +118 -0
- package/src/cli.mjs +1530 -7580
- package/src/commercial-parity.mjs +48 -2
- package/src/design-source-package.mjs +1 -1
- package/src/design-source-publication.mjs +898 -0
- package/src/deviation.mjs +13 -1
- package/src/diagnostic.mjs +6 -2
- package/src/directory-lock.mjs +270 -0
- package/src/doctor/checks.mjs +4654 -0
- package/src/doctor/inspect.mjs +678 -0
- package/src/doctor/next-step.mjs +731 -0
- package/src/doctor/source-provenance.mjs +184 -0
- package/src/install-invocation.mjs +29 -0
- package/src/invocation.mjs +183 -0
- package/src/live-campaign-refs.mjs +466 -0
- package/src/login.mjs +2 -2
- package/src/page-kit-store-profile.mjs +69 -12
- package/src/page-kit-sync.mjs +31 -12
- package/src/private-template-source.mjs +1 -1
- package/src/progress-node.mjs +9 -36
- package/src/proof-policy.mjs +1 -1
- package/src/qa-analytics-correctness.mjs +3 -0
- package/src/qa-binding-evidence.mjs +76 -11
- package/src/qa-browser.mjs +1316 -105
- package/src/qa-build-scope.mjs +47 -0
- package/src/qa-commercial-parity.mjs +48 -5
- package/src/qa-node.mjs +339 -19
- package/src/qa-test-order-topology.mjs +148 -0
- package/src/sdk-markup.mjs +72 -8
- package/src/source-html-intake.mjs +117 -1
- package/src/source-html-manifest.mjs +9 -2
- package/src/stage-ledger.mjs +28 -0
- package/src/stage-record.mjs +551 -0
- package/src/target-lock.mjs +54 -0
- package/src/template-brand-contract.mjs +17 -1
- package/src/upsell-selector-scope.mjs +112 -2
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ steps, in this order:
|
|
|
47
47
|
mkdir "<route>" && cd "<route>"
|
|
48
48
|
npm init -y && npm i next-campaign-page-kit
|
|
49
49
|
npx campaign-init --non-interactive --template <family> --slug "<route>" --name "<campaign name>"
|
|
50
|
-
npm install --save-dev --save-exact @nextcommerce/campaigns-os
|
|
50
|
+
npm install --save-dev --save-exact @nextcommerce/campaigns-os@<version>
|
|
51
51
|
npx --no-install campaigns-os tooling status --platform claude
|
|
52
52
|
npx --no-install campaigns-os install-skills --platform claude
|
|
53
53
|
mkdir -p source
|
|
@@ -57,7 +57,7 @@ The toolkit is also published to npm as `@nextcommerce/campaigns-os`, so the
|
|
|
57
57
|
CLI can be installed once, globally, instead of pinned per campaign:
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
|
-
npm install -g @nextcommerce/campaigns-os
|
|
60
|
+
npm install -g @nextcommerce/campaigns-os@<version>
|
|
61
61
|
campaigns-os tooling status --platform claude
|
|
62
62
|
campaigns-os install-skills --platform claude
|
|
63
63
|
```
|
|
@@ -73,9 +73,11 @@ runs the full check in an unprivileged job and publishes the verified tarball
|
|
|
73
73
|
with provenance from a second, environment-gated job.
|
|
74
74
|
|
|
75
75
|
For an existing page-kit campaign, skip the first three lines and `cd` into it
|
|
76
|
-
(its `package.json` already declares `next-campaign-page-kit`).
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
(its `package.json` already declares `next-campaign-page-kit`). `<version>` is
|
|
77
|
+
the exact release you reviewed. The newest published release is npm's `latest`
|
|
78
|
+
(`npm view @nextcommerce/campaigns-os version`), and
|
|
79
|
+
`contracts/release-ledger.json` and `CHANGELOG.md` list every release. Pin the
|
|
80
|
+
exact version, never a floating dist-tag, for a reproducible build. Commit `package.json` and `package-lock.json`.
|
|
79
81
|
`tooling diagnose` requires 1.35.0 or later and `demo` requires 1.37.0 or later.
|
|
80
82
|
A Git source pin remains supported when using an unreleased reviewed commit:
|
|
81
83
|
`npm install --save-dev --save-exact "github:NextCommerceCo/campaigns-os#<full-sha>"`.
|
|
@@ -94,7 +96,10 @@ check registry currency or establish trust. On a fresh profile, preflight exits
|
|
|
94
96
|
use `--platform codex` for a Codex-only profile. Without `--platform`, status
|
|
95
97
|
checks every supported agent profile.
|
|
96
98
|
`install-skills` writes `~/.claude/skills` (`--platform codex` writes
|
|
97
|
-
`~/.codex/skills`), replacing same-name folders
|
|
99
|
+
`~/.codex/skills`), replacing same-name folders, and lists each `SKILL.md` it
|
|
100
|
+
wrote under `Read now`. A running agent does not load skills installed after it
|
|
101
|
+
started, so read those files now in the same session; a new session loads them
|
|
102
|
+
on its own.
|
|
98
103
|
Run commands from the campaign folder: `npx` selects its local installation
|
|
99
104
|
even when another global copy is on PATH. A global-only installation prints
|
|
100
105
|
bare commands when its binary matches PATH, or an explicit `node` invocation
|
|
@@ -198,8 +203,8 @@ are template stock instead — no bespoke design, the starter family *is* the
|
|
|
198
203
|
design — there is no screenshot to honestly supply. Declare those pages out of
|
|
199
204
|
source scope (a manifest `skip_reason` entry, or CampaignSpec
|
|
200
205
|
`build_scope.mode: "partial"`): intake records them as template stock, demands
|
|
201
|
-
no design source for them, and
|
|
202
|
-
locked family's
|
|
206
|
+
no design source for them, and leaves them unbuilt unless the operator opts in
|
|
207
|
+
per page to materializing the locked family's stock. A family that publishes Template Reference proof
|
|
203
208
|
(today `apollo`) covers them with `template_baseline`; every other family
|
|
204
209
|
records an accepted Source Gap and intake lands at `ready_with_gaps`. See
|
|
205
210
|
[Template-stock pages: the family decides](docs/design-source-package.md#template-stock-pages-the-family-decides).
|
|
@@ -232,10 +237,25 @@ Then ask your AI tool to continue from the emitted handoff. Fresh target repos u
|
|
|
232
237
|
|
|
233
238
|
The current source adapter is `html_funnel`: bring prepared HTML/CSS/assets for the campaign pages, plus a CampaignSpec exported from Campaign Map Builder or authored by the coding agent through the [local-spec entry](docs/build-packet.md#local-spec-entry).
|
|
234
239
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
240
|
+
Standalone HTML mockups: keep them whole and set
|
|
241
|
+
`wrapper_policy: preserve_document_wrappers` in the source-html manifest at
|
|
242
|
+
`<source>/.campaigns-os/source-html-manifest.json` (or pass
|
|
243
|
+
`--wrapper-policy preserve_document_wrappers` to `start`). Source screenshot
|
|
244
|
+
proof must be of the standalone document, so a page kept whole needs no
|
|
245
|
+
conversion; doctor reports its document wrappers as a warning that names the
|
|
246
|
+
decision. For pages without a Figma `design_source`, no exporter is required:
|
|
247
|
+
a hand-written manifest is enough (when any active page's `design_source` is
|
|
248
|
+
Figma, the manifest must pass the Figma provenance gate, which needs the
|
|
249
|
+
exporter's handoff manifest), for example
|
|
250
|
+
`{"schema_version": "source-html-manifest/v0", "wrapper_policy": "preserve_document_wrappers", "pages": [{"page_id": "landing", "path": "landing.html"}]}`
|
|
251
|
+
(schema: `schemas/source-html-manifest.v0.schema.json`; see
|
|
252
|
+
[Selecting the wrapper policy at intake](docs/source-adapters.md#selecting-the-wrapper-policy-at-intake)).
|
|
253
|
+
|
|
254
|
+
Otherwise, for raw AI-generated or exported static HTML, "prepared" means
|
|
255
|
+
page-kit-ready source, not a browser document dropped in unchanged and not a
|
|
256
|
+
wholesale Liquid rewrite. Page Kit source is HTML with YAML frontmatter and
|
|
257
|
+
optional Liquid helpers. Convert standalone HTML into the target page format
|
|
258
|
+
first: remove outer
|
|
239
259
|
`<html>`, `<head>`, and `<body>` wrappers, add page frontmatter, move shared
|
|
240
260
|
CSS/assets into the campaign asset tree when useful, root links/assets with
|
|
241
261
|
`campaign_link` and `campaign_asset` when needed, and keep landing/presell
|
|
@@ -295,7 +315,8 @@ for a package install the pinned commit is the freshness answer, and there is
|
|
|
295
315
|
no npm dist-tag to compare against. Neither mode makes agent skills current on
|
|
296
316
|
its own: when skills are stale, run the refresh command the status output
|
|
297
317
|
prints (it names each stale platform, through the same prefix you ran
|
|
298
|
-
`tooling status` with)
|
|
318
|
+
`tooling status` with), then read the `SKILL.md` files it lists under `Read now`
|
|
319
|
+
in the running session (new sessions load them on their own). Without `--platform`,
|
|
299
320
|
status checks only the platforms where Campaigns OS skills are installed.
|
|
300
321
|
|
|
301
322
|
Run `campaigns-os qa install-browser` (`npm run qa:install-browser` from a
|
package/agents/claude/CLAUDE.md
CHANGED
|
@@ -25,7 +25,7 @@ Core rules:
|
|
|
25
25
|
- Do not copy Olympus-style `shipping_methods` frontmatter into `shop-three-step`; it uses dynamic shipping through `window.next.getShippingMethods()`.
|
|
26
26
|
- Run build/lint checks and record evidence in the assembly report, then hand off to polish. Before Polish becomes terminal or hands off to deploy/QA, install the package-owned Playwright browser with `npm run qa:install-browser`, serve the current build, and run `campaigns-os polish capture --packet campaign-runtime.build.json --base-url <served-current-build-url>`.
|
|
27
27
|
- After that checkpoint clears, QA uses the Campaigns OS Node/npm runner: run `campaigns-os qa resolve --packet campaign-runtime.build.json`, then run `campaigns-os qa run --packet campaign-runtime.build.json --base-url <url> --browser --test-order common`.
|
|
28
|
-
- Typed-card test-order proof uses `campaigns-os qa run --test-order <common|checkout|decline|accept|both|full|explicit-path>` through the deployed checkout and rendered upsell controls. `common` runs the checkout baseline, first-offer accept and decline, and a deduplicated shortest real receipt path when
|
|
28
|
+
- Typed-card test-order proof uses `campaigns-os qa run --test-order <common|checkout|decline|accept|both|full|explicit-path>` through the deployed checkout and rendered upsell controls. `common` runs every actual terminal path when they fit under the flood cap (`--max-test-orders`, 6 by default); above the cap it runs the checkout baseline, first-offer accept and decline, and a deduplicated shortest real receipt path, then adds one decline path per offer or downsell page not yet declined, up to the cap, and names any page left out. A page counts as covered only when an order clicks its decline; the `browser-test-order:upsell-action-coverage` verdict row warns naming each page whose decline no order clicked. `full` walks every actual terminal path in the selected checkout topology; cycles, missing routes, and reachable nonterminals block exhaustive proof before browser launch. The accidental-flood cap remains `6`, and an overflow names the exact explicit `--max-test-orders` raise. Coverage is the only control — there is no permission/approval step.
|
|
29
29
|
- Analytics correctness is two-phase: the campaign-root visit inventories declared providers/tags only, and the same canonical typed-card run proves Purchase only from the topology-recognized final receipt document after `--analytics-settle`. Missing/unrecognized receipts are manual-review warnings; recognized receipt no-signal and capture/settle errors block. Only the genuine recognized-receipt/no-signal failure is waivable; capture/settle errors are not. Checkout/upsell signals remain whole-journey parity evidence and cannot satisfy a silent receipt.
|
|
30
30
|
- Test-order proof must use the canonical Playwright typed-card path through the tested checkout: select the rendered cart, fill customer/shipping fields, type the sandbox card into active hosted payment iframes, click the real submit button, then click rendered SDK upsell accept/decline controls and verify receipt/order evidence.
|
|
31
31
|
- Do not use `next.getCartData().cartLines` as cart-populated proof; use typed-card order read-back, `cart:updated` payload `items` / `summary.lines`, and rendered bundle DOM evidence.
|
package/agents/codex/AGENTS.md
CHANGED
|
@@ -20,7 +20,7 @@ Use this context when working in a target campaign repo with Campaigns OS artifa
|
|
|
20
20
|
- For `shop-three-step`, keep dynamic shipping via `window.next.getShippingMethods()` and do not add Olympus-style static `shipping_methods` frontmatter.
|
|
21
21
|
- Build hands off to polish. Before Polish becomes terminal or hands off to deploy/QA, install the package-owned Playwright browser with `npm run qa:install-browser`, serve the current build, and run `campaigns-os polish capture --packet campaign-runtime.build.json --base-url <served-current-build-url>`.
|
|
22
22
|
- After that checkpoint clears, QA uses the Campaigns OS Node/npm runner: run `campaigns-os qa resolve`, then `campaigns-os qa run --browser --test-order common` against the tested URL.
|
|
23
|
-
- Typed-card test-order proof uses `campaigns-os qa run --test-order <common|checkout|decline|accept|both|full|explicit-path>` through the tested checkout and rendered upsell controls. Global test cards bypass the gateway and create no transactions, so no permission/approval is needed — coverage is the only control. `common` runs the checkout baseline, first-offer accept and decline, and a deduplicated shortest real receipt path when
|
|
23
|
+
- Typed-card test-order proof uses `campaigns-os qa run --test-order <common|checkout|decline|accept|both|full|explicit-path>` through the tested checkout and rendered upsell controls. Global test cards bypass the gateway and create no transactions, so no permission/approval is needed — coverage is the only control. `common` runs every actual terminal path when they fit under the flood cap (`--max-test-orders`, 6 by default); above the cap it runs the checkout baseline, first-offer accept and decline, and a deduplicated shortest real receipt path, then adds one decline path per offer or downsell page not yet declined, up to the cap, and names any page left out. A page counts as covered only when an order clicks its decline; the `browser-test-order:upsell-action-coverage` verdict row warns naming each page whose decline no order clicked. `full` walks every actual terminal path in the selected checkout topology; cycles, missing routes, and reachable nonterminals block exhaustive proof before browser launch. The accidental-flood cap remains `6`, and an overflow names the exact explicit `--max-test-orders` raise. Localhost on any port is a Campaigns App Development domain for SDK QA with analytics suppressed; non-localhost preview/production origins still need SDK origin allowlist confirmation. Do not use external browser skills, the SDK test-mode event, or hand-built backend API orders as launch proof.
|
|
24
24
|
- Analytics correctness is two-phase: the campaign-root visit inventories declared providers/tags only, and the same canonical typed-card run proves Purchase only from the topology-recognized final receipt document after `--analytics-settle`. Missing/unrecognized receipts are manual-review warnings; recognized receipt no-signal and capture/settle errors block. Only the genuine recognized-receipt/no-signal failure is waivable; capture/settle errors are not. Checkout/upsell signals remain whole-journey parity evidence and cannot satisfy a silent receipt.
|
|
25
25
|
- Do not use `next.getCartData().cartLines` as cart-populated proof; use typed-card order read-back, `cart:updated` payload `items` / `summary.lines`, and rendered bundle DOM evidence.
|
|
26
26
|
- Campaigns OS proof is not merchant launch readiness. Before launch, confirm production storefront URL, live payment methods, shipping markets, legal/support URLs, analytics expectations, and merchant-side configuration.
|
|
@@ -11,4 +11,4 @@ CampaignSpec validation is owned by the public `@nextcommerce/campaigns-os/campa
|
|
|
11
11
|
|
|
12
12
|
Preserve Campaign Cart SDK-owned commerce surfaces. Replace starter demo refs from CampaignSpec/API. Prepared AI/exported HTML must be converted into page-kit-ready source first: keep page-owned body markup, strip document wrappers, add YAML frontmatter, move shared CSS/assets into the campaign structure, and use Liquid helpers only for page-kit links/assets/includes. Landing/presell pages can preserve source design; checkout/upsell/downsell/receipt should use starter-template commerce surfaces as SDK contract references while campaign/source owns visual chrome. Copy starter template families atomically with dependent pages, `_includes/`, `_layouts/`, `assets/css/`, and `assets/js/`; do not copy only checkout/receipt pages. Do not claim launch readiness until build, polish, deploy, and QA evidence are recorded.
|
|
13
13
|
|
|
14
|
-
Before Polish becomes terminal or hands off to deploy/QA, install the package-owned Playwright browser with `npm run qa:install-browser`, serve the current build, and run `campaigns-os polish capture --packet campaign-runtime.build.json --base-url <served-current-build-url>`. After that checkpoint clears, QA must use the Campaigns OS Node/npm runner: run `campaigns-os qa resolve`, then run `campaigns-os qa run --browser --test-order common` against the tested URL. Typed-card test-order proof must use `campaigns-os qa run --test-order <common|checkout|decline|accept|both|full|explicit-path>` through the tested checkout and rendered upsell controls; global test cards bypass the gateway and create no transactions, so no permission/approval is needed. `common` runs the checkout baseline, first-offer accept and decline, and a deduplicated shortest real receipt path when
|
|
14
|
+
Before Polish becomes terminal or hands off to deploy/QA, install the package-owned Playwright browser with `npm run qa:install-browser`, serve the current build, and run `campaigns-os polish capture --packet campaign-runtime.build.json --base-url <served-current-build-url>`. After that checkpoint clears, QA must use the Campaigns OS Node/npm runner: run `campaigns-os qa resolve`, then run `campaigns-os qa run --browser --test-order common` against the tested URL. Typed-card test-order proof must use `campaigns-os qa run --test-order <common|checkout|decline|accept|both|full|explicit-path>` through the tested checkout and rendered upsell controls; global test cards bypass the gateway and create no transactions, so no permission/approval is needed. `common` runs every actual terminal path when they fit under the flood cap (`--max-test-orders`, 6 by default); above the cap it runs the checkout baseline, first-offer accept and decline, and a deduplicated shortest real receipt path, then adds one decline path per offer or downsell page not yet declined, up to the cap, and names any page left out. A page counts as covered only when an order clicks its decline; the `browser-test-order:upsell-action-coverage` verdict row warns naming each page whose decline no order clicked. `full` walks every actual terminal path in the selected checkout topology; cycles, missing routes, and reachable nonterminals block exhaustive proof before browser launch. The accidental-flood cap remains `6`, and an overflow names the exact explicit `--max-test-orders` raise. Analytics correctness is two-phase: the campaign-root visit inventories declared providers/tags only, and the same canonical typed-card run proves Purchase only from the topology-recognized final receipt document after `--analytics-settle`. Missing/unrecognized receipts are manual-review warnings; recognized receipt no-signal and capture/settle errors block. Only the genuine recognized-receipt/no-signal failure is waivable; capture/settle errors are not. Checkout/upsell signals remain whole-journey parity evidence and cannot satisfy a silent receipt. Do not use `next.getCartData().cartLines` as cart-populated proof; use typed-card order read-back, `cart:updated` payload `items` / `summary.lines`, and rendered bundle DOM evidence. Localhost on any port is a Campaigns App Development domain for SDK QA with analytics suppressed; non-localhost preview/production origins still need SDK origin allowlist confirmation. Do not use external browser skills, SDK test-mode events, or direct backend orders as launch proof. Campaigns OS proof is not merchant launch readiness; before launch, confirm production storefront URL, live payment methods, shipping markets, legal/support URLs, analytics expectations, and merchant-side configuration.
|
|
@@ -10,4 +10,4 @@ Read Campaigns OS artifacts before editing campaign pages. Treat CampaignSpec/AP
|
|
|
10
10
|
|
|
11
11
|
Do not carry over demo package, shipping, voucher, payment, tracking, footer, or SEO values. Prepared AI/exported HTML must be converted into page-kit-ready source first: keep page-owned body markup, strip document wrappers, add YAML frontmatter, move shared CSS/assets into the campaign structure, and use Liquid helpers only for page-kit links/assets/includes. Preserve prepared landing/presell source HTML when it is a real standalone design. For checkout/upsell/downsell/receipt, use starter-template commerce surfaces as SDK contract references while campaign/source owns visual chrome. Copy starter template families atomically with dependent pages, `_includes/`, `_layouts/`, `assets/css/`, and `assets/js/`; do not copy only checkout/receipt pages. Emit SDK routing meta tags as campaign-root paths such as `/campaign-slug/upsell/`. Preserve SDK-owned checkout/cart/upsell/receipt surfaces. For `shop-three-step`, shipping is dynamic via `window.next.getShippingMethods()`.
|
|
12
12
|
|
|
13
|
-
Before Polish becomes terminal or hands off to deploy/QA, install the package-owned Playwright browser with `npm run qa:install-browser`, serve the current build, and run `campaigns-os polish capture --packet campaign-runtime.build.json --base-url <served-current-build-url>`. After that checkpoint clears, QA uses the Campaigns OS Node/npm runner: `campaigns-os qa resolve`, then `campaigns-os qa run --browser --test-order common` against the tested URL. Test-order proof uses `campaigns-os qa run --test-order <common|checkout|decline|accept|both|full|explicit-path>` through the tested checkout and rendered upsell controls; global test cards bypass the gateway and create no transactions, so no permission/approval is needed. `common` runs the checkout baseline, first-offer accept and decline, and a deduplicated shortest real receipt path when
|
|
13
|
+
Before Polish becomes terminal or hands off to deploy/QA, install the package-owned Playwright browser with `npm run qa:install-browser`, serve the current build, and run `campaigns-os polish capture --packet campaign-runtime.build.json --base-url <served-current-build-url>`. After that checkpoint clears, QA uses the Campaigns OS Node/npm runner: `campaigns-os qa resolve`, then `campaigns-os qa run --browser --test-order common` against the tested URL. Test-order proof uses `campaigns-os qa run --test-order <common|checkout|decline|accept|both|full|explicit-path>` through the tested checkout and rendered upsell controls; global test cards bypass the gateway and create no transactions, so no permission/approval is needed. `common` runs every actual terminal path when they fit under the flood cap (`--max-test-orders`, 6 by default); above the cap it runs the checkout baseline, first-offer accept and decline, and a deduplicated shortest real receipt path, then adds one decline path per offer or downsell page not yet declined, up to the cap, and names any page left out. A page counts as covered only when an order clicks its decline; the `browser-test-order:upsell-action-coverage` verdict row warns naming each page whose decline no order clicked. `full` walks every actual terminal path in the selected checkout topology; cycles, missing routes, and reachable nonterminals block exhaustive proof before browser launch. The accidental-flood cap remains `6`, and an overflow names the exact explicit `--max-test-orders` raise. Analytics correctness is two-phase: the campaign-root visit inventories declared providers/tags only, and the same canonical typed-card run proves Purchase only from the topology-recognized final receipt document after `--analytics-settle`. Missing/unrecognized receipts are manual-review warnings; recognized receipt no-signal and capture/settle errors block. Only the genuine recognized-receipt/no-signal failure is waivable; capture/settle errors are not. Checkout/upsell signals remain whole-journey parity evidence and cannot satisfy a silent receipt. Do not use `next.getCartData().cartLines` as cart-populated proof; use typed-card order read-back, `cart:updated` payload `items` / `summary.lines`, and rendered bundle DOM evidence. Localhost on any port is a Campaigns App Development domain for SDK QA with analytics suppressed; non-localhost preview/production origins still need SDK origin allowlist confirmation. External browser skills, SDK test-mode events, and direct backend orders are not launch proof. Campaigns OS proof is not merchant launch readiness; before launch, confirm production storefront URL, live payment methods, shipping markets, legal/support URLs, analytics expectations, and merchant-side configuration.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AnalyticsContractShape — validates the optional top-level `analytics` block
|
|
3
3
|
* when present. The block declares a campaign's analytics/attribution/param
|
|
4
|
-
* contract so doctor + QA can validate against intent (cf.
|
|
5
|
-
* `?reviews=n`-has-no-handler QA finding and
|
|
4
|
+
* contract so doctor + QA can validate against intent (cf. a production
|
|
5
|
+
* `?reviews=n`-has-no-handler QA finding and a production Redtrack param
|
|
6
6
|
* conflict — both are gaps that had no declared contract to check against).
|
|
7
7
|
*
|
|
8
8
|
* The block is fully OPTIONAL — a spec without `analytics` is silent (SDK
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AnalyticsContractShape — validates the optional top-level `analytics` block
|
|
3
3
|
* when present. The block declares a campaign's analytics/attribution/param
|
|
4
|
-
* contract so doctor + QA can validate against intent (cf.
|
|
5
|
-
* `?reviews=n`-has-no-handler QA finding and
|
|
4
|
+
* contract so doctor + QA can validate against intent (cf. a production
|
|
5
|
+
* `?reviews=n`-has-no-handler QA finding and a production Redtrack param
|
|
6
6
|
* conflict — both are gaps that had no declared contract to check against).
|
|
7
7
|
*
|
|
8
8
|
* The block is fully OPTIONAL — a spec without `analytics` is silent (SDK
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
* profile fields introduced in Slice 4f.
|
|
4
4
|
*
|
|
5
5
|
* 1. campaign.store_phone_tel must be a `tel:`-prefixed URI containing
|
|
6
|
-
* a digit-shaped number when present.
|
|
6
|
+
* a digit-shaped number when present. Absent or null means "not
|
|
7
|
+
* provided" and is silent. An empty (or whitespace-only)
|
|
8
|
+
* string is not a defect: for the nine Store Profile fields an explicit
|
|
9
|
+
* "" says the merchant has no such value, and `page-kit sync` blanks
|
|
10
|
+
* the starter's demo value with it. The build wires this value
|
|
7
11
|
* into `<a href="tel:...">` attributes; a value without the scheme
|
|
8
12
|
* renders a broken link, and a value containing HTML metacharacters
|
|
9
13
|
* or alternative schemes (javascript:, data:) is rejected as a
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
* profile fields introduced in Slice 4f.
|
|
4
4
|
*
|
|
5
5
|
* 1. campaign.store_phone_tel must be a `tel:`-prefixed URI containing
|
|
6
|
-
* a digit-shaped number when present.
|
|
6
|
+
* a digit-shaped number when present. Absent or null means "not
|
|
7
|
+
* provided" and is silent. An empty (or whitespace-only)
|
|
8
|
+
* string is not a defect: for the nine Store Profile fields an explicit
|
|
9
|
+
* "" says the merchant has no such value, and `page-kit sync` blanks
|
|
10
|
+
* the starter's demo value with it. The build wires this value
|
|
7
11
|
* into `<a href="tel:...">` attributes; a value without the scheme
|
|
8
12
|
* renders a broken link, and a value containing HTML metacharacters
|
|
9
13
|
* or alternative schemes (javascript:, data:) is rejected as a
|
|
@@ -42,8 +46,8 @@ export const StoreProfileShape = {
|
|
|
42
46
|
check(spec) {
|
|
43
47
|
const violations = [];
|
|
44
48
|
const campaign = spec.campaign;
|
|
45
|
-
// 1. tel: prefix on store_phone_tel.
|
|
46
|
-
if (campaign?.store_phone_tel !== undefined) {
|
|
49
|
+
// 1. tel: prefix on store_phone_tel. Absent or null means "not provided".
|
|
50
|
+
if (campaign?.store_phone_tel !== undefined && campaign?.store_phone_tel !== null) {
|
|
47
51
|
const value = campaign.store_phone_tel;
|
|
48
52
|
if (typeof value !== 'string') {
|
|
49
53
|
violations.push({
|
|
@@ -55,13 +59,7 @@ export const StoreProfileShape = {
|
|
|
55
59
|
});
|
|
56
60
|
}
|
|
57
61
|
else if (!isNonEmptyString(value)) {
|
|
58
|
-
|
|
59
|
-
ruleId: 'StoreProfileShape',
|
|
60
|
-
severity: 'warning',
|
|
61
|
-
message: 'campaign.store_phone_tel is set but empty; remove the field or set a tel:-prefixed value (e.g. "tel:+18005551234").',
|
|
62
|
-
path: '/campaign/store_phone_tel',
|
|
63
|
-
data: { check: 'store-phone-tel-empty' },
|
|
64
|
-
});
|
|
62
|
+
// Intentionally empty: the merchant has no phone yet.
|
|
65
63
|
}
|
|
66
64
|
else {
|
|
67
65
|
const trimmed = value.trim();
|
|
@@ -496,8 +496,8 @@ export interface Campaign {
|
|
|
496
496
|
/**
|
|
497
497
|
* Analytics & attribution contract (Slice 4g) — what a campaign's analytics,
|
|
498
498
|
* tag-management, and querystring-param tracking are SUPPOSED to be, so doctor
|
|
499
|
-
* + QA can validate them instead of discovering gaps in QA (cf.
|
|
500
|
-
*
|
|
499
|
+
* + QA can validate them instead of discovering gaps in QA (cf. a production
|
|
500
|
+
* `?reviews=n`-has-no-handler finding and a production Redtrack/
|
|
501
501
|
* campaign.js sub1-6 param conflict).
|
|
502
502
|
*
|
|
503
503
|
* Modeled on real production-funnel usage, NOT the idealized "SDK fires the
|
|
@@ -67,6 +67,11 @@
|
|
|
67
67
|
"class": "cli_surface",
|
|
68
68
|
"_note": "The agent-facing entry points (skill install, agent context, the tooling-status revision check) are reachable from the supported argv surface, so a change under src/agent/ is a CLI-surface change even though the rest of src/ is unsupported implementation. This rule sits ahead of the broad src/ ignore on purpose: the ignore's reason is 'implementation reachable only through declared package exports', which is exactly what this subtree is not."
|
|
69
69
|
},
|
|
70
|
+
{
|
|
71
|
+
"match": { "kind": "prefix", "value": "src/doctor/" },
|
|
72
|
+
"class": "cli_surface",
|
|
73
|
+
"_note": "Doctor checks are kernel-declared behavior reachable from the supported argv surface (`doctor`, `next`, `start`, `prepare-build` and `qa run` read them), so a change under src/doctor/ is a CLI-surface change even though the rest of src/ is unsupported implementation. This rule sits ahead of the broad src/ ignore on purpose, as the src/agent/ rule does. The shared helper modules beside it under src/ (src/install-invocation.mjs, src/cli-helpers.mjs, src/campaigns-api-key.mjs) remain implementation under the broad src/ ignore."
|
|
74
|
+
},
|
|
70
75
|
{
|
|
71
76
|
"match": { "kind": "prefix", "value": "agents/" },
|
|
72
77
|
"class": "documentation",
|