@nextcommerce/campaigns-os 1.41.2 → 1.43.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +178 -0
- package/README.md +6 -4
- package/agents/claude/CLAUDE.md +5 -1
- package/campaign-spec/dist/types.d.ts +2 -0
- package/contracts/effects.v1.json +111 -18
- package/contracts/migration-sidecar-bundle.v0.json +9 -0
- package/contracts/release-ledger.json +752 -0
- package/contracts/supported-surface.json +12 -11
- package/docs/build-packet.md +56 -6
- package/docs/campaigns-os-build-flow.md +2 -2
- package/docs/effects.md +70 -1
- package/docs/local-setup.md +51 -0
- package/docs/migration-sidecar-bundle.md +6 -1
- package/docs/orientation-contract-reference.md +1 -1
- package/docs/progress-snapshots.md +6 -0
- package/docs/qa-and-test-orders.md +26 -10
- package/docs/runtime-readiness.md +1 -1
- package/docs/skills-revision.md +10 -10
- package/package.json +3 -2
- package/schemas/campaign-runtime-assembly-report.v0.schema.json +6 -1
- package/schemas/campaign-runtime-build-packet.v0.schema.json +6 -1
- package/schemas/campaign-spec.v4.schema.json +4 -0
- package/schemas/campaigns-os-progress-snapshot.v0.schema.json +1 -0
- package/schemas/campaigns-os-qa-verdict-sidecar.v0.schema.json +1 -0
- package/schemas/campaigns-os-qa-verdict.v0.schema.json +1 -0
- package/schemas/campaigns-os-run-record.v0.schema.json +1 -0
- package/skills/campaign-lifecycle-orientation/SKILL.md +13 -8
- package/skills/campaign-readback-classification/SKILL.md +3 -3
- package/skills/campaign-run-evidence/SKILL.md +8 -6
- package/skills/contribution-intake/SKILL.md +3 -3
- package/skills/next-campaigns-build/SKILL.md +3 -3
- package/skills/next-campaigns-os/SKILL.md +17 -4
- package/skills/next-campaigns-os/references/session-intake.md +4 -4
- package/skills/next-campaigns-os-setup/SKILL.md +3 -3
- package/skills/next-campaigns-polish/SKILL.md +3 -3
- package/skills/next-campaigns-qa/SKILL.md +10 -9
- package/skills.json +11 -11
- package/src/cli.mjs +187 -70
- package/src/finding-cause.mjs +14 -10
- package/src/lifecycle.mjs +5 -4
- package/src/polish-node.mjs +5 -2
- package/src/progress-node.mjs +3 -2
- package/src/progress.mjs +5 -3
- package/src/qa-node.mjs +58 -26
- package/src/qa-publish.mjs +4 -0
- package/src/qa-sidecar.mjs +2 -0
- package/src/qa-verdict-discovery.mjs +11 -0
- package/src/qa-verdict-publish.mjs +1 -0
- package/src/qa-verdict.mjs +8 -1
- package/src/readback.mjs +2 -1
- package/src/run-record-closeout.mjs +3 -4
- package/src/run-record.mjs +4 -0
- package/src/sidecar-bundle.mjs +21 -0
- package/src/spec-source-identity.mjs +44 -0
- package/src/stage-ledger.mjs +4 -1
- package/src/tooling-setup.mjs +160 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "The downstream contract manifest. Everything listed here is SUPPORTED SURFACE: consumers (campaigns-agent, campaign-builder, the private ops repo, page-kit campaign repos) may depend on it, and changing it is a deliberate act — hashed entries require a surface_version bump in the same change (check-supported-surface.mjs --base, mirroring the skills.json bump gate), named entries must keep existing at their path, cli_commands must keep resolving in the CLI dispatch, package_exports must stay exported, and every entry must ship in the npm pack (files[] coverage). Anything NOT listed here — src/** internals, scripts/** checkers, examples/**, prompts/**, contracts/** other than this file and the entries named[] below (the orientation contract, the release ledger, and the consumer-facing orientation fixtures) — is implementation: consumers may read it for context but must not build on it, and it can change without notice. Rationale and the compatibility promise: docs/supported-surface.md.",
|
|
3
|
-
"surface_version": "1.
|
|
3
|
+
"surface_version": "1.43.1",
|
|
4
4
|
"package_exports": [
|
|
5
5
|
"./commercial-journey",
|
|
6
6
|
"./commercial-parity",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
],
|
|
48
48
|
"hashed": {
|
|
49
49
|
"contracts/migration-sidecar-bundle.v0.json": {
|
|
50
|
-
"sha256": "
|
|
50
|
+
"sha256": "53269453dfdaac4b286124d445b60b0c46205dfbaf8037ac61b30254a32df53a"
|
|
51
51
|
},
|
|
52
52
|
"contracts/runtime-recipe.campaigns-os-node-v1.json": {
|
|
53
53
|
"sha256": "90aaaaade90cf2525ea1aa05be5cb2d02b57e6e59f9278a946efa8a087946fd3"
|
|
@@ -59,16 +59,16 @@
|
|
|
59
59
|
"sha256": "65bcd8b5f41f1e9ecfc36f3b8838cd4ed531bd74c5a318ee5147131f6c9b4a1c"
|
|
60
60
|
},
|
|
61
61
|
"schemas/campaign-runtime-assembly-report.v0.schema.json": {
|
|
62
|
-
"sha256": "
|
|
62
|
+
"sha256": "8a0d37be9a4bb34d0ed073c9d6bfa4406a7b499c801c34c5fbb26646e2665c0b"
|
|
63
63
|
},
|
|
64
64
|
"schemas/campaign-runtime-build-context.v0.schema.json": {
|
|
65
65
|
"sha256": "f310c1b7844d9b1994864d15858ff0c6f17efc1e5285ba193d181bdb2dd4be2f"
|
|
66
66
|
},
|
|
67
67
|
"schemas/campaign-runtime-build-packet.v0.schema.json": {
|
|
68
|
-
"sha256": "
|
|
68
|
+
"sha256": "47c2899f409ed5927cf410bddd63e7bb8a9d154eabf7a07455777aed118212e9"
|
|
69
69
|
},
|
|
70
70
|
"schemas/campaign-spec.v4.schema.json": {
|
|
71
|
-
"sha256": "
|
|
71
|
+
"sha256": "af56c3de638d3c4e1fd5df8c2d733754d9ad16caa23b5bec92ce3a6f71bd0271"
|
|
72
72
|
},
|
|
73
73
|
"schemas/campaigns-os-legacy-migration-inventory.v0.schema.json": {
|
|
74
74
|
"sha256": "d6edc4572900d15fdaf6b8c59916b0d885303c1d398bdadeb7c58285522c9049"
|
|
@@ -80,10 +80,10 @@
|
|
|
80
80
|
"sha256": "1405c32bb9698030e9a40d754191e413cdd505dde91ac7de2e41c8887700f8f2"
|
|
81
81
|
},
|
|
82
82
|
"schemas/campaigns-os-qa-verdict-sidecar.v0.schema.json": {
|
|
83
|
-
"sha256": "
|
|
83
|
+
"sha256": "3c40fd79f218d1b95f0424f9a2b67db140a306329e2ca02793e2740d3afded59"
|
|
84
84
|
},
|
|
85
85
|
"schemas/campaigns-os-qa-verdict.v0.schema.json": {
|
|
86
|
-
"sha256": "
|
|
86
|
+
"sha256": "ec4514e81a791a63bc0b358d7977aa823f3c5524e0f5caaba2712e66f262e18a"
|
|
87
87
|
},
|
|
88
88
|
"schemas/campaigns-os-doctor-output.v0.schema.json": {
|
|
89
89
|
"sha256": "87866e619d2a18f01a208a1682cb14a2079f61df51c642f4e1902b6e6bce0ce5"
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"sha256": "08ca132134b9e4610370e88082a5e888d09ddec0d5ee4512d84cc57181da722e"
|
|
96
96
|
},
|
|
97
97
|
"schemas/campaigns-os-run-record.v0.schema.json": {
|
|
98
|
-
"sha256": "
|
|
98
|
+
"sha256": "00dc9bcec79c12ea22a27f636188bcc33c6811df2d646ac7b49d4cc076e97355"
|
|
99
99
|
},
|
|
100
100
|
"schemas/campaigns-os-runtime-recipe.v1.schema.json": {
|
|
101
101
|
"sha256": "f8a2ab5eadbb71fb6d5653b670ee71e4471c3df74dd04000d3dbd3d9ae9e71fc"
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"sha256": "841c1f884260ce3eb3ddb518960a127bc915992a9539c818e5986ce156acff1f"
|
|
111
111
|
},
|
|
112
112
|
"schemas/campaigns-os-progress-snapshot.v0.schema.json": {
|
|
113
|
-
"sha256": "
|
|
113
|
+
"sha256": "ef31b4f20e39dfc1614dd4b45e4cf1692a51760b008cb51d133659307bd2a954"
|
|
114
114
|
},
|
|
115
115
|
"demo/apollo-v0/provenance.json": {
|
|
116
116
|
"sha256": "2e440be6513fe06b351c3a72c35424a04f807792621cb01e89803441fd925e06"
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"sha256": "dfc9abed38d456969e47a21f606d308a03bdf036f3466f7d6e47a602747dacf4"
|
|
120
120
|
},
|
|
121
121
|
"contracts/effects.v1.json": {
|
|
122
|
-
"sha256": "
|
|
122
|
+
"sha256": "121779835c14d8d48390c57268b50a60fe808f5d9ba91ea2dde5df22a64f8aaf"
|
|
123
123
|
},
|
|
124
124
|
"schemas/campaigns-os-effects.v1.schema.json": {
|
|
125
125
|
"sha256": "3eadd22169ab98bc7c2f682af2751267605170581182158d96be035b0cfe44dc"
|
|
@@ -212,6 +212,7 @@
|
|
|
212
212
|
"agents/codex/AGENTS.md",
|
|
213
213
|
"agents/copilot/copilot-instructions.md",
|
|
214
214
|
"agents/cursor/campaigns-os.mdc",
|
|
215
|
-
"docs/skills-revision.md"
|
|
215
|
+
"docs/skills-revision.md",
|
|
216
|
+
"docs/local-setup.md"
|
|
216
217
|
]
|
|
217
218
|
}
|
package/docs/build-packet.md
CHANGED
|
@@ -4,7 +4,7 @@ The Build Packet is the campaign assembly handoff. It wraps, but does not replac
|
|
|
4
4
|
|
|
5
5
|
It answers:
|
|
6
6
|
|
|
7
|
-
- Which CampaignSpec and Map ID are we building?
|
|
7
|
+
- Which CampaignSpec and saved Map ID or local-spec ID are we building?
|
|
8
8
|
- Which public route slug and campaign directory are expected?
|
|
9
9
|
- Where are the prepared HTML/assets?
|
|
10
10
|
- Which Campaign Build Brief is the merchandising/design presentation truth?
|
|
@@ -15,6 +15,56 @@ It answers:
|
|
|
15
15
|
|
|
16
16
|
The current schema is `schemas/campaign-runtime-build-packet.v0.schema.json`.
|
|
17
17
|
|
|
18
|
+
## Local-spec entry
|
|
19
|
+
|
|
20
|
+
A saved Map is optional for a prepared-HTML build. The coding agent authors an
|
|
21
|
+
ordinary CampaignSpec from the brief, source design and configured campaign's
|
|
22
|
+
real commerce values, following `schemas/campaign-spec.v4.schema.json`. The
|
|
23
|
+
operator supplies the selected store/campaign, public Campaigns API key, intended
|
|
24
|
+
pages and commercial choices, plus store contact details and policy URLs. Verify
|
|
25
|
+
the store/campaign binding and package/offer references; do not guess commerce
|
|
26
|
+
values. No gateway or Map provisioning is required for this entry.
|
|
27
|
+
|
|
28
|
+
Set `spec_identity.local_spec_id` to a new UUID once, commit it with the spec,
|
|
29
|
+
and keep it unchanged through revisions and fresh checkouts. It accepts 1–64
|
|
30
|
+
letters, digits, underscores or hyphens, with no surrounding whitespace. Local
|
|
31
|
+
IDs are checked exactly; the legacy normalization of saved Map IDs does not
|
|
32
|
+
apply. Malformed or conflicting local identities cannot be adopted into campaign
|
|
33
|
+
evidence; blocked diagnostic reports may still be written. Doctor reports local
|
|
34
|
+
identity failures as `spec.local_identity`, while
|
|
35
|
+
saved-Map failures retain `spec.map_id`. Set `spec_identity.public_route_slug`
|
|
36
|
+
to the intended route. Omit `map_id`, saved-Map URLs and saved-Map revision
|
|
37
|
+
metadata; a local ID is never a Map ID. A spec declaring both kinds is refused.
|
|
38
|
+
A separately authored campaign gets a new local ID even if its route matches.
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
npx --no-install campaigns-os start --spec campaign-spec.json --source source-html --target . --template-family <certified-family> --deploy-target local-serve
|
|
42
|
+
npx --no-install campaigns-os next --packet campaign-runtime.build.json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The packet and report retain `map_id: null` and carry `local_spec_id`. Doctor,
|
|
46
|
+
report writes, polish capture, progress, run closeout and QA compare that local
|
|
47
|
+
identity. Material spec hashes still bind the current revision; a changed ID or
|
|
48
|
+
content cannot reuse earlier proof. After a material revision, follow `next` to
|
|
49
|
+
refresh preparation and affected evidence. Keep the spec, source, dependency
|
|
50
|
+
pins and canonical sidecars in Git. Use `readback` and `next` after a fresh
|
|
51
|
+
checkout; identity survives the move, but proof freshness is assessed again.
|
|
52
|
+
|
|
53
|
+
Run QA through `--packet`. Local verdicts use the storage key
|
|
54
|
+
`local-spec-<local_spec_id>` and carry the explicit ID in the full verdict and
|
|
55
|
+
committed sidecar. A matching route alone cannot adopt a verdict. Local QA is
|
|
56
|
+
never posted to the Map portal: `qa run` suppresses publication even with
|
|
57
|
+
`--post-verdict`, while `qa publish` refuses with `local_spec`. Progress remains
|
|
58
|
+
local with `map_id_missing`. Run Telemetry retains
|
|
59
|
+
its existing consent controls. `spec derive --write-map` requires a real saved
|
|
60
|
+
Map. Moving to a saved Map requires fresh preparation and evidence; this entry
|
|
61
|
+
does not claim saved-Map revision alignment.
|
|
62
|
+
|
|
63
|
+
Existing saved-Map specs and packets continue to work. The identity change does
|
|
64
|
+
not relax template certification, source proof, store/SDK parity, polish,
|
|
65
|
+
commerce checks, or typed-card checkout proof. Resolve their reported gates;
|
|
66
|
+
localhost readiness is not production approval.
|
|
67
|
+
|
|
18
68
|
## Root-Served Campaigns (`campaign.route_root`)
|
|
19
69
|
|
|
20
70
|
Most campaigns are served under a slug prefix (`/<public_route_slug>/...`), and
|
|
@@ -78,7 +128,7 @@ campaigns-os page-kit sync --packet campaign-runtime.build.json [--dry-run] [--j
|
|
|
78
128
|
```
|
|
79
129
|
|
|
80
130
|
The CampaignSpec is the authority for the Store Profile: those values are
|
|
81
|
-
authored in the Map
|
|
131
|
+
authored in the saved Map or the repository-owned local spec, so `page-kit sync` writes the nine
|
|
82
132
|
fields the spec carries (`campaign.store_*`) unconditionally. The SDK pin is
|
|
83
133
|
different. On an existing campaign the repo pin moves first and the Map/spec
|
|
84
134
|
is stale until someone re-saves it, so a spec → repo write would undo a bump
|
|
@@ -103,7 +153,7 @@ covers only the governed fields. `--dry-run` prints the same diff without
|
|
|
103
153
|
writing. Exit 0 on success (including a no-op re-run); exit 2 with
|
|
104
154
|
`page_kit.sync.*` error codes and nothing written when the packet cannot be
|
|
105
155
|
read, the target entry or the spec is missing or not an object, the spec
|
|
106
|
-
identifies another campaign (`spec_identity.public_route_slug` or `
|
|
156
|
+
identifies another campaign (`spec_identity.public_route_slug`, `map_id` or `local_spec_id`
|
|
107
157
|
disagreeing with the packet: `page_kit.sync.spec_identity_mismatch`), or the
|
|
108
158
|
resolved `_data/campaigns.json` lies outside the target repo through a symlink
|
|
109
159
|
(`page_kit.sync.target_escapes_repo`).
|
|
@@ -1114,12 +1164,12 @@ and report proof policy fields above.
|
|
|
1114
1164
|
|
|
1115
1165
|
| Flag | Source | When to use |
|
|
1116
1166
|
| --- | --- | --- |
|
|
1117
|
-
| `--spec <path>` | Local JSON file |
|
|
1118
|
-
| `--map-id <id>` | Map Builder proxy (KV-backed) |
|
|
1167
|
+
| `--spec <path>` | Local JSON file | Agent-authored local specs, saved-Map exports, offline work or CI fixtures |
|
|
1168
|
+
| `--map-id <id>` | Map Builder proxy (KV-backed) | Saved-Map intake from the current KV revision |
|
|
1119
1169
|
|
|
1120
1170
|
When `--map-id <id>` is set, the CLI fetches `GET <proxy>/api/spec/<id>` (default `<proxy>` is `https://campaign-map.nextcommerce.com`) and caches the response to `<target>/.campaign-runtime/fetched-specs/<id>.json`. The cached file is what downstream stages read, so the packet's `spec.local_path` always resolves to an on-disk artifact regardless of intake mode.
|
|
1121
1171
|
|
|
1122
|
-
|
|
1172
|
+
Saved-Map retrieval behavior (`--map-id`):
|
|
1123
1173
|
|
|
1124
1174
|
- **Re-fetch by default.** Every `start` / `prepare-build` invocation re-fetches from KV. KV is the source of truth; the cache file is a debug/inspection artifact, not a performance optimization.
|
|
1125
1175
|
- **`--cached-spec`** reuses the cache without a network call. Use for offline iteration or when the proxy is temporarily unreachable.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The happy path is intentionally tight:
|
|
4
4
|
|
|
5
|
-
1.
|
|
5
|
+
1. Use a saved Map export, or have the coding agent author a CampaignSpec from the brief and verified campaign values through the [local-spec entry](build-packet.md#local-spec-entry). Preserve its Map ID or stable `local_spec_id`, plus its public route slug.
|
|
6
6
|
2. Run `campaigns-os start` with the CampaignSpec, prepared source files, target page-kit repo, and template family.
|
|
7
7
|
3. Treat doctor as the first gate. If its `next` block says `doctor-blocked` or `prepare-build` (the same stage names `campaigns-os next` uses), stop and resolve the named blocker.
|
|
8
8
|
4. Run setup when doctor asks for setup; otherwise continue to assembly.
|
|
@@ -11,7 +11,7 @@ The happy path is intentionally tight:
|
|
|
11
11
|
7. Install the package-owned Playwright browser with `npm run qa:install-browser`.
|
|
12
12
|
8. Run polish, serve the current built output, and run `campaigns-os polish capture --packet <packet> --base-url <served-current-build-url>`. Do not mark Polish terminal or begin deploy/QA until this package-owned page-load evidence passes or has an exact finding waiver.
|
|
13
13
|
9. Deploy a preview.
|
|
14
|
-
10. Run `campaigns-os qa resolve
|
|
14
|
+
10. Run `campaigns-os qa resolve --packet <packet>`, then `campaigns-os qa run --packet <packet> --browser --test-order common` with the tested URL. Saved-Map QA uses the existing consent and publication controls; pass `--no-post-verdict` to keep its verdict local. Local-spec QA always keeps verdicts and progress local, even with `--post-verdict`, and `qa publish` refuses local-spec packets. Run Telemetry retains its consent controls.
|
|
15
15
|
11. Treat test-order depth as the control: global test cards bypass the gateway and create no transactions, so no approval is needed. Localhost on any port is a Campaigns App Development domain (SDK allowed, analytics suppressed); non-localhost preview/production origins must still be allowlisted for the campaign API key so the SDK loads.
|
|
16
16
|
12. Promote, block, or iterate from the recorded build, polish, deploy, QA, and test-order evidence.
|
|
17
17
|
|
package/docs/effects.md
CHANGED
|
@@ -9,6 +9,13 @@ The point of the file is not the prose. It is that **every row is proved by a
|
|
|
9
9
|
test** (`src/effects.test.mjs`), and a row without its test cannot be published:
|
|
10
10
|
`npm run check:effects` refuses it.
|
|
11
11
|
|
|
12
|
+
`tooling setup` composes the existing skill/context/browser installers after a
|
|
13
|
+
project-pin and preservation preflight. It also appends a project `CLAUDE.md`
|
|
14
|
+
import. It bypasses session recovery, gateway credential reads and lifecycle
|
|
15
|
+
capture; `--dry-run` is read-only. Like `qa install-browser`, its browser download
|
|
16
|
+
has preflight-only effects proof offline; setup's preservation and recovery
|
|
17
|
+
behavior has focused tests.
|
|
18
|
+
|
|
12
19
|
- The contract: [`contracts/effects.v1.json`](../contracts/effects.v1.json)
|
|
13
20
|
- Its shape: [`schemas/campaigns-os-effects.v1.schema.json`](../schemas/campaigns-os-effects.v1.schema.json)
|
|
14
21
|
- The proof: `src/effects.test.mjs`
|
|
@@ -67,7 +74,7 @@ with one of these:
|
|
|
67
74
|
| `{lifecycle-journal}` | The command-lifecycle journal wherever it was selected for this invocation. |
|
|
68
75
|
| `{proxy-base}` | The endpoint `--proxy-base` names, or the canonical NEXT endpoint when it does not. |
|
|
69
76
|
| `{base-url}` | The campaign under test, as `--base-url` names it or as the packet derives it. |
|
|
70
|
-
| `{playwright-download-host}` | Where Playwright fetches browser builds from: `PLAYWRIGHT_DOWNLOAD_HOST` when set, else the Playwright CDN. The
|
|
77
|
+
| `{playwright-download-host}` | Where Playwright fetches browser builds from: `PLAYWRIGHT_DOWNLOAD_HOST` when set, else the Playwright CDN. The third-party browser download used by `qa install-browser` and `tooling setup`. |
|
|
71
78
|
|
|
72
79
|
The tokens matter because effects are not all under the target. `install-skills`
|
|
73
80
|
writes your **home** directory, not the campaign. `telemetry on` writes your
|
|
@@ -129,6 +136,63 @@ declared on the rows it belongs to: `start`, `prepare-build`, `build`,
|
|
|
129
136
|
`run start` and `run end` close out a **stale** run session at the root they are
|
|
130
137
|
about to act on *before* argv is refused.
|
|
131
138
|
|
|
139
|
+
A refusal is decided by argv alone. When file content or state on disk decides
|
|
140
|
+
the outcome, the command has reached a handler failure and journals it.
|
|
141
|
+
|
|
142
|
+
For intake, run-record, built-site QA, and `next`, argv-only checks run before
|
|
143
|
+
their handler reads the target; invalid values are refused without a journal
|
|
144
|
+
entry. For `start`, `prepare-build`, and `build`, bare, empty, and whitespace-only
|
|
145
|
+
values of `--spec`, `--map-id`, `--source`, `--target`, `--source-kind`,
|
|
146
|
+
`--proxy-base`, `--wrapper-policy`, `--design-manifest`, and
|
|
147
|
+
`--order-path-depth` are refused before local spec reads, Map fetches, or cache
|
|
148
|
+
writes on the `--spec`, `--map-id`, and `--map-id --cached-spec` paths.
|
|
149
|
+
The operator-facing `run-record` and `run end` commands refuse bare, empty, or
|
|
150
|
+
whitespace-only values for every value-taking inherited run-record flag before
|
|
151
|
+
packet work. The five agent
|
|
152
|
+
token and elapsed-time flags retain their non-negative-integer diagnostics;
|
|
153
|
+
`--surfaces` rejects unknown values, and `--dry-run` rejects a value. The
|
|
154
|
+
inherited boolean flags (`--no-remit`, `--no-write`, `--dry-run`, and `--json`)
|
|
155
|
+
retain their bare-flag behavior. `run end` also rejects `--new-run` and
|
|
156
|
+
`--run-id` because the saved session fixes its run ID. `run-record` also
|
|
157
|
+
rejects bare, empty, or whitespace-only `--run-id` and valued `--new-run`.
|
|
158
|
+
Internal stale-session and QA closeouts retain the previous handling of values
|
|
159
|
+
inherited from their invoking commands. A bare, empty, or whitespace-only
|
|
160
|
+
`--proxy-base` on a sweeping command still writes the stale Run Record.
|
|
161
|
+
Terminal QA auto-end tolerates whitespace-only inherited `--context`,
|
|
162
|
+
`--report`, or `--proxy-base`. A whitespace-only `--context` resolves as a
|
|
163
|
+
literal relative path, so the default context file is not read. Bare or empty
|
|
164
|
+
`--context` or `--report` still makes QA auto-end fail and leaves the session
|
|
165
|
+
open; bare or empty `--qa-verdict` fails a Run Record closeout when inherited,
|
|
166
|
+
though QA auto-end supplies its own verdict path. The underlying run-record
|
|
167
|
+
handler still rejects invalid agent
|
|
168
|
+
integers, unknown `--surfaces`, and any valued `--dry-run` that reaches it. QA
|
|
169
|
+
auto-end drops `--dry-run` from inherited flags; if another inherited value
|
|
170
|
+
fails in the handler, auto-end is skipped and the session stays open. QA's own
|
|
171
|
+
journal entry is unaffected because auto-end runs after QA persistence. A named
|
|
172
|
+
`--design-manifest` that is missing or is not a file is checked
|
|
173
|
+
against the filesystem after intake has begun, so that failure is journaled.
|
|
174
|
+
An invalid manifest's contents are likewise a handler failure. A `next` stage
|
|
175
|
+
must be one of the stages in the orchestration stage contract; an unknown name
|
|
176
|
+
is refused before the `next` handler reads the packet, runs doctor, or writes
|
|
177
|
+
doctor output. The ambient run-session lookup in `main()` may read a named
|
|
178
|
+
`--packet` before the handler runs.
|
|
179
|
+
|
|
180
|
+
`polish capture --packet` would report "polish capture requires
|
|
181
|
+
packet.assembly.target_repo to resolve to a local target repo" as a journaled
|
|
182
|
+
handler failure because packet content would decide it. Today the workspace
|
|
183
|
+
resolver always yields a local path, so this check does not fire through the
|
|
184
|
+
CLI. `run end` reports "run end needs a build packet" as a journaled handler failure
|
|
185
|
+
when the saved session has no packet and argv names none. For `qa run` and `qa
|
|
186
|
+
resolve`, "QA requires a Map ID" is a refusal when argv carries no non-empty
|
|
187
|
+
`--packet`, `--site`, `--built`, positional Map ID, or `--map-id` value. A selector
|
|
188
|
+
flag without a value is refused with "Missing value for --<flag>". If a named
|
|
189
|
+
packet yields neither a Map ID nor a valid local-spec identity after checkpoint
|
|
190
|
+
preflight reads the packet, spec, and report, the requirement is a journaled
|
|
191
|
+
handler failure. A conflicting local/Map identity is also a handler failure.
|
|
192
|
+
The nested run-record refusal scope in session closeout guards against future
|
|
193
|
+
changes. No internal closeout can currently create a refusal before its
|
|
194
|
+
invoking command journals.
|
|
195
|
+
|
|
132
196
|
## How a row is proved
|
|
133
197
|
|
|
134
198
|
`src/effects.test.mjs` runs the real CLI in a disposable target seeded from
|
|
@@ -279,3 +343,8 @@ reason. What it may not be is silent.
|
|
|
279
343
|
Change the effect, change the row, in the same PR. The effect test will tell you
|
|
280
344
|
which row is wrong before review does: it names the path that moved and the row
|
|
281
345
|
that failed to declare it.
|
|
346
|
+
|
|
347
|
+
Local-spec QA retains its artifacts locally. It never sends a verdict or progress
|
|
348
|
+
to the Map portal, even when `--post-verdict` is supplied; `qa publish` refuses
|
|
349
|
+
local-spec packets. Commerce API reads, served-page probes and requested typed-card
|
|
350
|
+
orders keep their existing effects. Run Telemetry still follows its consent controls.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Local campaign setup
|
|
2
|
+
|
|
3
|
+
For a new campaign, choose its working folder and run this from that folder:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install --save-dev --save-exact @nextcommerce/campaigns-os@1.43.1 next-campaign-page-kit@0.2.0 && npx --no-install campaigns-os tooling setup --target . --platform claude
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Review the release source/provenance before installation as described in
|
|
10
|
+
`AGENTS.md`. npm installs the dependencies first; `--no-install` then runs only
|
|
11
|
+
the project's installed CLI. Keep `package.json` and `package-lock.json` in
|
|
12
|
+
Git. For an existing project, preserve its reviewed pin: run `npm ci`, then
|
|
13
|
+
`npx --no-install campaigns-os tooling setup --target . --platform claude`
|
|
14
|
+
on a release that supports setup. Changing the pin is a separate update.
|
|
15
|
+
|
|
16
|
+
Setup checks the exact toolkit pin, its lockfile version and the installed
|
|
17
|
+
page-kit dependency before it changes files. It composes the existing
|
|
18
|
+
installers to:
|
|
19
|
+
|
|
20
|
+
1. Install the QA browser through this toolkit's own Playwright package.
|
|
21
|
+
2. Install the bundled skills into `~/.claude/skills` (same-name skills are
|
|
22
|
+
refreshed just as with `install-skills`).
|
|
23
|
+
3. Install the four context files under `.campaign-runtime/agent-context`
|
|
24
|
+
and the managed runtime ignore block.
|
|
25
|
+
4. Append one import to the project's `CLAUDE.md`, preserving existing text.
|
|
26
|
+
|
|
27
|
+
The import uses Claude Code's documented
|
|
28
|
+
[`@path` syntax](https://code.claude.com/docs/en/memory#import-additional-files).
|
|
29
|
+
Existing context that differs from the bundle and symlink destinations require
|
|
30
|
+
reconciliation before setup; setup does not overwrite them. A repeated run
|
|
31
|
+
preserves campaign pages, authored decisions and project instructions. If the
|
|
32
|
+
browser download fails, fix that error and rerun setup; shared skills and
|
|
33
|
+
project files have not been changed. If the runtime ignore block cannot be
|
|
34
|
+
written, setup reports `context_install_failed`; fix `.gitignore` and rerun.
|
|
35
|
+
`--dry-run --json` previews setup without any writes or browser download.
|
|
36
|
+
|
|
37
|
+
Restart Claude Code in the campaign folder. Use the `next-campaigns-os` skill
|
|
38
|
+
and provide the configured campaign details, HTML/assets and brief. The agent
|
|
39
|
+
authors a local CampaignSpec if there is no saved Map export; follow the
|
|
40
|
+
[local-spec entry](build-packet.md#local-spec-entry). The skill checks its
|
|
41
|
+
loaded bundle revision against the project copy.
|
|
42
|
+
`restart_required` means the files are installed; it does not prove that the
|
|
43
|
+
running agent has loaded them. Check Claude's `/context` view if the project
|
|
44
|
+
instructions are missing.
|
|
45
|
+
|
|
46
|
+
Setup does not scaffold template pages, create a CampaignSpec, connect the
|
|
47
|
+
gateway, change a saved Map, run a campaign session, remit telemetry, or prove
|
|
48
|
+
checkout. The agent performs intake and chooses the template before assembly.
|
|
49
|
+
A local spec uses `spec_identity.local_spec_id` and keeps its evidence in the
|
|
50
|
+
repository. Existing doctor/QA gates still apply. This entry is Claude Code first; other agents retain their existing
|
|
51
|
+
manual installation path.
|
|
@@ -55,12 +55,17 @@ contract. A packet found only at
|
|
|
55
55
|
remedy; conformance does not silently widen discovery.
|
|
56
56
|
|
|
57
57
|
The checker validates canonical paths, declared schema versions, strict UTC
|
|
58
|
-
timestamps, cross-artifact Map ID, public slug, campaign directory, live URL
|
|
58
|
+
timestamps, cross-artifact Map ID or local-spec ID, public slug, campaign directory, live URL
|
|
59
59
|
path, template family, and spec identity, doctor freshness, and the URL/order-
|
|
60
60
|
free QA projection. Safe repository-relative spellings such as
|
|
61
61
|
`campaign-runtime.build.json` and `./campaign-runtime.build.json` are
|
|
62
62
|
equivalent; absolute paths, URIs, backslashes, and parent traversal are not.
|
|
63
63
|
|
|
64
|
+
Local-spec bundles compare `local_spec_id` across the packet, report, doctor
|
|
65
|
+
output and QA sidecar. Their Map IDs remain null; the QA verdict's
|
|
66
|
+
`campaign_slug` is the storage key `local-spec-<local_spec_id>`. Mixing local
|
|
67
|
+
and saved-Map identities fails conformance; a shared public route is not enough.
|
|
68
|
+
|
|
64
69
|
Spec identity has two deliberately separate meanings. Build Context
|
|
65
70
|
`spec.hash` and Assembly Report `identity.spec_hash` retain exact raw-byte
|
|
66
71
|
integrity. Build Context `spec.material_hash`, Assembly Report
|
|
@@ -25,7 +25,7 @@ Ledger schema id: `campaigns-os-release-ledger/v1`
|
|
|
25
25
|
Change policy version: `1.0.0`
|
|
26
26
|
Reason-code vocabulary version: `1.0.0`
|
|
27
27
|
Limits version: `1.0.0`
|
|
28
|
-
Supported surface at generation time: `1.
|
|
28
|
+
Supported surface at generation time: `1.43.1`
|
|
29
29
|
|
|
30
30
|
## Forward compatibility
|
|
31
31
|
|
|
@@ -140,3 +140,9 @@ The planned immutable receiver key is
|
|
|
140
140
|
revision. A key match identifies scope; it is not authentication or trust. The
|
|
141
141
|
receiver must verify the digest and authorized Map scope and stamp its own trust.
|
|
142
142
|
Unknown, incomplete or conflicted histories must never yield a ready workspace.
|
|
143
|
+
|
|
144
|
+
Local-spec packets add optional `identity.local_spec_id`. Report binding compares
|
|
145
|
+
that ID and the local material hash, so local stages can be observed without a
|
|
146
|
+
saved Map. `map_id` and `map_revision_hash` remain null and
|
|
147
|
+
`saved_revision_alignment` remains `unconfirmed`; these observations stay on disk
|
|
148
|
+
with `map_id_missing` and have no portal storage key.
|
|
@@ -98,6 +98,11 @@ npm run campaigns-os -- qa resolve --packet campaign-runtime.build.json
|
|
|
98
98
|
|
|
99
99
|
Resolve reads the packet, loads the local CampaignSpec when available, derives deployed page URLs from the packet deploy URL or `--base-url`, probes the entry URLs it derived, and prints the funnel topology. It does not create a verdict.
|
|
100
100
|
|
|
101
|
+
Local-spec QA requires `--packet` and matching `local_spec_id` values in the
|
|
102
|
+
packet, CampaignSpec and Assembly Report, with a current report material hash.
|
|
103
|
+
A Map ID override is refused. See the [local-spec entry](build-packet.md#local-spec-entry)
|
|
104
|
+
for preparation and identity rules.
|
|
105
|
+
|
|
101
106
|
### Route reachability
|
|
102
107
|
|
|
103
108
|
A route set derived from the packet is not evidence that the deployment serves
|
|
@@ -289,7 +294,7 @@ npm run campaigns-os -- qa run \
|
|
|
289
294
|
--base-url https://preview.example.com/campaign/
|
|
290
295
|
```
|
|
291
296
|
|
|
292
|
-
The runner fetches deployed pages, checks route availability, verifies CampaignSpec `sdk_hints.meta_tags` (a key the Campaign Cart SDK does not read, `next-currency` or `next-predictive-address` from `src/sdk-meta-tags.mjs`, is a `warn` row at severity `warn` carrying the shared note, never `manual_review` and never a blocker, whether or not the tag rendered; doctor reports the same key as `sdk_hints.meta_tags.ignored_by_sdk`), writes a local verdict JSON under `<target-repo>/qa-output/<
|
|
297
|
+
The runner fetches deployed pages, checks route availability, verifies CampaignSpec `sdk_hints.meta_tags` (a key the Campaign Cart SDK does not read, `next-currency` or `next-predictive-address` from `src/sdk-meta-tags.mjs`, is a `warn` row at severity `warn` carrying the shared note, never `manual_review` and never a blocker, whether or not the tag rendered; doctor reports the same key as `sdk_hints.meta_tags.ignored_by_sdk`), writes a local verdict JSON under `<target-repo>/qa-output/<qa-storage-key>/<run-id>.json` (the packet's `assembly.target_repo`, else the packet's directory; `--output-dir` overrides it, and a packet-less run uses `qa-output/` under the current directory), and returns exit code `4` when the verdict is blocked. The storage key is the Map ID for saved-Map QA and `local-spec-<local_spec_id>` for local-spec packet QA. The target's managed ignore block lists `qa-output/`, because full verdicts carry live storefront URLs; the committed form is the `.campaign-runtime/qa-verdict.json` projection.
|
|
293
298
|
|
|
294
299
|
### Automatic commercial parity
|
|
295
300
|
|
|
@@ -353,7 +358,7 @@ nothing is ever selected by mtime or "latest":
|
|
|
353
358
|
```bash
|
|
354
359
|
campaigns-os qa promote \
|
|
355
360
|
--packet campaign-runtime.build.json \
|
|
356
|
-
--verdict qa-output/<
|
|
361
|
+
--verdict qa-output/<qa-storage-key>/<run-id>.json \
|
|
357
362
|
--json
|
|
358
363
|
```
|
|
359
364
|
|
|
@@ -381,10 +386,12 @@ Report's `identity.spec_material_hash` and the Build Context's
|
|
|
381
386
|
raw-byte digest of the spec file (the two meanings are deliberate; see
|
|
382
387
|
[docs/migration-sidecar-bundle.md](./migration-sidecar-bundle.md)).
|
|
383
388
|
`campaign_ref_id` is copied from the CampaignSpec's `campaign.ref_id` and
|
|
384
|
-
identifies the platform campaign
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
`
|
|
389
|
+
identifies the configured platform campaign, not this build: two specs for one
|
|
390
|
+
platform campaign share it by design, and it is `null` when the spec carries
|
|
391
|
+
none. `campaign_slug` carries the Map ID for saved-Map verdicts. Local-spec
|
|
392
|
+
verdicts carry explicit `local_spec_id` and use
|
|
393
|
+
`campaign_slug: "local-spec-<local_spec_id>"`; both survive sidecar projection.
|
|
394
|
+
`public_route_slug` is the route, not a substitute for either stable identity.
|
|
388
395
|
|
|
389
396
|
**Trust is stamped by the receiver, never by this CLI.** The QA portal
|
|
390
397
|
receiver accepts verdict posts publicly (after shape/size/rate checks) and
|
|
@@ -512,7 +519,8 @@ Exactly one comparison, against exactly one earlier run:
|
|
|
512
519
|
|
|
513
520
|
1. **Find the previous run.** The most recent Run Record under the Build
|
|
514
521
|
Packet's `.campaign-runtime/run-records/` whose `identity.map_id` matches
|
|
515
|
-
this
|
|
522
|
+
this saved Map, or whose `identity.local_spec_id` matches this local spec
|
|
523
|
+
with no Map ID. Only the first match counts — walking further back to find a
|
|
516
524
|
record that happens to carry usable evidence would compare this run against
|
|
517
525
|
a non-adjacent one and report anything introduced in between as
|
|
518
526
|
pre-existing.
|
|
@@ -624,7 +632,7 @@ QA evidence redacts checkout request bodies and generated QA emails. Verdict art
|
|
|
624
632
|
keep method, URL, response summaries, order refs, line-item summaries, and card last4,
|
|
625
633
|
but they should not contain full customer address/payment payloads.
|
|
626
634
|
|
|
627
|
-
QA runs **publish to the QA portal by default** — they appear in the Campaign Map
|
|
635
|
+
Saved-Map QA runs **publish to the QA portal by default** — they appear in the Campaign Map
|
|
628
636
|
QA tab and the run picker, and the command prints the portal link. No flag needed.
|
|
629
637
|
Pass `--no-post-verdict` (or `--local-only`) for offline / dev / CI runs that should
|
|
630
638
|
stay local-only; publishing never fails the QA run if the portal is unreachable.
|
|
@@ -636,7 +644,14 @@ local-only, and the output names the destination plus the opt-in
|
|
|
636
644
|
(`--post-verdict`, or `campaigns-os telemetry on`). Portal-managed campaigns —
|
|
637
645
|
spec resolved from the portal for the run — keep publish-by-default regardless
|
|
638
646
|
of consent: those verdicts are the QA tab's product surface, not telemetry.
|
|
639
|
-
Explicit flags always win in both directions.
|
|
647
|
+
Explicit flags always win in both directions for saved-Map QA.
|
|
648
|
+
|
|
649
|
+
A packet with `local_spec_id` always keeps its verdict and progress local.
|
|
650
|
+
`qa run` suppresses portal publication even with `--post-verdict`; the flag
|
|
651
|
+
does not turn a local ID into a Map destination. `qa publish` refuses such a
|
|
652
|
+
packet with `refusal.code: local_spec`, including under `--dry-run` or
|
|
653
|
+
`--republish`. Commerce reads, served-page probes and requested typed-card
|
|
654
|
+
orders still run; Run Telemetry follows its existing consent controls.
|
|
640
655
|
|
|
641
656
|
```bash
|
|
642
657
|
npm run campaigns-os -- qa run \
|
|
@@ -646,7 +661,7 @@ npm run campaigns-os -- qa run \
|
|
|
646
661
|
|
|
647
662
|
### Publish a stored verdict (`qa publish`)
|
|
648
663
|
|
|
649
|
-
"
|
|
664
|
+
For saved-Map packets, "run local, publish when clean" is one command, not a rerun. A run kept local
|
|
650
665
|
with `--no-post-verdict` writes the same full verdict under `qa-output/` and
|
|
651
666
|
the same committed sidecar as a publishing run; `qa publish` posts that stored
|
|
652
667
|
verdict to the QA portal through the rail `qa run` uses, without re-running
|
|
@@ -678,6 +693,7 @@ order placed — with a named `refusal.code`:
|
|
|
678
693
|
|
|
679
694
|
| `refusal.code` | What it means |
|
|
680
695
|
|---|---|
|
|
696
|
+
| `local_spec` | The packet has `local_spec_id` and no saved Map destination. Keep the verdict local; moving to a saved Map requires fresh preparation and evidence. |
|
|
681
697
|
| `spec_hash_mismatch` | The verdict's `spec_hash` is not the packet's current spec (`spec.local_path`, hashed the way every spec-identity check hashes it, so `sha256:` prefix and case do not matter). A verdict for a spec that has since changed is not evidence about the current one: re-run `qa run`, which publishes by default. The result carries both hashes. |
|
|
682
698
|
| `spec_hash_absent` | The verdict carries no `spec_hash`. Re-run `qa run`. |
|
|
683
699
|
| `already_published` | The run's Run Record records this verdict's `run_id` as published (by the run itself, or by an earlier `qa publish`). Pass `--republish` to post it again; the existing portal link is in the output either way. |
|
|
@@ -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.2`, 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.2`, validated by `schemas/campaigns-os-runtime-recipe.v1.schema.json` (`Campaigns OS Runtime Recipe v1`). Supported surface at generation time: `1.43.1`.
|
|
12
12
|
|
|
13
13
|
## What this is
|
|
14
14
|
|
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.43.1+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.43.1+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.43.1+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.43.1+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.43.1+skills.1",
|
|
94
94
|
"spelling": "bundle",
|
|
95
|
-
"on_disk": "1.
|
|
95
|
+
"on_disk": "1.43.1+skills.1",
|
|
96
96
|
"on_disk_skill": null,
|
|
97
|
-
"message": "match (1.
|
|
97
|
+
"message": "match (1.43.1+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.43.1+skills.1)
|
|
105
|
+
Skills revision: mismatch: loaded 1.39.0+skills.1, on disk 1.43.1+skills.1 — start a fresh session
|
|
106
|
+
Skills revision: unchecked (on disk 1.43.1+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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextcommerce/campaigns-os",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.43.1",
|
|
4
4
|
"description": "Toolkit for agent-assisted NEXT campaign builds.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -149,6 +149,7 @@
|
|
|
149
149
|
"docs/diagnostics.md",
|
|
150
150
|
"docs/progress-snapshots.md",
|
|
151
151
|
"demo",
|
|
152
|
-
"docs/demo-preview.md"
|
|
152
|
+
"docs/demo-preview.md",
|
|
153
|
+
"docs/local-setup.md"
|
|
153
154
|
]
|
|
154
155
|
}
|
|
@@ -28,8 +28,13 @@
|
|
|
28
28
|
"type": "object",
|
|
29
29
|
"additionalProperties": true,
|
|
30
30
|
"required": ["map_id", "public_route_slug", "campaign_directory", "live_url_path", "spec_hash"],
|
|
31
|
+
"oneOf": [
|
|
32
|
+
{ "properties": { "map_id": { "type": "string", "minLength": 1 } }, "not": { "required": ["local_spec_id"] } },
|
|
33
|
+
{ "required": ["local_spec_id", "spec_material_hash"], "properties": { "map_id": { "type": "null" } } }
|
|
34
|
+
],
|
|
31
35
|
"properties": {
|
|
32
|
-
"
|
|
36
|
+
"local_spec_id": { "type": "string", "pattern": "^[A-Za-z0-9_-]{1,64}$", "description": "Stable repository-owned CampaignSpec identity; never a saved Map ID. Keep unchanged across local revisions." },
|
|
37
|
+
"map_id": { "type": ["string", "null"], "minLength": 1 },
|
|
33
38
|
"public_route_slug": { "type": "string", "minLength": 1 },
|
|
34
39
|
"campaign_directory": { "type": "string", "minLength": 1 },
|
|
35
40
|
"live_url_path": { "type": "string", "minLength": 1 },
|
|
@@ -66,9 +66,14 @@
|
|
|
66
66
|
"type": "object",
|
|
67
67
|
"additionalProperties": false,
|
|
68
68
|
"required": ["map_id"],
|
|
69
|
+
"oneOf": [
|
|
70
|
+
{ "properties": { "map_id": { "type": "string", "minLength": 1 } }, "not": { "required": ["local_spec_id"] } },
|
|
71
|
+
{ "required": ["local_spec_id", "local_path"], "properties": { "map_id": { "type": "null" }, "local_path": { "type": "string", "minLength": 1 }, "spec_url": { "type": "null" } } }
|
|
72
|
+
],
|
|
69
73
|
"properties": {
|
|
74
|
+
"local_spec_id": { "type": "string", "pattern": "^[A-Za-z0-9_-]{1,64}$", "description": "Stable repository-owned CampaignSpec identity; never a saved Map ID. Keep unchanged across local revisions." },
|
|
70
75
|
"map_id": {
|
|
71
|
-
"type": "string",
|
|
76
|
+
"type": ["string", "null"],
|
|
72
77
|
"minLength": 1,
|
|
73
78
|
"description": "Saved Map Builder identity used for reopen, /api/spec/<map-id>, QA verdicts, and provenance."
|
|
74
79
|
},
|