Skip to content

fix: rebase design-audit regression hardening onto current main#846

Open
BigSimmo wants to merge 2 commits into
mainfrom
codex/merge-safe-819-rebased
Open

fix: rebase design-audit regression hardening onto current main#846
BigSimmo wants to merge 2 commits into
mainfrom
codex/merge-safe-819-rebased

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • Rebase design-audit regression hardening onto current main.
  • Keep affected design-audit, source routing, RAG, and migration regressions consolidated in one clean branch.

Verification

Verification not run: npm run verify:pr-local (local verification environment missing prettier from this worktree; can rerun after reinstall).
UI verification not run: no local browser run started in this workflow.
Verification not run: npm run eval:retrieval:quality (provider-backed command).
Verification not run: npm run eval:rag -- --limit 15 + npm run eval:quality -- --rag-only (provider-backed command).
Verification not run: npm run check:production-readiness (provider-backed command).
Verification not run: npm run check:deployment-readiness (not requested for this change set).

Risk and rollout

  • Risk: concentrated on routing/search/source/clinical workflow surfaces; expected to remain isolated but regression coverage is required in CI.
  • Rollback: revert this PR to restore previous behavior.
  • Provider or production effects: none beyond verification scope in this branch.

Clinical Governance Preflight

  • Source-backed claims still require linked source verification before clinical use
  • No patient-identifiable document workflow was introduced or expanded without explicit governance approval
  • Supabase target remains Clinical KB Database (sjrfecxgysukkwxsowpy)
  • Service-role keys and private document access remain server-only
  • Demo/synthetic content remains clearly separated from real clinical sources
  • Source metadata, review status, and outdated/unknown-source behavior remain conservative
  • Deployment classification/TGA SaMD impact was checked when clinical decision-support behavior changed

@supabase

supabase Bot commented Jul 18, 2026

Copy link
Copy Markdown

Updates to Preview Branch (codex/merge-safe-819-rebased) ↗︎

Deployments Status Updated
Database Sat, 18 Jul 2026 12:38:08 UTC
Services Sat, 18 Jul 2026 12:38:08 UTC
APIs Sat, 18 Jul 2026 12:38:08 UTC

Tasks are run on every commit but only new migration files are pushed.
Close and reopen this PR if you want to apply changes from existing seed or migration files.

Tasks Status Updated
Configurations Sat, 18 Jul 2026 12:38:09 UTC
Migrations Sat, 18 Jul 2026 12:38:12 UTC
Seeding ⏸️ Sat, 18 Jul 2026 12:38:01 UTC
Edge Functions ⏸️ Sat, 18 Jul 2026 12:38:01 UTC

❌ Branch Error • Sat, 18 Jul 2026 12:38:12 UTC

ERROR: Unsafe supabase_admin default privileges; migration blocked. (SQLSTATE 42501)
{"safe": false, "entries": ["function:PUBLIC:execute", "function:anon:execute", "function:authenticated:execute", "function:postgres:execute", "function:service_role:execute", "function:supabase_admin:execute", "sequence:anon:select", "sequence:anon:update", "sequence:anon:usage", "sequence:authenticated:select", "sequence:authenticated:update", "sequence:authenticated:usage", "sequence:postgres:select", "sequence:postgres:update", "sequence:postgres:usage", "sequence:service_role:select", "sequence:service_role:update", "sequence:service_role:usage", "sequence:supabase_admin:usage", "table:anon:delete", "table:anon:insert", "table:anon:maintain", "table:anon:references", "table:anon:select", "table:anon:trigger", "table:anon:truncate", "table:anon:update", "table:authenticated:delete", "table:authenticated:insert", "table:authenticated:maintain", "table:authenticated:references", "table:authenticated:select", "table:authenticated:trigger", "table:authenticated:truncate", "table:authenticated:update", "table:postgres:delete", "table:postgres:insert", "table:postgres:maintain", "table:postgres:references", "table:postgres:select", "table:postgres:trigger", "table:postgres:truncate", "table:postgres:update", "table:service_role:delete", "table:service_role:insert", "table:service_role:maintain", "table:service_role:references", "table:service_role:select", "table:service_role:trigger", "table:service_role:truncate", "table:service_role:update", "table:supabase_admin:delete", "table:supabase_admin:insert", "table:supabase_admin:maintain", "table:supabase_admin:references", "table:supabase_admin:select", "table:supabase_admin:trigger", "table:supabase_admin:truncate", "table:supabase_admin:update"], "role_exists": true, "schema_exists": true}
At statement: 3
do $$
declare
  v_status jsonb;
