@nextcommerce/campaigns-os 1.33.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.
Files changed (310) hide show
  1. package/AGENTS.md +204 -0
  2. package/CHANGELOG.md +5002 -0
  3. package/CONTEXT.md +685 -0
  4. package/LICENSE +202 -0
  5. package/NOTICE +4 -0
  6. package/README.md +368 -0
  7. package/agents/claude/CLAUDE.md +32 -0
  8. package/agents/codex/AGENTS.md +27 -0
  9. package/agents/copilot/copilot-instructions.md +14 -0
  10. package/agents/cursor/campaigns-os.mdc +13 -0
  11. package/bin/campaigns-os.mjs +38 -0
  12. package/campaign-spec/README.md +138 -0
  13. package/campaign-spec/dist/analytics-vocabulary.d.ts +47 -0
  14. package/campaign-spec/dist/analytics-vocabulary.js +74 -0
  15. package/campaign-spec/dist/index.d.ts +40 -0
  16. package/campaign-spec/dist/index.js +77 -0
  17. package/campaign-spec/dist/normalize.d.ts +22 -0
  18. package/campaign-spec/dist/normalize.js +41 -0
  19. package/campaign-spec/dist/routing.d.ts +190 -0
  20. package/campaign-spec/dist/routing.js +263 -0
  21. package/campaign-spec/dist/rules/analytics-contract-shape.d.ts +42 -0
  22. package/campaign-spec/dist/rules/analytics-contract-shape.js +303 -0
  23. package/campaign-spec/dist/rules/assembly-hints-shape.d.ts +42 -0
  24. package/campaign-spec/dist/rules/assembly-hints-shape.js +191 -0
  25. package/campaign-spec/dist/rules/campaign-metadata.d.ts +14 -0
  26. package/campaign-spec/dist/rules/campaign-metadata.js +40 -0
  27. package/campaign-spec/dist/rules/checkout-has-success-url.d.ts +31 -0
  28. package/campaign-spec/dist/rules/checkout-has-success-url.js +66 -0
  29. package/campaign-spec/dist/rules/cycle-detection.d.ts +12 -0
  30. package/campaign-spec/dist/rules/cycle-detection.js +141 -0
  31. package/campaign-spec/dist/rules/design-source-shape.d.ts +29 -0
  32. package/campaign-spec/dist/rules/design-source-shape.js +142 -0
  33. package/campaign-spec/dist/rules/downsell-without-upsell.d.ts +11 -0
  34. package/campaign-spec/dist/rules/downsell-without-upsell.js +40 -0
  35. package/campaign-spec/dist/rules/exit-intent-validation.d.ts +23 -0
  36. package/campaign-spec/dist/rules/exit-intent-validation.js +147 -0
  37. package/campaign-spec/dist/rules/funnel-count.d.ts +9 -0
  38. package/campaign-spec/dist/rules/funnel-count.js +37 -0
  39. package/campaign-spec/dist/rules/funnel-hypothesis-length.d.ts +22 -0
  40. package/campaign-spec/dist/rules/funnel-hypothesis-length.js +60 -0
  41. package/campaign-spec/dist/rules/funnel-identity.d.ts +15 -0
  42. package/campaign-spec/dist/rules/funnel-identity.js +57 -0
  43. package/campaign-spec/dist/rules/funnel-weight-sum.d.ts +20 -0
  44. package/campaign-spec/dist/rules/funnel-weight-sum.js +66 -0
  45. package/campaign-spec/dist/rules/index.d.ts +69 -0
  46. package/campaign-spec/dist/rules/index.js +131 -0
  47. package/campaign-spec/dist/rules/offer-ref-integrity.d.ts +13 -0
  48. package/campaign-spec/dist/rules/offer-ref-integrity.js +59 -0
  49. package/campaign-spec/dist/rules/package-pricing-sanity.d.ts +12 -0
  50. package/campaign-spec/dist/rules/package-pricing-sanity.js +42 -0
  51. package/campaign-spec/dist/rules/page-count.d.ts +11 -0
  52. package/campaign-spec/dist/rules/page-count.js +31 -0
  53. package/campaign-spec/dist/rules/page-id-uniqueness.d.ts +14 -0
  54. package/campaign-spec/dist/rules/page-id-uniqueness.js +47 -0
  55. package/campaign-spec/dist/rules/promo-code-input-validation.d.ts +8 -0
  56. package/campaign-spec/dist/rules/promo-code-input-validation.js +126 -0
  57. package/campaign-spec/dist/rules/promo-codes-shape.d.ts +30 -0
  58. package/campaign-spec/dist/rules/promo-codes-shape.js +187 -0
  59. package/campaign-spec/dist/rules/route-field-ignored-for-page-type.d.ts +33 -0
  60. package/campaign-spec/dist/rules/route-field-ignored-for-page-type.js +81 -0
  61. package/campaign-spec/dist/rules/route-target-resolves.d.ts +32 -0
  62. package/campaign-spec/dist/rules/route-target-resolves.js +112 -0
  63. package/campaign-spec/dist/rules/schema-version.d.ts +21 -0
  64. package/campaign-spec/dist/rules/schema-version.js +53 -0
  65. package/campaign-spec/dist/rules/sdk-version.d.ts +26 -0
  66. package/campaign-spec/dist/rules/sdk-version.js +96 -0
  67. package/campaign-spec/dist/rules/shipping-countries-shape.d.ts +10 -0
  68. package/campaign-spec/dist/rules/shipping-countries-shape.js +30 -0
  69. package/campaign-spec/dist/rules/shipping-methods-present.d.ts +10 -0
  70. package/campaign-spec/dist/rules/shipping-methods-present.js +26 -0
  71. package/campaign-spec/dist/rules/store-profile-shape.d.ts +30 -0
  72. package/campaign-spec/dist/rules/store-profile-shape.js +127 -0
  73. package/campaign-spec/dist/rules/thank-you-requirement.d.ts +16 -0
  74. package/campaign-spec/dist/rules/thank-you-requirement.js +50 -0
  75. package/campaign-spec/dist/rules/unknown-top-level-fields.d.ts +28 -0
  76. package/campaign-spec/dist/rules/unknown-top-level-fields.js +114 -0
  77. package/campaign-spec/dist/rules/upsell-has-packages.d.ts +9 -0
  78. package/campaign-spec/dist/rules/upsell-has-packages.js +35 -0
  79. package/campaign-spec/dist/rules/upsell-routing-complete.d.ts +10 -0
  80. package/campaign-spec/dist/rules/upsell-routing-complete.js +45 -0
  81. package/campaign-spec/dist/rules/upsell-without-checkout.d.ts +11 -0
  82. package/campaign-spec/dist/rules/upsell-without-checkout.js +44 -0
  83. package/campaign-spec/dist/rules/variant-labels-shape.d.ts +28 -0
  84. package/campaign-spec/dist/rules/variant-labels-shape.js +86 -0
  85. package/campaign-spec/dist/sdk-version-parse.d.ts +43 -0
  86. package/campaign-spec/dist/sdk-version-parse.js +62 -0
  87. package/campaign-spec/dist/types.d.ts +674 -0
  88. package/campaign-spec/dist/types.js +40 -0
  89. package/campaign-spec/package.json +12 -0
  90. package/compatibility.json +25 -0
  91. package/contracts/agent-relevant-change-policy.v1.json +111 -0
  92. package/contracts/brand-theme-source-defaults.figma-sections-export.v0.json +32 -0
  93. package/contracts/brand-theme-target-tokens.next-core.v0.json +65 -0
  94. package/contracts/campaign-cart-checkout-field-contract.v0.json +45 -0
  95. package/contracts/campaign-cart-sdk-support-policy.v0.json +11 -0
  96. package/contracts/commerce-surface-catalog.json +2452 -0
  97. package/contracts/fixtures/orientation/canonicalization/v1.json +34 -0
  98. package/contracts/fixtures/orientation/envelope/current.json +95 -0
  99. package/contracts/fixtures/orientation/envelope/freshness_unknown.json +97 -0
  100. package/contracts/fixtures/orientation/envelope/legacy_baseline.json +95 -0
  101. package/contracts/fixtures/orientation/envelope/orientation_available.json +136 -0
  102. package/contracts/fixtures/orientation/envelope/recovered_interrupted_update.json +136 -0
  103. package/contracts/fixtures/orientation/envelope/refused.json +100 -0
  104. package/contracts/fixtures/orientation/envelope/restart_required.json +137 -0
  105. package/contracts/fixtures/orientation/envelope/updated.json +135 -0
  106. package/contracts/fixtures/orientation/hostile-target/README.md +61 -0
  107. package/contracts/fixtures/orientation/hostile-target/manifest.json +82 -0
  108. package/contracts/fixtures/orientation/hostile-target/repo/CHANGELOG.md +18 -0
  109. package/contracts/fixtures/orientation/hostile-target/repo/bin/intended.mjs +12 -0
  110. package/contracts/fixtures/orientation/hostile-target/repo/bin/tripwire.mjs +15 -0
  111. package/contracts/fixtures/orientation/hostile-target/repo/contracts/release-ledger.json +48 -0
  112. package/contracts/fixtures/orientation/hostile-target/repo/contracts/supported-surface.json +17 -0
  113. package/contracts/fixtures/orientation/hostile-target/repo/docs/example-contract.md +13 -0
  114. package/contracts/fixtures/orientation/hostile-target/repo/hooks/post-checkout +5 -0
  115. package/contracts/fixtures/orientation/hostile-target/repo/hooks/post-merge +5 -0
  116. package/contracts/fixtures/orientation/hostile-target/repo/hooks/pre-commit +5 -0
  117. package/contracts/fixtures/orientation/hostile-target/repo/hostile-dependency-tripwire/package.json +15 -0
  118. package/contracts/fixtures/orientation/hostile-target/repo/hostile-dependency-tripwire/tripwire.mjs +9 -0
  119. package/contracts/fixtures/orientation/hostile-target/repo/package.json +20 -0
  120. package/contracts/fixtures/orientation/hostile-target/repo/schemas/example.v0.schema.json +15 -0
  121. package/contracts/fixtures/orientation/release-gate/cases.json +1073 -0
  122. package/contracts/fixtures/runtime-recipe/accept/current.json +299 -0
  123. package/contracts/fixtures/runtime-recipe/accept/minimal.json +294 -0
  124. package/contracts/fixtures/runtime-recipe/dist-states.json +51 -0
  125. package/contracts/fixtures/runtime-recipe/manifest.json +85 -0
  126. package/contracts/fixtures/runtime-recipe/reject/advisory-enforcement.json +299 -0
  127. package/contracts/fixtures/runtime-recipe/reject/allowlist-without-hosts.json +297 -0
  128. package/contracts/fixtures/runtime-recipe/reject/committed-output-claim.json +299 -0
  129. package/contracts/fixtures/runtime-recipe/reject/engines-disagreement-warns.json +299 -0
  130. package/contracts/fixtures/runtime-recipe/reject/lifecycle-scripts-enabled.json +299 -0
  131. package/contracts/fixtures/runtime-recipe/reject/missing-required-field.json +251 -0
  132. package/contracts/fixtures/runtime-recipe/reject/unknown-kind.json +299 -0
  133. package/contracts/fixtures/runtime-recipe/reject/unknown-network-policy.json +299 -0
  134. package/contracts/fixtures/runtime-recipe/reject/unknown-output-check.json +310 -0
  135. package/contracts/fixtures/runtime-recipe/reject/unknown-revision.json +299 -0
  136. package/contracts/fixtures/runtime-recipe/reject/unknown-step-id.json +299 -0
  137. package/contracts/fixtures/runtime-recipe/reject/unperformable-check-skipped.json +299 -0
  138. package/contracts/fixtures/runtime-recipe/reject/unpinned-lockfile.json +299 -0
  139. package/contracts/fixtures/sidecar-bundle/production-shaped/.campaign-runtime/assembly-report.json +180 -0
  140. package/contracts/fixtures/sidecar-bundle/production-shaped/.campaign-runtime/build-context.json +115 -0
  141. package/contracts/fixtures/sidecar-bundle/production-shaped/.campaign-runtime/doctor-output.json +29 -0
  142. package/contracts/fixtures/sidecar-bundle/production-shaped/.campaign-runtime/qa-verdict.json +27 -0
  143. package/contracts/fixtures/sidecar-bundle/production-shaped/campaign-runtime.build.json +141 -0
  144. package/contracts/migration-sidecar-bundle.v0.json +149 -0
  145. package/contracts/orientation-limits.v1.json +41 -0
  146. package/contracts/orientation-reason-codes.v1.json +196 -0
  147. package/contracts/private-template-sources.json +8 -0
  148. package/contracts/release-ledger.json +4598 -0
  149. package/contracts/reserved-skill-names.json +13 -0
  150. package/contracts/runtime-recipe.campaigns-os-node-v1.json +299 -0
  151. package/contracts/supported-surface.json +180 -0
  152. package/contracts/template-brand-contract.apollo-mv-single-step.v0.json +27 -0
  153. package/contracts/template-brand-contract.apollo.v0.json +27 -0
  154. package/contracts/template-brand-contract.demeter.v0.json +27 -0
  155. package/contracts/template-brand-contract.olympus-mv-single-step.v0.json +27 -0
  156. package/contracts/template-brand-contract.olympus-mv-two-step.v0.json +28 -0
  157. package/contracts/template-brand-contract.olympus.v0.json +27 -0
  158. package/contracts/template-brand-contract.shared-commerce.v0.json +190 -0
  159. package/contracts/template-brand-contract.shop-single-step.v0.json +27 -0
  160. package/contracts/template-brand-contract.shop-three-step.v0.json +29 -0
  161. package/contracts/template-slot-manifest.apollo-mv-single-step.v0.json +14 -0
  162. package/contracts/template-slot-manifest.apollo.v0.json +12 -0
  163. package/contracts/template-slot-manifest.demeter.v0.json +30 -0
  164. package/contracts/template-slot-manifest.olympus-mv-single-step.v0.json +14 -0
  165. package/contracts/template-slot-manifest.olympus-mv-two-step.v0.json +15 -0
  166. package/contracts/template-slot-manifest.olympus.v0.json +12 -0
  167. package/contracts/template-slot-manifest.shared-content-core.v0.json +4254 -0
  168. package/contracts/template-slot-manifest.shop-single-step.v0.json +47 -0
  169. package/contracts/template-slot-manifest.shop-three-step.v0.json +33 -0
  170. package/docs/brand-theme-bridge.md +159 -0
  171. package/docs/build-packet.md +1300 -0
  172. package/docs/campaign-build-brief.md +145 -0
  173. package/docs/campaign-standardization-report.md +329 -0
  174. package/docs/campaigns-os-build-flow.md +117 -0
  175. package/docs/design-source-package.md +784 -0
  176. package/docs/legacy-migration.md +58 -0
  177. package/docs/migration-sidecar-bundle.md +139 -0
  178. package/docs/orientation-contract-reference.md +1220 -0
  179. package/docs/polish-evidence.md +502 -0
  180. package/docs/qa-and-test-orders.md +1691 -0
  181. package/docs/release-ledger-authoring-guide.md +274 -0
  182. package/docs/runtime-readiness.md +211 -0
  183. package/docs/supported-surface.md +83 -0
  184. package/docs/versioning.md +55 -0
  185. package/docs/workflow-findings-sidecar.md +588 -0
  186. package/package.json +135 -0
  187. package/prompts/first-build.md +27 -0
  188. package/prompts/friction-log.md +30 -0
  189. package/schemas/campaign-build-brief.v1.schema.json +149 -0
  190. package/schemas/campaign-design-source-package.v0.schema.json +697 -0
  191. package/schemas/campaign-runtime-assembly-report.v0.schema.json +390 -0
  192. package/schemas/campaign-runtime-build-context.v0.schema.json +339 -0
  193. package/schemas/campaign-runtime-build-packet.v0.schema.json +452 -0
  194. package/schemas/campaign-spec.v4.schema.json +582 -0
  195. package/schemas/campaigns-os-doctor-output.v0.schema.json +43 -0
  196. package/schemas/campaigns-os-legacy-migration-inventory.v0.schema.json +112 -0
  197. package/schemas/campaigns-os-legacy-provisioning-plan.v0.schema.json +38 -0
  198. package/schemas/campaigns-os-legacy-provisioning-receipt.v0.schema.json +57 -0
  199. package/schemas/campaigns-os-qa-verdict-sidecar.v0.schema.json +150 -0
  200. package/schemas/campaigns-os-qa-verdict.v0.schema.json +438 -0
  201. package/schemas/campaigns-os-release-ledger.v1.schema.json +162 -0
  202. package/schemas/campaigns-os-run-record.v0.schema.json +343 -0
  203. package/schemas/campaigns-os-runtime-recipe.v1.schema.json +313 -0
  204. package/schemas/campaigns-os-sidecar-bundle-conformance.v0.schema.json +78 -0
  205. package/schemas/campaigns-os-tooling-orientation.v1.schema.json +381 -0
  206. package/schemas/campaigns-os-workflow-finding.v0.schema.json +134 -0
  207. package/schemas/source-html-manifest.v0.schema.json +252 -0
  208. package/skills/next-campaigns-build/SKILL.md +73 -0
  209. package/skills/next-campaigns-os/SKILL.md +101 -0
  210. package/skills/next-campaigns-os/references/session-intake.md +160 -0
  211. package/skills/next-campaigns-os-setup/SKILL.md +22 -0
  212. package/skills/next-campaigns-polish/SKILL.md +145 -0
  213. package/skills/next-campaigns-qa/SKILL.md +92 -0
  214. package/skills.json +56 -0
  215. package/skills.sh +64 -0
  216. package/src/adapter-decision-contract.mjs +333 -0
  217. package/src/brand-theme.mjs +1151 -0
  218. package/src/browser-launch.mjs +79 -0
  219. package/src/build-brief.mjs +781 -0
  220. package/src/built-site-scope.mjs +312 -0
  221. package/src/campaign-ecosystem.mjs +734 -0
  222. package/src/campaign-identity.mjs +405 -0
  223. package/src/campaign-workspace.mjs +127 -0
  224. package/src/checkpoint-waiver.mjs +302 -0
  225. package/src/cli.mjs +13442 -0
  226. package/src/commercial-journey.mjs +1119 -0
  227. package/src/commercial-parity.mjs +965 -0
  228. package/src/consent.mjs +347 -0
  229. package/src/content-residue.mjs +322 -0
  230. package/src/deadline.mjs +81 -0
  231. package/src/design-source-package.mjs +2604 -0
  232. package/src/deviation.mjs +107 -0
  233. package/src/doctor-check-registry.mjs +49 -0
  234. package/src/doctor-sidecar.mjs +106 -0
  235. package/src/finding-cause.mjs +557 -0
  236. package/src/findings.mjs +326 -0
  237. package/src/fs-identity.mjs +68 -0
  238. package/src/gate-actions.mjs +105 -0
  239. package/src/html-scan.mjs +53 -0
  240. package/src/install-mode.mjs +272 -0
  241. package/src/legacy-migration.d.ts +128 -0
  242. package/src/legacy-migration.mjs +510 -0
  243. package/src/lifecycle.mjs +338 -0
  244. package/src/local-proof.mjs +401 -0
  245. package/src/map-pin-writeback.mjs +210 -0
  246. package/src/orchestration-stage-contract.mjs +81 -0
  247. package/src/package-install-fixture.mjs +33 -0
  248. package/src/page-kit-build-summary.mjs +175 -0
  249. package/src/page-kit-campaign-config.mjs +57 -0
  250. package/src/page-kit-sdk-version.mjs +392 -0
  251. package/src/page-kit-store-profile.mjs +369 -0
  252. package/src/page-kit-sync.mjs +162 -0
  253. package/src/polish-browser.mjs +867 -0
  254. package/src/polish-capture.mjs +1094 -0
  255. package/src/polish-deadline.mjs +51 -0
  256. package/src/polish-gate.mjs +739 -0
  257. package/src/polish-node.mjs +639 -0
  258. package/src/polish-page-load.mjs +1100 -0
  259. package/src/private-template-source.mjs +237 -0
  260. package/src/proof-policy.mjs +82 -0
  261. package/src/qa-analytics-correctness.mjs +307 -0
  262. package/src/qa-analytics-errors.mjs +38 -0
  263. package/src/qa-analytics-parity.mjs +699 -0
  264. package/src/qa-binding-evidence.mjs +140 -0
  265. package/src/qa-browser.mjs +6608 -0
  266. package/src/qa-cart-entry.mjs +406 -0
  267. package/src/qa-commercial-parity.mjs +641 -0
  268. package/src/qa-node.mjs +3620 -0
  269. package/src/qa-order-bump.mjs +381 -0
  270. package/src/qa-parity-capture.mjs +428 -0
  271. package/src/qa-parity-fixture.mjs +359 -0
  272. package/src/qa-publish.mjs +362 -0
  273. package/src/qa-purchase-data-layer.mjs +263 -0
  274. package/src/qa-route-probe.mjs +272 -0
  275. package/src/qa-sidecar.mjs +188 -0
  276. package/src/qa-test-order-topology.mjs +207 -0
  277. package/src/qa-url-privacy.mjs +13 -0
  278. package/src/qa-verdict-discovery.mjs +192 -0
  279. package/src/qa-verdict-publish.mjs +105 -0
  280. package/src/qa-verdict.mjs +287 -0
  281. package/src/remit.mjs +388 -0
  282. package/src/repo-scan.mjs +83 -0
  283. package/src/route-identity.mjs +133 -0
  284. package/src/run-record-closeout.mjs +229 -0
  285. package/src/run-record.mjs +839 -0
  286. package/src/run-session.mjs +226 -0
  287. package/src/runtime-state-ignore.mjs +113 -0
  288. package/src/sdk-attribute-index.mjs +212 -0
  289. package/src/sdk-markup.mjs +358 -0
  290. package/src/sdk-meta-tags.mjs +52 -0
  291. package/src/shell-token.mjs +7 -0
  292. package/src/sidecar-bundle.mjs +399 -0
  293. package/src/source-asset-crawl.mjs +469 -0
  294. package/src/source-html-intake.mjs +627 -0
  295. package/src/source-html-manifest.mjs +276 -0
  296. package/src/source-prep.mjs +284 -0
  297. package/src/spec-derive-store.mjs +431 -0
  298. package/src/spec-derive.mjs +514 -0
  299. package/src/spec-fetch.mjs +66 -0
  300. package/src/spec-hash.mjs +48 -0
  301. package/src/spec-identity.mjs +27 -0
  302. package/src/stage-ledger.mjs +509 -0
  303. package/src/standardization-report.mjs +1297 -0
  304. package/src/template-brand-contract.mjs +473 -0
  305. package/src/template-freshness.mjs +196 -0
  306. package/src/template-reference.mjs +81 -0
  307. package/src/template-slot-manifest.mjs +150 -0
  308. package/src/text-safety.mjs +62 -0
  309. package/src/theme-gate.mjs +185 -0
  310. package/src/upsell-selector-scope.mjs +299 -0
