@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.
- package/AGENTS.md +204 -0
- package/CHANGELOG.md +5002 -0
- package/CONTEXT.md +685 -0
- package/LICENSE +202 -0
- package/NOTICE +4 -0
- package/README.md +368 -0
- package/agents/claude/CLAUDE.md +32 -0
- package/agents/codex/AGENTS.md +27 -0
- package/agents/copilot/copilot-instructions.md +14 -0
- package/agents/cursor/campaigns-os.mdc +13 -0
- package/bin/campaigns-os.mjs +38 -0
- package/campaign-spec/README.md +138 -0
- package/campaign-spec/dist/analytics-vocabulary.d.ts +47 -0
- package/campaign-spec/dist/analytics-vocabulary.js +74 -0
- package/campaign-spec/dist/index.d.ts +40 -0
- package/campaign-spec/dist/index.js +77 -0
- package/campaign-spec/dist/normalize.d.ts +22 -0
- package/campaign-spec/dist/normalize.js +41 -0
- package/campaign-spec/dist/routing.d.ts +190 -0
- package/campaign-spec/dist/routing.js +263 -0
- package/campaign-spec/dist/rules/analytics-contract-shape.d.ts +42 -0
- package/campaign-spec/dist/rules/analytics-contract-shape.js +303 -0
- package/campaign-spec/dist/rules/assembly-hints-shape.d.ts +42 -0
- package/campaign-spec/dist/rules/assembly-hints-shape.js +191 -0
- package/campaign-spec/dist/rules/campaign-metadata.d.ts +14 -0
- package/campaign-spec/dist/rules/campaign-metadata.js +40 -0
- package/campaign-spec/dist/rules/checkout-has-success-url.d.ts +31 -0
- package/campaign-spec/dist/rules/checkout-has-success-url.js +66 -0
- package/campaign-spec/dist/rules/cycle-detection.d.ts +12 -0
- package/campaign-spec/dist/rules/cycle-detection.js +141 -0
- package/campaign-spec/dist/rules/design-source-shape.d.ts +29 -0
- package/campaign-spec/dist/rules/design-source-shape.js +142 -0
- package/campaign-spec/dist/rules/downsell-without-upsell.d.ts +11 -0
- package/campaign-spec/dist/rules/downsell-without-upsell.js +40 -0
- package/campaign-spec/dist/rules/exit-intent-validation.d.ts +23 -0
- package/campaign-spec/dist/rules/exit-intent-validation.js +147 -0
- package/campaign-spec/dist/rules/funnel-count.d.ts +9 -0
- package/campaign-spec/dist/rules/funnel-count.js +37 -0
- package/campaign-spec/dist/rules/funnel-hypothesis-length.d.ts +22 -0
- package/campaign-spec/dist/rules/funnel-hypothesis-length.js +60 -0
- package/campaign-spec/dist/rules/funnel-identity.d.ts +15 -0
- package/campaign-spec/dist/rules/funnel-identity.js +57 -0
- package/campaign-spec/dist/rules/funnel-weight-sum.d.ts +20 -0
- package/campaign-spec/dist/rules/funnel-weight-sum.js +66 -0
- package/campaign-spec/dist/rules/index.d.ts +69 -0
- package/campaign-spec/dist/rules/index.js +131 -0
- package/campaign-spec/dist/rules/offer-ref-integrity.d.ts +13 -0
- package/campaign-spec/dist/rules/offer-ref-integrity.js +59 -0
- package/campaign-spec/dist/rules/package-pricing-sanity.d.ts +12 -0
- package/campaign-spec/dist/rules/package-pricing-sanity.js +42 -0
- package/campaign-spec/dist/rules/page-count.d.ts +11 -0
- package/campaign-spec/dist/rules/page-count.js +31 -0
- package/campaign-spec/dist/rules/page-id-uniqueness.d.ts +14 -0
- package/campaign-spec/dist/rules/page-id-uniqueness.js +47 -0
- package/campaign-spec/dist/rules/promo-code-input-validation.d.ts +8 -0
- package/campaign-spec/dist/rules/promo-code-input-validation.js +126 -0
- package/campaign-spec/dist/rules/promo-codes-shape.d.ts +30 -0
- package/campaign-spec/dist/rules/promo-codes-shape.js +187 -0
- package/campaign-spec/dist/rules/route-field-ignored-for-page-type.d.ts +33 -0
- package/campaign-spec/dist/rules/route-field-ignored-for-page-type.js +81 -0
- package/campaign-spec/dist/rules/route-target-resolves.d.ts +32 -0
- package/campaign-spec/dist/rules/route-target-resolves.js +112 -0
- package/campaign-spec/dist/rules/schema-version.d.ts +21 -0
- package/campaign-spec/dist/rules/schema-version.js +53 -0
- package/campaign-spec/dist/rules/sdk-version.d.ts +26 -0
- package/campaign-spec/dist/rules/sdk-version.js +96 -0
- package/campaign-spec/dist/rules/shipping-countries-shape.d.ts +10 -0
- package/campaign-spec/dist/rules/shipping-countries-shape.js +30 -0
- package/campaign-spec/dist/rules/shipping-methods-present.d.ts +10 -0
- package/campaign-spec/dist/rules/shipping-methods-present.js +26 -0
- package/campaign-spec/dist/rules/store-profile-shape.d.ts +30 -0
- package/campaign-spec/dist/rules/store-profile-shape.js +127 -0
- package/campaign-spec/dist/rules/thank-you-requirement.d.ts +16 -0
- package/campaign-spec/dist/rules/thank-you-requirement.js +50 -0
- package/campaign-spec/dist/rules/unknown-top-level-fields.d.ts +28 -0
- package/campaign-spec/dist/rules/unknown-top-level-fields.js +114 -0
- package/campaign-spec/dist/rules/upsell-has-packages.d.ts +9 -0
- package/campaign-spec/dist/rules/upsell-has-packages.js +35 -0
- package/campaign-spec/dist/rules/upsell-routing-complete.d.ts +10 -0
- package/campaign-spec/dist/rules/upsell-routing-complete.js +45 -0
- package/campaign-spec/dist/rules/upsell-without-checkout.d.ts +11 -0
- package/campaign-spec/dist/rules/upsell-without-checkout.js +44 -0
- package/campaign-spec/dist/rules/variant-labels-shape.d.ts +28 -0
- package/campaign-spec/dist/rules/variant-labels-shape.js +86 -0
- package/campaign-spec/dist/sdk-version-parse.d.ts +43 -0
- package/campaign-spec/dist/sdk-version-parse.js +62 -0
- package/campaign-spec/dist/types.d.ts +674 -0
- package/campaign-spec/dist/types.js +40 -0
- package/campaign-spec/package.json +12 -0
- package/compatibility.json +25 -0
- package/contracts/agent-relevant-change-policy.v1.json +111 -0
- package/contracts/brand-theme-source-defaults.figma-sections-export.v0.json +32 -0
- package/contracts/brand-theme-target-tokens.next-core.v0.json +65 -0
- package/contracts/campaign-cart-checkout-field-contract.v0.json +45 -0
- package/contracts/campaign-cart-sdk-support-policy.v0.json +11 -0
- package/contracts/commerce-surface-catalog.json +2452 -0
- package/contracts/fixtures/orientation/canonicalization/v1.json +34 -0
- package/contracts/fixtures/orientation/envelope/current.json +95 -0
- package/contracts/fixtures/orientation/envelope/freshness_unknown.json +97 -0
- package/contracts/fixtures/orientation/envelope/legacy_baseline.json +95 -0
- package/contracts/fixtures/orientation/envelope/orientation_available.json +136 -0
- package/contracts/fixtures/orientation/envelope/recovered_interrupted_update.json +136 -0
- package/contracts/fixtures/orientation/envelope/refused.json +100 -0
- package/contracts/fixtures/orientation/envelope/restart_required.json +137 -0
- package/contracts/fixtures/orientation/envelope/updated.json +135 -0
- package/contracts/fixtures/orientation/hostile-target/README.md +61 -0
- package/contracts/fixtures/orientation/hostile-target/manifest.json +82 -0
- package/contracts/fixtures/orientation/hostile-target/repo/CHANGELOG.md +18 -0
- package/contracts/fixtures/orientation/hostile-target/repo/bin/intended.mjs +12 -0
- package/contracts/fixtures/orientation/hostile-target/repo/bin/tripwire.mjs +15 -0
- package/contracts/fixtures/orientation/hostile-target/repo/contracts/release-ledger.json +48 -0
- package/contracts/fixtures/orientation/hostile-target/repo/contracts/supported-surface.json +17 -0
- package/contracts/fixtures/orientation/hostile-target/repo/docs/example-contract.md +13 -0
- package/contracts/fixtures/orientation/hostile-target/repo/hooks/post-checkout +5 -0
- package/contracts/fixtures/orientation/hostile-target/repo/hooks/post-merge +5 -0
- package/contracts/fixtures/orientation/hostile-target/repo/hooks/pre-commit +5 -0
- package/contracts/fixtures/orientation/hostile-target/repo/hostile-dependency-tripwire/package.json +15 -0
- package/contracts/fixtures/orientation/hostile-target/repo/hostile-dependency-tripwire/tripwire.mjs +9 -0
- package/contracts/fixtures/orientation/hostile-target/repo/package.json +20 -0
- package/contracts/fixtures/orientation/hostile-target/repo/schemas/example.v0.schema.json +15 -0
- package/contracts/fixtures/orientation/release-gate/cases.json +1073 -0
- package/contracts/fixtures/runtime-recipe/accept/current.json +299 -0
- package/contracts/fixtures/runtime-recipe/accept/minimal.json +294 -0
- package/contracts/fixtures/runtime-recipe/dist-states.json +51 -0
- package/contracts/fixtures/runtime-recipe/manifest.json +85 -0
- package/contracts/fixtures/runtime-recipe/reject/advisory-enforcement.json +299 -0
- package/contracts/fixtures/runtime-recipe/reject/allowlist-without-hosts.json +297 -0
- package/contracts/fixtures/runtime-recipe/reject/committed-output-claim.json +299 -0
- package/contracts/fixtures/runtime-recipe/reject/engines-disagreement-warns.json +299 -0
- package/contracts/fixtures/runtime-recipe/reject/lifecycle-scripts-enabled.json +299 -0
- package/contracts/fixtures/runtime-recipe/reject/missing-required-field.json +251 -0
- package/contracts/fixtures/runtime-recipe/reject/unknown-kind.json +299 -0
- package/contracts/fixtures/runtime-recipe/reject/unknown-network-policy.json +299 -0
- package/contracts/fixtures/runtime-recipe/reject/unknown-output-check.json +310 -0
- package/contracts/fixtures/runtime-recipe/reject/unknown-revision.json +299 -0
- package/contracts/fixtures/runtime-recipe/reject/unknown-step-id.json +299 -0
- package/contracts/fixtures/runtime-recipe/reject/unperformable-check-skipped.json +299 -0
- package/contracts/fixtures/runtime-recipe/reject/unpinned-lockfile.json +299 -0
- package/contracts/fixtures/sidecar-bundle/production-shaped/.campaign-runtime/assembly-report.json +180 -0
- package/contracts/fixtures/sidecar-bundle/production-shaped/.campaign-runtime/build-context.json +115 -0
- package/contracts/fixtures/sidecar-bundle/production-shaped/.campaign-runtime/doctor-output.json +29 -0
- package/contracts/fixtures/sidecar-bundle/production-shaped/.campaign-runtime/qa-verdict.json +27 -0
- package/contracts/fixtures/sidecar-bundle/production-shaped/campaign-runtime.build.json +141 -0
- package/contracts/migration-sidecar-bundle.v0.json +149 -0
- package/contracts/orientation-limits.v1.json +41 -0
- package/contracts/orientation-reason-codes.v1.json +196 -0
- package/contracts/private-template-sources.json +8 -0
- package/contracts/release-ledger.json +4598 -0
- package/contracts/reserved-skill-names.json +13 -0
- package/contracts/runtime-recipe.campaigns-os-node-v1.json +299 -0
- package/contracts/supported-surface.json +180 -0
- package/contracts/template-brand-contract.apollo-mv-single-step.v0.json +27 -0
- package/contracts/template-brand-contract.apollo.v0.json +27 -0
- package/contracts/template-brand-contract.demeter.v0.json +27 -0
- package/contracts/template-brand-contract.olympus-mv-single-step.v0.json +27 -0
- package/contracts/template-brand-contract.olympus-mv-two-step.v0.json +28 -0
- package/contracts/template-brand-contract.olympus.v0.json +27 -0
- package/contracts/template-brand-contract.shared-commerce.v0.json +190 -0
- package/contracts/template-brand-contract.shop-single-step.v0.json +27 -0
- package/contracts/template-brand-contract.shop-three-step.v0.json +29 -0
- package/contracts/template-slot-manifest.apollo-mv-single-step.v0.json +14 -0
- package/contracts/template-slot-manifest.apollo.v0.json +12 -0
- package/contracts/template-slot-manifest.demeter.v0.json +30 -0
- package/contracts/template-slot-manifest.olympus-mv-single-step.v0.json +14 -0
- package/contracts/template-slot-manifest.olympus-mv-two-step.v0.json +15 -0
- package/contracts/template-slot-manifest.olympus.v0.json +12 -0
- package/contracts/template-slot-manifest.shared-content-core.v0.json +4254 -0
- package/contracts/template-slot-manifest.shop-single-step.v0.json +47 -0
- package/contracts/template-slot-manifest.shop-three-step.v0.json +33 -0
- package/docs/brand-theme-bridge.md +159 -0
- package/docs/build-packet.md +1300 -0
- package/docs/campaign-build-brief.md +145 -0
- package/docs/campaign-standardization-report.md +329 -0
- package/docs/campaigns-os-build-flow.md +117 -0
- package/docs/design-source-package.md +784 -0
- package/docs/legacy-migration.md +58 -0
- package/docs/migration-sidecar-bundle.md +139 -0
- package/docs/orientation-contract-reference.md +1220 -0
- package/docs/polish-evidence.md +502 -0
- package/docs/qa-and-test-orders.md +1691 -0
- package/docs/release-ledger-authoring-guide.md +274 -0
- package/docs/runtime-readiness.md +211 -0
- package/docs/supported-surface.md +83 -0
- package/docs/versioning.md +55 -0
- package/docs/workflow-findings-sidecar.md +588 -0
- package/package.json +135 -0
- package/prompts/first-build.md +27 -0
- package/prompts/friction-log.md +30 -0
- package/schemas/campaign-build-brief.v1.schema.json +149 -0
- package/schemas/campaign-design-source-package.v0.schema.json +697 -0
- package/schemas/campaign-runtime-assembly-report.v0.schema.json +390 -0
- package/schemas/campaign-runtime-build-context.v0.schema.json +339 -0
- package/schemas/campaign-runtime-build-packet.v0.schema.json +452 -0
- package/schemas/campaign-spec.v4.schema.json +582 -0
- package/schemas/campaigns-os-doctor-output.v0.schema.json +43 -0
- package/schemas/campaigns-os-legacy-migration-inventory.v0.schema.json +112 -0
- package/schemas/campaigns-os-legacy-provisioning-plan.v0.schema.json +38 -0
- package/schemas/campaigns-os-legacy-provisioning-receipt.v0.schema.json +57 -0
- package/schemas/campaigns-os-qa-verdict-sidecar.v0.schema.json +150 -0
- package/schemas/campaigns-os-qa-verdict.v0.schema.json +438 -0
- package/schemas/campaigns-os-release-ledger.v1.schema.json +162 -0
- package/schemas/campaigns-os-run-record.v0.schema.json +343 -0
- package/schemas/campaigns-os-runtime-recipe.v1.schema.json +313 -0
- package/schemas/campaigns-os-sidecar-bundle-conformance.v0.schema.json +78 -0
- package/schemas/campaigns-os-tooling-orientation.v1.schema.json +381 -0
- package/schemas/campaigns-os-workflow-finding.v0.schema.json +134 -0
- package/schemas/source-html-manifest.v0.schema.json +252 -0
- package/skills/next-campaigns-build/SKILL.md +73 -0
- package/skills/next-campaigns-os/SKILL.md +101 -0
- package/skills/next-campaigns-os/references/session-intake.md +160 -0
- package/skills/next-campaigns-os-setup/SKILL.md +22 -0
- package/skills/next-campaigns-polish/SKILL.md +145 -0
- package/skills/next-campaigns-qa/SKILL.md +92 -0
- package/skills.json +56 -0
- package/skills.sh +64 -0
- package/src/adapter-decision-contract.mjs +333 -0
- package/src/brand-theme.mjs +1151 -0
- package/src/browser-launch.mjs +79 -0
- package/src/build-brief.mjs +781 -0
- package/src/built-site-scope.mjs +312 -0
- package/src/campaign-ecosystem.mjs +734 -0
- package/src/campaign-identity.mjs +405 -0
- package/src/campaign-workspace.mjs +127 -0
- package/src/checkpoint-waiver.mjs +302 -0
- package/src/cli.mjs +13442 -0
- package/src/commercial-journey.mjs +1119 -0
- package/src/commercial-parity.mjs +965 -0
- package/src/consent.mjs +347 -0
- package/src/content-residue.mjs +322 -0
- package/src/deadline.mjs +81 -0
- package/src/design-source-package.mjs +2604 -0
- package/src/deviation.mjs +107 -0
- package/src/doctor-check-registry.mjs +49 -0
- package/src/doctor-sidecar.mjs +106 -0
- package/src/finding-cause.mjs +557 -0
- package/src/findings.mjs +326 -0
- package/src/fs-identity.mjs +68 -0
- package/src/gate-actions.mjs +105 -0
- package/src/html-scan.mjs +53 -0
- package/src/install-mode.mjs +272 -0
- package/src/legacy-migration.d.ts +128 -0
- package/src/legacy-migration.mjs +510 -0
- package/src/lifecycle.mjs +338 -0
- package/src/local-proof.mjs +401 -0
- package/src/map-pin-writeback.mjs +210 -0
- package/src/orchestration-stage-contract.mjs +81 -0
- package/src/package-install-fixture.mjs +33 -0
- package/src/page-kit-build-summary.mjs +175 -0
- package/src/page-kit-campaign-config.mjs +57 -0
- package/src/page-kit-sdk-version.mjs +392 -0
- package/src/page-kit-store-profile.mjs +369 -0
- package/src/page-kit-sync.mjs +162 -0
- package/src/polish-browser.mjs +867 -0
- package/src/polish-capture.mjs +1094 -0
- package/src/polish-deadline.mjs +51 -0
- package/src/polish-gate.mjs +739 -0
- package/src/polish-node.mjs +639 -0
- package/src/polish-page-load.mjs +1100 -0
- package/src/private-template-source.mjs +237 -0
- package/src/proof-policy.mjs +82 -0
- package/src/qa-analytics-correctness.mjs +307 -0
- package/src/qa-analytics-errors.mjs +38 -0
- package/src/qa-analytics-parity.mjs +699 -0
- package/src/qa-binding-evidence.mjs +140 -0
- package/src/qa-browser.mjs +6608 -0
- package/src/qa-cart-entry.mjs +406 -0
- package/src/qa-commercial-parity.mjs +641 -0
- package/src/qa-node.mjs +3620 -0
- package/src/qa-order-bump.mjs +381 -0
- package/src/qa-parity-capture.mjs +428 -0
- package/src/qa-parity-fixture.mjs +359 -0
- package/src/qa-publish.mjs +362 -0
- package/src/qa-purchase-data-layer.mjs +263 -0
- package/src/qa-route-probe.mjs +272 -0
- package/src/qa-sidecar.mjs +188 -0
- package/src/qa-test-order-topology.mjs +207 -0
- package/src/qa-url-privacy.mjs +13 -0
- package/src/qa-verdict-discovery.mjs +192 -0
- package/src/qa-verdict-publish.mjs +105 -0
- package/src/qa-verdict.mjs +287 -0
- package/src/remit.mjs +388 -0
- package/src/repo-scan.mjs +83 -0
- package/src/route-identity.mjs +133 -0
- package/src/run-record-closeout.mjs +229 -0
- package/src/run-record.mjs +839 -0
- package/src/run-session.mjs +226 -0
- package/src/runtime-state-ignore.mjs +113 -0
- package/src/sdk-attribute-index.mjs +212 -0
- package/src/sdk-markup.mjs +358 -0
- package/src/sdk-meta-tags.mjs +52 -0
- package/src/shell-token.mjs +7 -0
- package/src/sidecar-bundle.mjs +399 -0
- package/src/source-asset-crawl.mjs +469 -0
- package/src/source-html-intake.mjs +627 -0
- package/src/source-html-manifest.mjs +276 -0
- package/src/source-prep.mjs +284 -0
- package/src/spec-derive-store.mjs +431 -0
- package/src/spec-derive.mjs +514 -0
- package/src/spec-fetch.mjs +66 -0
- package/src/spec-hash.mjs +48 -0
- package/src/spec-identity.mjs +27 -0
- package/src/stage-ledger.mjs +509 -0
- package/src/standardization-report.mjs +1297 -0
- package/src/template-brand-contract.mjs +473 -0
- package/src/template-freshness.mjs +196 -0
- package/src/template-reference.mjs +81 -0
- package/src/template-slot-manifest.mjs +150 -0
- package/src/text-safety.mjs +62 -0
- package/src/theme-gate.mjs +185 -0
- package/src/upsell-selector-scope.mjs +299 -0
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import { PAGE_KIT_CAMPAIGNS_REL_PATH } from "./page-kit-campaign-config.mjs";
|
|
2
|
+
import {
|
|
3
|
+
isDemoResidue,
|
|
4
|
+
normalizeStoreProfileValue,
|
|
5
|
+
PAGE_KIT_STORE_PROFILE_FIELDS,
|
|
6
|
+
PAGE_KIT_SYNC_COMMAND,
|
|
7
|
+
} from "./page-kit-store-profile.mjs";
|
|
8
|
+
import { normalizePublicRouteSlug } from "./route-identity.mjs";
|
|
9
|
+
import {
|
|
10
|
+
assessCheckpointWaivers,
|
|
11
|
+
checkpointStateFingerprint,
|
|
12
|
+
projectCheckpointWaiverAssessment,
|
|
13
|
+
} from "./checkpoint-waiver.mjs";
|
|
14
|
+
// Strict released-semver parsing lives in the campaign-spec module (built to
|
|
15
|
+
// campaign-spec/dist, same as the cli.mjs import) so the authoring-time
|
|
16
|
+
// SdkVersion rule and this checkpoint share exactly ONE parser.
|
|
17
|
+
import { isReleasedSdkVersion } from "../campaign-spec/dist/index.js";
|
|
18
|
+
|
|
19
|
+
export const PAGE_KIT_SDK_VERSION_SCOPE = "page_kit.sdk_version";
|
|
20
|
+
|
|
21
|
+
// The canonical bare spelling of the command that writes the repo pin back
|
|
22
|
+
// into the CampaignSpec (implemented in spec-derive.mjs, which imports this
|
|
23
|
+
// module and so cannot be imported here). The `repo_newer` advisory names it;
|
|
24
|
+
// printers spell it for the running install.
|
|
25
|
+
export const SPEC_DERIVE_COMMAND = "campaigns-os spec derive --packet <packet>";
|
|
26
|
+
|
|
27
|
+
// The one rule for reading the CampaignSpec's SDK pin. global_config
|
|
28
|
+
// .sdk_version is the CANONICAL home (33/33 real Map Builder exports declare
|
|
29
|
+
// it there); runtime.sdk_version is an accepted alias seen only in local
|
|
30
|
+
// drafts. Canonical first, alias as fallback. The gate below and `page-kit
|
|
31
|
+
// sync` both consume this, so what the gate expects and what sync writes can
|
|
32
|
+
// never drift apart. `status` is ok | spec_missing | spec_invalid |
|
|
33
|
+
// spec_conflict; `invalid_declarations` names the offending key(s).
|
|
34
|
+
export function resolveSpecSdkPin(spec) {
|
|
35
|
+
const hasCanonical = spec?.global_config != null && Object.hasOwn(spec.global_config, "sdk_version");
|
|
36
|
+
const hasAlias = spec?.runtime != null && Object.hasOwn(spec.runtime, "sdk_version");
|
|
37
|
+
const base = { has_canonical: hasCanonical, has_alias: hasAlias, invalid_declarations: [] };
|
|
38
|
+
if (!hasCanonical && !hasAlias) return { ...base, value: null, source: null, status: "spec_missing" };
|
|
39
|
+
const invalidDeclarations = [
|
|
40
|
+
...(hasCanonical && !isReleasedSdkVersion(spec.global_config.sdk_version) ? ["global_config.sdk_version"] : []),
|
|
41
|
+
...(hasAlias && !isReleasedSdkVersion(spec.runtime.sdk_version) ? ["runtime.sdk_version"] : []),
|
|
42
|
+
];
|
|
43
|
+
if (invalidDeclarations.length) {
|
|
44
|
+
return { ...base, value: null, source: null, status: "spec_invalid", invalid_declarations: invalidDeclarations };
|
|
45
|
+
}
|
|
46
|
+
if (hasCanonical && hasAlias && spec.global_config.sdk_version !== spec.runtime.sdk_version) {
|
|
47
|
+
return { ...base, value: null, source: null, status: "spec_conflict" };
|
|
48
|
+
}
|
|
49
|
+
return hasCanonical
|
|
50
|
+
? { ...base, value: spec.global_config.sdk_version, source: "global_config.sdk_version", status: "ok" }
|
|
51
|
+
: { ...base, value: spec.runtime.sdk_version, source: "runtime.sdk_version", status: "ok" };
|
|
52
|
+
}
|
|
53
|
+
const MISSING_TARGET_STATUSES = new Set(["target_repo_missing", "file_missing", "entry_missing"]);
|
|
54
|
+
|
|
55
|
+
// An entry still carrying the starter family's demo store profile is a fresh
|
|
56
|
+
// scaffold: its pin is the starter's seed, not a version anyone chose. Both
|
|
57
|
+
// directions read this one rule — `page-kit sync` seeds the pin while it
|
|
58
|
+
// holds, `spec derive` refuses to copy the seed into the spec while it holds.
|
|
59
|
+
export function entryInScaffoldState(entry) {
|
|
60
|
+
return PAGE_KIT_STORE_PROFILE_FIELDS.some((field) => (
|
|
61
|
+
typeof entry?.[field] === "string" && isDemoResidue(field, normalizeStoreProfileValue(entry[field]))
|
|
62
|
+
));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Whether `page-kit sync` may write the spec's pin over the target's. The
|
|
66
|
+
// spec is the authority for the Store Profile in every case (those values are
|
|
67
|
+
// authored in the Map, never in the repo), but the SDK pin is different: on an
|
|
68
|
+
// existing campaign the repo pin moves first and the Map/spec is stale until
|
|
69
|
+
// someone re-saves it, so spec -> repo would silently undo a bump. Sync
|
|
70
|
+
// therefore SEEDS the pin: it writes when the entry is still in scaffold
|
|
71
|
+
// state (the starter demo store profile is still in it) or the target pin is
|
|
72
|
+
// older than the spec's, and refuses to move a configured campaign's pin
|
|
73
|
+
// backwards. Both released versions are canonical MAJOR.MINOR.PATCH here.
|
|
74
|
+
export function sdkPinWriteDecision({ expected, observed, entry }) {
|
|
75
|
+
if (entryInScaffoldState(entry)) return "write";
|
|
76
|
+
if (!isReleasedSdkVersion(observed) || !isReleasedSdkVersion(expected)) return "write";
|
|
77
|
+
return compareReleasedSdkVersions(observed, expected) > 0 ? "target_newer" : "write";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Orders two canonical MAJOR.MINOR.PATCH versions (negative, zero, positive);
|
|
81
|
+
// both sides must already have passed isReleasedSdkVersion.
|
|
82
|
+
export function compareReleasedSdkVersions(a, b) {
|
|
83
|
+
const [am, an, ap] = a.split(".").map(Number);
|
|
84
|
+
const [bm, bn, bp] = b.split(".").map(Number);
|
|
85
|
+
return am - bm || an - bn || ap - bp;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function evaluatePageKitSdkVersion({
|
|
89
|
+
spec,
|
|
90
|
+
specStatus = "ok",
|
|
91
|
+
targetLoad,
|
|
92
|
+
waivers = [],
|
|
93
|
+
required = true,
|
|
94
|
+
now = new Date().toISOString(),
|
|
95
|
+
} = {}) {
|
|
96
|
+
const pin = resolveSpecSdkPin(spec);
|
|
97
|
+
const { has_canonical: hasCanonical, has_alias: hasAlias } = pin;
|
|
98
|
+
// The blocked branches below report the raw declaration the spec made, so
|
|
99
|
+
// the expected version is read back from the spec, not from the resolved pin.
|
|
100
|
+
const expected_sdk_version = hasCanonical
|
|
101
|
+
? spec.global_config.sdk_version
|
|
102
|
+
: spec?.runtime?.sdk_version;
|
|
103
|
+
const expected_source = hasCanonical ? "global_config.sdk_version" : "runtime.sdk_version";
|
|
104
|
+
const observed_sdk_version = targetLoad?.entry?.sdk_version;
|
|
105
|
+
const subject = {
|
|
106
|
+
public_route_slug: normalizePublicRouteSlug(targetLoad?.public_route_slug),
|
|
107
|
+
target_path: targetLoad?.target_path || PAGE_KIT_CAMPAIGNS_REL_PATH,
|
|
108
|
+
};
|
|
109
|
+
if (specStatus !== "ok") {
|
|
110
|
+
return {
|
|
111
|
+
id: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
112
|
+
scope: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
113
|
+
status: "blocked",
|
|
114
|
+
code: "page_kit.sdk_version.spec_unavailable",
|
|
115
|
+
reason: `Local CampaignSpec SDK pin is unavailable or malformed (${specStatus}); packet QA never fetches around missing local parity evidence.`,
|
|
116
|
+
waivable: false,
|
|
117
|
+
subject,
|
|
118
|
+
state: { spec_status: specStatus },
|
|
119
|
+
state_fingerprint: null,
|
|
120
|
+
expected_sdk_version: null,
|
|
121
|
+
observed_sdk_version: isReleasedSdkVersion(observed_sdk_version) ? observed_sdk_version : null,
|
|
122
|
+
expected_source: null,
|
|
123
|
+
waiver: null,
|
|
124
|
+
waiver_assessment: {
|
|
125
|
+
active: null,
|
|
126
|
+
inert_counts: { stale: 0, foreign: 0, malformed: 0, expired: 0 },
|
|
127
|
+
},
|
|
128
|
+
required_actions: [{
|
|
129
|
+
id: "repair_spec",
|
|
130
|
+
kind: "edit",
|
|
131
|
+
command: null,
|
|
132
|
+
description: "Restore a valid packet-local CampaignSpec export before build or QA.",
|
|
133
|
+
}],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (!hasCanonical && !hasAlias) {
|
|
137
|
+
return {
|
|
138
|
+
id: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
139
|
+
scope: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
140
|
+
status: "blocked",
|
|
141
|
+
code: "page_kit.sdk_version.spec_missing",
|
|
142
|
+
reason: "CampaignSpec is missing global_config.sdk_version (and the runtime.sdk_version alias); add an explicit released SDK pin before build or QA.",
|
|
143
|
+
waivable: false,
|
|
144
|
+
subject,
|
|
145
|
+
state: { spec_status: "missing" },
|
|
146
|
+
state_fingerprint: null,
|
|
147
|
+
expected_sdk_version: null,
|
|
148
|
+
observed_sdk_version: isReleasedSdkVersion(observed_sdk_version) ? observed_sdk_version : null,
|
|
149
|
+
expected_source: null,
|
|
150
|
+
waiver: null,
|
|
151
|
+
waiver_assessment: {
|
|
152
|
+
active: null,
|
|
153
|
+
inert_counts: { stale: 0, foreign: 0, malformed: 0, expired: 0 },
|
|
154
|
+
},
|
|
155
|
+
required_actions: [{
|
|
156
|
+
id: "repair_spec",
|
|
157
|
+
kind: "edit",
|
|
158
|
+
command: null,
|
|
159
|
+
description: "Add a released CampaignSpec SDK pin, then re-run doctor.",
|
|
160
|
+
}],
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
const invalidDeclarations = pin.invalid_declarations;
|
|
164
|
+
if (pin.status === "spec_invalid") {
|
|
165
|
+
return {
|
|
166
|
+
id: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
167
|
+
scope: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
168
|
+
status: "blocked",
|
|
169
|
+
code: "page_kit.sdk_version.spec_invalid",
|
|
170
|
+
reason: `CampaignSpec ${invalidDeclarations.join(" and ")} must be a released semantic version in canonical MAJOR.MINOR.PATCH form.`,
|
|
171
|
+
waivable: false,
|
|
172
|
+
subject,
|
|
173
|
+
state: { spec_status: "invalid", invalid_declarations: invalidDeclarations },
|
|
174
|
+
state_fingerprint: null,
|
|
175
|
+
expected_sdk_version: null,
|
|
176
|
+
observed_sdk_version: isReleasedSdkVersion(observed_sdk_version) ? observed_sdk_version : null,
|
|
177
|
+
expected_source: null,
|
|
178
|
+
waiver: null,
|
|
179
|
+
waiver_assessment: {
|
|
180
|
+
active: null,
|
|
181
|
+
inert_counts: { stale: 0, foreign: 0, malformed: 0, expired: 0 },
|
|
182
|
+
},
|
|
183
|
+
required_actions: [{
|
|
184
|
+
id: "repair_spec",
|
|
185
|
+
kind: "edit",
|
|
186
|
+
command: null,
|
|
187
|
+
description: "Set the CampaignSpec SDK declaration to a released MAJOR.MINOR.PATCH version, then re-run doctor.",
|
|
188
|
+
}],
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
if (pin.status === "spec_conflict") {
|
|
192
|
+
return {
|
|
193
|
+
id: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
194
|
+
scope: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
195
|
+
status: "blocked",
|
|
196
|
+
code: "page_kit.sdk_version.spec_conflict",
|
|
197
|
+
reason: "CampaignSpec global_config.sdk_version and runtime.sdk_version disagree; global_config is canonical — resolve the declarations before build or QA.",
|
|
198
|
+
waivable: false,
|
|
199
|
+
subject,
|
|
200
|
+
state: { spec_status: "conflict" },
|
|
201
|
+
state_fingerprint: null,
|
|
202
|
+
expected_sdk_version: null,
|
|
203
|
+
observed_sdk_version: isReleasedSdkVersion(observed_sdk_version) ? observed_sdk_version : null,
|
|
204
|
+
expected_source: null,
|
|
205
|
+
waiver: null,
|
|
206
|
+
waiver_assessment: {
|
|
207
|
+
active: null,
|
|
208
|
+
inert_counts: { stale: 0, foreign: 0, malformed: 0, expired: 0 },
|
|
209
|
+
},
|
|
210
|
+
required_actions: [{
|
|
211
|
+
id: "repair_spec",
|
|
212
|
+
kind: "edit",
|
|
213
|
+
command: null,
|
|
214
|
+
description: "Make the CampaignSpec canonical (global_config) and alias (runtime) SDK declarations identical, then re-run doctor.",
|
|
215
|
+
}],
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
const loadStatus = targetLoad?.status || "target_repo_missing";
|
|
219
|
+
if (loadStatus !== "ok") {
|
|
220
|
+
const optionalMissing = !required && MISSING_TARGET_STATUSES.has(loadStatus);
|
|
221
|
+
return {
|
|
222
|
+
id: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
223
|
+
scope: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
224
|
+
status: optionalMissing ? "not_applicable" : "blocked",
|
|
225
|
+
code: optionalMissing
|
|
226
|
+
? "page_kit.sdk_version.not_applicable"
|
|
227
|
+
: "page_kit.sdk_version.target_unavailable",
|
|
228
|
+
reason: optionalMissing
|
|
229
|
+
? `Target ${subject.target_path} entry is not present before scaffold; SDK-pin parity becomes mandatory once the target exists.`
|
|
230
|
+
: `Target ${subject.target_path} entry is unavailable or malformed (${loadStatus}); packet build and QA require an explicit released SDK pin.`,
|
|
231
|
+
waivable: false,
|
|
232
|
+
subject,
|
|
233
|
+
state: { target_status: loadStatus },
|
|
234
|
+
state_fingerprint: null,
|
|
235
|
+
expected_sdk_version,
|
|
236
|
+
observed_sdk_version: null,
|
|
237
|
+
expected_source,
|
|
238
|
+
waiver: null,
|
|
239
|
+
waiver_assessment: {
|
|
240
|
+
active: null,
|
|
241
|
+
inert_counts: { stale: 0, foreign: 0, malformed: 0, expired: 0 },
|
|
242
|
+
},
|
|
243
|
+
required_actions: optionalMissing ? [] : [{
|
|
244
|
+
id: "repair_target",
|
|
245
|
+
kind: "edit",
|
|
246
|
+
command: null,
|
|
247
|
+
description: `Create or repair ${subject.target_path}[${subject.public_route_slug || "<public-route-slug>"}] with a released SDK pin, then re-run doctor.`,
|
|
248
|
+
}],
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
const targetEntry = targetLoad?.entry;
|
|
252
|
+
const targetHasVersion = targetEntry != null && Object.hasOwn(targetEntry, "sdk_version");
|
|
253
|
+
if (!targetHasVersion || !isReleasedSdkVersion(observed_sdk_version)) {
|
|
254
|
+
const missing = !targetHasVersion;
|
|
255
|
+
return {
|
|
256
|
+
id: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
257
|
+
scope: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
258
|
+
status: "blocked",
|
|
259
|
+
code: missing
|
|
260
|
+
? "page_kit.sdk_version.target_missing"
|
|
261
|
+
: "page_kit.sdk_version.target_invalid",
|
|
262
|
+
reason: missing
|
|
263
|
+
? `Target ${subject.target_path}[${subject.public_route_slug}] is missing sdk_version; add the exact released CampaignSpec pin before build or QA.`
|
|
264
|
+
: `Target ${subject.target_path}[${subject.public_route_slug}].sdk_version must be a released semantic version in canonical MAJOR.MINOR.PATCH form.`,
|
|
265
|
+
waivable: false,
|
|
266
|
+
subject,
|
|
267
|
+
state: { target_status: missing ? "version_missing" : "version_invalid" },
|
|
268
|
+
state_fingerprint: null,
|
|
269
|
+
expected_sdk_version,
|
|
270
|
+
observed_sdk_version: null,
|
|
271
|
+
expected_source,
|
|
272
|
+
waiver: null,
|
|
273
|
+
waiver_assessment: {
|
|
274
|
+
active: null,
|
|
275
|
+
inert_counts: { stale: 0, foreign: 0, malformed: 0, expired: 0 },
|
|
276
|
+
},
|
|
277
|
+
required_actions: [{
|
|
278
|
+
id: "repair_target",
|
|
279
|
+
kind: "command",
|
|
280
|
+
command: PAGE_KIT_SYNC_COMMAND,
|
|
281
|
+
description: `Write the released CampaignSpec pin ${expected_sdk_version} into ${subject.target_path}[${subject.public_route_slug}].sdk_version, then re-run doctor.`,
|
|
282
|
+
}],
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
if (observed_sdk_version !== expected_sdk_version) {
|
|
286
|
+
const state = { expected: expected_sdk_version, observed: observed_sdk_version };
|
|
287
|
+
const state_fingerprint = checkpointStateFingerprint({
|
|
288
|
+
scope: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
289
|
+
subject,
|
|
290
|
+
state,
|
|
291
|
+
});
|
|
292
|
+
// Direction of authority (#413): the repo pin is what the funnel serves,
|
|
293
|
+
// the spec field is a build hint. A configured campaign whose repo pin is
|
|
294
|
+
// NEWER than the spec's (both released, no scaffold residue — the same
|
|
295
|
+
// decision `page-kit sync` uses to refuse moving it backwards) is a
|
|
296
|
+
// completed bump the Map has not been re-saved for: advisory, not a
|
|
297
|
+
// blocker, with the re-save as the action. The repo BEHIND the spec, or
|
|
298
|
+
// a scaffold that still carries the starter pin, stays a blocker with
|
|
299
|
+
// sync as the repair; a non-released target pin was refused above.
|
|
300
|
+
const checkpoint = { scope: PAGE_KIT_SDK_VERSION_SCOPE, subject, state_fingerprint };
|
|
301
|
+
if (sdkPinWriteDecision({ expected: expected_sdk_version, observed: observed_sdk_version, entry: targetEntry }) === "target_newer") {
|
|
302
|
+
// Nothing is waived here (there is nothing to waive), but the waiver
|
|
303
|
+
// history is still assessed so a stale, foreign, malformed or expired
|
|
304
|
+
// record recorded against an earlier pair keeps surfacing as inert
|
|
305
|
+
// rather than silently vanishing the moment the state turns advisory.
|
|
306
|
+
const waiver_assessment = projectCheckpointWaiverAssessment(
|
|
307
|
+
assessCheckpointWaivers(waivers, checkpoint, { now }),
|
|
308
|
+
checkpoint,
|
|
309
|
+
);
|
|
310
|
+
return {
|
|
311
|
+
id: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
312
|
+
scope: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
313
|
+
status: "pass",
|
|
314
|
+
code: "page_kit.sdk_version.repo_newer",
|
|
315
|
+
reason: `Target SDK version ${observed_sdk_version} is newer than the CampaignSpec pin ${expected_sdk_version}; the repo pin is what ships, so the build proceeds. Re-derive the spec (spec derive, the refresh_spec action; add --write-map to record ${observed_sdk_version} in the Map's Build hints too) or re-save the Map's Build hints (Campaign Cart SDK version) to ${observed_sdk_version} so the exported spec stops reading stale.`,
|
|
316
|
+
waivable: false,
|
|
317
|
+
subject,
|
|
318
|
+
state,
|
|
319
|
+
state_fingerprint,
|
|
320
|
+
expected_sdk_version,
|
|
321
|
+
observed_sdk_version,
|
|
322
|
+
expected_source,
|
|
323
|
+
waiver: null,
|
|
324
|
+
waiver_assessment,
|
|
325
|
+
required_actions: [],
|
|
326
|
+
advisory_actions: [{
|
|
327
|
+
id: "refresh_spec",
|
|
328
|
+
kind: "command",
|
|
329
|
+
command: SPEC_DERIVE_COMMAND,
|
|
330
|
+
description: `Write the repo pin ${observed_sdk_version} into the CampaignSpec's ${expected_source} (spec derive; with --write-map it is also recorded in the Map's Build hints field), or re-save the Map's Build hints field (Campaign Cart SDK version) to ${observed_sdk_version} and re-export; nothing in the repo needs to change.`,
|
|
331
|
+
}],
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
const waiver_assessment = projectCheckpointWaiverAssessment(
|
|
335
|
+
assessCheckpointWaivers(waivers, checkpoint, { now }),
|
|
336
|
+
checkpoint,
|
|
337
|
+
);
|
|
338
|
+
const waiver = waiver_assessment.active;
|
|
339
|
+
return {
|
|
340
|
+
id: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
341
|
+
scope: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
342
|
+
status: waiver ? "waived" : "blocked",
|
|
343
|
+
code: waiver ? "page_kit.sdk_version.waived" : PAGE_KIT_SDK_VERSION_SCOPE,
|
|
344
|
+
reason: waiver
|
|
345
|
+
? `Target SDK version ${observed_sdk_version} intentionally differs from the CampaignSpec pin ${expected_sdk_version} under an exact named-human decision.`
|
|
346
|
+
: `Target SDK version ${observed_sdk_version} does not match the CampaignSpec pin ${expected_sdk_version}; correct the target or record an explicit intentional-pin decision before build or QA.`,
|
|
347
|
+
waivable: true,
|
|
348
|
+
subject,
|
|
349
|
+
state,
|
|
350
|
+
state_fingerprint,
|
|
351
|
+
expected_sdk_version,
|
|
352
|
+
observed_sdk_version,
|
|
353
|
+
expected_source,
|
|
354
|
+
waiver,
|
|
355
|
+
waiver_assessment,
|
|
356
|
+
required_actions: waiver ? [] : [
|
|
357
|
+
{
|
|
358
|
+
id: "repair_target",
|
|
359
|
+
kind: "command",
|
|
360
|
+
command: PAGE_KIT_SYNC_COMMAND,
|
|
361
|
+
description: `Write the CampaignSpec pin ${expected_sdk_version} into ${subject.target_path}[${subject.public_route_slug}].sdk_version (currently ${observed_sdk_version}), then re-run doctor.`,
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
id: "waive_checkpoint",
|
|
365
|
+
kind: "command",
|
|
366
|
+
command: "campaigns-os checkpoint waive --packet <packet> --gate page_kit.sdk_version --reason \"<reason>\" --waived-by \"<named human>\" --review-condition \"<re-evaluation trigger>\"",
|
|
367
|
+
description: "Record an explicit bounded named-human intentional-pin decision for this exact expected/observed SDK pair.",
|
|
368
|
+
},
|
|
369
|
+
],
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
return {
|
|
373
|
+
id: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
374
|
+
scope: PAGE_KIT_SDK_VERSION_SCOPE,
|
|
375
|
+
status: "pass",
|
|
376
|
+
code: "page_kit.sdk_version.pass",
|
|
377
|
+
reason: `Target SDK version exactly matches the CampaignSpec (${expected_sdk_version}).`,
|
|
378
|
+
waivable: false,
|
|
379
|
+
subject,
|
|
380
|
+
state: { expected: expected_sdk_version, observed: observed_sdk_version },
|
|
381
|
+
state_fingerprint: null,
|
|
382
|
+
expected_sdk_version,
|
|
383
|
+
observed_sdk_version,
|
|
384
|
+
expected_source,
|
|
385
|
+
waiver: null,
|
|
386
|
+
waiver_assessment: {
|
|
387
|
+
active: null,
|
|
388
|
+
inert_counts: { stale: 0, foreign: 0, malformed: 0, expired: 0 },
|
|
389
|
+
},
|
|
390
|
+
required_actions: [],
|
|
391
|
+
};
|
|
392
|
+
}
|