@nextcommerce/campaigns-os 1.61.0 → 1.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -1
- package/CHANGELOG.md +127 -0
- package/README.md +86 -438
- package/agents/claude/CLAUDE.md +9 -4
- package/agents/codex/AGENTS.md +8 -4
- package/agents/copilot/copilot-instructions.md +8 -4
- package/agents/cursor/campaigns-os.mdc +10 -4
- package/campaign-spec/README.md +7 -0
- package/campaign-spec/dist/analytics-vendors.d.ts +40 -0
- package/campaign-spec/dist/analytics-vendors.js +44 -0
- package/campaign-spec/dist/checkout-flow.d.ts +18 -0
- package/campaign-spec/dist/checkout-flow.js +28 -0
- package/campaign-spec/dist/index.d.ts +4 -2
- package/campaign-spec/dist/index.js +5 -1
- package/campaign-spec/dist/rules/analytics-contract-shape.d.ts +8 -0
- package/campaign-spec/dist/rules/analytics-contract-shape.js +39 -0
- package/campaign-spec/dist/rules/campaign-currencies.d.ts +30 -0
- package/campaign-spec/dist/rules/campaign-currencies.js +130 -0
- package/campaign-spec/dist/rules/checkout-path-has-packages.d.ts +31 -0
- package/campaign-spec/dist/rules/checkout-path-has-packages.js +79 -0
- package/campaign-spec/dist/rules/index.d.ts +3 -0
- package/campaign-spec/dist/rules/index.js +9 -0
- package/campaign-spec/dist/rules/package-currency-prices.d.ts +29 -0
- package/campaign-spec/dist/rules/package-currency-prices.js +137 -0
- package/campaign-spec/dist/types.d.ts +59 -9
- package/compatibility.json +1 -1
- package/contracts/commerce-surface-catalog.json +59 -53
- package/contracts/effects.v1.json +549 -165
- package/contracts/fixtures/runtime-recipe/accept/current.json +4 -0
- package/contracts/fixtures/runtime-recipe/accept/minimal.json +4 -0
- package/contracts/fixtures/runtime-recipe/dist-states.json +1 -1
- package/contracts/fixtures/runtime-recipe/reject/advisory-enforcement.json +4 -0
- package/contracts/fixtures/runtime-recipe/reject/allowlist-without-hosts.json +4 -0
- package/contracts/fixtures/runtime-recipe/reject/committed-output-claim.json +4 -0
- package/contracts/fixtures/runtime-recipe/reject/engines-disagreement-warns.json +4 -0
- package/contracts/fixtures/runtime-recipe/reject/lifecycle-scripts-enabled.json +4 -0
- package/contracts/fixtures/runtime-recipe/reject/unknown-kind.json +4 -0
- package/contracts/fixtures/runtime-recipe/reject/unknown-network-policy.json +4 -0
- package/contracts/fixtures/runtime-recipe/reject/unknown-output-check.json +4 -0
- package/contracts/fixtures/runtime-recipe/reject/unknown-revision.json +4 -0
- package/contracts/fixtures/runtime-recipe/reject/unknown-step-id.json +4 -0
- package/contracts/fixtures/runtime-recipe/reject/unperformable-check-skipped.json +4 -0
- package/contracts/fixtures/runtime-recipe/reject/unpinned-lockfile.json +4 -0
- package/contracts/release-ledger.json +1260 -0
- package/contracts/runtime-recipe.campaigns-os-node-v1.json +4 -0
- package/contracts/supported-surface.json +8 -8
- package/contracts/template-brand-contract.shared-commerce.v0.json +23 -1
- package/docs/build-packet.md +430 -37
- package/docs/campaign-standardization-report.md +4 -4
- package/docs/campaigns-os-build-flow.md +54 -3
- package/docs/campaignspec-authoring-examples.md +59 -4
- package/docs/design-source-package.md +18 -6
- package/docs/effects.md +17 -9
- package/docs/local-setup.md +1 -1
- package/docs/orientation-contract-reference.md +1 -1
- package/docs/polish-evidence.md +2 -0
- package/docs/progress-snapshots.md +7 -4
- package/docs/qa-and-test-orders.md +147 -1
- package/docs/readback.md +40 -5
- package/docs/runtime-readiness.md +7 -3
- package/docs/sdk-storage-compatibility.md +1 -1
- package/docs/skills-revision.md +10 -10
- package/package.json +1 -1
- package/schemas/campaign-runtime-build-context.v0.schema.json +9 -0
- package/schemas/campaign-runtime-build-packet.v0.schema.json +9 -0
- package/schemas/campaign-spec.v4.schema.json +34 -3
- package/schemas/campaign-spec.v5.schema.json +34 -3
- package/schemas/campaigns-os-readback.v2.schema.json +62 -1
- package/skills/campaign-lifecycle-orientation/SKILL.md +3 -3
- package/skills/campaign-readback-classification/SKILL.md +3 -3
- package/skills/campaign-run-evidence/SKILL.md +3 -3
- package/skills/contribution-intake/SKILL.md +3 -3
- package/skills/next-campaigns-build/SKILL.md +4 -3
- package/skills/next-campaigns-os/SKILL.md +6 -4
- package/skills/next-campaigns-os-setup/SKILL.md +5 -3
- package/skills/next-campaigns-polish/SKILL.md +5 -4
- package/skills/next-campaigns-qa/SKILL.md +7 -4
- package/skills/next-campaigns-sdk-bump/SKILL.md +42 -9
- package/skills.json +11 -11
- package/src/brand-theme.mjs +2 -1
- package/src/build-brief.mjs +4 -1
- package/src/campaign-workspace.mjs +288 -15
- package/src/change-scope.mjs +284 -0
- package/src/cli.mjs +308 -86
- package/src/commercial-journey.mjs +16 -3
- package/src/commercial-parity.mjs +15 -7
- package/src/content-residue.mjs +4 -2
- package/src/design-source-package.mjs +36 -0
- package/src/design-source-publication.mjs +9 -6
- package/src/directory-lock.mjs +73 -19
- package/src/doctor/checks.mjs +79 -7
- package/src/doctor/ci.mjs +75 -10
- package/src/doctor/inspect.mjs +23 -6
- package/src/doctor/next-step.mjs +7 -0
- package/src/doctor-sidecar.mjs +3 -2
- package/src/evidence-debt.mjs +47 -7
- package/src/finding-cause.mjs +12 -11
- package/src/input-refresh.mjs +339 -32
- package/src/invocation.mjs +7 -1
- package/src/live-campaign-refs.mjs +7 -2
- package/src/local-preview-policy.mjs +35 -2
- package/src/page-kit-analytics-vendors.mjs +132 -0
- package/src/polish-browser.mjs +3 -1
- package/src/polish-readability.mjs +221 -9
- package/src/polish-visual.mjs +9 -2
- package/src/progress-node.mjs +3 -2
- package/src/qa-analytics-parity.mjs +17 -1
- package/src/qa-browser.mjs +40 -4
- package/src/qa-commercial-parity.mjs +50 -3
- package/src/qa-node.mjs +196 -16
- package/src/qa-publish.mjs +9 -8
- package/src/qa-sidecar.mjs +16 -4
- package/src/qa-vendor-beacons.mjs +232 -0
- package/src/qa-vendor-endpoints.mjs +306 -0
- package/src/qc-accept.mjs +29 -1
- package/src/qc-check-registry.mjs +5 -1
- package/src/qc-results.mjs +73 -26
- package/src/readback.mjs +58 -10
- package/src/route-identity.mjs +10 -0
- package/src/run-record.mjs +18 -10
- package/src/runtime-state-ignore.mjs +6 -2
- package/src/sdk-storage-compatibility.mjs +21 -2
- package/src/source-html-intake.mjs +15 -1
- package/src/spec-derive-campaign.mjs +216 -0
- package/src/spec-derive.mjs +473 -53
- package/src/spec-identity.mjs +14 -0
- package/src/stage-ledger.mjs +40 -1
- package/src/stage-record.mjs +58 -13
- package/src/target-lock.mjs +11 -1
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
How a checkout of this repository at one commit becomes a usable installed runtime, and how a consumer decides whether a prepared one is still trustworthy. Everything below is generated from `contracts/runtime-recipe.campaigns-os-node-v1.json`, which is the only authority for these values.
|
|
10
10
|
|
|
11
|
-
Recipe kind `campaigns-os-node-v1`, revision `1.0.3`, validated by `schemas/campaigns-os-runtime-recipe.v1.schema.json` (`Campaigns OS Runtime Recipe v1`). Supported surface at generation time: `1.
|
|
11
|
+
Recipe kind `campaigns-os-node-v1`, revision `1.0.3`, validated by `schemas/campaigns-os-runtime-recipe.v1.schema.json` (`Campaigns OS Runtime Recipe v1`). Supported surface at generation time: `1.63.0`.
|
|
12
12
|
|
|
13
13
|
## What this is
|
|
14
14
|
|
|
@@ -81,8 +81,9 @@ Not redundant with the install step. Because install runs with lifecycle scripts
|
|
|
81
81
|
|
|
82
82
|
The complete input set, enumerated explicitly rather than globbed. The compiler's configured include globs are NOT the input set: two root modules enter the compilation transitively through imports from the entry module and are emitted, so a fingerprint derived from the globs would cover 36 of the 38 compiled sources and miss one of the larger emitted surfaces. Test fixtures and the package's own tests are not inputs; nothing under them is emitted. A checker resolves the compiler's actual file list and asserts it equals this enumeration, so this list cannot rot silently.
|
|
83
83
|
|
|
84
|
-
Fingerprint algorithm `sha256`, over
|
|
84
|
+
Fingerprint algorithm `sha256`, over 51 enumerated files:
|
|
85
85
|
|
|
86
|
+
- `campaign-spec/analytics-vendors.ts`
|
|
86
87
|
- `campaign-spec/analytics-vocabulary.ts`
|
|
87
88
|
- `campaign-spec/checkout-flow.ts`
|
|
88
89
|
- `campaign-spec/index.ts`
|
|
@@ -91,9 +92,11 @@ Fingerprint algorithm `sha256`, over 47 enumerated files:
|
|
|
91
92
|
- `campaign-spec/routing.ts`
|
|
92
93
|
- `campaign-spec/rules/analytics-contract-shape.ts`
|
|
93
94
|
- `campaign-spec/rules/assembly-hints-shape.ts`
|
|
95
|
+
- `campaign-spec/rules/campaign-currencies.ts`
|
|
94
96
|
- `campaign-spec/rules/campaign-metadata.ts`
|
|
95
97
|
- `campaign-spec/rules/checkout-forward-target.ts`
|
|
96
98
|
- `campaign-spec/rules/checkout-has-success-url.ts`
|
|
99
|
+
- `campaign-spec/rules/checkout-path-has-packages.ts`
|
|
97
100
|
- `campaign-spec/rules/checkout-step-reaches-checkout.ts`
|
|
98
101
|
- `campaign-spec/rules/cycle-detection.ts`
|
|
99
102
|
- `campaign-spec/rules/design-source-shape.ts`
|
|
@@ -106,6 +109,7 @@ Fingerprint algorithm `sha256`, over 47 enumerated files:
|
|
|
106
109
|
- `campaign-spec/rules/index.ts`
|
|
107
110
|
- `campaign-spec/rules/offer-ref-integrity.ts`
|
|
108
111
|
- `campaign-spec/rules/one-checkout-per-path.ts`
|
|
112
|
+
- `campaign-spec/rules/package-currency-prices.ts`
|
|
109
113
|
- `campaign-spec/rules/package-pricing-sanity.ts`
|
|
110
114
|
- `campaign-spec/rules/page-count.ts`
|
|
111
115
|
- `campaign-spec/rules/page-id-uniqueness.ts`
|
|
@@ -137,7 +141,7 @@ The output directory is a build product. It is untracked and git-ignored, no com
|
|
|
137
141
|
|
|
138
142
|
Directory `campaign-spec/dist`. Committed: `false`. Type entry `campaign-spec/dist/index.d.ts`.
|
|
139
143
|
|
|
140
|
-
Expected inventory is derived, never listed twice. For every enumerated input under module_source_root whose path ends in .ts, the build is expected to emit campaign-spec/dist/<path relative to module_source_root, with .ts replaced> once per entry in emitted_extensions. The expected inventory is exactly that set: nothing missing, nothing extra. Emitted extensions: `.js`, `.d.ts`. At this revision that derivation yields
|
|
144
|
+
Expected inventory is derived, never listed twice. For every enumerated input under module_source_root whose path ends in .ts, the build is expected to emit campaign-spec/dist/<path relative to module_source_root, with .ts replaced> once per entry in emitted_extensions. The expected inventory is exactly that set: nothing missing, nothing extra. Emitted extensions: `.js`, `.d.ts`. At this revision that derivation yields 94 files.
|
|
141
145
|
|
|
142
146
|
### Mandatory checks
|
|
143
147
|
|
|
@@ -18,7 +18,7 @@ Dynamic storage keys, unresolved storage methods, shadowed storage names, missin
|
|
|
18
18
|
|
|
19
19
|
A `dynamic-key`, `unsupported-storage-method` or `storage-object-escape` line inside a loop, or an array callback such as `filter` or `forEach`, that tests a key it read from storage (a `k = sessionStorage.key(i)` variable, a `for…of Object.keys(sessionStorage)` or `for…in sessionStorage` variable, or the element parameter, the second for `reduce`, of a callback chained on `Object.keys(sessionStorage)`) with `k.indexOf('<prefix>') === 0` (or `!== 0`) or `k.startsWith('<prefix>')`, where the prefix is a scoped SDK key from the manifest (`next-cart-state` for `next-cart-state{__scope}`), ends in `[prefix loop: <prefix>]` and carries `prefixScan` in `--json`, when the line is where that key came from or reads that key by name. Other storage use in the loop, such as passing `sessionStorage` to a function, is not marked: the prefix test does not explain it. One note below the findings explains them all. Such a loop finds the SDK key with or without its scope suffix, so scoping alone does not break it. The lines still report unknown: Campaign Cart scopes these keys so campaigns on one origin cannot read each other's copy, and a prefix match reads whichever copy it meets first. Where the manifest names a public store for the key, as it does `useOrderStore` for `next-order`, the note names it too.
|
|
20
20
|
|
|
21
|
-
Storage `length` property reads are unaffected metadata (`storage-metadata-read`). Storage `key()` enumeration, extracted method references, and mutations of reserved members remain unknown; enumeration cannot prove an SDK key lookup safe. Git discovery failures return one bounded CLI error. Local script diagnostics retain repository-relative spellings from HTML source, including `../` paths; excluded/outside sources are not read. The Git root and operator target are compared by filesystem device/inode identity, so supported case aliases and symlinks can name the same root. Source containment uses realpaths below the Git root without case folding. Extra positional CLI arguments are rejected so an accidental scope or version value cannot silently disappear.
|
|
21
|
+
Storage `length` property reads are unaffected metadata (`storage-metadata-read`). Storage `key()` enumeration, extracted method references, and mutations of reserved members remain unknown; enumeration cannot prove an SDK key lookup safe. Git discovery failures return one bounded CLI error. The tracked-file inventory lists only the paths under `--scope`, so repository size does not limit it; when it fails, the error reads `Cannot inventory tracked Git source files: <reason>` with Git's own first stderr line as the reason, or, when Git printed nothing, how it ended (its exit status, the signal that stopped it, or a spawn error code), or a request to narrow a scope whose list passes 256 MiB. npm 1.61.0 and earlier listed the whole repository and stopped with `Cannot inventory tracked Git source files.` once that list passed 1 MiB (about 25,000 paths); update the install rather than running the check on a copy, which can lose tracked files. Local script diagnostics retain repository-relative spellings from HTML source, including `../` paths; excluded/outside sources are not read. The Git root and operator target are compared by filesystem device/inode identity, so supported case aliases and symlinks can name the same root. Source containment uses realpaths below the Git root without case folding. Extra positional CLI arguments are rejected so an accidental scope or version value cannot silently disappear.
|
|
22
22
|
|
|
23
23
|
## Rewriting hardcoded pins in a static repo
|
|
24
24
|
|
package/docs/skills-revision.md
CHANGED
|
@@ -16,7 +16,7 @@ that the copy on disk moved.
|
|
|
16
16
|
`skills.json` carries one top-level field:
|
|
17
17
|
|
|
18
18
|
```json
|
|
19
|
-
"bundle_revision": "1.
|
|
19
|
+
"bundle_revision": "1.63.0+skills.1"
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
The spelling is `<package version>+skills.<n>`:
|
|
@@ -25,7 +25,7 @@ The spelling is `<package version>+skills.<n>`:
|
|
|
25
25
|
skills ship with (`check-skill-versions.mjs` fails if the two disagree);
|
|
26
26
|
- `<n>` is a plain counter, not a semver component. It says "this is the *n*th
|
|
27
27
|
skill-text revision published against that package version" and it **resets
|
|
28
|
-
with the prefix**. `1.
|
|
28
|
+
with the prefix**. `1.63.0+skills.1` is therefore ahead of `1.40.0+skills.7`.
|
|
29
29
|
|
|
30
30
|
It is one identity for the bundle as a whole, on purpose. Per-skill versions
|
|
31
31
|
still exist and still gate per-skill changes, but an agent that loaded one skill
|
|
@@ -37,7 +37,7 @@ The first body line of every bundled `SKILL.md`, immediately after the
|
|
|
37
37
|
frontmatter, is exactly:
|
|
38
38
|
|
|
39
39
|
```
|
|
40
|
-
Bundle revision: 1.
|
|
40
|
+
Bundle revision: 1.63.0+skills.1
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
followed by a short paragraph telling the agent to run the check below at the
|
|
@@ -48,7 +48,7 @@ text the agent is actually reading, not from a file it would have to go and open
|
|
|
48
48
|
## The check
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
|
-
npx --no-install campaigns-os tooling status --skills-revision 1.
|
|
51
|
+
npx --no-install campaigns-os tooling status --skills-revision 1.63.0+skills.1
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
The value is compared against the bundle revision of the **CLI the command runs
|
|
@@ -90,20 +90,20 @@ reports the choice as `skills.scope` (`requested`, `installed_platforms`, or
|
|
|
90
90
|
"revision_check": "match",
|
|
91
91
|
"skills_revision": {
|
|
92
92
|
"status": "match",
|
|
93
|
-
"requested": "1.
|
|
93
|
+
"requested": "1.63.0+skills.1",
|
|
94
94
|
"spelling": "bundle",
|
|
95
|
-
"on_disk": "1.
|
|
95
|
+
"on_disk": "1.63.0+skills.1",
|
|
96
96
|
"on_disk_skill": null,
|
|
97
|
-
"message": "match (1.
|
|
97
|
+
"message": "match (1.63.0+skills.1)"
|
|
98
98
|
}
|
|
99
99
|
```
|
|
100
100
|
|
|
101
101
|
The text view prints one named line, as a header above the rest of the status:
|
|
102
102
|
|
|
103
103
|
```
|
|
104
|
-
Skills revision: match (1.
|
|
105
|
-
Skills revision: mismatch: loaded 1.39.0+skills.1, on disk 1.
|
|
106
|
-
Skills revision: unchecked (on disk 1.
|
|
104
|
+
Skills revision: match (1.63.0+skills.1)
|
|
105
|
+
Skills revision: mismatch: loaded 1.39.0+skills.1, on disk 1.63.0+skills.1 — start a fresh session
|
|
106
|
+
Skills revision: unchecked (on disk 1.63.0+skills.1)
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
`unchecked` is the state when the flag is absent. It is not an error — an
|
package/package.json
CHANGED
|
@@ -77,6 +77,11 @@
|
|
|
77
77
|
"pattern": "^sha256:[0-9a-f]{64}$",
|
|
78
78
|
"description": "Canonical semantic identity used to correlate QA with the authored spec. hash remains exact raw-byte integrity."
|
|
79
79
|
},
|
|
80
|
+
"route_masked_material_hash": {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"pattern": "^sha256:[0-9a-f]{64}$",
|
|
83
|
+
"description": "The spec material with every page's page_url left out. record spec compares it to tell a change of routes alone from one that also changed anything else the build reads (#531)."
|
|
84
|
+
},
|
|
80
85
|
"active_pages": {
|
|
81
86
|
"type": "array",
|
|
82
87
|
"items": {
|
|
@@ -164,6 +169,10 @@
|
|
|
164
169
|
"type": ["string", "null"],
|
|
165
170
|
"description": "Page Kit target file path relative to the target repo. This mirrors page_kit.output_path; source_path remains producer provenance."
|
|
166
171
|
},
|
|
172
|
+
"origin": {
|
|
173
|
+
"enum": ["repo"],
|
|
174
|
+
"description": "Set on a page added from the repo's page tree after handoff (#721): its source is the target page file (page_kit.output_path), not a design source file, so source_path and skip_reason are null."
|
|
175
|
+
},
|
|
167
176
|
"page_kit": {
|
|
168
177
|
"type": ["object", "null"],
|
|
169
178
|
"properties": {
|
|
@@ -149,6 +149,10 @@
|
|
|
149
149
|
"pattern": "^[0-9a-f]{64}$",
|
|
150
150
|
"description": "Optional sha256 of the source HTML file at the time the manifest was written. Doctor compares this to the on-disk file's actual hash and warns on mismatch (Slice 6 drift detection)."
|
|
151
151
|
},
|
|
152
|
+
"origin": {
|
|
153
|
+
"enum": ["repo"],
|
|
154
|
+
"description": "Set by record spec on a page added from the repo's page tree after handoff (#721): the page's source is its target page file (page_kit.output_path) in the target repo, not a file under source_html.root, so it carries no path. Doctor counts it as mapped, and as built once that file exists."
|
|
155
|
+
},
|
|
152
156
|
"page_kit": {
|
|
153
157
|
"type": "object",
|
|
154
158
|
"additionalProperties": false,
|
|
@@ -332,6 +336,11 @@
|
|
|
332
336
|
"type": "string",
|
|
333
337
|
"minLength": 1
|
|
334
338
|
},
|
|
339
|
+
"runtime_dir": {
|
|
340
|
+
"type": "string",
|
|
341
|
+
"pattern": "^\\.campaign-runtime(?:/funnels/[A-Za-z0-9_-][A-Za-z0-9._-]*)?$",
|
|
342
|
+
"description": "Where this funnel's records live, relative to target_repo (and, for the QA verdict sidecar and Run Records, to this packet's directory). prepare-build writes \".campaign-runtime/funnels/<public_route_slug>\" when the project already holds another funnel's records, so one Page Kit project can hold several funnels without one overwriting another's Build Context, Assembly Report, doctor output, theme output, inputs, QA verdict sidecar or Run Records. Absent (every packet before per-funnel records, and a project's first funnel) means the project-level \".campaign-runtime\". Any value other than those two for this packet's public_route_slug is refused."
|
|
343
|
+
},
|
|
335
344
|
"output_dir": {
|
|
336
345
|
"type": "string",
|
|
337
346
|
"minLength": 1
|
|
@@ -73,13 +73,13 @@
|
|
|
73
73
|
"id": { "type": "string", "description": "Campaign slug-style identifier (28/33 real specs)." },
|
|
74
74
|
"name": { "type": "string" },
|
|
75
75
|
"slug": { "type": "string" },
|
|
76
|
-
"currency": { "type": "string" },
|
|
76
|
+
"currency": { "type": "string", "description": "The campaign's default currency: a three-letter upper-case ISO 4217 code such as \"USD\". The CampaignCurrencies rule reports any other value as an error; a lower-case code can make Campaign Cart fall back to a cached USD campaign." },
|
|
77
77
|
"language": { "type": "string" },
|
|
78
78
|
"payment_env_key": { "type": "string" },
|
|
79
79
|
"campaigns_api_key": { "type": ["string", "null"], "description": "Public-by-design, domain-allowlisted Campaigns API key (32/33 real specs)." },
|
|
80
80
|
"available_payment_methods": { "type": "array" },
|
|
81
81
|
"available_express_payment_methods": { "type": "array" },
|
|
82
|
-
"available_currencies": { "type": "array", "items": { "type": "string" } },
|
|
82
|
+
"available_currencies": { "type": "array", "items": { "type": "string" }, "description": "Every currency the campaign sells in, the default currency included, as three-letter upper-case ISO 4217 code strings. The Campaigns API returns { code, label } objects here; write the code strings. This is the CampaignSpec field: the Campaigns App API's additional_currencies is the same list without the default and is not part of the spec. The CampaignCurrencies rule reports a malformed entry as an error, and a default currency missing from a non-empty list as a warning." },
|
|
83
83
|
"available_shipping_countries": {
|
|
84
84
|
"description": "Arrives in THREE incompatible shapes in real exports: bare string \"all\" (5 specs), an array of country-code strings incl. [] (22+), and an array of { code, label } objects (5). All three are accepted here; normalization to one canonical shape is deliberately deferred to a later change.",
|
|
85
85
|
"anyOf": [
|
|
@@ -254,13 +254,28 @@
|
|
|
254
254
|
"name": { "type": ["string", "null"] },
|
|
255
255
|
"price": { "type": ["string", "number", "null"] },
|
|
256
256
|
"price_retail": { "type": ["string", "number", "null"] },
|
|
257
|
+
"prices": {
|
|
258
|
+
"type": ["array", "null"],
|
|
259
|
+
"description": "The package's price in each currency the Campaigns App prices it in, one entry per currency, read from the Campaigns API (GET /campaigns/?currency=<code>), which returns only the packages priced in the requested currency. price and price_retail stay the default currency's. Optional: a row without prices (absent or null) says nothing about other currencies. A row with prices should list every currency in campaign.available_currencies and campaign.currency; the PackageCurrencyPrices rule warns when one is missing, since the campaign leaves the package out in that currency.",
|
|
260
|
+
"items": {
|
|
261
|
+
"type": "object",
|
|
262
|
+
"additionalProperties": true,
|
|
263
|
+
"required": ["currency", "price"],
|
|
264
|
+
"properties": {
|
|
265
|
+
"currency": { "type": "string", "description": "Three-letter upper-case ISO 4217 code." },
|
|
266
|
+
"price": { "type": ["string", "number"] },
|
|
267
|
+
"price_retail": { "type": ["string", "number", "null"] },
|
|
268
|
+
"price_recurring": { "type": ["string", "number", "null"] }
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
},
|
|
257
272
|
"product_name": { "type": ["string", "null"] },
|
|
258
273
|
"product_sku": { "type": ["string", "null"] },
|
|
259
274
|
"product_variant_name": { "type": ["string", "null"] },
|
|
260
275
|
"product_purchase_availability": { "type": ["string", "null"] },
|
|
261
276
|
"product_inventory_availability": { "type": ["string", "null"] },
|
|
262
277
|
"image": { "type": ["string", "null"] },
|
|
263
|
-
"is_upsell": { "type": "boolean", "description": "Boolean role flag. There is no 'role' field in real exports — role is expressed by the is_upsell/is_order_bump/default_selected boolean trio." },
|
|
278
|
+
"is_upsell": { "type": "boolean", "description": "Boolean role flag. There is no 'role' field in real exports — role is expressed by the is_upsell/is_order_bump/default_selected boolean trio. What the flag means depends on the page type. On an upsell or downsell page every package row is that page's post-purchase offer and never an order bump, whatever is_upsell says, so a plain { ref_id, qty } row and one with is_upsell: true are both the page's offer. On any other page (checkout or select), is_upsell: true or is_order_bump: true marks the row as an add-on (an order bump) offered beside the main package; a row with neither flag is a main package." },
|
|
264
279
|
"is_order_bump": { "type": "boolean" },
|
|
265
280
|
"default_selected": { "type": "boolean" },
|
|
266
281
|
"configurable": { "type": "boolean", "description": "Fixture/authoring extension marking quantity-configurable package rows." },
|
|
@@ -426,6 +441,22 @@
|
|
|
426
441
|
}
|
|
427
442
|
}
|
|
428
443
|
},
|
|
444
|
+
"vendors": {
|
|
445
|
+
"type": "object",
|
|
446
|
+
"description": "Starter-template vendor adapters, keyed by vendor key (ga4, axon, taboola, triplewhale, tiktok, northbeam, snap, pinterest), as the Map Builder emits them. Each is switched on by a flat key in the campaign's _data/campaigns.json entry; see AnalyticsVendor in campaign-spec/types.ts.",
|
|
447
|
+
"additionalProperties": {
|
|
448
|
+
"type": "object",
|
|
449
|
+
"additionalProperties": true,
|
|
450
|
+
"properties": {
|
|
451
|
+
"enabled": { "type": "boolean" },
|
|
452
|
+
"id": { "type": "string" },
|
|
453
|
+
"platform": { "type": "string" },
|
|
454
|
+
"identityEnabled": { "type": "boolean" },
|
|
455
|
+
"allowedEvents": { "type": "array", "items": { "type": "string" } },
|
|
456
|
+
"blockedEvents": { "type": "array", "items": { "type": "string" } }
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
},
|
|
429
460
|
"out_of_band_pixels": {
|
|
430
461
|
"type": "array",
|
|
431
462
|
"items": {
|
|
@@ -73,13 +73,13 @@
|
|
|
73
73
|
"id": { "type": "string", "description": "Campaign slug-style identifier (28/33 real specs)." },
|
|
74
74
|
"name": { "type": "string" },
|
|
75
75
|
"slug": { "type": "string" },
|
|
76
|
-
"currency": { "type": "string" },
|
|
76
|
+
"currency": { "type": "string", "description": "The campaign's default currency: a three-letter upper-case ISO 4217 code such as \"USD\". The CampaignCurrencies rule reports any other value as an error; a lower-case code can make Campaign Cart fall back to a cached USD campaign." },
|
|
77
77
|
"language": { "type": "string" },
|
|
78
78
|
"payment_env_key": { "type": "string" },
|
|
79
79
|
"campaigns_api_key": { "type": ["string", "null"], "description": "Public-by-design, domain-allowlisted Campaigns API key (32/33 real specs)." },
|
|
80
80
|
"available_payment_methods": { "type": "array" },
|
|
81
81
|
"available_express_payment_methods": { "type": "array" },
|
|
82
|
-
"available_currencies": { "type": "array", "items": { "type": "string" } },
|
|
82
|
+
"available_currencies": { "type": "array", "items": { "type": "string" }, "description": "Every currency the campaign sells in, the default currency included, as three-letter upper-case ISO 4217 code strings. The Campaigns API returns { code, label } objects here; write the code strings. This is the CampaignSpec field: the Campaigns App API's additional_currencies is the same list without the default and is not part of the spec. The CampaignCurrencies rule reports a malformed entry as an error, and a default currency missing from a non-empty list as a warning." },
|
|
83
83
|
"available_shipping_countries": {
|
|
84
84
|
"description": "Arrives in THREE incompatible shapes in real exports: bare string \"all\" (5 specs), an array of country-code strings incl. [] (22+), and an array of { code, label } objects (5). All three are accepted here; normalization to one canonical shape is deliberately deferred to a later change.",
|
|
85
85
|
"anyOf": [
|
|
@@ -254,13 +254,28 @@
|
|
|
254
254
|
"name": { "type": ["string", "null"] },
|
|
255
255
|
"price": { "type": ["string", "number", "null"] },
|
|
256
256
|
"price_retail": { "type": ["string", "number", "null"] },
|
|
257
|
+
"prices": {
|
|
258
|
+
"type": ["array", "null"],
|
|
259
|
+
"description": "The package's price in each currency the Campaigns App prices it in, one entry per currency, read from the Campaigns API (GET /campaigns/?currency=<code>), which returns only the packages priced in the requested currency. price and price_retail stay the default currency's. Optional: a row without prices (absent or null) says nothing about other currencies. A row with prices should list every currency in campaign.available_currencies and campaign.currency; the PackageCurrencyPrices rule warns when one is missing, since the campaign leaves the package out in that currency.",
|
|
260
|
+
"items": {
|
|
261
|
+
"type": "object",
|
|
262
|
+
"additionalProperties": true,
|
|
263
|
+
"required": ["currency", "price"],
|
|
264
|
+
"properties": {
|
|
265
|
+
"currency": { "type": "string", "description": "Three-letter upper-case ISO 4217 code." },
|
|
266
|
+
"price": { "type": ["string", "number"] },
|
|
267
|
+
"price_retail": { "type": ["string", "number", "null"] },
|
|
268
|
+
"price_recurring": { "type": ["string", "number", "null"] }
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
},
|
|
257
272
|
"product_name": { "type": ["string", "null"] },
|
|
258
273
|
"product_sku": { "type": ["string", "null"] },
|
|
259
274
|
"product_variant_name": { "type": ["string", "null"] },
|
|
260
275
|
"product_purchase_availability": { "type": ["string", "null"] },
|
|
261
276
|
"product_inventory_availability": { "type": ["string", "null"] },
|
|
262
277
|
"image": { "type": ["string", "null"] },
|
|
263
|
-
"is_upsell": { "type": "boolean", "description": "Boolean role flag. There is no 'role' field in real exports — role is expressed by the is_upsell/is_order_bump/default_selected boolean trio." },
|
|
278
|
+
"is_upsell": { "type": "boolean", "description": "Boolean role flag. There is no 'role' field in real exports — role is expressed by the is_upsell/is_order_bump/default_selected boolean trio. What the flag means depends on the page type. On an upsell or downsell page every package row is that page's post-purchase offer and never an order bump, whatever is_upsell says, so a plain { ref_id, qty } row and one with is_upsell: true are both the page's offer. On any other page (checkout, checkout_step, select), is_upsell: true or is_order_bump: true marks the row as an add-on (an order bump) offered beside the main package; a row with neither flag is a main package." },
|
|
264
279
|
"is_order_bump": { "type": "boolean" },
|
|
265
280
|
"default_selected": { "type": "boolean" },
|
|
266
281
|
"configurable": { "type": "boolean", "description": "Fixture/authoring extension marking quantity-configurable package rows." },
|
|
@@ -426,6 +441,22 @@
|
|
|
426
441
|
}
|
|
427
442
|
}
|
|
428
443
|
},
|
|
444
|
+
"vendors": {
|
|
445
|
+
"type": "object",
|
|
446
|
+
"description": "Starter-template vendor adapters, keyed by vendor key (ga4, axon, taboola, triplewhale, tiktok, northbeam, snap, pinterest), as the Map Builder emits them. Each is switched on by a flat key in the campaign's _data/campaigns.json entry; see AnalyticsVendor in campaign-spec/types.ts.",
|
|
447
|
+
"additionalProperties": {
|
|
448
|
+
"type": "object",
|
|
449
|
+
"additionalProperties": true,
|
|
450
|
+
"properties": {
|
|
451
|
+
"enabled": { "type": "boolean" },
|
|
452
|
+
"id": { "type": "string" },
|
|
453
|
+
"platform": { "type": "string" },
|
|
454
|
+
"identityEnabled": { "type": "boolean" },
|
|
455
|
+
"allowedEvents": { "type": "array", "items": { "type": "string" } },
|
|
456
|
+
"blockedEvents": { "type": "array", "items": { "type": "string" } }
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
},
|
|
429
460
|
"out_of_band_pixels": {
|
|
430
461
|
"type": "array",
|
|
431
462
|
"items": {
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
},
|
|
68
68
|
"clean": {
|
|
69
69
|
"type": "boolean",
|
|
70
|
-
"description": "True only when every artifact the readback found is loaded or absent (never unreadable or unrecognized), staleness is computable and NO loaded artifact is stale, staleness.unparseable_keys is empty (no loaded artifact recorded an age the readback could not read), divergences is empty, doctor.error_count is zero, and neither evidence_debt stage is owed (any owed Polish or QA stage makes clean false). Unknown debt alone does not make clean false; consumers must inspect evidence_debt even when clean is true. A readback-integrity flag, not a verdict: a blocked QA verdict whose artifacts all read cleanly is still clean, because the readback saw exactly what Campaigns OS recorded. docs/readback.md states the rule and its limits."
|
|
70
|
+
"description": "True only when every artifact the readback found is loaded or absent (never unreadable or unrecognized), staleness is computable and NO loaded artifact is stale, staleness.unparseable_keys is empty (no loaded artifact recorded an age the readback could not read), divergences is empty, doctor.error_count is zero, and neither evidence_debt stage is owed (any owed Polish or QA stage makes clean false, except Polish marked advisory for a page-only change). Unknown debt alone does not make clean false; consumers must inspect evidence_debt even when clean is true. A readback-integrity flag, not a verdict: a blocked QA verdict whose artifacts all read cleanly is still clean, because the readback saw exactly what Campaigns OS recorded. docs/readback.md states the rule and its limits."
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
73
|
"$defs": {
|
|
@@ -128,9 +128,62 @@
|
|
|
128
128
|
"stage_build_fingerprint_missing"
|
|
129
129
|
],
|
|
130
130
|
"description": "Null for current. Owed names a changed binding or the recorded required_by cause (build, brief, spec, or unspecified). Unknown names the unavailable input or fingerprint."
|
|
131
|
+
},
|
|
132
|
+
"change": {
|
|
133
|
+
"description": "On an owed stage, what changed since the build that stage reviewed: the rebuilds `record build` kept in stages.assembly.build_changes plus the drift on disk. Null when the stage is not owed.",
|
|
134
|
+
"oneOf": [{ "$ref": "#/$defs/evidence_debt_change" }, { "type": "null" }]
|
|
135
|
+
},
|
|
136
|
+
"advisory": {
|
|
137
|
+
"type": "boolean",
|
|
138
|
+
"description": "Polish only. True when Polish is owed but the change since it last reviewed the campaign is page-only and no brief or spec change requires it: Polish is reported and not required by next, doctor --ci or the QA gate."
|
|
139
|
+
},
|
|
140
|
+
"scope": {
|
|
141
|
+
"enum": [null, "pages", "full"],
|
|
142
|
+
"description": "QA only. pages: the change since the build QA reviewed is page-only, so QA is owed on owed_pages and qa run --page pays it. full: the change touches commerce, cannot be classified, or an input change requires QA. Null when QA is not owed."
|
|
143
|
+
},
|
|
144
|
+
"owed_pages": {
|
|
145
|
+
"type": "array",
|
|
146
|
+
"description": "QA only. The changed pages a page-scoped run must cover when scope is pages; empty otherwise.",
|
|
147
|
+
"items": { "$ref": "#/$defs/evidence_debt_page" }
|
|
131
148
|
}
|
|
132
149
|
}
|
|
133
150
|
},
|
|
151
|
+
"evidence_debt_page": {
|
|
152
|
+
"type": "object",
|
|
153
|
+
"additionalProperties": true,
|
|
154
|
+
"required": ["page_id", "built_path"],
|
|
155
|
+
"properties": {
|
|
156
|
+
"page_id": { "type": "string", "minLength": 1 },
|
|
157
|
+
"built_path": { "type": "string", "minLength": 1 }
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"evidence_debt_change_kind": {
|
|
161
|
+
"enum": ["none", "page_only", "commerce_affecting", "unknown"],
|
|
162
|
+
"description": "page_only: only pages changed, and none of them is a checkout page or changed its package, offer, shipping, upsell, route or script markup, and the campaign's Page Kit config entry is unchanged. commerce_affecting: anything else that could be read. unknown: the change could not be read (no usable manifest, no commerce signature on an older record, or a rebuild history that does not reach the reviewed build)."
|
|
163
|
+
},
|
|
164
|
+
"evidence_debt_reason": {
|
|
165
|
+
"type": "object",
|
|
166
|
+
"additionalProperties": true,
|
|
167
|
+
"required": ["code"],
|
|
168
|
+
"properties": {
|
|
169
|
+
"code": {
|
|
170
|
+
"enum": ["unmapped_file", "page_added", "page_removed", "checkout_page", "commerce_markup_changed", "commerce_signature_unavailable", "campaign_config_changed", "campaign_config_unavailable", "change_history_unavailable"]
|
|
171
|
+
},
|
|
172
|
+
"path": { "type": "string", "minLength": 1 }
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
"evidence_debt_change": {
|
|
176
|
+
"type": "object",
|
|
177
|
+
"additionalProperties": true,
|
|
178
|
+
"required": ["kind", "since_build_fingerprint", "changed_pages", "unmapped_files", "reasons"],
|
|
179
|
+
"properties": {
|
|
180
|
+
"kind": { "$ref": "#/$defs/evidence_debt_change_kind" },
|
|
181
|
+
"since_build_fingerprint": { "$ref": "#/$defs/build_fingerprint" },
|
|
182
|
+
"changed_pages": { "type": "array", "items": { "$ref": "#/$defs/evidence_debt_page" } },
|
|
183
|
+
"unmapped_files": { "type": "array", "items": { "type": "string" }, "description": "At most 20 paths." },
|
|
184
|
+
"reasons": { "type": "array", "items": { "$ref": "#/$defs/evidence_debt_reason" }, "description": "Why the change counts as commerce-affecting or unknown; at most 20." }
|
|
185
|
+
}
|
|
186
|
+
},
|
|
134
187
|
"evidence_debt_changes": {
|
|
135
188
|
"type": "object",
|
|
136
189
|
"additionalProperties": true,
|
|
@@ -223,6 +276,14 @@
|
|
|
223
276
|
"type": "string"
|
|
224
277
|
},
|
|
225
278
|
"description": "Complete sorted paths modified since the retained manifest, relative to the built output root."
|
|
279
|
+
},
|
|
280
|
+
"kind": {
|
|
281
|
+
"$ref": "#/$defs/evidence_debt_change_kind",
|
|
282
|
+
"description": "This drift from the retained assembly manifest, classified."
|
|
283
|
+
},
|
|
284
|
+
"reasons": {
|
|
285
|
+
"type": "array",
|
|
286
|
+
"items": { "$ref": "#/$defs/evidence_debt_reason" }
|
|
226
287
|
}
|
|
227
288
|
}
|
|
228
289
|
},
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: campaign-lifecycle-orientation
|
|
3
|
-
version: 1.0.
|
|
3
|
+
version: 1.0.49
|
|
4
4
|
description: Orient a reader to the Campaigns OS lifecycle artifacts a run has already emitted, without advancing any stage or changing any state.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Bundle revision: 1.
|
|
8
|
-
Run `npx --no-install campaigns-os tooling status --skills-revision 1.
|
|
7
|
+
Bundle revision: 1.63.0+skills.1
|
|
8
|
+
Run `npx --no-install campaigns-os tooling status --skills-revision 1.63.0+skills.1`
|
|
9
9
|
from the campaign's Page Kit folder, where it runs the project's pinned copy and
|
|
10
10
|
never installs one, at the start of each task. Start a fresh session if it
|
|
11
11
|
reports `mismatch`: this text is already in your context and is never re-read
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: campaign-readback-classification
|
|
3
|
-
version: 1.0.
|
|
3
|
+
version: 1.0.49
|
|
4
4
|
description: Classify a selected campaign from the readback projection's v2 fields and write a read-only handoff without turning diagnosis into permission.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Bundle revision: 1.
|
|
8
|
-
Run `npx --no-install campaigns-os tooling status --skills-revision 1.
|
|
7
|
+
Bundle revision: 1.63.0+skills.1
|
|
8
|
+
Run `npx --no-install campaigns-os tooling status --skills-revision 1.63.0+skills.1`
|
|
9
9
|
from the campaign's Page Kit folder, where it runs the project's pinned copy and
|
|
10
10
|
never installs one, at the start of each task. Start a fresh session if it
|
|
11
11
|
reports `mismatch`: this text is already in your context and is never re-read
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: campaign-run-evidence
|
|
3
|
-
version: 1.0.
|
|
3
|
+
version: 1.0.49
|
|
4
4
|
description: Interpret existing Campaigns OS doctor, QA and proof-depth evidence without claiming more proof than the artifacts contain.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Bundle revision: 1.
|
|
8
|
-
Run `npx --no-install campaigns-os tooling status --skills-revision 1.
|
|
7
|
+
Bundle revision: 1.63.0+skills.1
|
|
8
|
+
Run `npx --no-install campaigns-os tooling status --skills-revision 1.63.0+skills.1`
|
|
9
9
|
from the campaign's Page Kit folder, where it runs the project's pinned copy and
|
|
10
10
|
never installs one, at the start of each task. Start a fresh session if it
|
|
11
11
|
reports `mismatch`: this text is already in your context and is never re-read
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: contribution-intake
|
|
3
|
-
version: 1.0.
|
|
3
|
+
version: 1.0.49
|
|
4
4
|
description: Turn a suggestion about the agent surface into a classified, evidence-checked proposal and, only with attended approval, one issue on this repository's tracker.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Bundle revision: 1.
|
|
8
|
-
Run `npx --no-install campaigns-os tooling status --skills-revision 1.
|
|
7
|
+
Bundle revision: 1.63.0+skills.1
|
|
8
|
+
Run `npx --no-install campaigns-os tooling status --skills-revision 1.63.0+skills.1`
|
|
9
9
|
from the campaign's Page Kit folder, where it runs the project's pinned copy and
|
|
10
10
|
never installs one, at the start of each task. Start a fresh session if it
|
|
11
11
|
reports `mismatch`: this text is already in your context and is never re-read
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: next-campaigns-build
|
|
3
|
-
version: 1.0.
|
|
3
|
+
version: 1.0.54
|
|
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.
|
|
8
|
-
Run `npx --no-install campaigns-os tooling status --skills-revision 1.
|
|
7
|
+
Bundle revision: 1.63.0+skills.1
|
|
8
|
+
Run `npx --no-install campaigns-os tooling status --skills-revision 1.63.0+skills.1`
|
|
9
9
|
from the campaign's Page Kit folder, where it runs the project's pinned copy and
|
|
10
10
|
never installs one, at the start of each task. Start a fresh session if it
|
|
11
11
|
reports `mismatch`: this text is already in your context and is never re-read
|
|
@@ -76,6 +76,7 @@ Inputs:
|
|
|
76
76
|
- target page-kit repo
|
|
77
77
|
- starter-template commerce catalog
|
|
78
78
|
- Read the normalized Campaign Build Brief at `.campaign-runtime/input/campaign-build-brief.normalized.json` and the recorded decisions (`adapter_decisions`, `decisions` and `theme` in `.campaign-runtime/assembly-report.json`, and `assembly.template_decision_notes` in the Build Packet) before working on the campaign. The campaign intent summary at the top of the setup, build, Polish and QA prompts and in every `next` result is orientation, never a source of prices or commerce behaviour.
|
|
79
|
+
- A Page Kit project can hold several funnels. The first one set up uses `campaign-runtime.build.json` and the `.campaign-runtime/` paths named here; each later funnel has `campaign-runtime-<route>.build.json` and keeps the same files under `.campaign-runtime/funnels/<route>/` (the packet's `assembly.runtime_dir`). Read and pass the funnel's own packet and paths; the paths `next` prints are already the right ones.
|
|
79
80
|
|
|
80
81
|
Build rules:
|
|
81
82
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: next-campaigns-os
|
|
3
|
-
version: 1.0.
|
|
3
|
+
version: 1.0.69
|
|
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.
|
|
8
|
-
Run `npx --no-install campaigns-os tooling status --skills-revision 1.
|
|
7
|
+
Bundle revision: 1.63.0+skills.1
|
|
8
|
+
Run `npx --no-install campaigns-os tooling status --skills-revision 1.63.0+skills.1`
|
|
9
9
|
from the campaign's Page Kit folder, where it runs the project's pinned copy and
|
|
10
10
|
never installs one, at the start of each task. Start a fresh session if it
|
|
11
11
|
reports `mismatch`: this text is already in your context and is never re-read
|
|
@@ -81,7 +81,7 @@ the target plus a Run Record under the working directory, and they contact the
|
|
|
81
81
|
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.
|
|
82
82
|
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.
|
|
83
83
|
4. Run `campaigns-os doctor --packet <packet>` (tier `A`: inspection that writes nothing and is exempt from lifecycle capture, plus one read-only live campaign request once the site is built and a public campaign key resolves; `--write` is tier `A` (the same read, plus it writes doctor output); `--built` and `--built --emit-packet` are tier `B` and write doctor output or the emitted packet under the target).
|
|
84
|
-
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 `
|
|
84
|
+
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 `A`: writes the local CampaignSpec and doctor output, and once the campaign is built makes the one read-only live campaign read doctor makes; `--no-live-refs` keeps it tier `B`), which writes the repo pin — and the page routes and analytics ids the repo carries, after handoff the pages the page tree adds or removes, and the offer and package fields the spec mirrors from the Campaigns App — into the local CampaignSpec with a field-by-field diff (bind it with `campaigns-os record spec --packet <p>`), 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.
|
|
85
85
|
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.
|
|
86
86
|
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.
|
|
87
87
|
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. Stage completion is recorded by command, never by hand-editing `.campaign-runtime/` JSON: `campaigns-os record setup`, `record build` (after every page-kit build) and `record polish --evidence <file>` (tier `C` each: they overwrite the stage record they name and stamp the doctor output stale; `--dry-run` is tier `none`).
|
|
@@ -96,6 +96,7 @@ Map and run endpoints) with a local CampaignSpec, prepared HTML/assets source, t
|
|
|
96
96
|
retains each attributed exception as `ready_with_exceptions`, and one
|
|
97
97
|
exception never suppresses another blocker.
|
|
98
98
|
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`).
|
|
99
|
+
After launch, a rebuild that touches only some pages' HTML is the exception to steps 9 and 10: readback's `evidence_debt` marks Polish advisory and QA scoped to the changed pages, and `campaigns-os next` names `qa run --packet <packet> --page <page_id>`, which places no test orders. Follow `next`.
|
|
99
100
|
11. Treat typed-card proof coverage as the control: `qa run` has no permission flag. Test orders still land in the store as real orders (global test cards: no charge, no transaction) that someone may have to cancel. Unless the operator has already said test orders are fine for this campaign, ask once, up front in your first turn with your other setup questions, so the answer covers the whole build and QA and neither stops for it later. `common` runs every actual terminal path when they fit under the flood cap (`--max-test-orders`, 6 by default); above the cap it runs checkout, 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.
|
|
100
101
|
12. Discuss launch only from recorded build, polish, deploy, browser QA, and test-order evidence, or from explicit blockers.
|
|
101
102
|
|
|
@@ -133,6 +134,7 @@ Rules:
|
|
|
133
134
|
- Designed source owns visual composition and page-level content.
|
|
134
135
|
- 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.
|
|
135
136
|
- 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 a detour with `--deviation-reason "<the operator's reason>"` only when the operator has decided on that detour in this conversation, and quote their reason; never pass the flag on your own judgement. On `record build` after a brief or CampaignSpec change the flag records that the change needs no change to the built pages, so pass it there only on the operator's explicit decision, as `next-campaigns-build` says.
|
|
137
|
+
- A Page Kit project can hold several funnels. The first one set up uses `campaign-runtime.build.json` and the `.campaign-runtime/` paths named here; each later funnel has `campaign-runtime-<route>.build.json` and keeps the same files under `.campaign-runtime/funnels/<route>/` (the packet's `assembly.runtime_dir`). Read and pass the funnel's own packet and paths; the paths `next` prints are already the right ones.
|
|
136
138
|
- 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.
|
|
137
139
|
- Do not copy demo refs or unsupported optional surfaces into the target campaign.
|
|
138
140
|
- Use SDK conditionals such as `cart.hasCoupon("CODE")` for code-specific presentation; do not mutate visible prices from campaign-specific JavaScript.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: next-campaigns-os-setup
|
|
3
|
-
version: 2.0.
|
|
3
|
+
version: 2.0.52
|
|
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.
|
|
8
|
-
Run `npx --no-install campaigns-os tooling status --skills-revision 1.
|
|
7
|
+
Bundle revision: 1.63.0+skills.1
|
|
8
|
+
Run `npx --no-install campaigns-os tooling status --skills-revision 1.63.0+skills.1`
|
|
9
9
|
from the campaign's Page Kit folder, where it runs the project's pinned copy and
|
|
10
10
|
never installs one, at the start of each task. Start a fresh session if it
|
|
11
11
|
reports `mismatch`: this text is already in your context and is never re-read
|
|
@@ -53,6 +53,8 @@ Responsibilities:
|
|
|
53
53
|
- Public families resolve from the default `public` starter-templates source. A **private** family (one whose source lives in an access-controlled repo, e.g. a certified family not present in the public picker) is scaffolded via page-kit's template-source mechanism (`next-campaign-page-kit` >= 0.2.0): add a named source to the target repo's `_data/template-sources.json` (a `git` source with the SSH `url` + optional `ref`, or a `local` source `path`), then `campaign-init --source <name> --template <slug>`. The source repo must expose a root `templates.json` catalog + `src/<slug>/` tree. page-kit holds no family→repo mapping; the source config lives in the (private) consuming repo, and this skill (plus the family's certified contract) is where that source is known.
|
|
54
54
|
- Install or reference `.campaign-runtime/agent-context` without overwriting existing root agent files.
|
|
55
55
|
- Read the normalized Campaign Build Brief at `.campaign-runtime/input/campaign-build-brief.normalized.json` and the recorded decisions (`adapter_decisions`, `decisions` and `theme` in `.campaign-runtime/assembly-report.json`, and `assembly.template_decision_notes` in the Build Packet) before working on the campaign. The campaign intent summary at the top of the setup, build, Polish and QA prompts and in every `next` result is orientation, never a source of prices or commerce behaviour.
|
|
56
|
+
- A Page Kit project can hold several funnels. The first one set up uses `campaign-runtime.build.json` and the `.campaign-runtime/` paths named here; each later funnel has `campaign-runtime-<route>.build.json` and keeps the same files under `.campaign-runtime/funnels/<route>/` (the packet's `assembly.runtime_dir`). Read and pass the funnel's own packet and paths; the paths `next` prints are already the right ones.
|
|
57
|
+
- When prepare-build prints a `Funnel:` line, it set up a new route as another funnel beside the default packet. If the operator meant to rename the existing funnel's route, follow the steps that line prints (delete the new packet and its directory, then re-run with `--out campaign-runtime.build.json --force`); ask before running it, because `--force` clears that funnel's recorded stage evidence.
|
|
56
58
|
- Record setup with `campaigns-os record setup --packet <packet>` once the campaign output directory exists (tier `C`: it overwrites `stages.setup` in `.campaign-runtime/assembly-report.json` and the `scaffold` block of `.campaign-runtime/build-context.json`, and stamps the doctor output stale; `--dry-run` is tier `none`). It sets `scaffold.required` to false and `stages.setup` to completed, validates both files against their schemas, and writes nothing when a check fails. Do not hand-edit either file.
|
|
57
59
|
- Preserve existing Build Context `theme` inspection data and Assembly Report `theme` application data when setup is rerun against an existing campaign directory.
|
|
58
60
|
- Hand off to `next-campaigns-build`.
|