From d7a4064616b9e96d790471e2e9d5e6785192959d Mon Sep 17 00:00:00 2001 From: ducoterra Date: Mon, 24 Aug 2026 22:54:30 -0400 Subject: [PATCH] =?UTF-8?q?fix(build):=20Containerfile=20builds=20again=20?= =?UTF-8?q?=E2=80=94=20relative=20module=20imports,=20all=20four=20pages?= =?UTF-8?q?=20and=20shared=20assets=20in=20the=20image?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../01_fix_containerfile_build.md | 0 .../todo/22_background_animation/00_phase.md | 114 ------- .../02_e2e_story_suite_commit.md | 68 ---- .../23_containerfile_build/phase_report.md | 120 +++++++ .agent/user_stories/containerfile-build.md | 131 ++++++++ Containerfile | 15 +- frontend/assets/app.js | 2 +- frontend/assets/document.js | 2 +- frontend/assets/login.js | 2 +- frontend/assets/sources.js | 2 +- frontend/document.html | 7 +- frontend/index.html | 7 +- frontend/login.html | 5 +- frontend/sources.html | 7 +- .../integration/test_containerfile_assets.py | 303 ++++++++++++++++++ tests/unit/test_shared_header.py | 53 ++- 16 files changed, 616 insertions(+), 222 deletions(-) rename .agent/phases/{todo => complete}/23_containerfile_build/01_fix_containerfile_build.md (100%) delete mode 100644 .agent/phases/todo/22_background_animation/00_phase.md delete mode 100644 .agent/phases/todo/22_background_animation/02_e2e_story_suite_commit.md create mode 100644 .agent/reports/23_containerfile_build/phase_report.md create mode 100644 .agent/user_stories/containerfile-build.md create mode 100644 tests/integration/test_containerfile_assets.py diff --git a/.agent/phases/todo/23_containerfile_build/01_fix_containerfile_build.md b/.agent/phases/complete/23_containerfile_build/01_fix_containerfile_build.md similarity index 100% rename from .agent/phases/todo/23_containerfile_build/01_fix_containerfile_build.md rename to .agent/phases/complete/23_containerfile_build/01_fix_containerfile_build.md diff --git a/.agent/phases/todo/22_background_animation/00_phase.md b/.agent/phases/todo/22_background_animation/00_phase.md deleted file mode 100644 index a9007b9..0000000 --- a/.agent/phases/todo/22_background_animation/00_phase.md +++ /dev/null @@ -1,114 +0,0 @@ -# Phase 22 — Animated Background: Make It Actually Animate - -**Source:** `TODO.md` L5 — *"Fix background animation not working, just -blinking"* -**Story:** `.agent/user_stories/background-animation.md` (created by task 02) -**Context:** `frontend/assets/styles.css` — the phase-08 animated -background block (~lines 60–100): `body::before` (44px drifting grid, -1px lines at ~35% `--line` alpha, radial mask -`radial-gradient(120% 90% at 50% 0%, black 25%, transparent 78%)`, -`animation: bg-grid-drift 60s linear infinite`) and `body::after` (two -soft radial glows, `animation: bg-glow-breathe 14s ease-in-out infinite -alternate`, opacity 0.65↔1 + scale 1↔1.05). Both layers are -`position: fixed; inset: 0; z-index: -1; pointer-events: none`. `html` -owns the `var(--bg)` canvas and `body` is `background: transparent` -(~lines 42–54) — if any later rule occludes that, the layers vanish. -The **phase-08 design comments are the spec** for what "working" means. - -## Objective -Owner report 2026-08-24: the background "just blinks" — i.e. the motion -the phase-08 design promised (a slow, seamless grid drift + a gentle -glow breathe) is not perceived; at most a flicker/blink is visible. -Diagnose which layer(s) actually fail in a real Chromium viewport, fix -the CSS, and leave a background that visibly and smoothly animates as -designed — no blink, no static frame, no jank. - -## Owner-confirmed (2026-08-24, roadmap A3) -1. **Intended effect = the phase-08 design comments:** seamless 60s grid - drift (one cell per loop) + 14s ease glow breathing. The fix serves - that design, not a redesign. -2. **Pure CSS, zero JS** (phase-08 anchor) — no animation JS, no new - assets, no `filter: blur` (perf note in the block). - -## Design / diagnostic plan -The fix is found, not guessed — work through this checklist in a real -Chromium window (dev server, full page, ~15s of observation): -1. **Per-layer visibility:** toggle each pseudo-element (DevTools - generated-content / a temp outline) and screenshot — is the grid - visible at all? Is only the glow (the "blink" the user perceives) - alive? -2. **Grid layer:** sample `background-position` on `body::before` at two - timestamps — is it actually moving? Is the radial mask fading the - visible region so small that the 44px/60s drift is imperceptible? - (If the drift is real but too faint: raise the grid line alpha and/or - the mask's visible radius — smallest change that reads as "smooth - drift".) -3. **Glow layer:** is the 14s breathe reading as a *blink*? (If the - opacity swing 0.65↔1 is perceived as pulsing: lengthen the period - and/or narrow the opacity delta so it reads as breathing.) -4. **Occlusion check:** confirm nothing later in `styles.css` (or in - `html`/`body` rules) paints an opaque background over the - `z-index: -1` layers — the phase-08 comment at ~line 42 is the - contract. -5. **Apply the fix in `styles.css`** — document the found root cause in - the phase report (screenshot before/after in - `.agent/screenshots/22_background_animation/`). - -## Dependencies -- `08_story_dark_tech_theme` (complete) — owns the layers, the palette, - and the "pure CSS, zero JS" anchor this phase must respect. -- `07_story_responsive_polish` (complete) — no new overflow at 360px - (both layers are `fixed; inset: 0` — keep it that way). - -## Tasks -1. `01_fix_background_animation.md` — diagnosis + the CSS fix + - source-level unit pins. -2. `02_e2e_story_suite_commit.md` — `tests/e2e/test_background_animation.py` - (the story gate, isolated), regression suites, story file, final - validation, the single atomic commit, phase move to `complete/`. - -## Locked decisions -- **Phase-08 anchor honored** — pure CSS, zero JS, no `filter: blur`, - WCAG AA palette untouched (background layers carry no text). - **A11 untouched** — no CDN, no new assets. **A16 honored** — one new - story E2E suite + adapted regressions. No anchor changed. - -## Testing & Quality -- **Unit (source-level, new `tests/unit/test_background_animation.py`, - repo source-pin pattern):** `styles.css` still defines - `@keyframes bg-grid-drift` and `@keyframes bg-glow-breathe`; - `body::before` animates `bg-grid-drift` with `linear infinite`; - `body::after` animates `bg-glow-breathe`; both layers remain - `position: fixed; z-index: -1; pointer-events: none`; `html` keeps - `background: var(--bg)` and `body` keeps `background: transparent` - (the no-occlusion contract). Pin the **final** values the fix lands - on (durations/opacities may move per the design plan). -- **Integration:** none (no `app/` changes). -- **Coverage:** frontend-only; the >90% `app/` gate is unaffected. -- **E2E:** `tests/e2e/test_background_animation.py` (task 02), green - **in isolation** (prereq `podman compose up -d db`). -- **Lint/types:** `uv run ruff check . && uv run pyright` clean. - -## Completion Criteria -- [ ] In a real Chromium viewport, the background visibly and smoothly - animates (grid drift + glow breathe) — screenshot before/after in - the phase report; owner's "just blinking" perception gone. -- [ ] Root cause documented in `.agent/reports/22_background_animation/`. -- [ ] `uv run pytest` green; `uv run pytest --cov=app - --cov-report=term-missing` ≥ today's number. -- [ ] `uv run pytest tests/e2e/test_background_animation.py -v --no-cov` - green in isolation; regressions green in isolation: - `test_dark_tech_theme.py`, `test_responsive_polish.py`. -- [ ] `uv run ruff check . && uv run pyright` clean. -- [ ] UI Structure Check (AGENTS.md rule 5): layers stay behind content - (`z-index: -1`, `pointer-events: none`), no text/contrast impact, - no 360px overflow. -- [ ] `.agent/user_stories/background-animation.md` exists. -- [ ] One `--no-gpg-sign` commit (below); - `.agent/phases/todo/22_background_animation/` moved to - `.agent/phases/complete/`. - -## Commit -```bash -git add -A .agent/ frontend/ tests/ && git commit --no-gpg-sign -m "fix(ui): animated background actually animates — grid drift and glow breathe per the phase-08 design" -``` diff --git a/.agent/phases/todo/22_background_animation/02_e2e_story_suite_commit.md b/.agent/phases/todo/22_background_animation/02_e2e_story_suite_commit.md deleted file mode 100644 index 8124519..0000000 --- a/.agent/phases/todo/22_background_animation/02_e2e_story_suite_commit.md +++ /dev/null @@ -1,68 +0,0 @@ -# Task 02 — E2E story suite, story file, validation, commit - -**Phase:** `22_background_animation` · **Source:** `TODO.md` L5 - -## Objective -The story gate: `tests/e2e/test_background_animation.py` proves both -background layers are actually running animations (not just declared), -plus regressions, story file, final validation, and the single atomic -commit. - -## Work -1. `tests/e2e/test_background_animation.py` (new). The layers are CSS - pseudo-elements, so assert via computed style + the Web Animations - API (Chromium reports pseudo-element CSS animations through - `element.getAnimations()`): - 1. `test_grid_layer_animation_running` — - `getComputedStyle(document.body, "::before").animationName` is the - grid-drift keyframe (final name from task 01), timing function - `linear`, iteration count `infinite`; and a matching entry in - `document.body.getAnimations()` with `playState === "running"`. - 2. `test_glow_layer_animation_running` — same for `"::after"` with - the glow-breathe keyframe; `playState === "running"`. - 3. `test_animations_advance` — sample `animation.currentTime` (or - the `getAnimations()` entry's `currentTime`) for both layers, - wait ~500ms (`page.wait_for_timeout`), assert both advanced — - the animations are truly running, not paused. - 4. `test_background_layers_contracts` — both pseudo-elements: - `position: fixed`, `z-index: -1`, `pointer-events: none`; - `document.documentElement` computed `background-color` is the - palette bg (the canvas stays on `html`); `document.body` computed - `background-color` is `rgba(0, 0, 0, 0)` (no occlusion). - 5. `test_no_horizontal_overflow_with_layers` (regression, 360px) — - viewport 360px: `document.documentElement.scrollWidth <= - clientWidth` (the phase-07 pin, replicated locally). -2. `.agent/user_stories/background-animation.md` (new) — story file per - the repo format: goal, the bug report verbatim from `TODO.md` L5, the - owner-confirmed A3 decisions + the found root cause (from task 01's - report), E2E mapping table. -3. Run the suite **in isolation** (prereq `podman compose up -d db`): - `uv run pytest tests/e2e/test_background_animation.py -v --no-cov`. -4. Regressions, in isolation, one command each: - - `uv run pytest tests/e2e/test_dark_tech_theme.py -v --no-cov` - - `uv run pytest tests/e2e/test_responsive_polish.py -v --no-cov` -5. Final validation: `uv run pytest` green; `uv run pytest --cov=app - --cov-report=term-missing` ≥ today's number (>90% gate); - `uv run ruff check . && uv run pyright` clean. -6. **UI Structure Check** (AGENTS.md rule 5): layers stay behind - content, no text/contrast impact, no overflow at 360px. -7. Finish the phase report (`.agent/reports/22_background_animation/` — - E2E results + the task-01 screenshots). -8. Commit (one atomic commit) and move the phase: - ```bash - git add -A .agent/ frontend/ tests/ - git commit --no-gpg-sign -m "fix(ui): animated background actually animates — grid drift and glow breathe per the phase-08 design" - mv .agent/phases/todo/22_background_animation .agent/phases/complete/ - ``` - -## Testing & Quality -- Story suite green **in isolation**; both regression suites green in - isolation; full unit+integration suite green; `app/` coverage at or - above today's number (>90%); ruff + pyright clean. - -## Completion Criteria -- [ ] `test_background_animation.py` 5/5 in isolation. -- [ ] Regressions (dark tech theme, responsive polish) green in - isolation. -- [ ] Story file + phase report (with screenshots) exist. -- [ ] One `--no-gpg-sign` commit; phase directory in `complete/`. diff --git a/.agent/reports/23_containerfile_build/phase_report.md b/.agent/reports/23_containerfile_build/phase_report.md new file mode 100644 index 0000000..4df17cb --- /dev/null +++ b/.agent/reports/23_containerfile_build/phase_report.md @@ -0,0 +1,120 @@ +# Phase 23 report — Containerfile: build the whole app image again + +**Date:** 2026-08-24 · **Source:** `TODO.md` L6 ("Fix Containerfile build +not working") · **Story:** `.agent/user_stories/containerfile-build.md` + +## Root cause (verified, not guessed — logs in this directory) + +1. **Build failure:** phase 19's absolute `import … from + "/assets/header.js"` is resolved by esbuild as the *filesystem* path + `/assets/header.js` → `✘ [ERROR] Could not resolve "/assets/header.js"`, + reproduced with the exact pinned esbuild **0.25.5** + (`repro_esbuild_0.25.5.log`, `repro_podman_build_before_fix.log`). +2. **Under-shipped image:** stage 1 bundled only `app.js` + + `sources.js` and copied only `index.html` + `sources.html` — + `document.html` / `login.html` / `document.js` / `login.js` / + `markdown.js` were all missing from the image. +3. **Double-evaluation trap:** the four direct ` - - + diff --git a/frontend/index.html b/frontend/index.html index 45aae95..b278c66 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -113,10 +113,9 @@ - - + diff --git a/frontend/login.html b/frontend/login.html index 4853620..dc5894e 100644 --- a/frontend/login.html +++ b/frontend/login.html @@ -63,8 +63,9 @@ - + none appear). It loads through the page script's own + `import "./header.js"` (hoisted, evaluated before the page script + body calls initSharedHeader() at boot). --> diff --git a/frontend/sources.html b/frontend/sources.html index 40caa42..fb688f3 100644 --- a/frontend/sources.html +++ b/frontend/sources.html @@ -119,10 +119,9 @@ - - + diff --git a/tests/integration/test_containerfile_assets.py b/tests/integration/test_containerfile_assets.py new file mode 100644 index 0000000..b0e20c3 --- /dev/null +++ b/tests/integration/test_containerfile_assets.py @@ -0,0 +1,303 @@ +"""Integration: Containerfile stage-1 (frontend) asset coverage pin (phase 23). + +HERMETIC — no podman, no network, no database: this suite parses the +``Containerfile`` and ``frontend/`` as plain text and pins the image-build +coverage that the TODO L6 bug ("Fix Containerfile build not working") +demonstrated can silently rot in two independent ways: + +* the stage-1 ``cp`` line only copies the pages that existed when it was + written (``document.html`` / ``login.html`` + their scripts + + ``markdown.js`` were all missing from the image), and +* absolute module imports (``import … from "/assets/header.js"``) break + the esbuild bundle, so a "fixed" stage 1 can still ship a broken page. + +The pins (each is one test, per the phase-23 task file): + +1. every ``frontend/*.html`` page is copied into stage 1's ``/out`` + — exactly (a new page without a ``cp`` entry fails; a ``cp`` of a + deleted page also fails); +2. every local ``assets/`` / ``/assets/`` ``src=``/``href=`` reference in + the pages is produced by a stage-1 line (``esbuild … --outfile`` or + ``cp``) — the missing-``markdown.js``-style gap cannot reappear; +3. the set of ``type="module"`` page scripts the HTML references equals + the set of inputs esbuild ``--bundle``s in stage 1; +4. ``header.js`` is imported relatively by every page script and loaded + by NO direct ``