begin
  if not exists (select 1 from pg_catalog.pg_roles where rolname = 'supabase_admin') then
    raise notice 'role supabase_admin does not exist; default-privilege assertion is not applicable';
    return;
  end if;

  begin
    -- Local/Superuser-capable environments can assume the target role even
    -- when the migration role cannot use ALTER DEFAULT PRIVILEGES FOR ROLE
    -- directly. Hosted environments that cannot assume it fall through to the
    -- catalog assertion and block with operator instructions.
    execute 'set local role supabase_admin';
    -- Revokes must be global: per-schema ACLs cannot subtract privileges from
    -- built-in or previously granted global defaults.
    alter default privileges for role supabase_admin
      revoke all privileges on tables from public, anon, authenticated, service_role;
    alter default privileges for role supabase_admin in schema public
      revoke all privileges on tables from public, anon, authenticated, service_role;
    alter default privileges for role supabase_admin
      revoke all privileges on sequences from public, anon, authenticated, service_role;
    alter default privileges for role supabase_admin in schema public
      revoke all privileges on sequences from public, anon, authenticated, service_role;
    alter default privileges for role supabase_admin
      revoke execute on functions from public, anon, authenticated, service_role;
    alter default privileges for role supabase_admin in schema public
      revoke execute on functions from public, anon, authenticated, service_role;
    alter default privileges for role supabase_admin in schema public
      grant select, insert, update, delete on tables to service_role;
    alter default privileges for role supabase_admin in schema public
      grant usage, select on sequences to service_role;
    alter default privileges for role supabase_admin in schema public
      grant execute on functions to service_role;
    execute 'reset role';
  exception when insufficient_privilege then
    begin execute 'reset role'; exception when others then null; end;
    raise notice 'current role % cannot remediate supabase_admin default privileges; asserting the catalog postcondition', current_user;
  end;

  v_status := public.default_privileges_status('supabase_admin', 'public');
  if not coalesce((v_status->>'safe')::boolean, false) then
    raise exception using
      errcode = '42501',
      message = 'Unsafe supabase_admin default privileges; migration blocked.',
      detail = v_status::text,
      hint = E'Run these six statements as supabase_admin, then retry the migration:\n'
        'DO $remediate$ BEGIN ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin REVOKE ALL PRIVILEGES ON TABLES FROM PUBLIC, anon, authenticated, service_role; ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL PRIVILEGES ON TABLES FROM PUBLIC, anon, authenticated, service_role; END $remediate$;\n'
        'DO $remediate$ BEGIN ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin REVOKE ALL PRIVILEGES ON SEQUENCES FROM PUBLIC, anon, authenticated, service_role; ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE ALL PRIVILEGES ON SEQUENCES FROM PUBLIC, anon, authenticated, service_role; END $remediate$;\n'
        'DO $remediate$ BEGIN ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC, anon, authenticated, service_role; ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC, anon, authenticated, service_role; END $remediate$;\n'
        'ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO service_role;\n'
        'ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT USAGE, SELECT ON SEQUENCES TO service_role;\n'
        'ALTER DEFAULT PRIVILEGES FOR ROLE supabase_admin IN SCHEMA public GRANT EXECUTE ON FUNCTIONS TO service_role;';
  end if;
end;
$$

View logs for this Workflow Run ↗︎.
Learn more about Supabase for Git ↗︎.

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request adds abort-aware retrieval and classifier handling, refines answer-coalescing metrics, changes dashboard rendering and focus behavior, updates query parameter typing and Playwright motion settings, and refreshes UI, regression, schema, and manifest expectations.

Changes

RAG pipeline updates

Layer / File(s) Summary
Abortable retrieval RPCs
src/lib/rag-candidate-sources.ts, src/lib/rag.ts
Versioned and legacy retrieval RPCs accept abort signals through shared execution plumbing while preserving fallback behavior.
Classifier cancellation and coalescing metrics
src/lib/rag.ts
Classifier waits become abort-aware, retrieval forwards caller signals, and coalesced answer metrics are recorded conditionally.

Dashboard and browser behavior

Layer / File(s) Summary
Dashboard rendering and page contracts
src/app/page.tsx, src/components/ClinicalDashboard.tsx, src/components/route-error-boundary.tsx
Query parameters accept generic records, universal matches move for non-answer results, and route-error focus styling uses focus-visible.
Browser motion configuration
playwright.config.ts
Playwright defaults to reduced motion while Chromium Desktop Chrome explicitly uses no-preference.

