ci(windows): do not pre-create dist/node_modules before Defender exclusion

Run 25546676715 / job 74984469728 (Windows Studio UI CI / Chat UI Tests)
broke on the previous commit (2843e2a9). Symptom:

  install.log:  "frontend  up to date"
  studio.log:   FileNotFoundError:
                D:\\a\\unsloth\\unsloth\\studio\\frontend\\dist\\index.html
  Playwright:   TimeoutError waiting for "#new-password" (60s)

Root cause: the Pre-install Windows tweaks step's loop did

  if (-not (Test-Path $p)) { New-Item -ItemType Directory -Force -Path $p }
  Add-MpPreference -ExclusionPath $p

before install.ps1 ran. That created an empty studio/frontend/dist
directory whose mtime was newer than every source file. setup.ps1's
mtime-based "is the frontend stale?" check at studio/setup.ps1
line 1281-1296 then concluded "frontend up to date, skip rebuild",
so vite never wrote anything into dist. Studio booted with an empty
dist directory and crashed on GET /change-password (the static-file
handler at studio/backend/main.py:489 read_bytes()'d a non-existent
index.html).

The same trap broke the frontend-dist actions/cache attempt earlier
in this branch (commit d65f8b19 -> reverted in e1345d5f). Same root
cause: any process that puts a fresh-mtime directory at
studio/frontend/dist before the build silences the Vite rebuild.

Fix: drop the New-Item call. Add-MpPreference accepts paths that do
not yet exist; the exclusion is registered and applies when the path
materialises. The failure is bisected to this single line, and reverting
just that line restores green.

Applied identically to all 4 Windows workflows so api/ui/update/inference
jobs all stay green.
This commit is contained in:
Daniel Han 2026-05-08 09:08:46 +00:00
commit 4e1f1e959a
4 changed files with 41 additions and 6 deletions

View file

