You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The deterministic screenshot-table gate (screenshotTableGate, #2006) only checks that a PR body contains some markdown table with any image inside it. It has no concept of viewport or color-mode coverage. metagraphed's own public contributor skill (.claude/skills/metagraphed/SKILL.md, Phase C2, landed in #3770) documents an exact 3-viewport x 2-theme x before/after = 12-image contract for visual PRs, but nothing in the review engine enforces it, and metagraphed's deterministic gate is currently disabled entirely (relies on AI judgment only).
Confirmed live example: metagraphed PR #4661 shipped with 4/12 images (desktop only, light+dark) and the AI reviewer's comment stated "before/after screenshots for both themes are included as required," treating partial coverage as compliant. Root cause: the private review-context copy the AI reviewer reads its instructions from was never updated to mention viewport/theme completeness, even though the public skill file already documents it precisely.
Fix
screenshotTableGate config gains requireViewports/requireThemes (string arrays, empty by default -- opt-in per repo, byte-identical for repos that don't set them).
When requireViewports is non-empty, the evaluator matches each required (viewport, theme) pair against a labeled table row (case-insensitive substring match on the row's first cell, e.g. "Desktop · Light") and requires at least two image-bearing cells in that row (before + after). Missing pairs are named in the rejection reason.
action gains a real advisory value (distinct from the request_changes/comment values feat(review): wire bot-generated visual captures into screenshotTableGate #4110 removed as dead/unwired config -- this one is actually wired: advisory computes the violation but never contributes to the close-triggering match, exactly like close already only fires when action === "close").
Full config-as-code wiring: DB migration + Drizzle schema + settings resolver + .gittensory.yml manifest parser + OpenAPI, per the repo's own config-field-parity convention.
Scope
Not building in this PR: extending the bot's own automated visual-capture pipeline to actually shoot a tablet viewport or iterate themes (src/review/visual/*) -- this PR is about detecting and enforcing what a contributor submits, not automating capture. A skill-file link in the rejection message is handled via the existing per-repo message override (already fully custom text), not a new config field.
Problem
The deterministic screenshot-table gate (
screenshotTableGate, #2006) only checks that a PR body contains some markdown table with any image inside it. It has no concept of viewport or color-mode coverage. metagraphed's own public contributor skill (.claude/skills/metagraphed/SKILL.md, Phase C2, landed in #3770) documents an exact 3-viewport x 2-theme x before/after = 12-image contract for visual PRs, but nothing in the review engine enforces it, and metagraphed's deterministic gate is currently disabled entirely (relies on AI judgment only).Confirmed live example: metagraphed PR #4661 shipped with 4/12 images (desktop only, light+dark) and the AI reviewer's comment stated "before/after screenshots for both themes are included as required," treating partial coverage as compliant. Root cause: the private review-context copy the AI reviewer reads its instructions from was never updated to mention viewport/theme completeness, even though the public skill file already documents it precisely.
Fix
screenshotTableGateconfig gainsrequireViewports/requireThemes(string arrays, empty by default -- opt-in per repo, byte-identical for repos that don't set them).requireViewportsis non-empty, the evaluator matches each required (viewport, theme) pair against a labeled table row (case-insensitive substring match on the row's first cell, e.g. "Desktop · Light") and requires at least two image-bearing cells in that row (before + after). Missing pairs are named in the rejection reason.actiongains a realadvisoryvalue (distinct from therequest_changes/commentvalues feat(review): wire bot-generated visual captures into screenshotTableGate #4110 removed as dead/unwired config -- this one is actually wired:advisorycomputes the violation but never contributes to the close-triggering match, exactly likeclosealready only fires whenaction === "close")..gittensory.ymlmanifest parser + OpenAPI, per the repo's own config-field-parity convention.Scope
Not building in this PR: extending the bot's own automated visual-capture pipeline to actually shoot a tablet viewport or iterate themes (
src/review/visual/*) -- this PR is about detecting and enforcing what a contributor submits, not automating capture. A skill-file link in the rejection message is handled via the existing per-repomessageoverride (already fully custom text), not a new config field.