@nextcommerce/campaigns-os 1.50.0 → 1.53.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/CHANGELOG.md +474 -0
- package/agents/claude/CLAUDE.md +4 -2
- package/agents/codex/AGENTS.md +3 -1
- package/agents/copilot/copilot-instructions.md +3 -1
- package/agents/cursor/campaigns-os.mdc +3 -1
- package/campaign-spec/dist/rules/campaign-metadata.d.ts +5 -1
- package/campaign-spec/dist/rules/campaign-metadata.js +9 -2
- package/campaign-spec/dist/rules/design-source-shape.js +13 -3
- package/campaign-spec/dist/rules/sdk-version.js +2 -1
- package/compatibility.json +1 -1
- package/contracts/commerce-surface-catalog.json +26 -46
- package/contracts/effects.v1.json +282 -14
- package/contracts/release-ledger.json +1233 -0
- package/contracts/supported-surface.json +2 -2
- package/contracts/template-brand-contract.shared-commerce.v0.json +2 -2
- package/contracts/template-slot-manifest.shared-content-core.v0.json +24 -0
- package/docs/brand-theme-bridge.md +2 -0
- package/docs/build-packet.md +148 -23
- package/docs/campaign-build-brief.md +57 -2
- package/docs/effects.md +14 -0
- package/docs/local-setup.md +1 -1
- package/docs/orientation-contract-reference.md +1 -1
- package/docs/polish-evidence.md +12 -0
- package/docs/progress-snapshots.md +2 -4
- package/docs/qa-and-test-orders.md +47 -4
- package/docs/readback.md +19 -2
- package/docs/runtime-readiness.md +1 -1
- package/docs/sdk-storage-compatibility.md +1 -1
- package/docs/skills-revision.md +10 -10
- package/package.json +1 -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 +5 -3
- package/skills/next-campaigns-os/SKILL.md +11 -20
- package/skills/next-campaigns-os/references/session-intake.md +17 -9
- package/skills/next-campaigns-os-setup/SKILL.md +4 -3
- package/skills/next-campaigns-polish/SKILL.md +7 -5
- package/skills/next-campaigns-qa/SKILL.md +8 -5
- package/skills.json +10 -10
- package/src/adapter-decision-contract.mjs +1 -1
- package/src/brand-theme.mjs +33 -20
- package/src/brief-summary.mjs +275 -0
- package/src/build-brief.mjs +229 -30
- package/src/built-site-scope.mjs +39 -6
- package/src/built-smoke-qc.mjs +1117 -0
- package/src/campaign-identity.mjs +36 -2
- package/src/cart-placeholders.mjs +730 -0
- package/src/cli.mjs +467 -143
- package/src/commercial-journey.mjs +65 -4
- package/src/commercial-parity.mjs +6 -1
- package/src/contrast.mjs +649 -0
- package/src/design-source-publication.mjs +110 -3
- package/src/doctor/checks.mjs +415 -33
- package/src/doctor/inspect.mjs +53 -2
- package/src/doctor/next-step.mjs +16 -7
- package/src/input-currency.mjs +394 -0
- package/src/input-refresh.mjs +708 -0
- package/src/invocation.mjs +5 -2
- package/src/local-preview-policy.mjs +1 -1
- package/src/local-proof.mjs +4 -1
- package/src/polish-browser.mjs +660 -141
- package/src/polish-capture.mjs +1 -1
- package/src/polish-deadline.mjs +7 -0
- package/src/polish-media-weight.mjs +492 -0
- package/src/polish-node.mjs +400 -28
- package/src/polish-readability.mjs +828 -0
- package/src/progress-node.mjs +19 -3
- package/src/qa-browser.mjs +439 -180
- package/src/qa-content-params.mjs +889 -0
- package/src/qa-node.mjs +116 -13
- package/src/qa-order-bump.mjs +22 -1
- package/src/qa-policy-links.mjs +1019 -0
- package/src/qa-tracking-params.mjs +1389 -0
- package/src/qa-url-privacy.mjs +168 -0
- package/src/qc-accept.mjs +482 -0
- package/src/qc-check-registry.mjs +91 -0
- package/src/qc-results.mjs +1341 -0
- package/src/readback.mjs +58 -10
- package/src/sdk-attribute-index.mjs +71 -0
- package/src/sdk-markup.mjs +2 -2
- package/src/sdk-storage-compatibility.mjs +63 -3
- package/src/source-prep.mjs +37 -7
- package/src/stage-ledger.mjs +235 -44
- package/src/stage-record.mjs +165 -33
- package/src/tooling-setup.mjs +1 -1
|
@@ -104,11 +104,72 @@ function selectedShipping(page) {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
// One predicate for "this checkout row is an order bump": the spec marks a
|
|
107
|
-
// bump with `
|
|
107
|
+
// bump with `is_order_bump: true` (the schema's and authoring guide's flag) or
|
|
108
|
+
// `is_upsell: true` on a non-upsell page. Every consumer that must
|
|
108
109
|
// tell a bump from a main selector row (parity scenarios, bump deltas, the QA
|
|
109
|
-
// selector-tier planner) reads this, so a
|
|
110
|
+
// selector-tier planner, `next`'s order-bump QA command) reads this, so a
|
|
111
|
+
// marker change lands in one place.
|
|
110
112
|
export function isBumpRow(row) {
|
|
111
|
-
return Boolean(row?.is_upsell);
|
|
113
|
+
return Boolean(row?.is_order_bump || row?.is_upsell);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// A checkout package row's ref, with the doctor's specPackageRecords
|
|
117
|
+
// tolerance (ref_id, then package_id, then id).
|
|
118
|
+
function checkoutRowRef(pkg) {
|
|
119
|
+
return [pkg.ref_id, pkg.package_id, pkg.id]
|
|
120
|
+
.map((value) => (value == null ? "" : String(value).trim()))
|
|
121
|
+
.find(Boolean);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Order bumps declared on a checkout page (isBumpRow rows), as refs in
|
|
125
|
+
// declaration order. They are add-ons to a selected tier, not tiers, so the
|
|
126
|
+
// QA tier planner reports and skips them and `next` names the --cart run that
|
|
127
|
+
// toggles them.
|
|
128
|
+
export function declaredOrderBumps(checkoutPage) {
|
|
129
|
+
const refs = [];
|
|
130
|
+
for (const pkg of array(checkoutPage?.packages)) {
|
|
131
|
+
if (!pkg || typeof pkg !== "object" || !isBumpRow(pkg)) continue;
|
|
132
|
+
const ref = checkoutRowRef(pkg);
|
|
133
|
+
if (ref && !refs.includes(ref)) refs.push(ref);
|
|
134
|
+
}
|
|
135
|
+
return refs;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Selector tiers are the packages a spec declares on a checkout page, in
|
|
139
|
+
// declaration order. Order-bump rows are add-ons offered alongside the
|
|
140
|
+
// selected tier, not tiers of their own: they never become a tier.
|
|
141
|
+
export function declaredSelectorTiers(checkoutPage) {
|
|
142
|
+
const records = [];
|
|
143
|
+
const quantitiesByRef = new Map();
|
|
144
|
+
for (const pkg of array(checkoutPage?.packages)) {
|
|
145
|
+
if (!pkg || typeof pkg !== "object" || isBumpRow(pkg)) continue;
|
|
146
|
+
const ref = checkoutRowRef(pkg);
|
|
147
|
+
const declaredQuantity = Number(pkg.qty ?? pkg.quantity ?? 1);
|
|
148
|
+
if (!ref || !Number.isInteger(declaredQuantity) || declaredQuantity < 1) continue;
|
|
149
|
+
records.push({ pkg, ref, declaredQuantity });
|
|
150
|
+
if (!quantitiesByRef.has(ref)) quantitiesByRef.set(ref, new Set());
|
|
151
|
+
quantitiesByRef.get(ref).add(declaredQuantity);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const tiers = [];
|
|
155
|
+
const seen = new Set();
|
|
156
|
+
for (const { pkg, ref, declaredQuantity } of records) {
|
|
157
|
+
// A unique ref is a catalog package bought once, even when that package's
|
|
158
|
+
// own composition is 3x. Only repeated declarations of the SAME ref at
|
|
159
|
+
// different quantities express shopper purchase multipliers (e.g. a 1x
|
|
160
|
+
// and a 2x package).
|
|
161
|
+
const quantity = quantitiesByRef.get(ref).size > 1 ? declaredQuantity : 1;
|
|
162
|
+
const identity = `${ref}:${quantity}`;
|
|
163
|
+
if (seen.has(identity)) continue;
|
|
164
|
+
seen.add(identity);
|
|
165
|
+
const label = [pkg.name, pkg.title].find((value) => typeof value === "string" && value.trim());
|
|
166
|
+
tiers.push({
|
|
167
|
+
ref,
|
|
168
|
+
quantity,
|
|
169
|
+
declared_by: label ? label.trim() : undefined,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return tiers;
|
|
112
173
|
}
|
|
113
174
|
|
|
114
175
|
function lineForRow(row) {
|
|
@@ -932,7 +993,7 @@ function makePage(scenarios, catalog) {
|
|
|
932
993
|
row_index: row.row_index,
|
|
933
994
|
package_id: row.package_id,
|
|
934
995
|
quantity: row.quantity,
|
|
935
|
-
...(row
|
|
996
|
+
...(isBumpRow(row) ? { is_upsell: true } : {}),
|
|
936
997
|
name: row.name,
|
|
937
998
|
state: PricingState.Unresolved,
|
|
938
999
|
reason: pageReason,
|
|
@@ -607,7 +607,12 @@ function partitionCaptures(capturesValue, { countsOnly = false } = {}) {
|
|
|
607
607
|
|
|
608
608
|
function priceComparisonClaims(capture, page) {
|
|
609
609
|
const claims = array(capture?.price_claims);
|
|
610
|
-
|
|
610
|
+
// A voucher on the page that the plan cannot price (no calculated pair for
|
|
611
|
+
// its code) can move the shown price away from the planned total, so a
|
|
612
|
+
// difference there says nothing about the page. Its price claims stay
|
|
613
|
+
// unresolved, which already keeps coverage incomplete, rather than being
|
|
614
|
+
// reported as mismatches against the list-price total.
|
|
615
|
+
if (!exactMoneyFact(page?.representative_total) || voucherComparisonClaims(capture, page).unresolved > 0) {
|
|
611
616
|
return { compared: [], unresolved: claims.length };
|
|
612
617
|
}
|
|
613
618
|
const bindings = [...new Set(claims.map((claim) => String(claim.binding)))];
|