Regression and schema validation

Layer / File(s) Summary
Content and navigation regression contracts
tests/audit-content-services-regressions.test.ts, tests/audit-navigation-auth-regressions.test.ts, tests/ui-accessibility.spec.ts, tests/ui-smoke.spec.ts
Assertions now match updated provenance, navigation, gating, and “Clinical KB” heading behavior.
UI mock and interaction contracts
tests/ui-tools.spec.ts
Registry mocks isolate form records, form output excludes unrelated content, and mobile dock transitions are validated.
Schema fixtures and manifest metadata
tests/supabase-schema.test.ts, supabase/drift-manifest.json
Schema checks reference the current migration and normalized SQL contracts; manifest generation metadata is refreshed.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Request
  participant rag
  participant ClassifierFallback
  participant SupabaseRPC
  Request->>rag: start retrieval with AbortSignal
  rag->>ClassifierFallback: analyze query with caller signal
  ClassifierFallback-->>rag: classified query or AbortError
  rag->>SupabaseRPC: execute versioned or legacy RPC with signal
  SupabaseRPC-->>rag: retrieval data or error
  rag-->>Request: return result or cancellation
Loading

Possibly related PRs

Suggested labels: codex

Suggested reviewers: copilot, cursoragent

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: rebasing the design-audit regression hardening onto current main.
Description check ✅ Passed The description follows the required template with Summary, Verification, Risk and rollout, and Clinical Governance Preflight sections filled in.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/merge-safe-819-rebased

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/route-error-boundary.tsx`:
- Around line 59-62: Update the focused heading in the route error boundary,
identified by headingRef and its h1 className, to preserve a visible outline
when focused imperatively. Add a focus-based outline style while retaining the
existing focus-visible styling, or explicitly request focus-visible behavior
through headingRef.current?.focus({ focusVisible: true }).

In `@src/lib/rag-candidate-sources.ts`:
- Around line 91-99: Forward the caller’s args.signal through both vector RPC
retrieval call sites in rag.ts, including the fallback path, so the executeRpc
cancellation logic in rag-candidate-sources.ts receives it. Update the calls
near the existing retrieval paths without changing their other arguments or
behavior.

In `@src/lib/rag.ts`:
- Around line 1393-1399: Update the error handling in awaitWithCallerSignal so
caller-triggered aborts are re-thrown when opts?.signal?.aborted or error equals
opts?.signal?.reason, including custom abort reasons. Perform this check before
the existing AbortError transport check and preserve the current fallback that
returns analysis for non-abort failures.

In `@tests/supabase-schema.test.ts`:
- Around line 1372-1375: Update the assertions around cleanup to normalize SQL
formatting without lowercasing quoted values: use a separately normalized
representation for structural checks, while matching the raw cleanup SQL for the
case-sensitive literals 'clinical_registry_records' and 'kind'. Preserve the
existing checks for metadata fields and CASE structure.

In `@tests/ui-tools.spec.ts`:
- Around line 1021-1033: Update the transition inspection in the dock test
around the evaluate callback so it parses transitionProperty and
transitionDuration as paired lists and asserts the duration corresponding to the
transform transition, while treating all as the applicable fallback. Remove the
current maximum-duration assertion so unrelated transitions such as opacity
cannot satisfy the dock animation check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1cc2668c-b565-4a40-80d7-417241cda42f

📥 Commits

Reviewing files that changed from the base of the PR and between ea0251f and 477e010.

📒 Files selected for processing (13)
  • playwright.config.ts
  • src/app/page.tsx
  • src/components/ClinicalDashboard.tsx
  • src/components/route-error-boundary.tsx
  • src/lib/rag-candidate-sources.ts
  • src/lib/rag.ts
  • supabase/drift-manifest.json
  • tests/audit-content-services-regressions.test.ts
  • tests/audit-navigation-auth-regressions.test.ts
  • tests/supabase-schema.test.ts
  • tests/ui-accessibility.spec.ts
  • tests/ui-smoke.spec.ts
  • tests/ui-tools.spec.ts

Comment on lines 59 to +62
<h1
ref={headingRef}
tabIndex={-1}
className="mt-4 text-lg font-semibold tracking-tight text-[color:var(--text-heading)] focus:outline focus:outline-2 focus:outline-offset-2 focus:outline-[color:var(--focus-ring,Highlight)]"
className="mt-4 text-lg font-semibold tracking-tight text-[color:var(--text-heading)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[color:var(--focus-ring,Highlight)]"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== route-error-boundary.tsx ==\n'
sed -n '1,220p' src/components/route-error-boundary.tsx

printf '\n== focus-related usages ==\n'
rg -n "focus-visible:outline|focus:outline|headingRef|tabIndex=\{-1\}|focus\(\)" src/components src -g '!**/*.map' || true

Repository: BigSimmo/Database

Length of output: 50374


🌐 Web query:

CSS :focus-visible programmatic focus non-interactive element browser behavior

💡 Result:

When using the programmatic .focus() method on a non-interactive element (e.g., a

with tabindex="-1"), the :focus-visible pseudo-class does not typically match by default [1][2]. This occurs because the browser's heuristic for :focus-visible generally suppresses the focus indicator when the focus change is triggered by a pointer interaction or a script, aiming to match native behavior where focus rings are often hidden unless a keyboard-driven navigation path is detected [3][4][5]. Key behaviors and workarounds include: Programmatic Focus Limitations: By default, calling element.focus() does not trigger :focus-visible because the user agent's heuristic often classifies programmatic focus as a non-keyboard-driven event [2][6]. Forcing Visibility: To ensure a focus indicator appears regardless of the browser's internal heuristics, you can use the focusVisible option in the HTMLElement.focus() method [6][7]: element.focus({ focusVisible: true }); This explicitly tells the browser to treat the focus as "visible," causing the :focus-visible pseudo-class to match [2][6]. Browser Inconsistencies: While the focusVisible option is now widely supported in modern browsers (e.g., Firefox 104+, Chrome, Safari), behavior for non-interactive elements without this option can still vary slightly across engines [1][7]. Non-interactive elements (like those with tabindex="-1") that are focusable via script but not by keyboard navigation may not consistently show a focus ring depending on how the browser's focus management heuristics classify the triggering event [1][5]. Recommendations: Use the { focusVisible: true } option if you want to guarantee that your :focus-visible styles apply to an element receiving programmatic focus [2][6]. Avoid relying on implicit browser heuristics to show focus on non-interactive elements that are not part of your natural keyboard tab order, as this behavior is not guaranteed to be consistent across different browsers or future spec updates [1][4].

Citations:


Preserve the focus outline on the imperatively focused heading. headingRef.current?.focus() can land on this h1 without matching :focus-visible in some browsers, so sighted users may lose the visible focus location. Keep focus:outline here, or switch to focus({ focusVisible: true }) if you want to rely on focus-visible styling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/route-error-boundary.tsx` around lines 59 - 62, Update the
focused heading in the route error boundary, identified by headingRef and its h1
className, to preserve a visible outline when focused imperatively. Add a
focus-based outline style while retaining the existing focus-visible styling, or
explicitly request focus-visible behavior through headingRef.current?.focus({
focusVisible: true }).

