diff --git a/AGENTS.md b/AGENTS.md index 7f17aec..784c678 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -34,13 +34,6 @@ 스타일 없는 페이지를 렌더한 것으로 기록된다. 보관 근거는 `out/assets/.builds.json` 대장이고 파일 mtime 이 아니다. → 재굽기는 여전히 필요하지만 **급하지 않다**. 디자인이 반영 안 될 뿐, 깨지지는 않는다. -- **★ 대장(`out/assets/.builds.json`)에 없는 자산은 지우지 않는다** — "지금 처음 본 것" 으로 - 치고 보관 기간을 새로 준다(`pruneAssets`). **이 규칙을 깨면 운영 사이트가 즉시 끊긴다.** - 실제로 그랬다(2026-09-07): 대장은 이 기능과 함께 생겼으므로 **배포 직후 첫 실행에는 대장이 - 없고**, 그때 디스크에 있던 기존 자산이 전부 "대장에 없음" 으로 분류돼 한꺼번에 삭제됐다. - 옛 자산을 남기려고 만든 코드가 첫 실행에서 정확히 반대로 동작했다. - → 자산을 지우는 코드를 손볼 때는 **"기록이 없다"와 "만료됐다"를 절대 같이 묶지 않는다.** - → 이미 끊겼다면 복구는 `docker compose restart solution-frontend` (기동하며 전체 재굽기). - **★ 프론트(`solution/site`)를 배포하면 반드시 전체 재굽기 + 전체 재업로드.** `azure_static.publish(slug)` 는 공용 자산 + `s/` 만 올린다 — **렌더러를 고쳐도 다른 사이트에는 반영되지 않는다.** diff --git a/docs/DEVLOG.md b/docs/DEVLOG.md index 234c61f..0d33e6c 100644 --- a/docs/DEVLOG.md +++ b/docs/DEVLOG.md @@ -5,32 +5,6 @@ --- -## 2026-09-07 — (사고) 자산 보관 첫 배포에 운영 사이트 CSS 가 끊겼다 - -**무슨 일** -바로 아래 항목(옛 해시 자산 30일 보관)을 배포하자 **기존 사이트의 CSS·JS 가 전부 404** 가 됐다. -옛 자산을 남기려고 만든 코드가 첫 실행에서 정확히 반대로 동작했다. - -**왜** -`pruneAssets` 가 "대장(`.builds.json`)에 없는 파일" 을 만료로 보고 지웠다. 그런데 **대장은 이 -기능과 함께 처음 생긴다** — 배포 직후 첫 실행에는 대장이 없으므로, 디스크에 있던 기존 자산이 -전부 "대장에 없음" 으로 분류돼 한꺼번에 삭제됐다. 아직 다시 굽지 않은 사이트는 그 순간 죽는다. - -**놓친 것** — 검증을 `out/` 을 비운 상태에서만 돌렸다. 재현해야 했던 건 빈 디렉토리가 아니라 -**"옛 자산은 있는데 대장은 없는"** 상태, 즉 실제 배포 직전의 서버 모습이었다. - -**고친 것** (`scripts/prerender.ts` `pruneAssets`) -- 대장에 없는 파일은 지우지 않고 **"지금 처음 본 것" 으로 입양해** 보관 기간을 새로 준다 -- 규칙으로 굳혀 둔다: **"기록이 없다" 와 "만료됐다" 를 같이 묶지 않는다**(AGENTS.md 함정 목록) - -**복구** — `docker compose restart solution-frontend` (기동하며 전체 재굽기 → HTML 이 새 해시를 -가리킨다). 자산을 되살리는 게 아니라 HTML 을 새로 굽는 쪽이 빠르다. - -**검증** — 배포 직전 상태를 재현: `out/assets` 에 옛 해시 파일만 두고 대장 없이 첫 실행 → -옛 파일 2개가 그대로 남고 대장에 입양 항목으로 들어간다. 재실행해도 대장이 늘지 않는다. - ---- - ## 2026-09-07 — 옛 해시 자산을 30일 남긴다 — 배포와 재굽기를 뗀다 **왜** diff --git a/solution/site/scripts/prerender.ts b/solution/site/scripts/prerender.ts index 495dc79..22941c6 100644 --- a/solution/site/scripts/prerender.ts +++ b/solution/site/scripts/prerender.ts @@ -531,8 +531,8 @@ function readAssetLedger(assetsDir: string): AssetBuild[] { }; return Array.isArray(parsed.builds) ? parsed.builds : []; } catch { - // 없거나 깨졌으면 빈 대장으로 시작한다. 디스크에 있던 파일은 pruneAssets 가 - // "처음 본 것" 으로 입양하므로 지워지지 않는다 — 그 ★ 주석이 이 실패의 근거다. + // 없거나 깨졌으면 이번 빌드부터 다시 센다. 옛 파일은 그대로 남는다 — + // 대장을 못 읽었다고 지우는 쪽으로 실패하면 사이트가 깨진다. return []; } } @@ -545,32 +545,13 @@ function readAssetLedger(assetsDir: string): AssetBuild[] { */ function pruneAssets(assetsDir: string, current: string[]) { const signature = (files: string[]) => [...files].sort().join('\n'); - const now = new Date().toISOString(); const previous = readAssetLedger(assetsDir); - const head: AssetBuild = {at: now, files: current}; + const head: AssetBuild = {at: new Date().toISOString(), files: current}; const builds = previous[0] && signature(previous[0].files) === signature(current) ? [head, ...previous.slice(1)] : [head, ...previous]; - /** - * ★ 대장에 없는 파일은 **지우지 않는다.** 언제 깔렸는지 모를 뿐이므로 지금 처음 본 것으로 - * 치고 보관 기간을 새로 준다. - * - * 이 줄이 없어서 실제로 운영 사이트가 끊겼다(2026-09-07). 대장은 이 기능과 함께 생겼으니 - * **배포 직후 첫 실행에는 대장이 없다** — 그때 디스크에 있던 기존 자산이 전부 "대장에 없음" - * 으로 분류돼 한꺼번에 삭제됐고, 아직 다시 굽지 않은 사이트의 CSS 가 통째로 404 가 됐다. - * 옛 자산을 남기려고 만든 코드가 첫 실행에서 정확히 반대로 동작했다. - */ - const recorded = new Set(builds.flatMap((build) => build.files)); - const adopted = listRelativeFiles(assetsDir).filter( - (file) => file !== ASSET_LEDGER && !recorded.has(file), - ); - if (adopted.length > 0) { - builds.push({at: now, files: adopted}); - console.log(` ✓ 대장에 없던 자산 ${adopted.length}개를 보관 대상으로 넣는다`); - } - const cutoff = Date.now() - ASSET_RETENTION_DAYS * 24 * 60 * 60 * 1000; const kept = builds.filter( (build, index) => index < ASSET_MIN_BUILDS || Date.parse(build.at) >= cutoff,