@@ -0,0 +1,58 @@
1
+ # Legacy migration contract
2
+
3
+ `@nextcommerce/campaigns-os/legacy-migration` is the portable contract for
4
+ planning a bounded Campaign Cart SDK 0.3.x to 0.4.x shadow-campaign migration.
5
+ It does not connect to a store or authorize a write.
6
+
7
+ The v0 contract includes three schemas:
8
+
9
+ - `campaigns-os-legacy-migration-inventory/v0` captures an exact source
10
+ campaign, unit-product package identities, shipping methods, wire-ready
11
+ Offer intents, and authorized-domain intents.
12
+ - `campaigns-os-legacy-provisioning-plan/v0` records the stable preview and its
13
+ campaign/package/shipping operations. Offer rows remain keyed intents until
14
+ package IDs exist at apply time.
15
+ - `campaigns-os-legacy-provisioning-receipt/v0` records resource IDs and
16
+ readback evidence, including one `offer.create` row per applied intent.
17
+
18
+ ## Safety boundary
19
+
20
+ The contract contains no Admin API token, authenticated transport, session,
21
+ write executor, audit-store implementation, receipt store, rollback, or delete
22
+ operation. Inventory and plan inputs reject credential-like field names
23
+ recursively. Receipts may retain the public campaign `api_key` returned by the
24
+ Admin API, but reject private credential fields; their build-evidence projection
25
+ removes raw readback entirely. Execution is owned by the connector and must
26
+ retain read-before-write, explicit preview and apply, read-after-write, audit,
27
+ durable receipt, and stop-on-ambiguity rules.
28
+
29
+ Package rows identify exactly one product variant. Quantity tiers, vouchers,
30
+ and post-purchase pricing are Offers, never duplicate or quantity-shaped
31
+ packages. The upstream Offers API supports `all_packages`, but this migration
32
+ contract deliberately refuses it: a migration Offer must list stable package
33
+ keys and resolve those keys to IDs immediately before apply.
34
+
35
+ ## Offer application
36
+
37
+ `buildLegacyOfferRequest(intent, packageIdByKey)` produces the documented
38
+ Offers create body. It refuses unresolved keys and emits `package_ids`; it does
39
+ not leak local `intent_key` or `package_keys` into the request.
40
+
41
+ The API read shape is not the write shape. Offer `package_ids` read back under
42
+ `condition.packages[]`, while package `price` reads back under `prices[]`.
43
+ `compareLegacyOfferReadback` and `compareLegacyPackageReadback` project those
44
+ known differences. If a field cannot be projected, they return
45
+ `unprojectable`; they never infer or guess a value. Package price comparison
46
+ therefore requires the campaign currency.
47
+
48
+ ## Determinism and evidence
49
+
50
+ `normalizeLegacyMigrationInventory` sorts packages, shipping methods, Offers,
51
+ Offer package keys, and domains by their logical keys. Combined with
52
+ `stableCanonicalStringify` and `hashLegacyMigrationArtifact`, equivalent input
53
+ ordering yields the same digest.
54
+
55
+ `projectLegacyProvisioningReceipt` emits token-free build evidence: campaign,
56
+ package, shipping, and Offer IDs keyed by their stable identities, applied
57
+ Offer intent keys, plan hash, receipt hash, and applied timestamp. It omits
58
+ audit keys and raw readback payloads.
@@ -0,0 +1,139 @@
1
+ # Migration sidecar bundle v0
2
+
3
+ The migration sidecar bundle is the strict JSON boundary between a campaign
4
+ repository, its CI producer, and Campaigns Agent readback. It does not replace
5
+ the underlying artifacts and it does not create another manifest file. The
6
+ machine contract is
7
+ [`contracts/migration-sidecar-bundle.v0.json`](../contracts/migration-sidecar-bundle.v0.json),
8
+ and the conformance command is:
9
+
10
+ ```bash
11
+ campaigns-os bundle check --packet campaign-runtime.build.json --json
12
+ ```
13
+
14
+ Add `--require-qa` when the migration or campaign claims QA is complete.
15
+
16
+ ## Conformance is not readiness
17
+
18
+ `status: conformant` (and `ok: true`) means the sidecars agree with each other
19
+ and with the contract: every required artifact is present, valid JSON, on its
20
+ declared schema version, freshly timestamped, and carrying the same campaign
21
+ identity. It says nothing about whether doctor or QA passed. A doctor sidecar
22
+ that records a blocked run is a well-formed artifact whose content says the
23
+ campaign cannot proceed, and a blocked QA verdict is schema-valid.
24
+
25
+ Read readiness from two places instead:
26
+
27
+ - The findings. A doctor sidecar recording a blocked run (`status: blocked`
28
+ or `ok: false`) emits `bundle.doctor_output.blocked`; a QA verdict whose
29
+ `disposition` is `blocked` emits `bundle.qa_verdict.blocked`. Both are
30
+ warnings by default (the bundle is still conformant) and errors under
31
+ `--require-qa` (a QA-complete handoff cannot ride either block, so the bundle
32
+ is nonconformant and the command exits 2).
33
+ - `stage_blocked` keeps its published meaning: `true` only when a required
34
+ QA verdict (`--require-qa`) is blocked. The doctor case is carried by the
35
+ finding alone until a schema bump widens the field.
36
+
37
+ The text report prints a `Readiness:` line directly under `Status:` that reads
38
+ those fields for you. The remedy for a blocked doctor is to resolve its errors
39
+ and re-run `campaigns-os doctor --packet campaign-runtime.build.json
40
+ --write --strip-paths` so the retained sidecar records a ready run.
41
+
42
+ ## Canonical bundle
43
+
44
+ | Kind | Canonical path | Requirement | Schema/version | Freshness |
45
+ | --- | --- | --- | --- | --- |
46
+ | Build Packet | `campaign-runtime.build.json` | Required | `campaign-runtime-build-packet/v0` | Its `generated_at` is the bundle-selection authority. Never select a packet by mtime. |
47
+ | Build Context | `.campaign-runtime/build-context.json` | Required | `campaign-runtime-build-context/v0` | Producer-stamped `generated_at`; `packet_path` must point to the root packet. |
48
+ | Assembly Report | `.campaign-runtime/assembly-report.json` | Required | `campaign-runtime-assembly-report/v0` | Producer-stamped `generated_at`; authored stage evidence is preserved. |
49
+ | Doctor Output | `.campaign-runtime/doctor-output.json` | Required | `campaigns-os-doctor-output/v0` | Refresh after any doctor-input change; an explicit `stale: true` fails conformance. `generated_by` names the command that persisted it (`doctor`, `next`, `start`, `build`, `qa run`); a sidecar without it predates the stamp. |
50
+ | QA Verdict projection | `.campaign-runtime/qa-verdict.json` | Required after QA | QA schema `1.0`, constrained by the sidecar projection schema | `generated_at` is the projection/promotion instant. |
51
+
52
+ The packet stays at repository root because that is the default discovery
53
+ contract. A packet found only at
54
+ `.campaign-runtime/campaign-runtime.build.json` is reported with a root-path
55
+ remedy; conformance does not silently widen discovery.
56
+
57
+ The checker validates canonical paths, declared schema versions, strict UTC
58
+ timestamps, cross-artifact Map ID, public slug, campaign directory, live URL
59
+ path, template family, and spec identity, doctor freshness, and the URL/order-
60
+ free QA projection. Safe repository-relative spellings such as
61
+ `campaign-runtime.build.json` and `./campaign-runtime.build.json` are
62
+ equivalent; absolute paths, URIs, backslashes, and parent traversal are not.
63
+
64
+ Spec identity has two deliberately separate meanings. Build Context
65
+ `spec.hash` and Assembly Report `identity.spec_hash` retain exact raw-byte
66
+ integrity. Build Context `spec.material_hash`, Assembly Report
67
+ `identity.spec_material_hash`, and QA Verdict `spec_hash` carry the canonical
68
+ semantic identity used for cross-producer correlation. Harmless JSON formatting
69
+ and the declared volatile top-level metadata do not change the material hash;
70
+ commerce or funnel changes do. A partially regenerated material-identity set
71
+ fails closed. For stored bundles produced before the material fields existed,
72
+ the checker uses the contract's explicit strict-legacy mode and requires the
73
+ three historical hash values to match exactly.
74
+
75
+ A blocked doctor remains readable evidence. Under `--require-qa`, a schema-
76
+ valid QA Verdict whose disposition is `blocked` is nonconformant for handoff and
77
+ the result carries `stage_blocked: true`; shape-valid does not mean ready.
78
+
79
+ The Build Packet schema keeps `campaign_directory` and `live_url_path`
80
+ nullable for older or partial packet compatibility. Bundle conformance is
81
+ deliberately stricter: both identities must be non-empty so equality with the
82
+ Assembly Report can be proved. Regenerate the packet with `start` or
83
+ `prepare-build` before checking a bundle whose packet carries either value as
84
+ `null`.
85
+
86
+ ## Headless CI producer
87
+
88
+ Resolve and check out one commit before producing anything. The initial
89
+ `campaigns-os start` run writes the packet, context, report, and doctor output
90
+ from explicit CampaignSpec/source/template inputs. `prepare-build` writes the
91
+ packet, context, and report; refresh Doctor output with the command below.
92
+ Later CI runs must preserve the authored packet, context, and Assembly Report
93
+ rather than recreating them with `--force` and erasing stage decisions.
94
+
95
+ Refresh generated evidence at that commit:
96
+
97
+ ```bash
98
+ campaigns-os doctor \
99
+ --packet campaign-runtime.build.json \
100
+ --write \
101
+ --strip-paths \
102
+ --json
103
+
104
+ # Only when carrying forward a named historical full verdict:
105
+ campaigns-os qa promote \
106
+ --packet campaign-runtime.build.json \
107
+ --verdict "$EXPLICIT_FULL_VERDICT" \
108
+ --json
109
+
110
+ campaigns-os bundle check \
111
+ --packet campaign-runtime.build.json \
112
+ --require-qa \
113
+ --json
114
+ ```
115
+
116
+ `qa promote` requires one explicit full-verdict path. CI must not pick a verdict
117
+ by mtime, filename sort, or a directory's apparent “latest” entry. If there is
118
+ no historical verdict to promote, run QA and let `qa run` write the committed
119
+ projection.
120
+
121
+ The checker emits both exact per-file SHA-256 digests and one
122
+ `material_digest`. The material digest canonicalizes object-key order and
123
+ removes only the volatile fields declared in the machine contract (generation
124
+ timestamps and run IDs). Repeating the producer over the same substantive
125
+ evidence therefore keeps the material digest stable; changing a disposition,
126
+ identity, stage state, or assertion changes it.
127
+
128
+ ## Consumer and compatibility fixture
129
+
130
+ The supported production-shaped fixture lives at
131
+ `contracts/fixtures/sidecar-bundle/production-shaped/`. It contains the root
132
+ packet and all four canonical sidecars, including a URL/order-free QA verdict.
133
+ Campaigns Agent can copy or read that tree in both its deterministic and
134
+ real-Campaigns-OS lanes without this public repository importing private Agent
135
+ code.
136
+
137
+ Markdown reports, equivalence ledgers, and migration-specific scripts may live
138
+ beside the bundle as supporting evidence. They never satisfy a missing JSON
139
+ artifact and are never substituted for current readback truth.