From 7984a7d2df20355aeaf40968b49ff272b4c92fbc Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Sun, 5 Jul 2026 21:28:17 +0200 Subject: [PATCH] =?UTF-8?q?docs(memory):=20capitalize=20tour=20residuals?= =?UTF-8?q?=20=E2=80=94=20BDR-006/007,=20LRN-003,=20journal,=20TOUR=20foll?= =?UTF-8?q?ow-up?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BDR-006 supersedes BDR-004 infra detail (hardened container: nginx-unprivileged :1.28 / port 8080 / uid 101) — closes reconcile REC-1. BDR-007 supersedes BDR-003 geo (canonical = Nantes relocation) — records the CLN-9 owner decision. LRN-003: prove CSS cleanup behavior-preserving via before/after PDF render-hash. journal 2026-07-05; TOUR.md follow-up documenting all 5 residuals closed. --- .claude/audits/TOUR.md | 15 +++++++++++++++ .claude/memory/decisions.md | 24 ++++++++++++++++++++++++ .claude/memory/journal.md | 8 ++++++++ .claude/memory/learnings.md | 10 ++++++++++ 4 files changed, 57 insertions(+) diff --git a/.claude/audits/TOUR.md b/.claude/audits/TOUR.md index 0755f1b..b439f72 100644 --- a/.claude/audits/TOUR.md +++ b/.claude/audits/TOUR.md @@ -152,3 +152,18 @@ CSS braces balanced. No automated tests/lint/build (static site). Commits: 2 (clean 30b0e44 + this report). BREAKING: 0. Branch left UNMERGED. Scratch reports (.tour-semgrep, .tour-clean, .tour-semgrep-it2) folded here then deleted (STEP 3.2). + +## Follow-up 2026-07-05-2 — all 5 residuals closed (chore/tour-2026-07-05-2, owner GO) + +| ID | Resolution | +|----|-----------| +| CLN-6 | `aria-hidden="true"` added to the 2 decorative CTA arrows (match sibling download arrow). Visual identical, a11y-tree only. Commit `607124a`. | +| CLN-7 | `.footer` bg `#061008` → `var(--dark)` #0d1b12 (the design-system footer color). Commit `ede7576`. | +| CLN-8 | CV off-palette → tokens: `.tag` border `#a8d4bc` → `var(--g300)` (nearest visible green); body+print texture `rgba(26,71,48,.05)` → `rgba(27,94,59,.05)` (--g700); gradient stops `#edeadf`/`#f2efe6` → `var(--tag)`/`var(--page)`. PDF regenerated, render verified (2 pages, layout intact, page-1 eyeballed). Commit `ede7576`. | +| CLN-9 | Owner chose the CV wording as canonical (Option B): landing about-para + callout aligned to "installation région nantaise prévue" + "hybride Nantes"; `CLAUDE.md` geography note updated to match. CV unchanged. Commit `f515875` → BDR-007. | +| REC-1 | BDR-004 drift resolved by superseding entry **BDR-006** (nginx-unprivileged:1.28 / port 8080 / uid 101). | +| REC-2 | BDR-002 "box-shadow warning" note now historical (declaration removed in `30b0e44`) — left as-is (append-only registry), noted here. | + +Checks: CSP-hash MATCH, braces balanced (index 204/204, CV 68/68), PDF 2 pages. +Commits: 3 fixes (`607124a`/`ede7576`/`f515875`) + capitalize (BDR-006/007, LRN-003, +journal) + this follow-up. Branch finished → develop + pushed on owner GO. diff --git a/.claude/memory/decisions.md b/.claude/memory/decisions.md index 565faed..a1ce7cb 100644 --- a/.claude/memory/decisions.md +++ b/.claude/memory/decisions.md @@ -27,6 +27,8 @@ rules: | BDR-003 | 2026-05-15 | Position pro: CDI prioritaire, freelance parallèle | accepted | | BDR-004 | 2026-05-15 | Containerize site with nginx:alpine behind reverse proxy | accepted | | BDR-005 | 2026-05-17 | Favicon: SVG primary + PIL raster fallback | accepted | +| BDR-006 | 2026-07-05 | Hardened container: nginx-unprivileged + port 8080 | accepted (supersedes BDR-004 infra detail) | +| BDR-007 | 2026-07-05 | Profile geo canonical: Nantes relocation | accepted (supersedes BDR-003 geo) | --- @@ -95,3 +97,25 @@ rules: - Online favicon generator — external dep, opaque rendering, no source control. - **CV HTML**: not modified (user's WIP M state). Browser auto-fetches `/favicon.ico` from root → CV tab still shows icon. Link block mirror logged in `.claude/tasks/TODO.md` for later. - **Reference**: `favicon.svg`, `favicon-32.png`, `favicon.ico`, `apple-touch-icon.png`, `index.html` head, commit `ef31fb3`. + +--- + +## BDR-006 — Hardened container: nginx-unprivileged base + port 8080 + +- **Date**: 2026-07-05 +- **Status**: accepted — supersedes the base-image/port detail of BDR-004 +- **Decision**: Container base = `nginxinc/nginx-unprivileged:1.28-alpine` (digest-pinned), runs as uid 101, listens on **8080** (not 80). Compose maps `127.0.0.1:${PORT}:8080`; `USER root` scoped to the one build-time `rm` only; `cap_add` dropped; `server_tokens off`; `set_real_ip_from 127.0.0.1`; `nginx-security-headers.conf` re-included per `location`; CSP `script-src` hash-pinned. +- **Why**: SEC-1 tour finding — stock `nginx:*-alpine` runs its master as root inside the container. Unprivileged image + port 8080 removes the root master; the rest shrinks blast radius. BDR-004's "port 80 / nginx:1.27-alpine / HSTS omitted at container" no longer matched the tree. +- **Supersedes**: BDR-004 — topology unchanged (native front proxy → container on loopback); only the base image, internal port, and uid change. +- **Reference**: `Dockerfile`, `docker-compose.yml`, `nginx.conf`, `nginx-security-headers.conf`. Fix commit `ba13d69`; drift caught by tour REC-1 (`.claude/audits/TOUR.md`, run 2026-07-05-2). + +--- + +## BDR-007 — Profile geo canonical: Nantes relocation + +- **Date**: 2026-07-05 +- **Status**: accepted — supersedes the geography detail of BDR-003 +- **Decision**: Canonical profile geo = "Yerres (91) now; installation région nantaise prévue à moyen terme; full remote, hybride possible sur Nantes, ou 1–2 j/mois Paris." CV was the source of truth; `index.html` + `CLAUDE.md` aligned to it. +- **Why**: tour CLN-9 found the landing ("mobilité Pays de la Loire") drifting from the CV ("installation région nantaise" + "hybride Nantes"). Owner chose the CV wording as truth — more current/specific, and Nantes ∈ Pays de la Loire so not contradictory. Cross-file profile-state consistency is a CLAUDE.md content rule. +- **Alternatives rejected**: align CV down to the landing (would delete real, more-specific relocation info). +- **Reference**: `index.html` (about para + about-callout), `CV_Bastien_Chanot.html`, `CLAUDE.md` geography note. Commit `f515875`. diff --git a/.claude/memory/journal.md b/.claude/memory/journal.md index f7857df..5ce64ad 100644 --- a/.claude/memory/journal.md +++ b/.claude/memory/journal.md @@ -33,3 +33,11 @@ rules: - Favicon set added (commit `ef31fb3`): SVG primary + PIL-generated PNG/ICO/apple-touch. Brand pulse-dot translated to icon. BDR-005 + LRN-002 logged. - CV files (`CV_Bastien_Chanot.html`, `.pdf`) untouched — user's WIP M state, off-scope per brief. - User pushed + reported favicon 404 in prod. Root cause: Dockerfile selective `COPY` whitelist never included favicon files. Fix shipped (commit `f1e4392`): COPY line appended + nginx long-cache rule for image assets. BLK-001 logged. VPS rebuild required. + +## 2026-07-05 + +- Grouped tours (security+clean+reconcile+doc): container hardened (SEC-1..7 → nginx-unprivileged:1.28 / port 8080 / uid 101, per-location security headers, `server_tokens off`, CSP script-src hash-pinned), palette + dead-code clean, README synced. Merged via chore/tour + chore/tour-residuals. Detail in `.claude/audits/TOUR.md`. +- Re-run tour (chore/tour-2026-07-05-2) CONVERGED 2 it: fresh semgrep PASS, dead CSS removed (`30b0e44`, render-hash proven behavior-preserving → LRN-003), reconcile caught BDR-004 drift, doc no-drift. +- Closed all 5 residuals on owner GO: CLN-6 aria-hidden CTA arrows (`607124a`), CLN-7/8 palette conformance (5 off-palette colors → tokens, PDF regen render-verified, `ede7576`), CLN-9 geo aligned landing→CV = Nantes relocation (`f515875`). +- Decided: BDR-006 (hardened container, supersedes BDR-004 infra), BDR-007 (geo canonical = Nantes, supersedes BDR-003 geo). +- Branch chore/tour-2026-07-05-2 finished → develop + pushed. diff --git a/.claude/memory/learnings.md b/.claude/memory/learnings.md index 538dfbd..3fd4fc1 100644 --- a/.claude/memory/learnings.md +++ b/.claude/memory/learnings.md @@ -21,6 +21,7 @@ rules: |----|------|---------|------------| | LRN-001 | 2026-05-15 | certbot --nginx matches `server_name`, not filename | nginx + certbot on multi-site VPS | | LRN-002 | 2026-05-17 | PIL supersample ×8 + Lanczos = clean icon antialiasing | Python stdlib icon generation | +| LRN-003 | 2026-07-05 | Prove CSS cleanup behavior-preserving via before/after PDF render-hash | weasyprint / paged-media PDF projects | --- @@ -39,3 +40,12 @@ rules: - **Pattern**: Render icon at 8× target size via `ImageDraw.rounded_rectangle` + `ellipse` on RGBA canvas, then `Image.resize((target, target), Image.LANCZOS)`. Output rivals `rsvg-convert` / `inkscape` for simple geometric shapes. Crisp at 16×16 favicon scale, no visible jaggies. - **Context**: Generated `favicon-32.png`, `apple-touch-icon.png` (180×180), `favicon.ico` (multi-size 16/24/32/48) for `bchanot.fr` from scratch — no `rsvg-convert` / `inkscape` / `ImageMagick` on host. Single PIL script, ~20 lines. - **Future application**: Any project needing a PNG/ICO icon set with a stdlib-only Python toolchain. Skip if shape is complex (text rendering, gradients, curves) — use `rsvg-convert` or commit a finalized PNG instead. + +--- + +## LRN-003 — Prove CSS cleanup is behavior-preserving via before/after PDF render-hash + +- **Date**: 2026-07-05 +- **Pattern**: To confirm a CSS/HTML edit is truly behavior-preserving on a project whose deliverable is a weasyprint PDF: render a baseline PDF from the pre-edit HTML, apply the edit, regenerate, then compare (a) `pdftotext | sha256` and (b) per-page `pdftoppm -r 150 -png | sha256`. Text-hash alone misses `font-size`/color changes — the render-hash catches them. Identical render-hash = provably no visual change; and since weasyprint output is deterministic, an unchanged render yields a byte-identical PDF → nothing new to commit. +- **Context**: tour clean phase on `bchanot-cv` removed dead CSS (`.reveal.d6`, `position:running()`, no-op `box-shadow`, dead `.skills-grid font-size`). Render-hash matched on both pages → proven before commit `30b0e44`. The same tooling later confirmed the intentional palette edit DID change the render (expected), distinguishing dead-code removal from real visual change. +- **Future application**: Any weasyprint / paged-media project where you must tell "dead code removal" (must render identically) apart from "intended visual change". General trick: verify a refactor by hashing the rendered artifact, not the source.