From 97f0359eb7d9a55c284cac6e04827c298e609d8c Mon Sep 17 00:00:00 2001 From: Ashlee Radka Date: Wed, 22 Apr 2026 16:42:28 -0400 Subject: [PATCH] fix(ci): multiline match + empty-allowlist tolerance in flexframe lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses two Codex review findings on #27554: P1: Main scan now uses `rg -U --multiline-dotall` so `.frame(` wrapped across lines (opening paren on one line, `maxWidth:` on the next) is caught. The prior single-line regex missed a real instance at ChatLoadingSkeleton.swift:58-61 — now allowlisted. P2: `grep -v` against the allowlist is now guarded with `|| true` so a header-only allowlist (possible after a bulk cleanup or fresh `--update-baseline` with zero violations) doesn't abort the script under `set -euo pipefail`. Tests: - dry-run passes (172 allowlisted, 0 new) - injected multi-line violation caught and exits 1 - injected single-line violation still caught (P1 regression check) - empty allowlist + no violations = exit 0 (P2 new path) Co-Authored-By: Claude Opus 4.7 (1M context) --- clients/scripts/check-flexframe.sh | 21 +++++++++++++++++++-- clients/scripts/flexframe-allowlist.txt | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/clients/scripts/check-flexframe.sh b/clients/scripts/check-flexframe.sh index 159a12d0e28..da3b2f9f7c6 100755 --- a/clients/scripts/check-flexframe.sh +++ b/clients/scripts/check-flexframe.sh @@ -70,7 +70,16 @@ fi # (lines whose first non-whitespace is `//` or `///`). AGENTS.md-style # warnings like `// ⚠️ No .frame(maxWidth:) in LazyVStack cells` would # otherwise false-positive. -RAW_HITS=$(rg -n --no-heading "$PATTERN" "${SCAN_DIRS[@]}" 2>/dev/null \ +# +# `-U --multiline-dotall` enables multiline matching so `.frame(` wrapped +# across lines (opening paren on one line, `maxWidth:` on the next) is +# caught. Without this, code formatted as `.frame(\n maxWidth: …\n)` +# bypasses the lint silently — a real escape already present at +# ChatLoadingSkeleton.swift before this PR. ripgrep reports only the +# START line of a multiline match, so the comment filter (which only +# inspects that line) stays correct: the outer `.frame(` never itself +# starts with `//`. +RAW_HITS=$(rg -U --multiline-dotall -n --no-heading "$PATTERN" "${SCAN_DIRS[@]}" 2>/dev/null \ | grep -vE '^[^:]+:[0-9]+:[[:space:]]*//' \ || true) @@ -131,9 +140,17 @@ HEADER fi # Load the allowlist (strip comments + blank lines), preserving multiplicity. +# +# `grep -v` exits 1 when no lines match — under `set -euo pipefail` that +# would abort the script if the allowlist is ever header-only (e.g. after +# a full cleanup or `--update-baseline` with zero observed violations). +# `|| true` tolerates that edge case so a clean state stays clean. ALLOWLIST_ENTRIES="" if [[ -f "$ALLOWLIST_FILE" ]]; then - ALLOWLIST_ENTRIES=$(grep -vE '^([[:space:]]*#|[[:space:]]*$)' "$ALLOWLIST_FILE" | sort) + ALLOWLIST_RAW=$(grep -vE '^([[:space:]]*#|[[:space:]]*$)' "$ALLOWLIST_FILE" || true) + if [[ -n "$ALLOWLIST_RAW" ]]; then + ALLOWLIST_ENTRIES=$(printf '%s\n' "$ALLOWLIST_RAW" | sort) + fi fi # New violations = observed - allowlist (multiset difference preserved by `comm -23`). diff --git a/clients/scripts/flexframe-allowlist.txt b/clients/scripts/flexframe-allowlist.txt index 74ca2c8643f..ef3d9ac4c70 100644 --- a/clients/scripts/flexframe-allowlist.txt +++ b/clients/scripts/flexframe-allowlist.txt @@ -40,11 +40,13 @@ clients/macos/vellum-assistant/Features/Chat/ChatEmptyStateView.swift|.frame(max clients/macos/vellum-assistant/Features/Chat/ChatEmptyStateView.swift|.frame(maxWidth: VSpacing.chatBubbleMaxWidth) clients/macos/vellum-assistant/Features/Chat/ChatErrorToastView.swift|.frame(maxWidth: .infinity) clients/macos/vellum-assistant/Features/Chat/ChatErrorToastView.swift|.frame(maxWidth: .infinity, alignment: .leading) +clients/macos/vellum-assistant/Features/Chat/ChatLoadingSkeleton.swift|.frame( clients/macos/vellum-assistant/Features/Chat/ChatLoadingSkeleton.swift|.frame(maxWidth: .infinity, alignment: .trailing) clients/macos/vellum-assistant/Features/Chat/ChatLoadingSkeleton.swift|.frame(maxWidth: VSpacing.chatBubbleMaxWidth * 0.45, alignment: .trailing) clients/macos/vellum-assistant/Features/Chat/ChatLoadingSkeleton.swift|.frame(maxWidth: VSpacing.chatBubbleMaxWidth * 0.65) clients/macos/vellum-assistant/Features/Chat/ChatLoadingSkeleton.swift|.frame(maxWidth: VSpacing.chatBubbleMaxWidth, alignment: .leading) clients/macos/vellum-assistant/Features/Chat/ChatLoadingSkeleton.swift|.frame(maxWidth: VSpacing.chatColumnMaxWidth, alignment: .leading) +clients/macos/vellum-assistant/Features/Chat/ChatLoadingSkeleton.swift|maxWidth: VSpacing.chatBubbleMaxWidth * assistantLineWidths[idx], clients/macos/vellum-assistant/Features/Chat/ChatView.swift|.frame(maxWidth: .infinity, maxHeight: .infinity) clients/macos/vellum-assistant/Features/Chat/ChatView.swift|.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top) clients/macos/vellum-assistant/Features/Chat/ChatView.swift|.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)