web-deploy Focus-Page Icon Deploy Efficiency + Astro Patch Bump
Section titled “web-deploy Focus-Page Icon Deploy Efficiency + Astro Patch Bump”What was fixed
Section titled “What was fixed”Talbot noticed every focus-page deploy seemed to “regenerate” a series of icons and asked for
an efficiency audit. The real cause wasn’t regeneration — Astro just copies static files from
public/ to dist/, which is near-instant. The waste was in the FTP deploy step:
deploy_sdc_focus.py / deploy_mbr_focus.py spawned a brand-new subprocess + fresh FTP
connect/login for every one of the 13 favicon/PWA icon files, on every single deploy,
regardless of whether content had changed. Visible in deployment.log as the same 13 files
re-”deployed” every run — that’s what read as regeneration.
Fix: added focus-deploy/icon_manifest.py (sha256-based skip logic) and refactored both
deploy scripts to open one FTP connection per run instead of one per file, importing
ftp_deploy.py’s functions directly rather than shelling out to a subprocess per icon. A
manifest hit still triggers a cheap FTP SIZE check (control-channel only, no data transfer)
before skipping — so a manually deleted/corrupted remote icon is still caught and re-uploaded,
preserving the single-source-of-truth guarantee without paying for a full re-upload every time.
focus.html still deploys unconditionally every run (its content is expected to change).
Also investigated the “upgrade dependencies like Vite” part of the ask: no direct vite
dependency exists anywhere in the monorepo (it’s bundled transitively via astro). Found
astro pinned to 7.0.6 with 7.0.7 available — a pure patch (verified via upstream
changelog: fixes a lightningcss CSS-module hash bug, unused here) — and bumped it across all
four sites (template, sdc, mbr, ts). Other outdated deps (tailwindcss 3→4,
typescript 5→7, eslint 9→10, wrangler 3→4) are all major-version bumps with likely
breaking changes — left alone as out of scope for a low-risk ops task.
Tested end-to-end against production (both SDC and MBR): cold run uploads all 13 icons +
builds the manifest; immediate re-run uploads 0/13 (all skipped), only focus.html deploys;
a single modified favicon triggers exactly 1/13 re-uploads; restoring the original content
correctly re-triggers a re-upload back to the byte-identical original. Re-ran again after the
astro bump to confirm the skip logic still works on 7.0.7. Both live pages verified 200
throughout.
Efficiency win: a typical deploy with unchanged icons now opens 1 FTP connection instead of 14, and transfers 1 file instead of 14.
While cleaning up for commit, also caught and fixed: focus-deploy/deployment.log was a
tracked, ever-growing log file dirtying the repo on every deploy — untracked it
(git rm --cached) and added it to .gitignore (kept locally). Also picked up an unrelated,
previously-uncommitted focus-deploy/README.md rewrite that had been sitting in the working
tree since the sdc-mission-deploy → focus-deploy rename (4315574) — the committed
version was still describing the old, pre-rename folder.
Files changed
Section titled “Files changed”web-deploy repo (commit fdf12ce):
focus-deploy/icon_manifest.py(new) — hash-based upload-skip + drift-check logicfocus-deploy/deploy_sdc_focus.py,focus-deploy/deploy_mbr_focus.py— single FTP connection per run, direct function imports instead of subprocess-per-filefocus-deploy/.gitignore— excludes.icon-manifest-*.json(local cache) anddeployment.log(now untracked)focus-deploy/README.md— rewritten to describe the current focus-deploy setup + document icon-skip behaviorCHANGELOG.md(0.4.1),pyproject.toml(version bump, closing a pre-existing 0.3.3 → 0.4.0 drift between the two files)
monorepo repo (commit 147382b):
sites/{template,sdc,mbr,ts}/package.json,pnpm-lock.yaml— astro7.0.6→7.0.7sites/mbr/src/data/rates.generated.json— refreshed automatically by mbr’s ownprebuildhook (sync-rates.mjs) during test builds; routinely-committed live data, not hand-editedCHANGELOG.md
Left out of both commits (pre-existing, unrelated, present before this session started):
config.yaml and submodule pointers kb-business/kb-mbr in web-deploy; untracked
.vscode/ in monorepo.
Key gotchas
Section titled “Key gotchas”- A per-file subprocess + fresh FTP connect/login is a silent, compounding cost that looks like “regeneration” from the outside. If a deploy script’s per-file loop shells out to a helper script instead of reusing one connection, every additional static asset (icons, manifests, cache-config files) multiplies connection overhead linearly — profile the actual bottleneck (connections/transfers) before assuming a build step is slow.
- A hash-manifest skip should not blindly trust its own cache. A lightweight remote check
(FTP
SIZE, here — cheap because it’s control-channel only) before skipping preserves “what’s live matches what we think is live” even if the manifest itself never lies about local state — protects against out-of-band remote drift (manual deletion, corruption, another process touching the same path). - Check
git statusfor pre-existing dirty/uncommitted state before scoping a task’s commit. This repo had 3 unrelated pre-existing uncommitted changes (config.yaml,kb-business,kb-mbrsubmodule pointers) sitting from before the task started, plus one relevant orphaned change (README.mdrewrite from a prior rename that was never committed) mixed into the same file being edited. Stage by explicit filename, notgit add -A/git add ., so task-scoped commits don’t silently sweep in unrelated work — but do fold in genuinely-related orphaned changes rather than re-doing them. pyproject.tomlversion andCHANGELOG.md’s latest entry can drift (found at 0.3.3 vs. 0.4.0 here) if a past session added a changelog entry without bumping the version file, or vice versa. Worth a quick diff-check before adding a new version bump.