From c9bc5991c8db16d61df2295dfbb76b79435bf5b2 Mon Sep 17 00:00:00 2001 From: Luiz Carlos Date: Tue, 25 Aug 2026 18:15:13 -0300 Subject: [PATCH 1/2] TEST: design change to exercise design-diff Throwaway branch. Two changes with a known expected output: - radius-nav 10 -> 12, which the token layer should catch - Chip padding $space-3 -> $space-4, which touches no token and no component name, so only the structural layer should catch it Not for merge. --- design/pendev/youtube-channel.pen | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/design/pendev/youtube-channel.pen b/design/pendev/youtube-channel.pen index 6bf84b4..1af894d 100644 --- a/design/pendev/youtube-channel.pen +++ b/design/pendev/youtube-channel.pen @@ -2022,7 +2022,7 @@ "cornerRadius": "$radius-sm", "padding": [ 0, - "$space-3" + "$space-4" ], "justifyContent": "center", "alignItems": "center", @@ -5552,7 +5552,7 @@ }, "radius-nav": { "type": "number", - "value": 10 + "value": 12 }, "radius-md": { "type": "number", From 2bdbbe85efc3fb2dacc2e51de189cf7609ea24a7 Mon Sep 17 00:00:00 2001 From: Luiz Carlos Date: Tue, 25 Aug 2026 18:19:58 -0300 Subject: [PATCH 2/2] Make the drift scan see design-only changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Testing the diff workflow exposed a hole in the audit next to it. On a PR that only moves the design, the code diff is empty, so the scan reported "no code files" and stopped — leaving the agent to work out on its own which components had shifted. It found the token that changed, because a variable is easy to spot, and missed the Chip, whose padding had moved from $space-3 to $space-4 while components/chip.tsx still said px-3. That is the case that escapes review hardest: nothing in app/ or components/ shows up in the PR to draw the eye, and the code is stale from the moment the design lands. The scan now diffs the .pen against the base whenever it changed and reports two lists: the tokens that moved, with enough context to name them, and the components whose structure moved. The agent gets "check Chip" instead of having to derive it. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/drift-scan.sh | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/scripts/drift-scan.sh b/scripts/drift-scan.sh index 0a44b8b..b68907d 100755 --- a/scripts/drift-scan.sh +++ b/scripts/drift-scan.sh @@ -11,7 +11,44 @@ FILES=("$@") if [ ${#FILES[@]} -eq 0 ]; then mapfile -t FILES < <(git diff --name-only "$BASE...HEAD" -- 'app/**' 'components/**' | grep -E '\.(tsx|ts|css)$' || true) fi -[ ${#FILES[@]} -eq 0 ] && { echo "nenhum arquivo de código no diff"; exit 0; } +# O design também pode ter andado sozinho. Nesse caso o diff de código é +# vazio, mas o código pode ter ficado defasado — e é o caso que mais escapa, +# porque nenhum arquivo de código aparece no PR para chamar atenção. +design_side() { + local pen="${PEN_FILE:-design/pendev/youtube-channel.pen}" + git diff --quiet "$BASE...HEAD" -- "$pen" && return + local strip='walk(if type == "object" then del(.id, .x, .y) else . end)' + git show "$BASE:$pen" > /tmp/base.pen 2>/dev/null || return + + jq -S '.variables // {}' /tmp/base.pen > /tmp/base.tok + jq -S '.variables // {}' "$pen" > /tmp/head.tok + # com contexto: sem ele o diff mostra "10 -> 12" sem dizer QUAL token + local tok + tok=$(diff -U4 /tmp/base.tok /tmp/head.tok | tail -n +3 || true) + [ -n "$tok" ] && printf '\n## design mudou — TOKENS (transcreva para app/globals.css, §13)\n%s\n' "$tok" + + # quais componentes mudaram por dentro + local changed="" + while read -r name; do + [ -z "$name" ] && continue + a=$(jq -S --arg n "$name" "[.. | objects | select(.reusable == true and .name == \$n)] | map($strip)" /tmp/base.pen) + b=$(jq -S --arg n "$name" "[.. | objects | select(.reusable == true and .name == \$n)] | map($strip)" "$pen") + [ "$a" != "$b" ] && changed="$changed$name"$'\n' + done < <(jq -r '[.. | objects | select(.reusable == true) | .name] | .[]' "$pen") + + if [ -n "$changed" ]; then + printf '\n## design mudou — COMPONENTES (confira o .tsx de mesmo nome)\n%s\n' "$changed" + fi +} + +if [ ${#FILES[@]} -eq 0 ]; then + echo "nenhum arquivo de código no diff" + { design_side; } > /tmp/drift-scan.txt + if [ -s /tmp/drift-scan.txt ]; then + echo; echo "=== mas o design andou ==="; cat /tmp/drift-scan.txt + fi + exit 0 +fi # Descarta linhas de comentário: o próprio código cita as regras nos # comentários ("NÃO os 56px de p-14"), e isso casaria com os padrões. @@ -48,6 +85,7 @@ hit 8 "prop className exposta (componente deve ser fechado)" \ # rounded-nav e rounded-full não são ambíguos; os outros colidem com o .pen hit 3 "radius na zona de colisão — conferir contra a tabela do §6" \ '\brounded-(xs|sm|md|lg|xl|2xl|3xl)\b' +design_side } > /tmp/drift-scan.txt # Regra 7, metade mecânica: todo data-component precisa existir como frame