PDN migration — RESUME HANDOFF (written 2026-07-30)
Working handoff for the Porte de Novembre (portedenovembre.ch) migration. Read this first, then
.claude/docs/domain/pdn-migration-plan.mdand the memory notes it links. This file says: what is DONE, what is LEFT, HOW to do it, and a paste-ready resume prompt at the very bottom.
0. State of the branch (as of 2026-07-30)
- Branch
develop, NOT pushed (user pushes). User is sole commit author, NOCo-Authored-Bytrailer. - ~15 PDN commits landed this session (fonts, age-gate removal, interior hero, footer seed, card titles, bottles-media, wine-detail empty Détails, hero mask, probes). See the memory
gilliard-migration.mdtail (## 2026-07-29 — PDN RESUMED) for the exact commit list + hashes. - ⚠️ The working tree currently has UNCOMMITTED
.cshtmledits made by the USER / a linter (ASCII-ising comments across many views:_MasterLayout,main.scss,childListing,BlogPost,Event,card,cardCollection,ctaBanner,HomePage,_listCard, ...). Do NOT revert or commit these — they are the user's. Reconcile before committing your own work (they may have committed by resume time).
⚠️ 1. CONCURRENCY — check before touching the server/DB
The user was doing backoffice work in a concurrent session. Before ANY of these, confirm it is safe:
GET /seed-pdn— overwrites backoffice content changes.dotnet build/ restarting the dev server — locksbin/Web.exeand interrupts their session.- Any DB write.
Read-only work (measuring LIVE, curl/Playwright GET of local pages, reading files) is fine anytime, but a concurrent re-publish can shift local pages under you.
2. THE DISCIPLINE (do not shortcut — this is why the last pass was criticised)
The home was gated on the pixel harness and that MISSED real defects, because the harness is blind to:
- Masked regions' internals. The Slider Revolution hero is masked (drifts per-slide). Masking exempts it from the pixel count only — you STILL must visually match its image scale, layout and transitions.
- Hover / focus / entrance transitions. They change no geometry and no static-screenshot pixel. They require the CDP interaction gate (
tools/fidelity/interact.mjs, usesCSS.forcePseudoState) plus actually watching the animation. This gate was run for gilliard/chevaliers but NEVER for PDN.
The loop, per page AND per region/control:
- Screenshot LIVE vs LOCAL at 375 / 768 / 1024 / 1440 / 1920 + read DOM/computed-CSS (geometry, typography, colour, image scale).
- Run the CDP interaction check (hover/focus/active + entrance transitions) on every interactive/animated element.
- Source of truth = live DOM + computed CSS, never the eye, never a code comment (comments have been wrong — e.g. the
153f348hero "re-measure" was a regression). Verify every candidate vs live BEFORE and AFTER. - Fix the CAUSE; systemic-first (a token/shared rule fixes many pages); commit per root cause.
- Document deviations in
assets-substitues.mdand masks intools/fidelity/config.jswith written reasons.
3. TOOLS & COMMANDS (all measured against live)
- Local host:
http://portedenovembre.localtest.me:12953(paths == live paths, NO/fr/). Live:https://portedenovembre.ch./de/is out of scope. - Sweep (all PDN pages):
MSYS_NO_PATHCONV=1 node tools/fidelity/sweep.mjs pdn --widths 1440(add375,768,1024,1440,1920for the full pass). Reports ->tools/fidelity/reports/pdn/<name>/(live/local/diff PNGs + report.json). Sweep pages are defined intools/fidelity/sweep.mjs(PDN inventory added 2026-07-29). - Single page diff:
MSYS_NO_PATHCONV=1 node tools/fidelity/diff.mjs --site pdn --path /X/ --local-path /X/ --widths 1440 --report-only - Interaction gate (CDP hover/focus):
tools/fidelity/interact.mjs— the ONLY reliable way to measure hover; a bare Playwright.hover()silently misses off-screen elements. UseCSS.forcePseudoState. - Probes (in
tools/fidelity/probes/, domcontentloaded + settle — live never reaches networkidle):pdn_theme.mjs <url> <w> <shot>(theme tokens + shot),pdn_fonts.mjs <url> <w>(painted text-node fonts),pdn_page.mjs <url> <w> <shot>(full-page shot + band structure). Write throwaway probes as_tmp_*.mjsINSIDEprobes/(Node resolvesplaywrightfromtools/fidelity/node_modules, so a scratchpad script can't import it) and delete after. - Build/run/seed loop (ONLY after the go-signal):
taskkill //IM Web.exe //F->dotnet build Gilliard.sln->dotnet run --no-build --project src/Web/Web.csproj(bg) -> pollcurl http://portedenovembre.localtest.me:12953/for 200 ->curl .../seed-pdn. SCSS-only changes need justnpm run --prefix src/Web build(no server restart; CSS is static)..cshtml/C# changes need the full rebuild+restart (runtime Razor does NOT hot-reload here). - Seeder is GENERATED:
tools/seed-gen/pdn-gen.mjs(readstools/seed-gen/data/pdn.json, scraped bypdn-bands.mjs) ->src/Web/Controllers/DevSeedPdnController.cs. NEVER hand-edit the controller — edit the generator and re-runnode tools/seed-gen/pdn-gen.mjs. - Fonts: GothamPro is REAL (self-hosted, identity in
config.js, NOT substituted), Yeseva One (display), Krona One (buttons). An unexpected family fails the harness. - Masks (config.js pdn): Complianz cookie banner, Instagram feed, the Slider Revolution home hero.
4. WHAT'S LEFT (the backlog — agreed order: FULL AUDIT across all pages, then fix worst-first)
4a. The agreed next move: FULL visual + CDP-interaction audit across ALL PDN pages
Region-by-region, 5 widths, screenshot + DOM/CSS + hover/focus/active + entrance transitions. Produce ONE complete measured defect list (systemic vs per-page), THEN fix systemically worst-first. Pages: home, vins, 7 wine details (/vins/{johannisberg-pdn,mousseux,ice-pdn,ice-rose-pdn,ice-0-0,rose-pdn,rouge-pdn}/), cocktails, news, evenements, news-events, club, goodies, idees-cadeaux, contact, politique-de-confidentialite. Note: the system-prompt for this project forbids spawning subagents unless the user asks — do it serially, or the user can opt into agents.
4b. Specific home defects the user flagged + MEASURED (2026-07-29) — do these in the audit
- SHARE-slide bottle image TOO SMALL. Live 686w@1440 / 860w@1920 (~44-48vw); local stuck 593w at both. Cause 1: this session's
153f348replaced the width-based sizing (width:min(47.6vw,860px), which matched live) withheight:62%/max-width:46%— a regression. Cause 2: local hero imageaccueil-hero-1.pngaspect 1.26 (593x471) ≠ livegamme_portedenovembre_gilliardaspect 1.86 (686x369) = DIFFERENT asset/crop. Fix: verify the local hero foreground IS live's SHARE asset, then size per-slide by WIDTH to hit 686/860 (SHARE = 7 bottles wide; Enjoy/Cheers = ~3 bottles narrower —153f348went height-based to stop those two blowing up, so reconcile per-slide, don't blind-revert). Rule lives instyles/themes/pdn/_overrides.scss.theme-pdn .hero-slider__product-figure. - "Découvrez nos vins" grid HOVER transition. Local
.card-collection--bottles .g-cardtransitions only box-shadow; live card transitionsall. ⚠️ My hover probe hit the WRONG live element (.sc_blogger_item= a blog teaser). RE-IDENTIFY the live wine-grid element and CDP-measure its rest->hover delta (transform/scale/opacity/filter) before replicating. - Slider image FADE-IN entrance. Live SR foreground image fades/moves in on slide change; our hero-slider has no matching entrance. Measure the live entrance, replicate on the hero-slider images.
4c. Per-page structural items already measured (P5)
- Wine-detail TWO-COLUMN hero (7 pages, biggest). Live band-1 = ONE pink section: LEFT title Yeseva WHITE 60px @x85,y267 + body(white) + ACHETER (white bg/black text, x85,y597, 134x55); RIGHT bottle
johannis.png@x649,y177 290x567 OVERLAPPING landscape photojohannisberg.jpg@x806,y150 500x619. Our build renders pageHero title at the 150px LISTING scale (centred) + a SEPARATE stackedmediaText--product-detailbelow => title DUPLICATED + wrong scale + wrong layout. Fix: fold band-1 into the pageHero (heroTitle 60 white left + heroText body + heroCta ACHETER; bottle+photo right image column) and DON'T emit the mediaText for band 1. ⚠️ pageHero is a SHARED composition (4 brands) — scope the two-column/60px/white to wine detail via a modifier and regression-check gilliard/chevaliers. - Listing-card LAYOUT (evenements/cocktails/news/news-events/idees-cadeaux). Live card = image + "EVENT" kicker(pink) + title(Yeseva black) + excerpt + arrow, transparent on amber. Ours =
cards-blog: badge-on-image + white bar (title + chevron), no kicker/excerpt. Layout is fixable NOW; the excerpt TEXT is the WP excerpt field = NOT in the scrape (P6/WXR). - Footer STRUCTURE (content is correct now). Live = [logo + "Vins de la Maison Gilliard" + MAISON GILLIARD sublogo] [contact] [Liens] [Newsletter] + dark bar with socials IN the bar. Ours = [Liens][Newsletter][contact][socials] + dark bar, NO logo column, socials as a column. Needs a shared
_footer.cshtmlenhancement (logo column + socials-in-bar) or a documented deviation — cross-brand risk. - Article-detail body carries RAW ELEMENTOR markup (pdnArticle
bodyon theme-post pages, generator ~line 556 emits richIntro fromp.post.html). Standing rule: port the rendered result, never the plugin. Re-check the theme-post branch.
4d. FAVICONS (all brands) — user request 2026-07-30
_MasterLayout.cshtml (lines ~88-92) hardcodes ONE shared favicon set at /images/favicons/... (Umbraco template default) for ALL 4 brands, so PDN/gilliard/chevaliers all show the generic favicon. Fix: fetch each brand's LIVE favicon (PDN = portedenovembre.ch/wp-content/uploads/2024/11/cropped-favicon_porte_de_novembre-1-{32x32,192x192,180x180}.jpg; gilliard + chevaliers from their live <link rel=icon>), store per-theme (wwwroot/images/<theme>/favicons/ — those dirs already exist), and make the <link>s theme-scoped via the existing theme var (/images/@theme/favicons/...) with the shared set as fallback. Needs build+restart (part of the post-go-signal batch).
4e. BLOCKED — P6 exact content re-seed
The PDN WXR export still isn't available. When it arrives, parse it (tools/seed-gen/wxr-extract.mjs -> data/sources/pdn/), re-seed ALL PDN content verbatim (text, articles, product copy, images, dates, listing excerpts), then re-run fidelity. Until then, representative/approximated content stays.
5. PASTE-READY RESUME PROMPT
Resume the Porte de Novembre (PDN / portedenovembre.ch) migration.
FIRST, before touching the server/DB, ask me whether my concurrent backoffice session is closed and it's
safe to /seed-pdn, dotnet build, and restart the dev server. Do only read-only work until I confirm.
Read .claude/docs/domain/pdn-resume.md (the handoff — state, method, backlog, tools), then
.claude/docs/domain/pdn-migration-plan.md and the pdn-migration-plan + gilliard-migration memories. Follow
the SAME discipline as gilliard/chevaliers, no shortcuts, and specifically FIX THE THOROUGHNESS GAP that
the pixel harness caused: it is BLIND to (a) masked-region internals (the hero: image scale + transitions)
and (b) hover/focus/entrance transitions. So the agreed next move is a FULL per-region + CDP-interaction
audit across EVERY PDN page at 375/768/1024/1440/1920 (screenshot live vs local + DOM/CSS + hover/focus/
active + entrance animations via tools/fidelity/interact.mjs and the probes in tools/fidelity/probes/),
producing ONE complete measured defect list, then fix systemically worst-first — measure live BEFORE and
AFTER every candidate, commit per root cause, me as sole author with NO Co-Authored-By trailer.
Known measured defects to fold into the audit (details + numbers in pdn-resume.md §4): the SHARE-slide
bottle image is too small (my commit 153f348 regressed it + the local hero image is the wrong crop); the
"Découvrez nos vins" grid hover transition is missing; the slider image has no fade-in entrance; the 7
wine-detail pages need the two-column hero (title 60px white + body + ACHETER left, bottle overlapping a
landscape photo right, no duplicated 150px title); the listing cards need live's kicker+title+excerpt+arrow
layout (not badge+white-bar); the footer structure needs live's logo column + socials-in-copyright-bar; the
article-detail body still carries raw Elementor markup; and ADD PER-BRAND FAVICONS (all 4 brands currently
share the generic template favicon — fetch each site's live favicon and make _MasterLayout's favicon links
theme-scoped).
Restart the dev server on :12953 if it's down (steps in pdn-resume.md §3) — but only after I confirm it's
safe. Keep going autonomously; stop only for a content/seed decision. Do NOT do P6 (exact WXR content
re-seed) — the PDN WXR export still isn't available, so representative content stays. Do NOT spawn subagents
unless I ask.
