From 436363076044fc799b9ca12e97759c83415603c0 Mon Sep 17 00:00:00 2001 From: Oladotun Olatunji Date: Sun, 5 Jul 2026 10:14:10 -0500 Subject: [PATCH 1/3] fix: normalize compact shopping pack tokens - Treat compact quantity tokens like 2Pack as pack for query relevance. - Preserve unrelated word strictness with Backpack coverage. Co-authored-by: Codex --- src/providers/shopping-report/rules.ts | 2 ++ tests/providers-shopping-report.test.ts | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/providers/shopping-report/rules.ts b/src/providers/shopping-report/rules.ts index 5931752c..d1bc882e 100644 --- a/src/providers/shopping-report/rules.ts +++ b/src/providers/shopping-report/rules.ts @@ -76,6 +76,7 @@ const SOFT_DESCRIPTOR_TOKENS = new Set([ ]); const BUDGET_PRICE_TOKEN_PATTERN = /\b(?:under|below|less than|no more than|max(?:imum)?|budget|up to)\s+(?:[$\u20ac\u00a3\u00a5]\s*)?(\d+(?:[.,]\d+)?)(?:\s*(?:usd|cad|eur|gbp))?\b|[$\u20ac\u00a3\u00a5]\s*(\d+(?:[.,]\d+)?)/gi; +const COMPACT_QUANTITY_PACK_TOKEN_PATTERN = /^\d+pack$/; const PRODUCT_EVIDENCE_ATTRIBUTE_KEYS = new Set([ "brand", @@ -90,6 +91,7 @@ const PRODUCT_EVIDENCE_ATTRIBUTE_KEYS = new Set([ ]); const normalizeToken = (token: string): string => { + if (COMPACT_QUANTITY_PACK_TOKEN_PATTERN.test(token)) return "pack"; if (token === "ergo") return "ergonomic"; if (token === "mic" || token === "microphones") return "microphone"; if (token === "mice") return "mouse"; diff --git a/tests/providers-shopping-report.test.ts b/tests/providers-shopping-report.test.ts index 76df2f55..43a5e972 100644 --- a/tests/providers-shopping-report.test.ts +++ b/tests/providers-shopping-report.test.ts @@ -364,6 +364,19 @@ describe("shopping-report", () => { expect(emptyQueryRelevance.missingTokens).toEqual([]); }); + it("matches compact quantity pack title tokens without accepting unrelated words", () => { + const compactPackRelevance = assessQueryRelevance("pack", "Durcord USB C Cable 2Pack 100W 6ft"); + const hyphenatedPackRelevance = assessQueryRelevance("pack", "Durcord USB C Cable 2-pack 100W 6ft"); + const unrelatedBackpackRelevance = assessQueryRelevance("pack", "Travel Backpack"); + + expect(compactPackRelevance.status).toBe("strong"); + expect(compactPackRelevance.missingTokens).toEqual([]); + expect(hyphenatedPackRelevance.status).toBe("strong"); + expect(hyphenatedPackRelevance.missingTokens).toEqual([]); + expect(unrelatedBackpackRelevance.status).toBe("weak"); + expect(unrelatedBackpackRelevance.missingTokens).toEqual(["pack"]); + }); + it("ignores budget price numbers in query relevance while preserving product spec numbers", () => { const budgetBriefing = buildShoppingBriefing(briefingInput({ query: "ergonomic mouse under $150", From c7beff5acd1e1f53bd8b964f09b85b0aa4d37ce9 Mon Sep 17 00:00:00 2001 From: Oladotun Olatunji Date: Sun, 5 Jul 2026 21:27:59 -0500 Subject: [PATCH 2/3] fix: harden workflow readiness evidence gates - Normalize supplemental Pinterest visual evidence as skipped after pin-media authority is complete. - Validate product-video readiness sidecars instead of bundle presence only. - Keep docs, skill guidance, public surface manifest, and regressions aligned. Co-authored-by: Codex --- docs/CLI.md | 2 +- docs/SURFACE_REFERENCE.md | 2 +- scripts/product-video-fixture-live-probe.mjs | 188 +++++++++++++-- skills/opendevbrowser-best-practices/SKILL.md | 2 +- .../inspiredesign-advanced-brief.v1.json | 12 +- src/providers/workflows.ts | 130 ++++++++-- src/public-surface/generated-manifest.json | 2 +- src/public-surface/generated-manifest.ts | 2 +- src/public-surface/source.ts | 2 +- ...media-analysis-dependency-guidance.test.ts | 2 +- .../product-video-fixture-live-probe.test.ts | 228 +++++++++++++++++- ...ders-inspiredesign-brief-expansion.test.ts | 17 ++ .../providers-inspiredesign-workflow.test.ts | 135 +++++++++-- tests/public-surface-manifest.test.ts | 2 +- 14 files changed, 645 insertions(+), 81 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index 63b4915f..b8268a77 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -618,7 +618,7 @@ Notes: - Workflow outputs can include typed `nextStepGuidance` with `readiness`, `reasonCode`, `primaryAction`, command examples, `paramsExamples`, `validationChecks`, `fallbackPolicy`, and `doNotProceedIf` blockers. - Harvest outputs separate operational completion, guidance readiness, and product readiness. `success:true` or `ok:true` means the command completed and wrote artifacts; top-level `ready` is product-ready only when `productSuccess=true`, `artifactAuthority=product_ready`, and `evidenceAuthority` is non-diagnostic. `readiness` and `guidanceReadiness` expose the next-step guidance state. - Treat product readiness as the gate between artifact completion and design readiness. Continue to Canvas only when top-level `ready=true`, `productSuccess=true`, `artifactAuthority=product_ready`, ranked references are non-empty, manifest-backed authority evidence exists, and no `doNotProceedIf` condition applies. For canonical Pinterest pin-media harvests, Canvas continuation requires `evidenceAuthority=pin_media_ready` and manifest-backed `pin-media-index.json`; `snapshot_ready` and `motion_ready` are not substitutes for pin-media readiness. -- Pinterest product readiness is pin-media-first: canonical pin URLs become product-ready only when their first-party pin-media artifact is captured, persisted, present in its manifest-backed index, and free of blocking warnings. Screenshot and screencast artifacts can inform diagnostics or motion design, but they do not satisfy required Pinterest pin-media readiness. The exact `login_or_challenge_state` and strict byte-backed `interface_chrome_shell` diagnostics are non-blocking only for trusted first-party manifest-backed pin-media bytes; broader login, challenge, captcha, search-shell, promoted, ad, blank, tiny, or chrome-only blockers still demote readiness unless query-discovered canonical pins also produce complete pin-media authority. Screenshot failure after pin-media success is a non-blocking caveat when pin-media authority is complete. `pin-media-index.json` remains Pinterest authority, `media-analysis.json` remains advisory, and `motion-evidence.json` remains browser replay authority. Multimodal agents reason over those artifacts directly. +- Pinterest product readiness is pin-media-first: canonical pin URLs become product-ready only when their first-party pin-media artifact is captured, persisted, present in its manifest-backed index, and free of blocking warnings. Screenshot and screencast artifacts can inform diagnostics or motion design, but they do not satisfy required Pinterest pin-media readiness. The exact `login_or_challenge_state` and strict byte-backed `interface_chrome_shell` diagnostics are non-blocking only for trusted first-party manifest-backed pin-media bytes; broader login, challenge, captcha, search-shell, promoted, ad, blank, tiny, or chrome-only blockers still demote readiness unless query-discovered canonical pins also produce complete pin-media authority. When pin-media authority is complete, unavailable supplemental viewport screenshot evidence is recorded as skipped and satisfied by pin media, not as product-readiness failure. `pin-media-index.json` remains Pinterest authority, `media-analysis.json` remains advisory, and `motion-evidence.json` remains browser replay authority. Multimodal agents reason over those artifacts directly. - CLI completion text includes `guidanceReadiness= productSuccess=false artifactAuthority= evidenceAuthority=` when guidance readiness exists but product readiness is false. Product-ready runs can still emit `readiness=`. - For `needs_recovery`, `blocked`, or `diagnostic_only`, follow the primary recovery action first. Common blockers are zero references, empty ranked references, failed required screenshot, screencast, or pin-media evidence, provider unavailability, login or challenge screens, and diagnostic-only captures. - The ready follow-through path is explicit: read `advanced-brief.md`, `meta-prompt.md`, `evidence.json`, `ranked-references.json`, `bundle-manifest.json`, `media-analysis.json` when present, and screenshot, screencast, or pin-media evidence first; load `opendevbrowser_skill_load opendevbrowser-best-practices "quick start"`, `opendevbrowser_skill_load opendevbrowser-design-agent "canvas-contract"`, and `opendevbrowser_skill_load opendevbrowser-motion-design "quick start"`; continue only if `canvas-plan.request.json` exists; open a Canvas session; fill the session ids in `canvas-plan.request.json`; run `opendevbrowser canvas --command canvas.plan.set --params-file ./canvas-plan.request.json`; confirm `planStatus=accepted`; then patch only the governance blocks called out by `design-agent-handoff.json`. diff --git a/docs/SURFACE_REFERENCE.md b/docs/SURFACE_REFERENCE.md index 0bb829bc..e27bd7fc 100644 --- a/docs/SURFACE_REFERENCE.md +++ b/docs/SURFACE_REFERENCE.md @@ -595,7 +595,7 @@ Auth and policy: - Workflow response keys: artifact-bearing workflow success payloads use `artifact_path`; provider follow-up summaries use `meta.primaryConstraintSummary`; typed recovery and handoff payloads use `nextStepGuidance.readiness`, `reasonCode`, `primaryAction`, `paramsExamples`, `validationChecks`, `fallbackPolicy`, and `doNotProceedIf` when available. Inspiredesign harvest also reports product `ready`, `guidanceReady`, `guidanceReadiness`, `productSuccess`, `harvestReadiness`, `readiness`, `rankedReferenceCount`, `evidenceAuthority`, and `artifactAuthority` so wrapper success is not confused with design readiness. Product `ready` is true only when authority gates pass. - `design-contract.json.colorSystem.tokens` and `implementation-plan.json.tokenStrategy.colors` use explicit `{ light, dark }` semantic token maps. `design-agent-handoff.json.implementationContext.tokenStrategy` carries the same dual-mode token strategy for implementation agents. - Continue to Canvas only when top-level `ready=true`, `productSuccess=true`, `artifactAuthority=product_ready`, ranked references are non-empty, no matching `doNotProceedIf` blockers remain active, and manifest-backed authority evidence exists. Strict proof reviews should inspect `evidence.json`, `ranked-references.json`, `pin-media-index.json`, `motion-evidence.json`, `media-analysis.json`, and `bundle-manifest.json` directly before accepting release or Canvas follow-through evidence. For canonical Pinterest pin-media harvests, Canvas continuation requires `evidenceAuthority=pin_media_ready` and manifest-backed `pin-media-index.json`; `snapshot_ready` and `motion_ready` are not substitutes for pin-media readiness. For `needs_recovery`, `blocked`, or `diagnostic_only`, follow recovery-first guidance and do not treat emitted artifacts as design-ready. -- Pinterest product readiness is pin-media-first: canonical pin URLs become product-ready only when their first-party pin-media artifact is captured, persisted, present in its manifest-backed index, and free of blocking warnings. `pin-media-index.json` remains the only pin-media readiness and provenance authority for persisted first-party bytes. Screenshot and screencast artifacts can inform diagnostics or motion design, but they do not satisfy required Pinterest pin-media readiness. The exact `login_or_challenge_state` and strict byte-backed `interface_chrome_shell` diagnostics are non-blocking only for trusted first-party manifest-backed pin-media bytes; broader login, challenge, captcha, search-shell, promoted, ad, blank, tiny, or chrome-only blockers still demote readiness unless query-discovered canonical pins also produce complete pin-media authority. Screenshot failure after pin-media success is a non-blocking caveat when pin-media authority is complete. `media-analysis.json` remains advisory, and `motion-evidence.json` remains browser replay authority. +- Pinterest product readiness is pin-media-first: canonical pin URLs become product-ready only when their first-party pin-media artifact is captured, persisted, present in its manifest-backed index, and free of blocking warnings. `pin-media-index.json` remains the only pin-media readiness and provenance authority for persisted first-party bytes. Screenshot and screencast artifacts can inform diagnostics or motion design, but they do not satisfy required Pinterest pin-media readiness. The exact `login_or_challenge_state` and strict byte-backed `interface_chrome_shell` diagnostics are non-blocking only for trusted first-party manifest-backed pin-media bytes; broader login, challenge, captcha, search-shell, promoted, ad, blank, tiny, or chrome-only blockers still demote readiness unless query-discovered canonical pins also produce complete pin-media authority. When pin-media authority is complete, unavailable supplemental viewport screenshot evidence is recorded as skipped and satisfied by pin media, not as product-readiness failure. `media-analysis.json` remains advisory, and `motion-evidence.json` remains browser replay authority. - Routine workflow bundles should omit output roots and inspect the returned `artifact_path` first. When output roots are omitted, persisted bundles use `.opendevbrowser//` and include `bundle-manifest.json`. CLI invocations resolve omitted roots from cwd before daemon dispatch; direct daemon RPC uses `core.workspaceRoot/.opendevbrowser`; direct OpenCode workflow tools use `deps.workspaceRoot/.opendevbrowser`. If a wrapper must pass an explicit workflow root, prefer `.opendevbrowser`; explicit external output roots remain caller-controlled for intentional temp, release, debug, audit, screenshot, and screencast lanes. - `artifacts cleanup --expired-only` without `--output-dir` targets the current working directory's `.opendevbrowser` root. Use `--output-dir /tmp/opendevbrowser` only when intentionally cleaning an explicit temp artifact root. - Browser evidence omitted outputs use workspace-local artifact roots: screenshots write `.opendevbrowser/screenshot//capture.png` with `path` and `artifact_path`, and screencasts write `.opendevbrowser/screencast/` with replay files. Explicit `--path` and `--output-dir` remain caller-controlled. Browser screenshot, screencast, Canvas, annotation, desktop audit, and release proof outputs are intentional non-bundle lanes, do not promise `bundle-manifest.json`, and are not targets for bundle manifest cleanup. diff --git a/scripts/product-video-fixture-live-probe.mjs b/scripts/product-video-fixture-live-probe.mjs index ec33d46d..8fd05aa7 100644 --- a/scripts/product-video-fixture-live-probe.mjs +++ b/scripts/product-video-fixture-live-probe.mjs @@ -29,6 +29,22 @@ const PNG_BYTES = Buffer.from( "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+jX1QAAAAASUVORK5CYII=", "base64" ); +const PRODUCT_VIDEO_PASS_STATUS = "pass"; +const PRODUCT_VIDEO_READINESS_GATES = [ + { file: "manifest.json", path: ["readiness", "presentation", "status"], label: "manifest.readiness.presentation.status" }, + { file: "manifest.json", path: ["readiness", "productVideo", "status"], label: "manifest.readiness.productVideo.status" }, + { file: "presentation-readiness.json", path: ["summary", "status"], label: "presentation-readiness.json.summary.status" }, + { file: "presentation-readiness.json", path: ["presentationReadiness", "status"], label: "presentation-readiness.json.presentationReadiness.status" }, + { file: "presentation-readiness.json", path: ["productVideoReadiness", "status"], label: "presentation-readiness.json.productVideoReadiness.status" }, + { file: "product.json", path: ["presentationReadiness", "status"], label: "product.json.presentationReadiness.status" }, + { file: "product.json", path: ["productVideoReadiness", "status"], label: "product.json.productVideoReadiness.status" } +]; +const PRODUCT_VIDEO_REQUIRED_BUNDLE_FILES = [ + "manifest.json", + "presentation-readiness.json", + "product.json", + "bundle-manifest.json" +]; function parseArgs(argv) { const options = { @@ -65,9 +81,17 @@ function parseArgs(argv) { return options; } -function createProductFixtureServer() { +function resolveFixtureRequestOrigin(request) { + const host = typeof request.headers.host === "string" && request.headers.host.length > 0 + ? request.headers.host + : "127.0.0.1"; + return `http://${host}`; +} + +export function createProductFixtureServer() { return http.createServer((request, response) => { - const url = new URL(request.url ?? "/", "http://127.0.0.1"); + const requestOrigin = resolveFixtureRequestOrigin(request); + const url = new URL(request.url ?? "/", requestOrigin); if (url.pathname.startsWith("/assets/")) { response.writeHead(200, { "content-type": "image/png", @@ -84,12 +108,13 @@ function createProductFixtureServer() { } response.writeHead(200, { "content-type": "text/html; charset=utf-8" }); + const productDescription = "Type Desk Organizer. Connectivity Wireless charging and magnetic cable routing. Widget Pro keeps your desk clear with integrated charging and storage."; response.end(` Widget Pro | Acme Labs - +