From f947469a36459765e60c4f41edd51129d2634363 Mon Sep 17 00:00:00 2001 From: OoO Date: Wed, 13 May 2026 18:51:46 +0800 Subject: [PATCH] =?UTF-8?q?=E8=9E=8D=E5=90=88=E8=A7=80=E6=B8=AC=E5=8F=B0?= =?UTF-8?q?=E9=BB=9E=E9=99=A3=E8=A6=96=E8=A6=BA=E8=AA=9E=E5=BD=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.py | 2 +- .../check_observability_visual_contract.js | 33 +++++-- static/css/observability-system.css | 95 +++++++++++++++++++ web/static/css/observability-system.css | 95 +++++++++++++++++++ 4 files changed, 218 insertions(+), 7 deletions(-) diff --git a/config.py b/config.py index 0e1e0de..0032c1d 100644 --- a/config.py +++ b/config.py @@ -320,7 +320,7 @@ YOUTUBE_API_KEY = os.getenv('YOUTUBE_API_KEY', '') # ========================================== # 系統版本與路徑 # ========================================== -SYSTEM_VERSION = "V10.116" +SYSTEM_VERSION = "V10.117" LOG_FILE_PATH = os.path.join(BASE_DIR, 'logs/system.log') public_url = PUBLIC_URL # 用於模板顯示 diff --git a/scripts/check_observability_visual_contract.js b/scripts/check_observability_visual_contract.js index 7fb9dea..d99cf90 100755 --- a/scripts/check_observability_visual_contract.js +++ b/scripts/check_observability_visual_contract.js @@ -3,7 +3,7 @@ * Rendered visual contract for AI observability pages. * * This complements the static template guard by checking computed CSS in a - * browser: typography, warm-token surfaces, radius, hero backgrounds, and + * browser: typography, warm-token surfaces, dot-matrix texture, radius, and * mobile density across the 10 observability pages. */ @@ -195,6 +195,11 @@ function contrastRatio(fg, bg) { return (lighter + 0.05) / (darker + 0.05); } +function isDotMatrixBackground(backgroundImage) { + const value = String(backgroundImage || ''); + return value.includes('radial-gradient') && !value.includes('linear-gradient'); +} + async function collectMetrics(page) { return page.evaluate(({ heroSelectors, titleSelectors, surfaceSelectors }) => { const parseRgbValue = (value) => { @@ -234,6 +239,7 @@ async function collectMetrics(page) { const title = document.querySelector(titleSelectors); const badRadius = []; const badBackground = []; + const missingMatrix = []; const badChipContrast = []; for (const el of document.querySelectorAll(`.momo-observability-mode :is(${surfaceSelectors})`)) { @@ -246,13 +252,24 @@ async function collectMetrics(page) { text: String(el.textContent || '').trim().replace(/\s+/g, ' ').slice(0, 80), }); } - if ((el.matches(heroSelectors) || el.matches('.obs-panel,.agent-panel,.biz-panel,.runtime-panel,.calls-panel,.gov-panel,.gate-panel,.rag-panel,.qa-panel,.quality-panel,.ppt-panel')) && style.backgroundImage !== 'none') { + const mustUseMatrix = el.matches(heroSelectors) + || el.matches('.obs-panel,.agent-panel,.biz-panel,.runtime-panel,.calls-panel,.gov-panel,.gate-panel,.rag-panel,.qa-panel,.quality-panel,.ppt-panel') + || el.matches('.obs-signal,.agent-signal,.biz-signal,.runtime-signal,.calls-signal,.gov-signal,.gate-signal,.rag-signal,.qa-signal,.quality-signal,.ppt-signal'); + const hasRadialMatrix = style.backgroundImage.includes('radial-gradient'); + const hasLegacyGradient = style.backgroundImage.includes('linear-gradient'); + if (mustUseMatrix && (!hasRadialMatrix || hasLegacyGradient)) { badBackground.push({ className: String(el.className || '').slice(0, 100), backgroundImage: style.backgroundImage.slice(0, 100), }); } - if (badRadius.length >= 8 && badBackground.length >= 8) break; + if (mustUseMatrix && !hasRadialMatrix) { + missingMatrix.push({ + className: String(el.className || '').slice(0, 100), + text: String(el.textContent || '').trim().replace(/\s+/g, ' ').slice(0, 80), + }); + } + if (badRadius.length >= 8 && badBackground.length >= 8 && missingMatrix.length >= 8) break; } for (const el of document.querySelectorAll('.momo-observability-mode :is(.badge,.obs-pill,[class$="-pill"],.biz-badge)')) { @@ -292,6 +309,7 @@ async function collectMetrics(page) { } : null, badRadius, badBackground, + missingMatrix, badChipContrast, }; }, { heroSelectors: HERO_SELECTORS, titleSelectors: TITLE_SELECTORS, surfaceSelectors: SURFACE_SELECTORS }); @@ -323,13 +341,16 @@ function issuesFor(metrics, viewport) { issues.push('missing hero selector'); } else { if (px(metrics.hero.radius) > 8.5) issues.push(`hero radius ${metrics.hero.radius}`); - if (metrics.hero.backgroundImage !== 'none') issues.push('hero background image is not none'); + if (!isDotMatrixBackground(metrics.hero.backgroundImage)) { + issues.push('hero missing tokenized dot-matrix background'); + } if (metrics.hero.height > viewport.maxHeroHeight) { issues.push(`hero too tall ${metrics.hero.height}px > ${viewport.maxHeroHeight}px`); } } if (metrics.badRadius.length) issues.push(`surface radius offenders ${metrics.badRadius.length}`); - if (metrics.badBackground.length) issues.push(`surface background-image offenders ${metrics.badBackground.length}`); + if (metrics.badBackground.length) issues.push(`surface non-matrix background offenders ${metrics.badBackground.length}`); + if (metrics.missingMatrix.length) issues.push(`surface missing dot-matrix offenders ${metrics.missingMatrix.length}`); if (metrics.badChipContrast.length) issues.push(`chip contrast offenders ${metrics.badChipContrast.length}`); return issues; } @@ -385,7 +406,7 @@ async function main() { const hero = result.metrics?.hero ? `${result.metrics.hero.height}px r=${result.metrics.hero.radius}` : 'n/a'; console.log(`${status} ${result.viewport} ${result.route} title=${title} hero=${hero}${result.issues.length ? ` issues=${result.issues.join('; ')}` : ''}`); if (!result.passed && result.metrics) { - for (const bucket of ['badRadius', 'badBackground', 'badChipContrast']) { + for (const bucket of ['badRadius', 'badBackground', 'missingMatrix', 'badChipContrast']) { for (const offender of result.metrics[bucket] || []) { console.log(` ${bucket}: ${JSON.stringify(offender)}`); } diff --git a/static/css/observability-system.css b/static/css/observability-system.css index daa97d4..2770c22 100644 --- a/static/css/observability-system.css +++ b/static/css/observability-system.css @@ -1761,6 +1761,101 @@ } } +/* v3.8 dot-matrix integration: surfaces carry the product texture without legacy gradients. */ +.momo-observability-mode { + --obs-matrix-dot: radial-gradient(color-mix(in srgb, var(--obs-accent) 14%, transparent) 0.85px, transparent 0.95px); + --obs-matrix-dot-soft: radial-gradient(color-mix(in srgb, var(--obs-muted) 12%, transparent) 0.75px, transparent 0.9px); + --obs-matrix-size: 13px 13px; +} + +.momo-observability-mode :is( + .obs-hero, + .agent-hero, + .biz-command, + .runtime-hero, + .calls-hero, + .gov-hero, + .gate-hero, + .rag-hero, + .qa-hero, + .quality-hero, + .ppt-hero, + .obs-panel, + .agent-panel, + .biz-panel, + .runtime-panel, + .calls-panel, + .gov-panel, + .gate-panel, + .rag-panel, + .qa-panel, + .quality-panel, + .ppt-panel, + .obs-signal, + .agent-signal, + .biz-signal, + .runtime-signal, + .calls-signal, + .gov-signal, + .gate-signal, + .rag-signal, + .qa-signal, + .quality-signal, + .ppt-signal, + .biz-filter-card, + .biz-alert-strip, + .biz-strategy-card, + .biz-mini-metric, + .biz-decision-card, + .episode-card, + .similar-box, + .fix-card, + .root-card, + .rec-card, + .agent-card, + .caller-card, + .host-lane, + .strategy-card, + .obs-route-card +) { + background-color: var(--momo-bg-surface, #faf6ec) !important; + background-image: var(--obs-matrix-dot) !important; + background-position: 0 0 !important; + background-size: var(--obs-matrix-size) !important; +} + +.momo-observability-mode :is( + .obs-panel, + .agent-panel, + .biz-panel, + .runtime-panel, + .calls-panel, + .gov-panel, + .gate-panel, + .rag-panel, + .qa-panel, + .quality-panel, + .ppt-panel, + .biz-filter-card, + .biz-strategy-card, + .episode-card, + .host-lane, + .caller-card, + .agent-card, + .rec-card, + .fix-card, + .root-card, + .strategy-card +) { + background-image: var(--obs-matrix-dot-soft) !important; +} + +.momo-observability-mode :is(.obs-pill, [class$="-pill"], .biz-badge, .badge) { + background-image: var(--obs-matrix-dot-soft) !important; + background-position: 0 0 !important; + background-size: 10px 10px !important; +} + /* v3.7 typography tightening: no legacy tracking, poster-scale numerals, or wrapped action buttons. */ .momo-observability-mode :is( .obs-kicker, diff --git a/web/static/css/observability-system.css b/web/static/css/observability-system.css index daa97d4..2770c22 100644 --- a/web/static/css/observability-system.css +++ b/web/static/css/observability-system.css @@ -1761,6 +1761,101 @@ } } +/* v3.8 dot-matrix integration: surfaces carry the product texture without legacy gradients. */ +.momo-observability-mode { + --obs-matrix-dot: radial-gradient(color-mix(in srgb, var(--obs-accent) 14%, transparent) 0.85px, transparent 0.95px); + --obs-matrix-dot-soft: radial-gradient(color-mix(in srgb, var(--obs-muted) 12%, transparent) 0.75px, transparent 0.9px); + --obs-matrix-size: 13px 13px; +} + +.momo-observability-mode :is( + .obs-hero, + .agent-hero, + .biz-command, + .runtime-hero, + .calls-hero, + .gov-hero, + .gate-hero, + .rag-hero, + .qa-hero, + .quality-hero, + .ppt-hero, + .obs-panel, + .agent-panel, + .biz-panel, + .runtime-panel, + .calls-panel, + .gov-panel, + .gate-panel, + .rag-panel, + .qa-panel, + .quality-panel, + .ppt-panel, + .obs-signal, + .agent-signal, + .biz-signal, + .runtime-signal, + .calls-signal, + .gov-signal, + .gate-signal, + .rag-signal, + .qa-signal, + .quality-signal, + .ppt-signal, + .biz-filter-card, + .biz-alert-strip, + .biz-strategy-card, + .biz-mini-metric, + .biz-decision-card, + .episode-card, + .similar-box, + .fix-card, + .root-card, + .rec-card, + .agent-card, + .caller-card, + .host-lane, + .strategy-card, + .obs-route-card +) { + background-color: var(--momo-bg-surface, #faf6ec) !important; + background-image: var(--obs-matrix-dot) !important; + background-position: 0 0 !important; + background-size: var(--obs-matrix-size) !important; +} + +.momo-observability-mode :is( + .obs-panel, + .agent-panel, + .biz-panel, + .runtime-panel, + .calls-panel, + .gov-panel, + .gate-panel, + .rag-panel, + .qa-panel, + .quality-panel, + .ppt-panel, + .biz-filter-card, + .biz-strategy-card, + .episode-card, + .host-lane, + .caller-card, + .agent-card, + .rec-card, + .fix-card, + .root-card, + .strategy-card +) { + background-image: var(--obs-matrix-dot-soft) !important; +} + +.momo-observability-mode :is(.obs-pill, [class$="-pill"], .biz-badge, .badge) { + background-image: var(--obs-matrix-dot-soft) !important; + background-position: 0 0 !important; + background-size: 10px 10px !important; +} + /* v3.7 typography tightening: no legacy tracking, poster-scale numerals, or wrapped action buttons. */ .momo-observability-mode :is( .obs-kicker,