@ -89,6 +89,12 @@ jobs:
Write-Host "npm version before upgrade: $(npm -v)"
npm install -g 'npm@^11' 2>&1 | Out-Host
Write-Host "npm version after upgrade: $(npm -v)"
# NOTE: do NOT pre-create these directories. See
# studio-windows-update-smoke.yml for the full rationale --
# creating an empty studio/frontend/dist trips setup.ps1's
# mtime-based staleness check into "frontend up to date, skip
# rebuild" and Studio boots with an empty dist directory.
# Add-MpPreference accepts paths that do not yet exist.
foreach ($p in @(
"$env:USERPROFILE\.unsloth",
"$env:USERPROFILE\AppData\Local\uv",
@ -96,7 +102,6 @@ jobs:
"$env:GITHUB_WORKSPACE\studio\frontend\dist"
)) {
try {
if (-not (Test-Path $p)) { New-Item -ItemType Directory -Force -Path $p | Out-Null }
Add-MpPreference -ExclusionPath $p -ErrorAction Stop
Write-Host "Defender exclusion added: $p"
} catch {

View file

@ -99,6 +99,12 @@ jobs:
Write-Host "npm version before upgrade: $(npm -v)"
npm install -g 'npm@^11' 2>&1 | Out-Host
Write-Host "npm version after upgrade: $(npm -v)"
# NOTE: do NOT pre-create these directories. See
# studio-windows-update-smoke.yml for the full rationale --
# creating an empty studio/frontend/dist trips setup.ps1's
# mtime-based staleness check into "frontend up to date, skip
# rebuild" and Studio boots with an empty dist directory.
# Add-MpPreference accepts paths that do not yet exist.
foreach ($p in @(
"$env:USERPROFILE\.unsloth",
"$env:USERPROFILE\AppData\Local\uv",
@ -106,7 +112,6 @@ jobs:
"$env:GITHUB_WORKSPACE\studio\frontend\dist"
)) {
try {
if (-not (Test-Path $p)) { New-Item -ItemType Directory -Force -Path $p | Out-Null }
Add-MpPreference -ExclusionPath $p -ErrorAction Stop
Write-Host "Defender exclusion added: $p"
} catch {
@ -390,6 +395,12 @@ jobs:
Write-Host "npm version before upgrade: $(npm -v)"
npm install -g 'npm@^11' 2>&1 | Out-Host
Write-Host "npm version after upgrade: $(npm -v)"
# NOTE: do NOT pre-create these directories. See
# studio-windows-update-smoke.yml for the full rationale --
# creating an empty studio/frontend/dist trips setup.ps1's
# mtime-based staleness check into "frontend up to date, skip
# rebuild" and Studio boots with an empty dist directory.
# Add-MpPreference accepts paths that do not yet exist.
foreach ($p in @(
"$env:USERPROFILE\.unsloth",
"$env:USERPROFILE\AppData\Local\uv",
@ -397,7 +408,6 @@ jobs:
"$env:GITHUB_WORKSPACE\studio\frontend\dist"
)) {
try {
if (-not (Test-Path $p)) { New-Item -ItemType Directory -Force -Path $p | Out-Null }
Add-MpPreference -ExclusionPath $p -ErrorAction Stop
Write-Host "Defender exclusion added: $p"
} catch {
@ -763,6 +773,12 @@ jobs:
Write-Host "npm version before upgrade: $(npm -v)"
npm install -g 'npm@^11' 2>&1 | Out-Host
Write-Host "npm version after upgrade: $(npm -v)"
# NOTE: do NOT pre-create these directories. See
# studio-windows-update-smoke.yml for the full rationale --
# creating an empty studio/frontend/dist trips setup.ps1's
# mtime-based staleness check into "frontend up to date, skip
# rebuild" and Studio boots with an empty dist directory.
# Add-MpPreference accepts paths that do not yet exist.
foreach ($p in @(
"$env:USERPROFILE\.unsloth",
"$env:USERPROFILE\AppData\Local\uv",
@ -770,7 +786,6 @@ jobs:
"$env:GITHUB_WORKSPACE\studio\frontend\dist"
)) {
try {
if (-not (Test-Path $p)) { New-Item -ItemType Directory -Force -Path $p | Out-Null }
Add-MpPreference -ExclusionPath $p -ErrorAction Stop
Write-Host "Defender exclusion added: $p"
} catch {

View file

@ -98,6 +98,12 @@ jobs:
Write-Host "npm version before upgrade: $(npm -v)"
npm install -g 'npm@^11' 2>&1 | Out-Host
Write-Host "npm version after upgrade: $(npm -v)"
# NOTE: do NOT pre-create these directories. See
# studio-windows-update-smoke.yml for the full rationale --
# creating an empty studio/frontend/dist trips setup.ps1's
# mtime-based staleness check into "frontend up to date, skip
# rebuild" and Studio boots with an empty dist directory.
# Add-MpPreference accepts paths that do not yet exist.
foreach ($p in @(
"$env:USERPROFILE\.unsloth",
"$env:USERPROFILE\AppData\Local\uv",
@ -105,7 +111,6 @@ jobs:
"$env:GITHUB_WORKSPACE\studio\frontend\dist"
)) {
try {
if (-not (Test-Path $p)) { New-Item -ItemType Directory -Force -Path $p | Out-Null }
Add-MpPreference -ExclusionPath $p -ErrorAction Stop
Write-Host "Defender exclusion added: $p"
} catch {

View file

@ -103,6 +103,17 @@ jobs:
Write-Host "npm version before upgrade: $(npm -v)"
npm install -g 'npm@^11' 2>&1 | Out-Host
Write-Host "npm version after upgrade: $(npm -v)"
# NOTE: do NOT pre-create these directories before adding the
# exclusion -- creating an empty studio/frontend/dist trips
# setup.ps1 line 1281-1296's mtime-based "is the frontend
# stale?" check into "up to date, skip rebuild", because the
# newly-created dist's mtime is younger than every source
# file. Studio then boots with an empty dist and 500s on
# GET / with FileNotFoundError: dist\index.html. See run
# 25546676715 / job 74984469728.
# Add-MpPreference accepts paths that do not yet exist; the
# exclusion is registered and applies when the path
# materialises.
foreach ($p in @(
"$env:USERPROFILE\.unsloth",
"$env:USERPROFILE\AppData\Local\uv",
@ -110,7 +121,6 @@ jobs:
"$env:GITHUB_WORKSPACE\studio\frontend\dist"
)) {
try {
if (-not (Test-Path $p)) { New-Item -ItemType Directory -Force -Path $p | Out-Null }
Add-MpPreference -ExclusionPath $p -ErrorAction Stop
Write-Host "Defender exclusion added: $p"
} catch {