@nextcommerce/campaigns-os 1.47.0 → 1.48.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 +194 -0
- package/README.md +30 -3
- package/agents/claude/CLAUDE.md +2 -0
- package/agents/codex/AGENTS.md +1 -0
- package/agents/copilot/copilot-instructions.md +1 -0
- package/agents/cursor/campaigns-os.mdc +1 -1
- package/compatibility.json +1 -1
- package/contracts/commerce-surface-catalog.json +17 -17
- package/contracts/release-ledger.json +465 -0
- package/contracts/supported-surface.json +1 -1
- package/contracts/template-brand-contract.shared-commerce.v0.json +1 -1
- package/docs/build-packet.md +1 -1
- package/docs/campaign-build-brief.md +25 -28
- package/docs/local-setup.md +7 -2
- package/docs/orientation-contract-reference.md +1 -1
- package/docs/qa-and-test-orders.md +49 -2
- package/docs/runtime-readiness.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 +9 -4
- package/skills/contribution-intake/SKILL.md +3 -3
- package/skills/next-campaigns-build/SKILL.md +4 -3
- package/skills/next-campaigns-os/SKILL.md +3 -3
- package/skills/next-campaigns-os-setup/SKILL.md +3 -3
- package/skills/next-campaigns-polish/SKILL.md +4 -4
- package/skills/next-campaigns-qa/SKILL.md +3 -3
- package/skills.json +10 -10
- package/src/cli.mjs +6 -3
- package/src/content-residue.mjs +18 -90
- package/src/doctor/checks.mjs +21 -29
- package/src/doctor/inspect.mjs +13 -3
- package/src/doctor/next-step.mjs +4 -0
- package/src/gate-actions.mjs +8 -0
- package/src/local-preview-policy.mjs +92 -0
- package/src/page-kit-sdk-version.mjs +8 -1
- package/src/polish-node.mjs +26 -2
- package/src/progress-node.mjs +5 -1
- package/src/qa-binding-evidence.mjs +1 -1
- package/src/qa-browser.mjs +62 -13
- package/src/qa-node.mjs +33 -4
- package/src/readback.mjs +19 -10
- package/src/source-prep.mjs +1 -1
package/src/readback.mjs
CHANGED
|
@@ -1065,8 +1065,11 @@ function artifactData(views, key) {
|
|
|
1065
1065
|
}
|
|
1066
1066
|
|
|
1067
1067
|
/**
|
|
1068
|
-
* Bucket the QA verdict's assertions by recorded status
|
|
1068
|
+
* Bucket the QA verdict's assertions by recorded status: `{ fail, pass,
|
|
1069
|
+
* skipped, review, other }`.
|
|
1069
1070
|
*
|
|
1071
|
+
* `review` collects the verdict's `warn` and `manual_review` statuses: evidence
|
|
1072
|
+
* that still needs reading, which the disposition counts as an exception.
|
|
1070
1073
|
* `other` collects any status this readback does not project (it renders those
|
|
1071
1074
|
* rows as written rather than reclassifying them). Non-object entries are
|
|
1072
1075
|
* dropped: an assertion the readback cannot address by status is not an
|
|
@@ -1075,13 +1078,15 @@ function artifactData(views, key) {
|
|
|
1075
1078
|
* branch.
|
|
1076
1079
|
*/
|
|
1077
1080
|
export function partitionAssertions(views) {
|
|
1078
|
-
const buckets = { fail: [], pass: [], skipped: [], other: [] };
|
|
1081
|
+
const buckets = { fail: [], pass: [], skipped: [], review: [], other: [] };
|
|
1079
1082
|
const verdict = artifactData(views, "qa_verdict");
|
|
1080
1083
|
if (verdict === null) return buckets;
|
|
1081
1084
|
for (const assertion of verdict.assertions ?? []) {
|
|
1082
1085
|
if (!isPlainObject(assertion)) continue;
|
|
1083
1086
|
const status = assertion.status;
|
|
1084
|
-
const bucket = status === "fail" || status === "pass" || status === "skipped"
|
|
1087
|
+
const bucket = status === "fail" || status === "pass" || status === "skipped"
|
|
1088
|
+
? status
|
|
1089
|
+
: status === "warn" || status === "manual_review" ? "review" : "other";
|
|
1085
1090
|
buckets[bucket].push(assertion);
|
|
1086
1091
|
}
|
|
1087
1092
|
return buckets;
|
|
@@ -1414,15 +1419,17 @@ function renderVerdict(views, lines) {
|
|
|
1414
1419
|
lines.push(
|
|
1415
1420
|
`QA VERDICT [QA verdict; disposition: ${verdict.disposition} — Campaigns OS is the verdict authority]`,
|
|
1416
1421
|
);
|
|
1417
|
-
const { fail: failed, pass: passed, skipped, other } = partitionAssertions(views);
|
|
1422
|
+
const { fail: failed, pass: passed, skipped, review, other } = partitionAssertions(views);
|
|
1418
1423
|
let countLine = ` assertions: ${failed.length} fail, ${passed.length} pass, ${skipped.length} skipped`;
|
|
1424
|
+
if (review.length) countLine += `, ${review.length} warn or manual review`;
|
|
1419
1425
|
if (other.length) countLine += `, ${other.length} unrecognized status`;
|
|
1420
1426
|
lines.push(countLine);
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1427
|
+
// fail, warn and manual_review rows print what Campaigns OS recorded: the
|
|
1428
|
+
// row's actual value and any evidence problems.
|
|
1429
|
+
const renderRecordedRow = (assertion) => {
|
|
1430
|
+
const severityText = assertion.severity ? `, severity ${assertion.severity}` : "";
|
|
1424
1431
|
lines.push(
|
|
1425
|
-
`
|
|
1432
|
+
` ${assertion.status} ${recorded(assertion.id, "(no id)")} ` +
|
|
1426
1433
|
`(family ${recorded(assertion.family, "(no family)")}${severityText})`,
|
|
1427
1434
|
);
|
|
1428
1435
|
const actual = assertion.actual;
|
|
@@ -1433,7 +1440,9 @@ function renderVerdict(views, lines) {
|
|
|
1433
1440
|
lines.push(` recorded problems (${problems.length}):`);
|
|
1434
1441
|
for (const problem of problems) lines.push(` - ${problem}`);
|
|
1435
1442
|
}
|
|
1436
|
-
}
|
|
1443
|
+
};
|
|
1444
|
+
for (const assertion of failed) renderRecordedRow(assertion);
|
|
1445
|
+
for (const assertion of review) renderRecordedRow(assertion);
|
|
1437
1446
|
for (const assertion of passed) {
|
|
1438
1447
|
const family = assertion.family || assertion.id || "(no family)";
|
|
1439
1448
|
lines.push(` pass ${recorded(assertion.id, "(no id)")} (family ${family})`);
|
|
@@ -1442,7 +1451,7 @@ function renderVerdict(views, lines) {
|
|
|
1442
1451
|
lines.push(
|
|
1443
1452
|
` unrecognized status ${JSON.stringify(assertion.status ?? null)} ${recorded(assertion.id, "(no id)")} ` +
|
|
1444
1453
|
`(family ${assertion.family || "(no family)"}) — shown as written; this readback ` +
|
|
1445
|
-
"projects fail, pass, and
|
|
1454
|
+
"projects fail, pass, skipped, warn and manual_review statuses",
|
|
1446
1455
|
);
|
|
1447
1456
|
}
|
|
1448
1457
|
|
package/src/source-prep.mjs
CHANGED
|
@@ -201,7 +201,7 @@ function describeFinding(code, pages, { wrapperPolicy }) {
|
|
|
201
201
|
const policyNote = wrapperPolicy === "preserve_document_wrappers"
|
|
202
202
|
? " The adapter contract records wrapper_policy \"preserve_document_wrappers\", so this is reported without blocking."
|
|
203
203
|
: "";
|
|
204
|
-
return `Mapped source HTML is a full browser document, not page-kit-ready source: ${listed}${more}. Strip <!doctype>, <html>, <head>, and <body> so the campaign layout can wrap the page, or record wrapper_policy "preserve_document_wrappers" as an explicit adapter decision.${policyNote} See ${docs}.`;
|
|
204
|
+
return `Mapped source HTML is a full browser document, not page-kit-ready source: ${listed}${more}. Strip <!doctype>, <html>, <head>, and <body> so the campaign layout can wrap the page, or, for a standalone page meant to stay whole, record wrapper_policy "preserve_document_wrappers" as an explicit adapter decision: re-run start or prepare-build with --wrapper-policy preserve_document_wrappers, or set "wrapper_policy" in the source-html manifest.${policyNote} See ${docs}.`;
|
|
205
205
|
}
|
|
206
206
|
if (code === SOURCE_PREP_FRONTMATTER_RESIDUE) {
|
|
207
207
|
const listed = sample.map((page) => {
|