Comment on lines +91 to 99
signal?: AbortSignal,
): Promise<{ data: T | null; error: SupabaseRpcError }> {
const client = supabase as unknown as {
rpc: (name: string, rpcArgs: Record<string, unknown>) => Promise<{ data: T | null; error: SupabaseRpcError }>;
const client = supabase as unknown as SupabaseRpcClient;
const executeRpc = async (name: string, rpcArgs: Record<string, unknown>) => {
const pending = client.rpc(name, rpcArgs) as AbortableRpc<T>;
const pendingWithAbort =
signal && typeof pending.abortSignal === "function" ? pending.abortSignal(signal) : pending;
return await pendingWithAbort;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Forward args.signal at both retrieval call sites.

Lines 91-99 only apply cancellation when a signal is supplied, but src/lib/rag.ts Lines 2837-2849 and 2945-2956 omit it. Both vector RPC paths therefore continue after caller abort.

Proposed fix
 const { data, error } = await callVersionedRetrievalRpc(
   supabase,
   "match_document_chunks_hybrid_v2",
   "match_document_chunks_hybrid",
   {
     // ...
   },
+  args.signal,
 );

Apply the same fifth argument to the fallback call at src/lib/rag.ts Lines 2945-2956.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/rag-candidate-sources.ts` around lines 91 - 99, Forward the caller’s
args.signal through both vector RPC retrieval call sites in rag.ts, including
the fallback path, so the executeRpc cancellation logic in
rag-candidate-sources.ts receives it. Update the calls near the existing
retrieval paths without changing their other arguments or behavior.

Comment thread src/lib/rag.ts
Comment on lines +1393 to +1399
} catch (error) {
if (
error &&
(error instanceof DOMException || typeof error === "object") &&
(error as { name?: string }).name === "AbortError"
)
throw error;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
node - <<'NODE'
const controller = new AbortController();
const reason = new Error("caller cancelled");
controller.abort(reason);
console.log(controller.signal.aborted, controller.signal.reason === reason, controller.signal.reason.name);
NODE

Repository: BigSimmo/Database

Length of output: 171


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant region around the reported lines
sed -n '1365,1415p' src/lib/rag.ts

echo
echo '---'
echo

# Find the helper that awaits with the caller signal
rg -n "awaitWithCallerSignal|signal\.reason|AbortError|opts\?\.signal\?\.aborted" src/lib/rag.ts

Repository: BigSimmo/Database

Length of output: 2872


Propagate caller aborts here src/lib/rag.ts:1393-1399awaitWithCallerSignal() can reject with signal.reason, so an AbortController.abort(new Error(...)) falls through to return analysis instead of cancelling. Re-throw when opts?.signal?.aborted (or when error === opts?.signal?.reason) before treating it as a transport failure.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/rag.ts` around lines 1393 - 1399, Update the error handling in
awaitWithCallerSignal so caller-triggered aborts are re-thrown when
opts?.signal?.aborted or error equals opts?.signal?.reason, including custom
abort reasons. Perform this check before the existing AbortError transport check
and preserve the current fallback that returns analysis for non-abort failures.

Comment on lines +1372 to +1375
const cleanupLower = cleanup.toLowerCase();
expect(cleanupLower).toContain("metadata->>'registry_record_id' = old.id::text");
expect(cleanupLower).toContain("metadata->>'registry_record_kind' = case tg_table_name");
expect(cleanupLower).toMatch(/when 'clinical_registry_records' then (pg_catalog\.)?to_jsonb\(old\)->>'kind'/);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve case-sensitive registry literals in this assertion.

cleanup.toLowerCase() also lowercases quoted string values. A migration that changes 'clinical_registry_records' or 'kind' to the wrong case would still satisfy these checks, even though PostgreSQL compares those metadata values case-sensitively. Normalize SQL formatting separately, but assert the quoted registry literals from the raw SQL.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/supabase-schema.test.ts` around lines 1372 - 1375, Update the
assertions around cleanup to normalize SQL formatting without lowercasing quoted
values: use a separately normalized representation for structural checks, while
matching the raw cleanup SQL for the case-sensitive literals
'clinical_registry_records' and 'kind'. Preserve the existing checks for
metadata fields and CASE structure.

Comment thread tests/ui-tools.spec.ts
Comment on lines +1021 to +1033
const transition = await dock.evaluate((node) => {
const style = window.getComputedStyle(node);
const durationMs = Math.max(
...style.transitionDuration.split(",").map((value) => {
const normalized = value.trim();
const duration = Number.parseFloat(normalized);
return normalized.endsWith("ms") ? duration : duration * 1000;
}),
);
return { durationMs, property: style.transitionProperty };
});
expect(transition.property).toMatch(/transform|all/);
expect(transition.durationMs).toBeGreaterThanOrEqual(100);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the matched transition’s own duration. tests/ui-tools.spec.ts:1021-1033 uses the maximum duration across all transitions, so a transform 0ms, opacity 200ms case can still pass even though the dock animation is instant. Pair transform/all with its corresponding duration instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/ui-tools.spec.ts` around lines 1021 - 1033, Update the transition
inspection in the dock test around the evaluate callback so it parses
transitionProperty and transitionDuration as paired lists and asserts the
duration corresponding to the transform transition, while treating all as the
applicable fallback. Remove the current maximum-duration assertion so unrelated
transitions such as opacity cannot satisfy the dock animation check.

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown

CI triage

CI failed on this PR. Automated classification of the 2 failed job(s):

  • Production UIneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.
  • PR requiredneeds investigation: inspect the failing step and uploaded diagnostics; rerun only after classifying the cause.

Compared with main CI run #3269 (success).

Classification is evidence routing, not permission to ignore a failure. Exact quarantined Playwright identities remain governed by the flake ledger.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant