mirror of
https://github.com/adobe/skills.git
synced 2026-09-19 08:06:09 +08:00
Merge pull request #376 from adobe/stardust/prune-historical-notes
chore(stardust): prune six historical planning notes; archive the deploy improvement ledger
This commit is contained in:
+10
-2
@@ -1,6 +1,14 @@
|
||||
# Snowflake skill — improvement notes
|
||||
# Deploy skill — improvement ledger (archive, findings #1–#80)
|
||||
|
||||
Running log of friction and gaps found while applying `stardust-to-snowflake`
|
||||
**Frozen 2026-09-18.** This was the deploy skill's running log of friction and
|
||||
gaps; `skills/deploy/SKILL.md` and the deploy/diff scripts cite its entries as
|
||||
`(#NN)` provenance for the rules they state. The rules themselves live in the
|
||||
skill text — this file is the evidence behind them, kept for reference. Entries
|
||||
were last added at #80; citations #81 and above in the skill text were never
|
||||
written up here. New findings go to `skills/stardust/reference/learnings.md`
|
||||
(the ledger format every skill now uses), not to this file.
|
||||
|
||||
Originally written while applying the skill (then `stardust-to-snowflake`)
|
||||
to the `samples/**` claude-design prototypes in this repo. Each test converts
|
||||
**one** prototype on a `snowflake-blocks-test-N` subbranch and deploys to DA at
|
||||
`/snowflake-blocks/test-N`; durable skill fixes are implemented here on
|
||||
@@ -1,119 +0,0 @@
|
||||
# Cross-site E2E learnings — stardust Fable 5 refactor (6 sites)
|
||||
|
||||
Sites: **site A (healthcare)**, **site B (industrial conglomerate)**, **site C (agency)**, **site D (airline)**, **site E (tools retailer)**, **site F (nonprofit shelter)**. All runs 2026-07-02, hands-off mode.
|
||||
Source: 6 ledgers, ~109 raw entries. After dedup: **42 distinct pending issues** (16 systemic/multi-site + 26 single-site) and **~14 win/observation classes**.
|
||||
|
||||
---
|
||||
|
||||
## 1. Ranked pending fixes (by cross-site frequency)
|
||||
|
||||
Systemic issues only (hit ≥2 sites), most-frequent first. Single-site issues are in §3.
|
||||
|
||||
| # | Issue (one line) | Skill/file + section | Sites hit | Severity | Proposed fix (one line) |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | Playwright not preinstalled; `npm i playwright` fails ERESOLVE on aem-boilerplate eslint peers | skills/extract/SKILL.md § Setup / prerequisites | site A, site B, site C, site D, site E, site F (6) | high (blocks crawl start) | Preflight `require.resolve('playwright')` from project root; remediate with `npm i --no-save --legacy-peer-deps playwright` (document sibling-symlink / global-symlink fallback) |
|
||||
| 2 | Bundled `.mjs` scripts can't resolve playwright from plugin path (ESM resolves from script dir) — must copy to project root; recurs at crawl, vision-gate, mobile-nav, migrate audits, diff, shot | skills/extract, skills/prototype (Phase 2.5/2.7 fixtures), skills/migrate (Phase 3 audits), skills/diff scripts | site B, site C, site D, site E, site F, site A (6) | high | Add `createRequire(process.cwd())` shim to bundled scripts, or document copy-to-project-root once as a shared bundled-script rule |
|
||||
| 3 | `crawl.mjs` writes no `_provenance` block (renderedBy/fetchedAt only; no waitMs/waitMode/httpStatus) — violates its own SKILL live-render contract; `validateProvenance()` would reject every page | skills/extract/scripts/crawl.mjs (capturePage/writer, ~L410) | site B, site C, site D, site F (4) | high | Emit `_provenance:{renderedBy,fetchedAt,waitMs,waitMode,httpStatus,finalUrl}` as first key; thread `resp.status()` + measured wait out of capturePage |
|
||||
| 4 | `crawl.mjs` capture() covers ~1/4 of the mandatory recipe/schema (no heroHeadline/heroLede, font intercept, forms, per-section styles, videos/iframes, landmarks, resolves flags) — every run re-implements it by hand | skills/extract/scripts/crawl.mjs capture(); reference/current-state-schema.md + playwright-recipe.md | site B, site C, site D, site E (4) | high | Fold the per-run extensions (site E's crawl-extended.mjs / site D heroHeadline+font+forms+styleSummary + site C videos[]/iframes[]) back into the shipped crawler |
|
||||
| 5 | `migrate` hard-stops unless `DESIGN.json.extensions.canon` + `stardust/canon/{header,footer,canon.css}` exist — but core pipeline (extract→direct→prototype→migrate) and direction.md command sequence never run prepare-migration/`--prep`, so canon is always absent | skills/migrate/SKILL.md § Setup steps 3-4; skills/stardust/SKILL.md pipeline; skills/direct command-sequence | site A, site C, site D, site E (4) | **blocking** | When canon absent but ≥1 approved prototype exists, auto-derive canon inline (same write-back as prototype --prep); OR insert prepare-migration as an explicit pipeline step |
|
||||
| 6 | `resolves` probe (in-page fetch / bare HEAD) gives false-negatives — CORS-blocked cross-origin CDNs and mp4s served text/html on HEAD; migrate would omit/repair nearly every real image | skills/extract/reference/playwright-recipe.md § Capture list 11 (Source-URL fidelity) | site B, site C, site E (3) | high | For `<img>` use `naturalWidth>2` after load (CORS-exempt) as resolution evidence; reserve GET-with-Range (`bytes=0-0`)+UA for backgrounds/srcset; never bare HEAD |
|
||||
| 7 | Asset rewrite to root-relative `/assets/…` (asset-bundling) directly contradicts migrate Phase-3 portability audit which greps `(href\|src)="/[^/]` as FATAL — the two contracts can't both pass | skills/migrate/SKILL.md § Phase 2/3; reference/asset-bundling.md § Rewrite | site D, site E, site F (3) | med | Specify depth-relative rewrite (`../`×depth) as the portable form, or gate `/assets/` behind a served-at-host-root profile the audit relaxes — make both docs agree |
|
||||
| 8 | `direct` Phase 1 "wait for the user's confirmation" + one-shot tuning questions conflict with `state.json.handsOff=true`; no hands-off clause exists | skills/direct/SKILL.md § Phase 1 | site C, site D, site F (3) | med | Add hands-off clause: when handsOff, take each question's documented default, stamp `(default, hands-off)` in direction.md, auto-confirm the plan |
|
||||
| 9 | `impeccable` PostToolUse hook fires on the brand-review template's own mandated chrome (side-tab left-borders, single captured font, em-dash, numbered markers) — false positives on a descriptive artifact | skills/extract/reference/brand-review-template.md § Styling rules | site C, site E, site F (3) | low | Restyle the mandated Components list off side-tab borders, or ship an inline `impeccable-disable` waiver header in the template |
|
||||
| 10 | Extract "Phase 2.5 vision gate" is referenced by crawl.mjs/reference but absent from the (Skill-tool-served) extract SKILL.md; harness serves a stale revision vs on-disk | skills/extract/SKILL.md (add Phase 2.5); plugin release/skill-cache process | site C, site E, site D (3) | med | Add the Phase 2.5 section to SKILL.md; rebuild skill/tile cache on SKILL.md change; agents treat on-disk SKILL.md as authoritative |
|
||||
| 11 | `impeccable` detector/hook false-positives on captured brand properties under Mode A (overused-font on pinned family, em-dash on captured voice, numbered-markers on real dates, repeated-eyebrow kicker system) | skills/prototype/SKILL.md § Phase 2.5 auto-dismiss / Discipline 9 captured-verbatim bypass | site A, site C, site F (3) | low-med | Extend captured-verbatim/reflexRejectAudit bypass to data-detector rules and declared `DESIGN.json.components[]` (eyebrow); let the hook read a `reflexRejectAudit.bypassed` marker |
|
||||
| 12 | Consent/geo dismissal misses: runs before late-injected banners, no geo/locale-modal handling, no Usercentrics shadow-DOM traversal, no loose "agree/accept" matcher — pollutes vision-gate screenshots, forces recapture | skills/extract/scripts/crawl.mjs § dismissConsent; reference/playwright-recipe.md § Pre-flight | site B, site D, site E (3) | high | Wait ~1.5-2s for late injection; add loose `/agree\|accept/i` text fallback; add geo/locale-gate handling; traverse `#usercentrics-root.shadowRoot`; assert no fixed cookie/privacy element remains pre-shot |
|
||||
| 13 | `bootstrap-authorkit.mjs` default ref `main` fetches a DRIFTED (block-based `loadBlock(header)`) runtime; the mandatory static-fragment postlcp edit hard-fails AFTER files are deleted, bricking the repo with no rollback | skills/deploy/scripts/bootstrap-authorkit.mjs; deploy/SKILL.md § Runtime bootstrap | site A, site D (2) | **blocking** | Pin `AUTHORKIT_REF` to a known-good static-fragment commit by default; make the port transactional (stage+swap, roll back on verify fail); bundle known-good postlcp.js as a skill asset |
|
||||
| 14 | Block decode silently drops the CTA — authored `<strong><a>` arrives without a `<p>` wrapper and decorateButton unwraps the emphasis; `<p>`-scoped/`querySelector('a')` reads return null; passes lint+harness, only content-diff catches it | skills/deploy/SKILL.md § Block JS scaffold (#42/#79) | site A, site D (2) | high (silent content drop) | Read CTA by cell and match self-OR-descendant (`block.querySelector('a')`, clone `.closest('div')`); ship a hardened `hero` block in a reference set |
|
||||
| 15 | DA/AuthorKit delivery strips inner author `class=` and flattens nested divs, and the runtime doesn't add a `.block` class — so CSS keyed to author classes / `.<name>.block` silently no-ops; `.plain.html` assertions can't see the layout failure | skills/deploy/SKILL.md § ENCODE contract / Blocks | site F, site B (2) | high | LOUD up-front rule + worked fixture: author cells as SEMANTIC content only; block `decorate()` rebuilds all presentational DOM/classes; scope CSS under `.<block-name>` only; add a post-deploy screenshot/vdiff to the atomic contract |
|
||||
| 16 | `content-diff` false-positives: whitespace run-on across element boundaries and curly-vs-straight quotes reported as paired 🔴 MISSING + 🟠 EXTRA | skills/diff/scripts/content-diff.mjs | site A, site B (2) | low (noise) | Normalize match keys (strip all whitespace; fold typographic punctuation); keep href as primary CTA key; downrank pure-glyph deltas to a single advisory |
|
||||
|
||||
---
|
||||
|
||||
## 2. Wins confirmed (capabilities that worked, by how many sites confirmed them)
|
||||
|
||||
| Capability | Sites confirming | What it caught / did |
|
||||
|---|---|---|
|
||||
| Atomic DA deploy contract (PUT 201 → preview 200 → live 200 → `.plain.html` 1×h1/0 about:error/imgs) | site A, site C, site D, site E, site F (5) | Clean end-to-end delivery every deploy; media rehost to DA 201 on first try; caught unwrapped-`<p>` copy drop via deployed-page count probe |
|
||||
| refero reference-research **tier-1** (MCP loadable via ToolSearch, no fallback) | site B, site C, site D, site F (4) | On-brief anchors within ≤5 search/≤4 retrieval budget (Peloton/Airbnb/n26/Warp…); n26 Deep Teal #088177 ≈ site F #008192 — validation the deterministic seed couldn't supply |
|
||||
| **Phase 2.5 vision gate** catching silent capture/render gaps heuristics missed | site B, site C, site E (3) | Consent+geo overlays over hero (records were clean); zero-media record vs on-screen demo video; missing hero headline; invisible Vue form; blank above-fold hero (opacity:0 reveal) that the deterministic detector passed |
|
||||
| `stardust:diff` structural/content probe catching defects atomic+pixel+harness missed | site A, site C, site D (3) | `.textContent` dropping inline CTAs; band/quote role-swap to `<h2>` inflating outline; dropped hero "Find your flight" CTA — all invisible to decoration/height/grid + pixel checks |
|
||||
| Hands-off pipeline ran extract→deploy unattended | all 6 (6) | Whole redesign completed without a user (only gap: the direct §1 doc contradiction, §1 #8) |
|
||||
| Canon reuse across multiple templates (`data-canon`/`data-module`/`data-slot`) | site C, site F (2) | home+man-page / home+get-help read as one system; shared chrome transferred verbatim, per-band re-skin kept structure |
|
||||
| customProps first-party token capture | site C, site D (2) | Complete `--color-*` / `--*-font-size` token sets cited verbatim instead of lossy frequency clustering; caught a `--swiper-theme-color` framework-default leak |
|
||||
| Bot-management fallback ladder validated | site B, site D (2) | site B = class-2 per-request Akamai needing headed real Chrome (tier 2); site D = Akamai origin crawled headless 6/6 in ~40s (ladder never needed) |
|
||||
| impeccable design hook catching real defects pre-deploy (deterministic) | site B (1) | `layout-transition` compositor-thrash (nav underline animating `width`) → fixed to `transform:scaleX()` before any gate ceremony |
|
||||
| Anti-fabrication catch | site D (1) | Render-step re-grep of page JSON caught a fully fabricated "promo" section falsely labeled captured-verbatim |
|
||||
| spec-plate fallback pattern | site E (1) | 15/25 saw cards missing renders got captured model-code spec-plates, not stock/placeholder/mismapped photos — grid stayed honest, no imagery invented |
|
||||
|
||||
---
|
||||
|
||||
## 3. Site-unique findings (one site only — worth keeping)
|
||||
|
||||
**skills/extract (crawl.mjs / recipe / schema):**
|
||||
- site B: `crawl.mjs` discover() doesn't recurse `<sitemapindex>` — would queue 6 XML files and fail each.
|
||||
- site B: wait-mode vocabulary mismatch — recipe `fast|medium|spec` vs crawl.mjs `fast|medium|slow`; `--wait spec` silently falls to medium.
|
||||
- site B: extract crash between Phase 2 and 3 leaves `state=extracted` but no `_brand-extraction.json`; no `--consolidate-only` resume seam, so direct hard-stops and forces a full re-crawl of a bot-protected origin.
|
||||
- site C: discovery collapses to 1 page on apex→www redirect (same-origin filter uses pre-redirect origin; sitemap on apex returns the redirect body).
|
||||
- site C: referenced media not saved to `assets/media/` (only screenshots); woff2 fonts not saved either.
|
||||
- site D: `crawl.mjs` never sets `prefers-reduced-motion: reduce`; animated h1 captured at opacity:0 → dropped from heading outline; needs post-settle re-query.
|
||||
- site E: heroHeadline resolver blind to styled-`div` stage headlines (falls to meta fallback) — add largest-visible-font-node candidate ≥28px.
|
||||
- site E: Vue-managed forms render 6 fields with zero `<form>` elements → forms[] empty; emit synthetic `formless:true` entry when ≥3 inputs sit outside any form.
|
||||
- site E: catalog/listing pages don't scroll to trigger lazy-load → 15/25 product cards had no captured image; also record per-card image association, not DOM-order guess.
|
||||
- site E: extract SKILL.md § Phase 4 points at impeccable `reference/teach.md`, which no longer exists in impeccable 3.9.1 — inline the PRODUCT.md section list instead.
|
||||
|
||||
**skills/direct:**
|
||||
- site F: `DESIGN.json.systemComponentRoles.header` ("deep-harbor ground") contradicts the captured WHITE header in the screenshot; direct should cross-check role constraints against the screenshot; under Mode A the screenshot wins.
|
||||
|
||||
**skills/prototype (gates / disciplines):**
|
||||
- site A: contrast probe false-positives on image/gradient grounds (walks to BODY for a solid bg) — spec pixel-sampling or scrim-compositing math; classify nearest-ancestor misses as needs-vision-verify.
|
||||
- site A: LCP audit selects first-in-DOM image (the 139×40 logo), not the largest above-fold image / PerformanceObserver LCP entry.
|
||||
- site A: `detect.mjs` advisory noise — functional alpha ramps (scrim stops, hairline families) flagged as undocumented colors; allow a `divergence.functional_ramps[]` declaration.
|
||||
- site E: side-tab detector fires on a CSS-triangle play glyph (`border-left` with other sides transparent) — exempt the width:0/height:0 triangle idiom.
|
||||
- site E: reveal-on-scroll gated the above-fold hero to opacity:0 (blank hero) — escalate any JS-gated hidden initial state inside the first viewport band to P0.
|
||||
- site D: shape-brief lineage/voice citations (Discipline 1/5) are prose contracts an LLM can satisfy by assertion — make them validator-enforced substring matches against `current/pages/<slug>.json`; the content-sourcing scan must validate literals against the page JSON, never the brief's self-reported classifications.
|
||||
- site F: substrate-transition cap (Discipline 4) has no carve-out for signature full-bleed color-band-rhythm brands — add a third exemption when the captured signature motif is a band rhythm.
|
||||
|
||||
**skills/migrate:**
|
||||
- site A: `pagemap-audit.mjs` requires `state.json.migrate.pageMap[]`, but the SKILL § State contract never enumerates `pageMap` (only in migration-procedure.md) — add `pageMap[]{slug,sourceUrl,outputPath}` to the state-block fields.
|
||||
|
||||
**skills/deploy:**
|
||||
- site B: ENCODE dropped section-head secondary chrome (eyebrow "What we do" + "see all →" links) — no block owns them; author them as default content before the block.
|
||||
- site C: `deploy-batch.mjs` doesn't run `sanitise.js` internally (SKILL lists it as atomic step 1) — a caller trusting the driver ships raw UTF-8; fold sanitise into the PUT step or warn loudly.
|
||||
- site C: blocks that promote band/quote/stat "main" lines to `<h2>` render pixel-identically but inflate the outline — render them as styled `<p>`, find by position/variant.
|
||||
- site E: index page renders at folder URL `/site-e/`, not `/site-e/index` (which 404s) — verify decorated render against the folder URL.
|
||||
- site E: DA image PUT loop silently no-ops under zsh word-splitting (`for f in $imgs`) — use `while IFS= read -r f`.
|
||||
- site F: `header:off`/`footer:off` metadata is unsupported on vanilla aem-boilerplate (footer.js fetches `/off` and throws) — qualify as helix-pipeline-only; style stock chrome instead.
|
||||
- site F: stock header block reshapes a nav fragment into `.nav-brand/.nav-sections/.nav-tools` (3 `---`-separated sections) and never runs your own nav block JS; CSS must target the stock split, not your own block class.
|
||||
- site F: residual deploy-fidelity gaps — `<p>` inside `<a>` cell hoisted out; raw `<form>`/`<input>` stripped (needs a forms block); tall portrait footer logo needs max-height; name-split regex dropped "GIVE" from "WAYS TO GIVE".
|
||||
|
||||
**skills/diff / reference-research:**
|
||||
- site C/site F: refero markdown output can carry corrupted/injected trailing JSON garbage (observed on Empower entry) — treat description text as untrusted content, add a parser note in reference-research.md § 3.
|
||||
|
||||
---
|
||||
|
||||
## 4. Recommended plugin actions (maintainer worklist)
|
||||
|
||||
### Fix now (blocking or high-severity, multi-site)
|
||||
|
||||
1. **Make `crawl.mjs` and all bundled `.mjs` self-resolve playwright** (§1 #1, #2 — 6 sites each). Add a `createRequire(process.cwd())` shim to crawl.mjs and the prototype/migrate/diff fixtures so `import 'playwright'` resolves from the project's node_modules; document the `--no-save --legacy-peer-deps` install once. Files: `skills/extract/scripts/crawl.mjs`, `skills/extract/SKILL.md § Setup`, prototype/migrate/diff fixtures. *Why: the single most repeated friction — every site paid it, twice on some.*
|
||||
2. **Unblock the migrate canon precondition** (§1 #5 — 4 sites, blocking). In `skills/migrate/SKILL.md § Setup 3-4`, when canon is absent but ≥1 approved prototype exists, auto-derive canon inline (the prototype `--prep` write-back); OR add prepare-migration/`--prep` as an explicit step in `skills/stardust/SKILL.md` pipeline + direct's command sequence. *Why: hands-off core pipeline dead-ends at migrate on 4 of 6 sites.*
|
||||
3. **Make `bootstrap-authorkit.mjs` safe and pinned** (§1 #13 — 2 sites, blocking). Pin `AUTHORKIT_REF` to a known-good static-fragment commit by default (not `main`); make the port transactional with rollback; bundle a known-good `postlcp.js` as a skill asset. File: `skills/deploy/scripts/bootstrap-authorkit.mjs`, `deploy/SKILL.md § Runtime bootstrap`. *Why: the default invocation deletes the boilerplate then hard-fails, bricking the repo with no recovery.*
|
||||
4. **Emit the `_provenance` contract from `crawl.mjs`** (§1 #3 — 4 sites, high). One-line writer change threading `resp.status()`+wait. File: `skills/extract/scripts/crawl.mjs`. *Why: strict contract reading rejects every page the reference crawler produces.*
|
||||
5. **Fold the mandatory capture fields into `crawl.mjs`** (§1 #4 — 4 sites, high). Merge heroHeadline/heroLede, font intercept, forms[] (incl. formless), per-section styleSummary, videos[]/iframes[], landmarks, resolves flags. File: `skills/extract/scripts/crawl.mjs`. *Why: every run re-writes a ~600-line extension the bundled crawler exists to remove.*
|
||||
6. **Fix the `resolves` probe to naturalWidth for `<img>`** (§1 #6 — 3 sites, high). File: `playwright-recipe.md § Capture list 11`. *Why: CORS/HEAD false-negatives would make migrate omit/repair nearly every real image on CDN-hosted sites.*
|
||||
7. **Harden consent/geo dismissal** (§1 #12 — 3 sites, high). Late-injection wait, loose agree/accept matcher, geo/locale gate, Usercentrics shadow-DOM traversal, pre-shot assertion. Files: `crawl.mjs § dismissConsent`, `playwright-recipe.md § Pre-flight`. *Why: overlays pollute the vision gate and force full recaptures on bot-protected origins.*
|
||||
8. **Ship hardened `hero`/CTA block decode + LOUD class-stripping rule** (§1 #14, #15 — 2 sites each, high, silent). Reference block set reading CTA by cell (self-or-descendant) and rebuilding presentational DOM in `decorate()`; add a post-deploy screenshot/vdiff to the atomic contract. Files: `skills/deploy/SKILL.md § Block JS / ENCODE`, reference block set. *Why: silent content/layout drops that pass lint+harness+`.plain.html`; only diff catches them.*
|
||||
|
||||
### Backlog (med/low, or single-site)
|
||||
|
||||
9. **Add a hands-off clause to `skills/direct/SKILL.md § Phase 1`** (§1 #8 — 3 sites, med): take documented defaults, stamp `(default, hands-off)`, auto-confirm.
|
||||
10. **Reconcile the asset-rewrite vs portability contradiction** (§1 #7 — 3 sites, med): depth-relative rewrite in `asset-bundling.md` + `migrate/SKILL.md § Phase 3`.
|
||||
11. **Add the Phase 2.5 section to `extract/SKILL.md` and rebuild the skill cache on change** (§1 #10 — 3 sites, med).
|
||||
12. **Extend Mode-A / captured-verbatim bypass** to data-detectors and declared `DESIGN.json.components[]`, and let the impeccable hook read a `reflexRejectAudit.bypassed` marker (§1 #11, #9 — 3 sites each, low).
|
||||
13. **Normalize `content-diff` match keys** (whitespace + typographic punctuation) (§1 #16 — 2 sites, low). File: `skills/diff/scripts/content-diff.mjs`.
|
||||
14. **Validator-enforce shape-brief lineage/voice against page JSON** (site D single-site, high-leverage): make Discipline 1/5 mechanical substring checks; the content-sourcing scan grounds on `current/pages/<slug>.json`, never the brief's self-report.
|
||||
15. Single-site crawler robustness: sitemap-index recursion, apex→www redirect adoption, wait-mode vocab alignment, prefers-reduced-motion, listing lazy-load scroll, styled-div hero resolver, Vue formless capture, media/font download pass, `--consolidate-only` resume seam (§3, various — mostly high-value where they gate capture completeness).
|
||||
16. Single-site deploy gotchas: sanitise-in-deploy-batch, band/quote-as-`<p>`, index folder-URL verify, zsh `while read` PUT loop, vanilla-EDS header/footer:off + stock-nav-split docs, forms-block note, `<p>`-not-inside-`<a>` rule (§3).
|
||||
17. Single-site prototype/audit precision: LCP largest-above-fold selection, image/gradient contrast sampling, functional-ramp color declaration, CSS-triangle side-tab exemption, above-fold reveal→P0, band-rhythm substrate exemption, pageMap in migrate state contract (§3).
|
||||
18. Docs/hygiene: inline PRODUCT.md spec (drop dead impeccable `teach.md` ref), brand-review-template impeccable waiver, refero untrusted-description parser note (§3).
|
||||
@@ -1,192 +0,0 @@
|
||||
# Stardust Fable 5 Refactor — Session Assessment
|
||||
|
||||
**Date:** 2026-07-02 · **Branch:** `fable5-refactor` · **Versions:** 0.14.0 → 0.14.2
|
||||
|
||||
The stardust plugin was authored with/for Opus 4.8. This session reviewed it
|
||||
top to bottom, refactored it for Fable 5 (a more capable model), added three
|
||||
new capabilities, and validated the whole surface end-to-end on **seven live
|
||||
websites** — six paused mid-run on a spend limit and resumed on Opus, plus
|
||||
stardust.style on Fable. All seven deployed to real AEM Edge Delivery pages.
|
||||
|
||||
---
|
||||
|
||||
## 1. The core thesis and whether it held
|
||||
|
||||
**Thesis:** the plugin's design-quality ceiling was capped by *generator*
|
||||
guardrails written so a weaker model wouldn't wander — a deterministic MD5
|
||||
"divergence seed" roll and closed creative catalogs. A stronger model does
|
||||
better with **real reference research** than with injected entropy. Keep the
|
||||
*detector* half (anti-slop lists, cream-ground hex test, reflex-font list) as
|
||||
cheap validators; replace the generator half with grounded research.
|
||||
|
||||
**Held.** Refero reference-research fired at **tier 1 on all seven sites** and
|
||||
materially shaped each redesign (decade/craft/register + the improvements list)
|
||||
while Mode A kept palette and type pinned to the captured brand. Every redesign
|
||||
reads a clear decade newer while staying unmistakably its own brand. This is
|
||||
the single biggest quality change and it is now the default path, with the seed
|
||||
roll demoted to a fallback/convergence-tiebreaker.
|
||||
|
||||
---
|
||||
|
||||
## 2. Improvements made (the refactor)
|
||||
|
||||
### Design quality
|
||||
- **Reference-grounded direction** — new shared procedure
|
||||
`skills/stardust/reference/reference-research.md` (Refero MCP → WebSearch →
|
||||
seed fallback ladder). `direct` now researches real category references and
|
||||
records them as `picked_by: "reasoned: <anchor>"` with citations; the seed
|
||||
roll is the fallback, not the default.
|
||||
- **Mode A+ brand-adjacent refinement tier** — a sanctioned middle between
|
||||
Mode A's hard pins and `--rebrand`: evidence-gated same-classification body
|
||||
face upgrade and single-role palette recolor (each requires an improvements
|
||||
-list citation). This is where "dramatically better while honoring the
|
||||
brand" actually lives for a median mediocre source.
|
||||
- **Opened creative catalogs** — the what-if candidate list, non-template move
|
||||
bank, and motion registers became worked exemplars with an evidence-shaped
|
||||
**extension rule** (a novel move is admissible with the same citation shape),
|
||||
not closed sets.
|
||||
- **Palette library reframed as an anchor bank** — the model derives a full
|
||||
role-ramped, AA-validated palette from an anchor instead of being restricted
|
||||
to five scraped hexes (determinism moved to the contrast math, not taste).
|
||||
|
||||
### Fidelity & safety
|
||||
- **Vision gates** — extract Phase 2.5 (screenshot-verify each captured page
|
||||
against the record, re-capture on mismatch) and prototype Phase 2.5 (judge
|
||||
the proposed render against the source screenshot).
|
||||
- **Runtime-contract detection** in deploy (AuthorKit vs vanilla), **atomic
|
||||
per-page delivery contract**, **DA_TOKEN lifecycle preflight**.
|
||||
- **rollout hardening** — foundation-first gate, per-template headless render
|
||||
check, link-audit completeness, query-index resilience.
|
||||
- **prepare-migration Phase 4.5** — dynamic-blocks pre-import gate (Tier 1/2/3
|
||||
metadata contract before bulk import).
|
||||
|
||||
### Performance & structure
|
||||
- **Concurrency contracts** — state.json merge-by-slug with documented parallel
|
||||
lanes; crawl.mjs worker-pool concurrency; A-first-then-parallel variants.
|
||||
- **Fixed the parallel-authoring drift** — 10 review findings (contract
|
||||
contradictions, dangling refs, real crawl.mjs bugs) all resolved before the
|
||||
first commit.
|
||||
|
||||
---
|
||||
|
||||
## 3. New capabilities
|
||||
|
||||
| Capability | What it is | Validated |
|
||||
|---|---|---|
|
||||
| **`stardust:audit`** | One URL → 7-dimension scorecard (brand-expression, hierarchy, conversion, a11y, technical-SEO, LLM-visibility, performance) + prioritized findings + craft-rendered `report.html` + uplift-shaped closing directions. Optional Refero benchmarking, marketing-skills / modern-web-guidance / PageSpeed integration with graceful degradation. | ✅ ran on stardust.style: 68/100, 22 findings (5 P1/8 P2/9 P3), Refero benchmarks (Langbase/Eraser/Metaview), report.html craft-rendered + validated. audit.json matches the designed schema exactly. |
|
||||
| **Cross-site same-brand** | `extract --brand-source <url>` (sibling-property enrichment) and `--design-source <url>` (design-donor mode, formalizing the design-donor pattern first exercised on a camera-maker site); sibling-site discovery; `origins[]` provenance. `direct` pins to the donor surface and can amplify traits captured on a sibling. | ✅ implemented + wired; not exercised in the E2E set (single-origin runs). |
|
||||
| **Hands-off production mode** | Folds the external 298-line master migration prompt into the skills as enforced gates. `--hands-off` (or an explicit phrase): every interactive gate auto-resolves from captured evidence, quality gates never weaken, hard blockers still stop. | ✅ ran end-to-end on all 7 sites. |
|
||||
| **Learnings + status contracts** | `stardust/learnings.md` per-run ledger and `stardust/status.jsonl` deterministic progress surface (the stardust app wanted the latter; no model-emitted milestones). | ✅ status.jsonl written by every skill; ~109 learnings captured across sites. |
|
||||
| **modern-web-guidance consult** | prototype/audit query the Chrome-team guides for scroll/motion/CWV/modern-CSS best practices when the plugin is installed. | ✅ wired, optional. |
|
||||
|
||||
---
|
||||
|
||||
## 4. Test results — 7 sites, 13 pages, all live
|
||||
|
||||
Every page returns 200 on both the `.aem.page` (preview) and `.aem.live`
|
||||
(production) trees of the test project
|
||||
`github.com/paolomoz/stardust-plugin-refactor-fable`, each on its own branch
|
||||
and DA folder. Diff verdict faithful/clean on all.
|
||||
|
||||
| Site | Model | Pages deployed (aem.page) | Diff | Highlight |
|
||||
|---|---|---|---|---|
|
||||
| **site A (healthcare)** | Fable | `/site-a/` | 0 structural | multilingual healthcare; 4 AA/nav defects caught by gates |
|
||||
| **site B (industrial conglomerate)** | Opus | `/site-b`, `/site-b/abrasives` | faithful | recovered from a broken extract state **without re-crawling** an Akamai-walled site |
|
||||
| **site C (agency)** | Opus | `/site-c/`, `/site-c/man/git` | 0 structural | hero demo **video reproduced** (static + reduced-motion fallback) |
|
||||
| **site D (airline)** | Opus | `/site-d`, `/site-d/where-we-fly/north-america/usa/new-york` | 1 defect fixed | **anti-fabrication caught + dropped an invented section** at render |
|
||||
| **site E (tools retailer)** | Opus | `/site-e/`, `/site-e/products/saws` | 1 inline CTA caught | Usercentrics shadow-DOM consent; listing → real wayfinding |
|
||||
| **site F (nonprofit shelter)** | Opus | `/site-f/home`, `/site-f/get-help` | 8/8 headings, 0 dropped | nonprofit; **crisis/donation IA fully preserved** |
|
||||
| **stardust.style** | Fable | `/stardust-style/`, `/stardust-style/docs` | clean + SEO/LLM green | **audit-first**; validated both 0.14.2 fixes live |
|
||||
|
||||
Base URL pattern: `https://test-<site>--stardust-plugin-refactor-fable--paolomoz.aem.page/<path>`
|
||||
|
||||
stardust.style audit report: `stardust/audit/stardust-style/report.html` (craft-rendered).
|
||||
|
||||
### What the gates caught (that nothing else would have)
|
||||
- **Vision gate** — silent capture/render gaps on 3 sites (site E's `opacity:0`
|
||||
above-fold hero; site C's invisible demo video the record said didn't exist).
|
||||
- **Anti-fabrication** — dropped an invented "promo" section on
|
||||
site D that the shape brief had mislabeled `captured-verbatim`.
|
||||
- **`stardust:diff` structural probe** — real content/decode defects (dropped
|
||||
CTAs, quote→heading role swaps) on all 6 EDS sites that the atomic
|
||||
`.plain.html` and pixel checks passed green. Strongest single argument for
|
||||
wiring diff into the deploy loop.
|
||||
|
||||
### The two 0.14.2 fixes, validated live on stardust.style
|
||||
- **migrate canon auto-bootstrap** — status log: *"canon auto-bootstrapped from
|
||||
index (hands-off, Setup step 4)"*. On the six prior sites every agent had to
|
||||
bootstrap canon by hand; here it was automatic.
|
||||
- **computed-layout gate** — status log: *"computed-layout gate pass (9
|
||||
decorated blocks/page, all index grids grid)"* — the assertion that would
|
||||
have caught site B's silently-stacked layout.
|
||||
|
||||
---
|
||||
|
||||
## 5. Learnings loop
|
||||
|
||||
109 raw ledger entries → **42 distinct issues** after dedup (full digest:
|
||||
`notes/e2e-learnings-consolidated.md`). The three blocking multi-site issues
|
||||
were folded into the plugin this session (0.14.1 + 0.14.2):
|
||||
|
||||
1. **migrate canon dead-end** (4/6 sites) → auto-bootstrap from first approved
|
||||
prototype.
|
||||
2. **authorkit bootstrap bricking on `main` drift** (2 sites) → transactional
|
||||
ordering + refuse unpinned default.
|
||||
3. **silent stacked-layout ship** (the `.plain.html`-green-but-broken class) →
|
||||
headless computed-layout assertion in the atomic contract.
|
||||
|
||||
Plus 0.14.1 extract fixes confirmed by the runs: `_provenance` emission,
|
||||
apex→www origin adoption, Usercentrics shadow-DOM consent, video/iframe
|
||||
capture, and the playwright preflight guidance (`--no-save --legacy-peer-deps`
|
||||
+ copy-to-project ESM resolution) that every run had paid for by hand.
|
||||
|
||||
### Confirmed wins (by sites confirming)
|
||||
- Atomic DA deploy contract — 5 · Refero reference-research tier-1 — 5·
|
||||
hands-off pipeline end-to-end — 7 · Phase 2.5 vision gate — 3 ·
|
||||
`stardust:diff` structural probe — 6 · canon reuse across templates — 3 ·
|
||||
bot-management fallback ladder — 2 · anti-fabrication render catch — 1.
|
||||
|
||||
---
|
||||
|
||||
## 6. Backlog (documented, not yet folded)
|
||||
|
||||
From the consolidated digest, the highest-value remaining items:
|
||||
- **Fold the mandatory capture fields into `crawl.mjs`** (heroHeadline, font
|
||||
intercept, forms, per-section style summary) so runs stop re-implementing a
|
||||
~600-line extension. (4 sites)
|
||||
- **Validator-enforce shape-brief lineage/voice against the page JSON** — make
|
||||
Discipline 1/5 mechanical substring checks so a brief cannot self-report
|
||||
`captured-verbatim` on invented copy. (high-leverage; site D)
|
||||
- **Reconcile migrate's asset-rewrite vs portability contradiction**
|
||||
(depth-relative rewrite). (3 sites)
|
||||
- **Wire `stardust:diff` into the deploy loop** as a per-page gate (it caught
|
||||
what nothing else did on every EDS site).
|
||||
- Bundle a known-good `postlcp.js` as a deploy skill asset (removes the
|
||||
author-kit drift dependency entirely).
|
||||
- Cross-site same-brand and the audit `--deploy` path are implemented but not
|
||||
yet exercised on a live multi-property run.
|
||||
|
||||
### Known caveats on the deployed pages
|
||||
- A few sites self-hosted proprietary fonts (Metropolis, HarmoniaSans/DIN,
|
||||
Gotham, 3MCircular) for fidelity — each raised a licensing alert; confirm
|
||||
embedding rights before any production publish.
|
||||
- Motion registers were selected but rendered static on most runs (the
|
||||
cinematic layer is opt-in); stardust.style produced an `index-cinematic.html`
|
||||
but migration ships the static prototype per contract.
|
||||
|
||||
---
|
||||
|
||||
## 7. Bottom line
|
||||
|
||||
The refactor is committed on `fable5-refactor` (0.14.0 → 0.14.2, ~40 files).
|
||||
The design-quality thesis is validated: reference-grounded direction plus Mode
|
||||
A pinning produces demonstrably better redesigns that stay on-brand, on seven
|
||||
independent sites. Three new capabilities ship (audit, cross-site brand,
|
||||
hands-off mode) and the audit skill self-validated against its own schema on a
|
||||
live run. The pipeline runs fully hands-off from URL to deployed AEM page, and
|
||||
the new safety gates (vision, anti-fabrication, computed-layout, diff) each
|
||||
caught real defects the old text-level checks passed. The learnings loop is
|
||||
closed: the runs' own findings became plugin fixes in the same session.
|
||||
|
||||
Ready to merge `fable5-refactor`; stardust.style is deployed to the test
|
||||
project for you to move to production.
|
||||
@@ -1,246 +0,0 @@
|
||||
# Stardust improvement plan — harvest of two replica+deploy sessions — an energy-company site (EN) + a healthcare-insurer site (HI) — (2026-08-26/27)
|
||||
|
||||
**How to use this doc:** start a session with working directory
|
||||
`/Users/paolo/stardust/source/260826/skills` (repo root, branch `main`) and work
|
||||
the tiers in order. Every item is self-contained: evidence, target file, exact
|
||||
change, risk, and acceptance check. All paths below are repo-relative.
|
||||
|
||||
## Inputs
|
||||
|
||||
- Energy-company-site (EN) ledger: `/Users/paolo/stardust/2026-08/<energy-site>/<energy-site>/stardust/learnings.md` (items EN-1…12)
|
||||
- Healthcare-insurer-site (HI) ledger: `/Users/paolo/stardust/2026-08/<insurer-site>/<insurer-site>/stardust/learnings.md` (items HI-1…12)
|
||||
- Reference implementation for EN-1/2/3: `/Users/paolo/stardust/2026-08/<energy-site>/<energy-site>/scripts/replica/stitch-shot.mjs`
|
||||
(a modified copy of `plugins/stardust/skills/replica/scripts/stitch-shot.mjs`, +86 lines, commented; verified working in that session)
|
||||
|
||||
## Selection principles (agreed with Paolo)
|
||||
|
||||
1. **General improvements only.** Nothing site-specific ships. Items that
|
||||
generalize to a *class* of sources (e.g. "any AEM-classic site", "any
|
||||
bootstrap-era grid") qualify; single-site quirks do not.
|
||||
2. **Conservative: low-risk × high-impact beats high-impact alone.**
|
||||
Doc-only additions and additive fallbacks first. Changes that alter existing
|
||||
behavior (shared classifier semantics, default ports, capture strategy) are
|
||||
deferred to a guarded tier with an explicit validation protocol, or dropped.
|
||||
3. **Cross-session recurrence is the strongest signal.** Three failures
|
||||
recurred independently in both sessions (port collision, consent banners,
|
||||
live embeds) — those are Tier 1.
|
||||
|
||||
---
|
||||
|
||||
## Tier 1 — Recurred in BOTH sessions (do first; doc-only or additive)
|
||||
|
||||
### 1.1 Consent dismissal: visible-button text-match fallback
|
||||
- **Evidence:** EN-4 ⇄ HI-2. Two different consent widgets (the energy-company site's custom
|
||||
dialog; the insurer site's cookieconsent `a.cc-btn`) were missed by the selector list.
|
||||
On the insurer site the banner baked into ground truth AND repeated at all 7 stitch
|
||||
seams → 32% false pixel diff, one gate round invalidated.
|
||||
- **Target:** `plugins/stardust/skills/extract/scripts/crawl.mjs`,
|
||||
`dismissConsent()` (~line 271).
|
||||
- **Change (additive — runs only when the existing selector pass matched
|
||||
nothing):** scan visible `button, a, [role="button"]` elements for an exact,
|
||||
short-text match on Accept / Accept all / Allow all / Agree / OK / Decline /
|
||||
Alle akzeptieren / Accepter — click the first hit. Keep the length guard
|
||||
tight (≤ ~25 chars, visible, in a fixed/overlay container) so it can never
|
||||
hit an in-content link.
|
||||
- **Risk:** low. Fallback only; existing selectors keep priority. Worst case =
|
||||
same behavior as today (banner stays).
|
||||
- **Accept when:** the existing crawl selectors still fire on OneTrust/TrustArc
|
||||
test pages, and a synthetic page with only a text-labelled consent button
|
||||
gets dismissed.
|
||||
|
||||
### 1.2 Gate identity assertion — never diff an unverified localhost URL
|
||||
- **Evidence:** EN-11 ⇄ HI-1. Identical incident, opposite directions: a
|
||||
stale `:8791` server from another stardust project served a foreign site into
|
||||
a gate round (73% diff misread as "prototype broke"; on the insurer site the energy-company
|
||||
prototype was measured as "the build"). Every skill doc suggests the same
|
||||
port, so cross-project collision is guaranteed on a shared machine.
|
||||
- **Targets:**
|
||||
- `plugins/stardust/skills/replica/scripts/gate.sh` — before diffing, fetch
|
||||
the prototype URL and assert it contains a page-specific marker (the
|
||||
`<slug>` from the filename is already in the URL path; assert the fetched
|
||||
HTML title/body contains it, or accept a `--marker <string>` arg). Exit
|
||||
loudly with the `lsof -nP -iTCP:<port> -sTCP:LISTEN` owner on mismatch.
|
||||
- `plugins/stardust/skills/replica/SKILL.md` (~line 181),
|
||||
`plugins/stardust/skills/replica/reference/source-fidelity-gate.md` (~line 35),
|
||||
`plugins/stardust/skills/deploy/SKILL.md` (~line 820),
|
||||
`plugins/stardust/skills/diff/SKILL.md` (~line 49) — one added line each
|
||||
where `8791` is suggested: "verify the port is yours first
|
||||
(`lsof -nP -iTCP:8791 -sTCP:LISTEN`); prefer a per-project port."
|
||||
- **Change is additive:** do NOT change the documented default port (11 files
|
||||
reference it; churn + retraining cost outweighs benefit). The assertion makes
|
||||
the collision loud instead.
|
||||
- **Risk:** low. A false assertion failure is a 1-line marker fix; a missed
|
||||
collision today costs a full gate round.
|
||||
- **Accept when:** gate.sh against a deliberately wrong server exits non-zero
|
||||
naming the process; against the right server it proceeds unchanged.
|
||||
|
||||
### 1.3 recreation-procedure.md: two new permanent-residual classes
|
||||
- **Evidence:** EN-12 ⇄ HI-3 (live embeds, confirmed in both sessions) and
|
||||
EN-12 (randomized decorative positions).
|
||||
- **Target:** `plugins/stardust/skills/replica/reference/recreation-procedure.md`
|
||||
(residual-classes area, near the existing permanent-residual guidance at
|
||||
~lines 155–187 and the class list at ~line 371).
|
||||
- **Change (doc-only):** add two entries:
|
||||
1. **Live-data embeds** (stock tickers, YouTube, euroland-style widgets):
|
||||
the winning move is loading the SAME live embed (same src) on both sides
|
||||
so the data cancels out in the pixel diff — not freezing a snapshot.
|
||||
The insurer site's same-src YouTube iframe canceled to zero.
|
||||
2. **Randomized decorative elements** (inline positions regenerated per page
|
||||
load, e.g. generative line art): class-level permanent residual; log it,
|
||||
don't chase it.
|
||||
- **Risk:** none (reference doc).
|
||||
|
||||
---
|
||||
|
||||
## Tier 2 — Single-session but general; additive script hardening
|
||||
|
||||
### 2.1 Capture freeze: pause videos + neutralize JS timers
|
||||
- **Evidence:** EN-1. The CSS-only freeze stops neither `<video>` playback nor
|
||||
slick-style autoplay timers — ~20% of the energy-company page was video noise; every
|
||||
capture grabbed different frames/slides.
|
||||
- **Target:** `plugins/stardust/skills/replica/scripts/stitch-shot.mjs`
|
||||
(freeze block, ~line 193). **Port from the energy-company reference implementation**
|
||||
(path in Inputs) rather than rewriting.
|
||||
- **Change:** after settle + CSS freeze: pause every `<video>` and seek `t=0`;
|
||||
clear all pending timeouts/intervals. Symmetric — applied identically to both
|
||||
sides of a diff, so it cannot bias the comparison.
|
||||
- **Risk:** low-medium. Instrument change, but symmetric and already proven in
|
||||
a real session. Clearing timers *after* settle can't starve lazyload (settle
|
||||
already ran).
|
||||
- **Accept when:** two consecutive captures of a video-heavy page are
|
||||
pixel-identical in the video regions; a static page's capture is unchanged
|
||||
vs current main.
|
||||
|
||||
### 2.2 Carousel t=0 determinism
|
||||
- **Evidence:** EN-3. Autoplay advances during settle → slide identity
|
||||
arbitrary per capture. Clicking the first slick-convention dot after the
|
||||
freeze (transitions frozen → instant reset, symmetric) took residual 4% → 0.8%.
|
||||
- **Target:** same file/block as 2.1; also in the energy-company reference implementation.
|
||||
- **Change:** after freeze, click the first element matching the slick dot
|
||||
conventions (`.slick-dots li:first-child button` and equivalents) when
|
||||
present. No-op on pages without carousels.
|
||||
- **Risk:** low. Convention-scoped selector; symmetric; no-op otherwise.
|
||||
- **Accept when:** repeated captures of a slick-carousel page show the same
|
||||
slide; non-carousel pages byte-identical to pre-change captures.
|
||||
|
||||
### 2.3 Favicon on bounded extracts: cheap capture + loud skip
|
||||
- **Evidence:** HI-4. `--single`/`--pages` extracts skip Phase 3 (brand
|
||||
surface) where favicon capture lives; deploy's favicon step then skips
|
||||
*silently* ("never invent one") — deployed site ships the default icon.
|
||||
- **Targets & change (two halves, both additive):**
|
||||
1. `plugins/stardust/skills/extract/scripts/crawl.mjs`: on the entry page,
|
||||
read `link[rel~="icon"]` (fall back to `/favicon.ico`) and fetch it to
|
||||
`stardust/current/assets/favicon.<ext>` — one cheap request, runs in all
|
||||
modes.
|
||||
2. `plugins/stardust/skills/deploy/SKILL.md` Favicon step (~line 308) and
|
||||
final checklist (~line 947): change the silent skip to a loud warning —
|
||||
"no favicon captured: WARN and record in the deploy log; likely a bounded
|
||||
extract."
|
||||
- **Risk:** low. One extra fetch; doc line.
|
||||
- **Accept when:** `--single` extract of any site yields
|
||||
`assets/favicon.<ext>`; deploy without one prints the warning.
|
||||
|
||||
### 2.4 Deploy Step 3 (foundation) — two new warnings, one new pattern
|
||||
- **Evidence:** HI-7, EN-6, EN-7. All bit silently with green text gates.
|
||||
- **Target:** `plugins/stardust/skills/deploy/SKILL.md`, Step 3 foundation
|
||||
section (~line 275) and the #81 chrome-reservation passage (~line 282).
|
||||
- **Change (doc-only), three additions:**
|
||||
1. **box-sizing:** the boilerplate ships no global `border-box`. Any
|
||||
%-width + padding grid ported from a bootstrap-era source silently wraps
|
||||
every column (insurer site: cards 2+1, 2-col bands stacked, footer wrapped,
|
||||
+1731px doc height — all text gates green). Foundation should add the
|
||||
reset (or, minimum, warn when block CSS uses `width: N%` + padding).
|
||||
2. **Block-internal `<header>`:** boilerplate
|
||||
`header { height: var(--nav-height) }` collapses every semantic
|
||||
`<header>` a block emits (natural when porting prototypes; broke all such
|
||||
blocks at once on the energy-company site). Scope the reservation to `body > header`, or warn
|
||||
against `<header>` in block DOM.
|
||||
3. **Overlay chrome pattern (#81 gap):** transparent header floating over
|
||||
the hero → `--nav-height: 0` + absolute header, no reservation needed
|
||||
(measured CLS 0.0004 with this pattern on the energy-company site).
|
||||
- **Risk:** none-to-low. Additions 2's *code* variant (scoping the stock CSS
|
||||
selector) would touch the boilerplate contract — ship the doc warning now;
|
||||
scoping change only if the boilerplate is already being edited for #1.
|
||||
|
||||
### 2.5 Deploy brief template + gate procedure — two cheap guards
|
||||
- **Evidence:** EN-9 (mobile override loses to desktop *variant* specificity
|
||||
regardless of media query — the insurer site's `feature`/`panel` variants have exactly
|
||||
this shape, so it WILL recur on multi-variant rollouts) and EN-10
|
||||
(byte-identical differing-pixel count after a "fix" = the rule was a no-op;
|
||||
a burned gate round).
|
||||
- **Targets:** `plugins/stardust/skills/deploy/SKILL.md` brief template
|
||||
(~line 562) — add "mobile overrides must match variant specificity
|
||||
(`.cards.color .card-list` beats `.cards .card-list` in ANY media query)";
|
||||
gate/iteration guidance — add "before counting an iteration, verify the fix
|
||||
changed the render: an unchanged differing-pixel count means a no-op rule."
|
||||
- **Risk:** none (doc-only).
|
||||
|
||||
---
|
||||
|
||||
## Tier 3 — Reference-doc batch (low individual impact, zero risk; ship as one commit)
|
||||
|
||||
All doc-only; each generalizes beyond its source site.
|
||||
|
||||
| # | Evidence | Target | Addition |
|
||||
|---|----------|--------|----------|
|
||||
| 3.1 | HI-8 | `deploy/SKILL.md` images→background-LAYER rule | Never copy the pipeline's fallback `<img src>` into CSS `background` — it's the 750px rendition; rewrite `width=2000`. `<picture>`-rendered images unaffected. |
|
||||
| 3.2 | HI-9 | `deploy/SKILL.md` | `<picture>` wrapper adds an inline baseline descender (+6/7px per image paragraph vs bare `<img>` source); `line-height: 0` on the image paragraph restores parity. |
|
||||
| 3.3 | HI-10 | `deploy/SKILL.md` | Pipeline drops whitespace-only authored content (`<p> </p>`, trailing `<br> `): model those live line boxes as block CSS, never authored whitespace. |
|
||||
| 3.4 | HI-6, HI-11 | `replica/reference/recreation-procedure.md` + `deploy/SKILL.md` | `display: flow-root` reproduces clearfix margin containment (fixed −48/−20px per-section errors in one rule); un-floating columns in a media query loses the float's BFC — add `flow-root` to the mobile override. |
|
||||
| 3.5 | HI-5 | `replica/reference/recreation-procedure.md` | AEM-classic richtext byte patterns are load-bearing (`<p><br>\r\n </p>` = TWO line boxes; headings lead `<br>`; trailing ` ` = real line). Mirror byte patterns; diff `innerHTML` when a wrap-count mismatch survives width parity. General to the AEM-classic source class. |
|
||||
| 3.6 | HI-12 | `deploy/SKILL.md` block-CSS guidance | A wrapper reset can out-specify the block's own rules (`footer .footer > div` beats `footer .f-root`) — padding silently 0. |
|
||||
| 3.7 | EN-5 | `extract/SKILL.md` bot-wall section | Page-level bot walls (Cloudflare challenge) usually do NOT gate assets: media/CSS/fonts return 200 to a browser-UA curl. Say so before reaching for in-page-fetch machinery. |
|
||||
|
||||
---
|
||||
|
||||
## Deferred — high impact but NOT low risk (needs a decision + validation protocol)
|
||||
|
||||
### D.1 Shared classifier: element-boundary separators in textContent joins
|
||||
- **Evidence:** EN-8, corroborated on the insurer site (all `append()`-built blocks).
|
||||
JS-built DOM concatenates textContent without separators
|
||||
("...MediaLinkedIn...") → mismatch vs live HTML newlines → **13 false reds**
|
||||
in one session. Highest-impact single fix in this harvest.
|
||||
- **Why deferred:** the change lands in the shared classifier
|
||||
(`plugins/stardust/skills/diff/scripts/content-inventory.mjs`, textContent
|
||||
reads at ~lines 92/100, mirrored in `deploy/scripts/content-inventory.mjs`)
|
||||
and alters diff keys **globally** — every round-trip and content-diff
|
||||
comparison shifts. A bug here silently green-lights real content losses.
|
||||
- **If taken up:** normalize at *both* read sites identically (separator at
|
||||
element boundaries, then whitespace-collapse) so keys move in lockstep;
|
||||
validate by running the eval suite (`plugins/stardust/evals/`, esp.
|
||||
`replica-source-fidelity`, `reskin-content-fidelity`) plus a round-trip on
|
||||
one existing deployed project before/after — zero verdict changes expected
|
||||
on the fixtures.
|
||||
|
||||
### D.2 stitch-shot `--fullpage` escape hatch
|
||||
- **Evidence:** EN-2. Chunked stitching reproducibly corrupted the last chunk
|
||||
(scroll-state header baked into a seam + 720px horizontal wrap). fullPage
|
||||
fixed it, but needs three bundled mitigations (entrance-animation final
|
||||
state, iframe height locks, `img.decode()`).
|
||||
- **Why deferred:** it's an alternative capture *strategy*, not a hardening of
|
||||
the current one — a bigger behavioral surface than 2.1/2.2, and it was needed
|
||||
on one site. The energy-company reference implementation exists if a second session
|
||||
hits seam corruption; harvest then.
|
||||
|
||||
### D.3 Repo-wide per-project port defaults
|
||||
- Superseded by 1.2 (identity assertion makes collisions loud at near-zero
|
||||
cost). Changing the documented port in 11 files is churn without removing
|
||||
the underlying failure mode (any port can go stale).
|
||||
|
||||
## Explicitly not harvested (site-specific)
|
||||
|
||||
None of the 24 ledger items was purely site-specific; the closest (HI-5
|
||||
AEM-classic byte patterns) generalizes to a source-CMS class and ships as a
|
||||
scoped doc note (3.5).
|
||||
|
||||
## Suggested execution order
|
||||
|
||||
1. Tier 1 (three commits: 1.1 crawl fallback, 1.2 gate assertion + doc lines, 1.3 doc).
|
||||
2. Tier 2 (2.1+2.2 together — one stitch-shot commit ported from the energy-company
|
||||
reference; 2.3; 2.4+2.5 as one deploy-doc commit).
|
||||
3. Tier 3 as a single reference-doc commit.
|
||||
4. Decide on D.1 separately — it's the highest-impact remaining item but the
|
||||
only one that can silently change gate verdicts. Do not bundle it.
|
||||
|
||||
After each script change, both learnings ledgers' "Status: pending harvest"
|
||||
lines should be updated to record what was harvested where.
|
||||
@@ -1,211 +0,0 @@
|
||||
# Three new use cases — research synthesis + candidate approaches
|
||||
|
||||
> Round 1 exploration (2026-07-03). Constraint: no changes to existing skills in this round —
|
||||
> new skills/commands that orchestrate or wrap the existing pipeline. Synergy refactors come later.
|
||||
>
|
||||
> Research inputs: full plugin capability map (agent report), aemcoder/skills migration analysis
|
||||
> (agent report), nebula/greenfield research analysis (agent report), and direct reads of prior
|
||||
> experiments (`migrate-<airport-site>{,-eds}`, `migrate-<healthcare-site>`, `migrations/`).
|
||||
|
||||
---
|
||||
|
||||
## UC1 — Same-design migration to AEM (near pixel-perfect)
|
||||
|
||||
**User story:** migrate a site from any platform to AEM EDS keeping its current design. "Almost
|
||||
pixel-perfect": exactly the same page/content/design, except identified inconsistencies or minimal
|
||||
alignment improvements. Flow: static stardust prototypes of key pages (page types) first, then
|
||||
deploy to AEM reusing the same blocks site-wide.
|
||||
|
||||
### What research established
|
||||
|
||||
- **~80% of the pipeline is reusable as-is.** extract (`--prep`) already captures per-page
|
||||
screenshots, per-section computed styles, first-party CSS custom props, fonts (network-intercepted
|
||||
woff2), media, systemComponents, and authors a *descriptive* `current/DESIGN.{md,json}` in
|
||||
impeccable format. prepare-migration's archetype→sibling model = "key pages as page types, apply
|
||||
across site". deploy+rollout need nothing: deploy is design-preserving by construction relative
|
||||
to its input prototype; rollout Phase B literally implements "reuse the same blocks across the
|
||||
whole site" (`coverage/blocks.json` single conversion point per block).
|
||||
- **Two real gaps:** (1) no "reproduce the current design" direction mode — Mode A pins palette+type
|
||||
but still re-designs surface; `ia-fidelity: verbatim` freezes IA, not surface. (2) no fidelity gate
|
||||
pointing at the *source*: all diff machinery verifies prototype↔build, never live-site↔prototype.
|
||||
- **Prior art proves the flow end-to-end, manually:** `migrate-<airport-site>` (verbatim content
|
||||
model + component catalog + deterministic PDF↔site verifier, 83.6% verbatim) and its EDS sibling
|
||||
(bespoke-block + content-model fill, 62/62 pages live, harvested SKILL-IMPROVEMENTS.md).
|
||||
`migrate-<healthcare-site>` proved 291-page scale with "Variant A: faithful + identified improvements".
|
||||
- **Key methodology lesson (airport site):** *fidelity values come from the original site's own CSS,
|
||||
not the eye* — fetch stylesheets, lift exact tokens (container max-width, button spec, type ramp,
|
||||
hero heights) before any screenshot-eyeball loop. Converts 3–4 guess loops into one.
|
||||
- **aemcoder counter-evidence:** direct-to-EDS with LLM-eyeballed fidelity loops costs ~$35/page,
|
||||
90% of it in the conflated (content × EDS mechanics × visual) iteration; their own README steers
|
||||
pixel-critical cases away from block-rewrite. Validates prototype-first + measured diff.
|
||||
|
||||
### Candidate approaches
|
||||
|
||||
**UC1-A — new skill `stardust:replica` (preserve-mode orchestrator).** *[primary candidate]*
|
||||
1. `extract --prep` (unchanged) → full inventory, page types, module candidates.
|
||||
2. **Mechanical direction promotion** (new, inside the skill — does NOT touch `direct`): promote
|
||||
`stardust/current/DESIGN.{md,json}` + `PRODUCT.md` verbatim to project root as the *target* spec;
|
||||
no divergence roll, no craft re-direction. Permitted deltas = only items from `stardust:audit`
|
||||
design findings (or user-supplied list), recorded in a `brand_adjacent_refinements[]`-shaped
|
||||
ledger ("inconsistency register"). ia-fidelity implicitly `verbatim`, design-fidelity `verbatim`.
|
||||
3. **Recreation loop per archetype** (new): author clean semantic HTML/CSS per page type using
|
||||
(a) captured page JSON for content, (b) *source CSS extraction* for exact values
|
||||
(airport-site lesson — pull the live stylesheets, lift tokens/specs), (c) captured screenshot as
|
||||
ground truth. Gate: **source-fidelity gate** = `diff` scripts pointed at live URL vs prototype
|
||||
(`--profile generic`) + pixel-level screenshot compare; iterate to convergence with hard caps.
|
||||
4. Existing `migrate` (sibling tier) → `deploy` (favor template-slotted decode) → `rollout`.
|
||||
|
||||
**UC1-B — CSS-portation variant.** Same as A but step 3 *ports* the source site's own CSS
|
||||
(downloaded stylesheets, tree-shaken to used rules) instead of re-authoring clean CSS. Maximum
|
||||
fidelity, but: carries source's CSS debt into blocks, conflicts with "better implementation of key
|
||||
pages", and dirty CSS scoping under block classes is fragile. Keep as fallback for pixel-critical
|
||||
sections only.
|
||||
|
||||
**UC1-C — snowflake overlay path.** Byte-for-byte DOM preservation (snowflake skill exists).
|
||||
Maximum pixel fidelity but zero re-implementation value: no clean blocks, no reusable design
|
||||
system, defeats the stated goal ("better implementation of the key pages"). **Discard for UC1
|
||||
mainline**; document as the escape hatch for a page that must be byte-identical.
|
||||
|
||||
### Hypotheses to validate (experiment UC1-E1)
|
||||
|
||||
- **H1 (riskiest):** a clean re-authored prototype can reach near-pixel fidelity vs a live page
|
||||
(measured: 0 structural 🔴 on content-diff; visual-diff clean; pixel diff of section screenshots
|
||||
under an agreed threshold) within ≤3 measured iterations, when armed with captured JSON +
|
||||
source-CSS token lifting + screenshot.
|
||||
- **H2:** the "source-fidelity gate" is buildable from existing diff scripts (`--profile generic`)
|
||||
plus a small pixel-compare addition — no new instrument needed.
|
||||
- **H3:** the mechanical direction promotion (current→target) is sufficient for prototype-stage
|
||||
work without invoking `direct` at all.
|
||||
|
||||
Promote UC1-A if H1+H2 hold; if H1 fails on fidelity, test UC1-B on the failing sections.
|
||||
|
||||
---
|
||||
|
||||
## UC2 — Reskin (existing content × separately-defined new design)
|
||||
|
||||
**User story:** site A has the content; the new design already exists elsewhere (another site,
|
||||
static HTML prototypes, Figma, …). Rebuild A's pages with faithful content on the new design
|
||||
system. Same design-recreation precision as UC1 (toward the *donor*), but content mapping is the
|
||||
crux: faithful content, flexibly re-laid-out onto the new system.
|
||||
|
||||
### What research established
|
||||
|
||||
- **The live-site donor case is already specced:** `extract <content-url> --design-source <donor-url>`
|
||||
captures the donor to `stardust/canon-source/` and `direct` pins the donor surface as target while
|
||||
content stays with the primary origin. Content preservation in migrate is airtight and
|
||||
battle-tested (anti-fabrication catches in e2e runs).
|
||||
- **Gaps:** (1) non-URL donors — local static prototypes (small variant: serve on localhost) and
|
||||
Figma (new adapter via Figma MCP: variables→palette, text styles→type, screenshots→vision gates,
|
||||
new provenance class). (2) No cross-origin section-mapping contract (content site's page content →
|
||||
donor's module vocabulary). (3) Strict donor fidelity inherits UC1's preserve-mode gap, pointed at
|
||||
`canon-source/`.
|
||||
- **From aemcoder:** `dom-equality.mjs` (snowflake half) is exactly the UC2 content gate —
|
||||
whitespace-normalized visible-text byte comparison + image-set comparison, with tag-sequence
|
||||
divergence expected/informational. `metadata-extract.js` = the SEO carry-over checklist.
|
||||
|
||||
### Candidate approaches
|
||||
|
||||
**UC2-A — new skill `stardust:reskin` (donor-pinned orchestrator).** *[primary candidate]*
|
||||
1. Ingest donor: live URL → existing `--design-source` path; local prototype dir → serve on
|
||||
localhost and run the same path; Figma → adapter producing `canon-source/`-shaped artifacts
|
||||
(brand surface + descriptive DESIGN + screenshots).
|
||||
2. Extract content site fully (`--prep`).
|
||||
3. **Cross-origin mapping step** (new): for each content page type, a mapping brief — every content
|
||||
slot (from typed slots in page JSON) assigned to a donor module/pattern (from donor
|
||||
DESIGN/modules), with explicit lineage citations both ways (content from `current/pages/`,
|
||||
layout from `canon-source/`). This is the shape-brief Discipline-1 form extended cross-origin.
|
||||
4. Prototype per archetype against donor-pinned target; **dual gates**: content byte-fidelity
|
||||
(dom-equality-style: text bytes + image set + metadata carry-over) AND donor design adherence
|
||||
(UC1's source-fidelity gate pointed at donor pages/screenshots).
|
||||
5. migrate → deploy → rollout unchanged.
|
||||
|
||||
**UC2-B — reskin via canon transplant.** Run UC1-style recreation *of the donor* first (donor
|
||||
canon: header/footer/canon.css/modules), then treat the content site's migration as `migrate`
|
||||
sibling-tier renders into transplanted canon. More mechanical, likely better cross-page
|
||||
consistency; depends on donor canon quality. Candidate for the scale path after UC2-A validates
|
||||
the per-page mapping.
|
||||
|
||||
### Hypotheses to validate (experiment UC2-E1)
|
||||
|
||||
- **H4 (riskiest):** an agent can produce a faithful-content reskin in one archetype pass — content
|
||||
byte-fidelity (whitespace-normalized text equality, zero dropped slots, image set carried) while
|
||||
adopting the donor's tokens/modules (measured vs donor DESIGN.json + donor screenshots).
|
||||
- **H5:** the cross-origin mapping brief is decidable — content slots map onto donor modules
|
||||
without inventing new patterns for ≥80% of slots; the remainder is an explicit "new module in
|
||||
donor vocabulary" list, not silent improvisation.
|
||||
- **H6:** dom-equality-style byte-level text checking is adoptable as the content gate (adapted
|
||||
from the aemcoder clone) alongside the existing content-diff.
|
||||
|
||||
---
|
||||
|
||||
## UC3 — Greenfield creative generation ("Claude Design as a skill")
|
||||
|
||||
**User story:** generate a NEW design for a page/site from heterogeneous inputs (existing site,
|
||||
text description, brand pictures, Figma, inspiration sites, refero references). Core value =
|
||||
CREATIVITY: unexpected but balanced/modern/usable, no AI slop; variants along axes the user can
|
||||
pin to explore.
|
||||
|
||||
### What research established
|
||||
|
||||
- **nebula (local `stardust-greenfield`, one unpushed commit ahead of GitHub) is the mature front
|
||||
door**: brief → direct (non-web anchor + register + 5 axes from human-curated pools + named
|
||||
tension + distinctiveness gate vs named LLM-defaults) → render (signature specimens with
|
||||
load-bearing details, accent territory, baked palettes, impeccable gates). Validated 5/5
|
||||
distinctiveness (test-11a) after the v2 convergence fix.
|
||||
- **Its gaps are exactly this use case's asks:** single page only; text-brief-only input (no brand
|
||||
images / Figma / inspiration-site / refero ingestion); no variant fan-out with axis pinning
|
||||
(though pool-ID-based DESIGN.json is the right substrate); image generation unimplemented; pool
|
||||
content debt (gestures/axes partly TODO).
|
||||
- **stardust side:** divergence toolkit, refero tier-1 grounding (validated on 4/6 e2e sites),
|
||||
Mode B anchors, variant role contracts + convergence detector, motion registers — all reusable;
|
||||
but everything upstream assumes an extracted site, and the content-sourcing/placeholder economy
|
||||
is inverted for greenfield.
|
||||
- Motion signature library: 15 runnable clean-room specimens with production notes (S1–S20),
|
||||
plus hovers H1–H17, buttons B1–B12, links L1–L12, vocabularies V1–V11.
|
||||
|
||||
### Candidate approaches
|
||||
|
||||
**UC3-A — new skill `stardust:genesis` = nebula core + multi-input ingestion + variant axes.**
|
||||
*[primary candidate]*
|
||||
1. **Ingestion front door** (new): accept any mix of {text brief, existing-site URL(s), brand
|
||||
images, Figma file, inspiration URLs, refero queries}. Each input becomes an *origin* in a
|
||||
synthetic brand surface (`origins[]` pattern from `--brand-source`): images → palette/mood/motif
|
||||
evidence (vision); Figma → variables/type/components; existing site → standard extract; refero →
|
||||
grounded pattern references (reconciled with nebula's non-web-anchor stance: refero for
|
||||
layout/pattern evidence, non-web anchors keep owning personality).
|
||||
2. **Direction via nebula's machinery** (pools, anchor, register, tension, distinctiveness gate) —
|
||||
consumed as a library, not by modifying nebula.
|
||||
3. **Variant fan-out with pinning** (new): N variants = points in axis space; user pins axes
|
||||
(e.g. "keep this typography, re-roll motion+substrate"); re-rolls sample away from pinned
|
||||
variants (anti-convergence: minimum axis-distance between variants, per the v2 lesson).
|
||||
Contact-sheet artifact for review; pin → explore loop.
|
||||
4. Render per variant via impeccable + signature library; placeholder economy inverted
|
||||
(placeholders expected + enumerated, `--publish-sample` carve-out pattern).
|
||||
5. Optional back half: hand the pinned winner to stardust prototype/migrate/deploy for
|
||||
multi-page/EDS delivery (nebula's declared non-goal, stardust's strength).
|
||||
|
||||
**UC3-B — thin wrapper around nebula as-is + stardust back half.** Fastest to ship but fails the
|
||||
brief: no multi-input, no pinning. **Discard as end state**; useful only as the skeleton for A.
|
||||
|
||||
### Hypotheses to validate (experiment UC3-E1)
|
||||
|
||||
- **H7 (riskiest):** variant fan-out with axis pinning produces *genuinely distinct, non-slop*
|
||||
variants — measured with nebula's own instruments: per-variant distinctiveness table (≥4/5 axes
|
||||
off-default), pairwise axis distance ≥2 between variants, named tension present per variant.
|
||||
- **H8:** heterogeneous inputs measurably steer direction: the same brief with vs without
|
||||
image/inspiration inputs yields different, evidence-cited pool picks (origins → picks traceable).
|
||||
- **H9:** refero can be reconciled with the anti-slop stance (layout evidence only, personality
|
||||
stays with non-web anchors) without re-introducing "like Linear" convergence.
|
||||
|
||||
---
|
||||
|
||||
## Validation experiments (running now)
|
||||
|
||||
| Exp | Where | What |
|
||||
|---|---|---|
|
||||
| UC1-E1 | `/Users/paolo/stardust/uc1-replica-test/` | Recreate one live page (strict-design brand) as clean prototype; measured source-fidelity loop; ≤3 iterations |
|
||||
| UC2-E1 | `/Users/paolo/stardust/uc2-reskin-test/` | One content page × one donor design; content byte-fidelity + donor adherence gates |
|
||||
| UC3-E1 | `/Users/paolo/stardust/uc3-genesis-test/` | One brief + inspiration inputs; 3 variants along axes; pin one axis-set, re-roll; distinctiveness measured |
|
||||
|
||||
Promote/discard is recorded per hypothesis in `VALIDATION.md` in each experiment folder and
|
||||
synthesized back into this doc.
|
||||
@@ -1,124 +0,0 @@
|
||||
# Round-1 report — three new use cases: validated approaches + proposed skills
|
||||
|
||||
> 2026-07-03. Companion to `DESIGN-OPTIONS.md` (research synthesis + pre-registered hypotheses).
|
||||
> All three validation experiments ran to completion; verdicts below. Experiment folders:
|
||||
> `/Users/paolo/stardust/uc1-replica-test/`, `uc2-reskin-test/`, `uc3-genesis-test/`
|
||||
> (each has a `VALIDATION.md` with full evidence).
|
||||
> Round-1 constraint held: no existing skill was modified; every proposal ships as a new skill
|
||||
> that consumes existing skills/scripts in place.
|
||||
|
||||
## Verdict summary
|
||||
|
||||
| Hypothesis | Verdict | Headline evidence |
|
||||
|---|---|---|
|
||||
| H1 clean re-authored replica reaches near-pixel fidelity ≤3 iterations | **CONFIRMED** | a typographic retail home page: pixel-diff 8.31% → 2.93% → **1.31%**, height Δ 0px, content-diff "findings: none" (198/198 nodes, 59/59 CTAs) |
|
||||
| H2 source-fidelity gate buildable from existing diff scripts + small pixel add-on | **CONFIRMED** | generic profile worked; 4 adaptations needed (see UC1 notes) |
|
||||
| H3 direction step can be mechanical (current → target) | **CONFIRMED** | zero creative decisions; only measurement-policy calls |
|
||||
| H4 faithful-content reskin in one archetype pass | **CONFIRMED** | a healthcare site × a payments-company donor: text byte-identical 2281/2281, 7/7 images, 47/47 slots, 13/13 metadata, 17/17 donor-token probe |
|
||||
| H5 cross-origin mapping brief decidable (≥80% mapped) | **CONFIRMED** | 91% mapped to named donor modules, 1 explicit new-module, 0 silent improvisation |
|
||||
| H6 dom-equality adoptable as content gate | **CONFIRMED** | adapted with structure checks informational; shared normalization module capture↔gate |
|
||||
| H7 variant fan-out + axis pinning → distinct non-slop variants | **CONFIRMED** | pairwise axis distance 5/5/5; pins byte-verified; 1 variant partially collapsed via anchor↔signature incoherence (→ new gate) |
|
||||
| H8 heterogeneous inputs measurably steer direction | **CONFIRMED** | 9/9 pool picks changed baseline→informed, all cited; photos falsified the text brief's vibe |
|
||||
| H9 refero grounding without convergence | **PARTIAL** | screens grounded structure cleanly; styles search leaked into personality picks → firewall needed |
|
||||
|
||||
Discarded in round 1: **UC1-C** snowflake overlay as UC1 mainline (byte-fidelity without
|
||||
re-implementation value — kept as escape hatch); **UC1-B** CSS-portation as default (kept as a
|
||||
scoped reserve, see below); **UC3-B** thin nebula wrapper (fails multi-input + pinning brief).
|
||||
|
||||
---
|
||||
|
||||
## UC1 — PROMOTED: `stardust:replica` (same-design migration to AEM)
|
||||
|
||||
**Flow** (new skill orchestrating existing ones, no core changes):
|
||||
1. `extract --prep` unchanged → inventory, page types, module candidates, screenshots, fonts, media.
|
||||
2. **Mechanical direction promotion** (inside replica): `stardust/current/{PRODUCT,DESIGN}.{md,json}`
|
||||
promoted verbatim as target spec. Permitted deltas only from an **inconsistency register**
|
||||
(audit design findings and/or user-supplied list), `brand_adjacent_refinements[]`-shaped.
|
||||
3. **Recreation loop per archetype**: clean semantic HTML/CSS authored from captured content +
|
||||
values lifted from the source site's own CSS + screenshot ground truth. Gated by the
|
||||
**source-fidelity gate** (below), ≤3 iterations per breakpoint pass.
|
||||
4. `migrate` (sibling tier) → `deploy` (bias toward template-slotted decode) → `rollout`
|
||||
(block dedup already implements "same blocks across the whole site").
|
||||
|
||||
**Source-fidelity gate** (new scripts owned by replica; consumes diff scripts in place):
|
||||
- `content-diff.mjs` + `visual-diff.mjs` `--profile generic`, live URL vs served prototype.
|
||||
- Pixel probe: **scroll-and-stitch** capturer (Chromium `fullPage:true` renders lazy-decoded
|
||||
images as placeholders — stitching is mandatory) + pixelmatch; navigate by the **per-500px band
|
||||
breakdown**, not the overall %. Pass bar used: ≤~10% pixels, 0 structural 🔴, all visual flags justified.
|
||||
- Hardening required (H2 evidence): `domcontentloaded` instead of `networkidle` (live sites never
|
||||
idle); **real-Chrome UA** (default UA gets a Cloudflare challenge page that the diff then
|
||||
silently measures as the source — false-measurement trap); symmetric `--main` scoping.
|
||||
|
||||
**Design notes from the experiment:**
|
||||
- Two things computed-style capture missed and only the gate caught: rendered heading face living
|
||||
on an inner span (width-probe font fork caught it), and a hero scrim invisible to DOM/style
|
||||
probes (recovered by per-row luminance fitting). Keep both probes in the gate.
|
||||
- "0 structural 🔴" required mirroring live DOM quirks (span-in-heading granularity, hidden
|
||||
carousel clones, sr-only labels) — the known #87 JOIN/SPLIT tension; replica needs a documented
|
||||
"granularity parity" policy rather than fighting it per page.
|
||||
- **Mobile is not free**: 360px reference diff was 24% — the gate runs per breakpoint.
|
||||
- "Capture-state" policy: CDN-403'd images and "Loading…" hydration states are replicated as
|
||||
captured, logged, and flagged for the delivery phase.
|
||||
- **CSS-portation reserve** (from UC1-B): only for paint-level effects, JS-hydrated commerce
|
||||
components, and video/animated heroes — per-section, never page-level.
|
||||
- Prior art to fold into the skill text: the airport-site `SKILL-IMPROVEMENTS.md` (fidelity-by-CSS-
|
||||
extraction, neutralize boilerplate block CSS, preserve-and-move, coverage guards) and the
|
||||
the healthcare site's archetype→sibling scale pattern.
|
||||
|
||||
## UC2 — PROMOTED: `stardust:reskin` (existing content × defined new design)
|
||||
|
||||
**Flow:**
|
||||
1. **Donor ingestion**: live URL → the existing `--design-source` capture shape; local static
|
||||
prototypes → same path served on localhost; Figma → adapter (Figma MCP: variables→palette,
|
||||
text styles→type, screenshots→vision refs; new provenance class) — Figma adapter is round-2
|
||||
scope, the contract is defined now.
|
||||
2. **Content-model capture** of the content site (new profile, the round-1 gap): slot-granular
|
||||
text, CTAs with absolute hrefs, ordered visible images, metadata, an explicit content-root
|
||||
scope declaration, and an **executable normalization ledger** (cookie chrome, carousel
|
||||
de-duplication) shared between capture and gate.
|
||||
3. **Mapping brief** (per content slot): donor module id + rationale + status ∈ {mapped,
|
||||
new-module, chrome}; gate: ≥80% mapped, new-modules explicit, zero silent improvisation.
|
||||
4. **Programmatic render** from `content-model.json` — never retype strings; byte fidelity holds
|
||||
by construction. Donor tokens + module patterns supply the surface.
|
||||
5. **Dual gates**: adapted dom-equality (text bytes + ordered image set; structure informational)
|
||||
+ slot coverage + metadata carry-over; donor-token computed-style probe. Then migrate/deploy/
|
||||
rollout unchanged.
|
||||
|
||||
**Guards from the experiment:** content-root discovery (naive scoping silently dropped 30% of
|
||||
content), carousels break byte determinism (normalize at both ends), donors running multiple
|
||||
design systems concurrently (pin one donor reference page per module).
|
||||
|
||||
## UC3 — PROMOTED: `stardust:genesis` (greenfield creative, Claude-Design-as-skill)
|
||||
|
||||
**Flow:**
|
||||
1. **Input dossier**: any mix of text brief / site URLs / brand images / Figma / inspiration URLs /
|
||||
refero — each an origin with citations; conflicts recorded and resolved explicitly (photos can
|
||||
outvote the text brief — that happened and was correct).
|
||||
2. **Direction via nebula machinery as a read-only library** (`stardust-greenfield` pools, anchor
|
||||
selection, register, tension, distinctiveness gate). **Refero firewall**: screens = structure
|
||||
evidence only; styles search = category/avoid evidence; personality cites non-web anchors + register.
|
||||
3. **Variant fan-out**: `variants.json` with **6 pinnable slots** (typography, density, substrate,
|
||||
accent, motion, edges — colour split into substrate/accent); pairwise axis-distance floor ≥2;
|
||||
**anchor-promotion policy** (variant anchors = direction's scored winner + runner-ups — gave
|
||||
distance 5 for free); named tension per variant.
|
||||
4. **Renders + contact sheet** as first-class artifact: ≥2 scroll states per variant
|
||||
(hero-blindness finding: re-rolls can be invisible at rest) + axis table + a "what moves" line.
|
||||
5. **Pin + re-roll loop**: constrained resample (register bias, signature anti-pairs re-run —
|
||||
V11×S14 collision was caught this way, tech budget); plus one **qualitative anchor↔signature
|
||||
coherence gate** (the instrument gap that let variant C partially collapse).
|
||||
6. Optional back half: pinned winner → stardust prototype/migrate/deploy for multi-page delivery.
|
||||
|
||||
**Open items (round 2):** image generation hook; pool content debt surfaced as findings (edges
|
||||
pool has no playful posture; registers/gestures stubs forced substitutions); precedence decision
|
||||
where impeccable's "overused font" hook flags pool-curated picks (genesis must declare which
|
||||
instrument wins); nebula upstream is one unpushed commit ahead of GitHub — sync before depending on it.
|
||||
|
||||
---
|
||||
|
||||
## Round-2 synergy candidates (deliberately NOT done in round 1)
|
||||
|
||||
- `extract`: content-model capture profile; `--design-source-dir`; Figma provenance class.
|
||||
- `direct`: native preserve mode (replaces replica's mechanical promotion).
|
||||
- `diff`: absorb the pixel probe + UA/wait hardening + granularity-parity policy (#87).
|
||||
- nebula pools upstreamed/shared; refero firewall generalized to uplift/direct Mode B.
|
||||
- Evals: none of the seven existing evals cover these flows — each new skill needs its own.
|
||||
@@ -1,193 +0,0 @@
|
||||
# stardust:replica improvement — motion parity (observe, don't infer)
|
||||
|
||||
Self-contained spec for a general plugin improvement, written from the
|
||||
an energy-company migration (2026-08). Everything here is site-agnostic; that site's examples
|
||||
are marked as evidence. Reference implementation artifacts in this project:
|
||||
|
||||
- Instrument: `scripts/replica/motion-observe.mjs` (this repo — copy into
|
||||
the plugin next to `skills/replica/scripts/stitch-shot.mjs`)
|
||||
- Implementation layer produced by the method:
|
||||
`stardust/prototypes/css/motion.css` + `stardust/prototypes/js/motion.js`
|
||||
- Runtime evidence files: `stardust/replica/motion-observe-*.json`
|
||||
- Ledger entries: `stardust/learnings.md` items 13 (first attempt) and 14
|
||||
(correction — the actual method)
|
||||
|
||||
## 1. Problem
|
||||
|
||||
The replica source-fidelity gate is static-pixels-at-t=0 only. A prototype
|
||||
passes all four probes (pixel, anchor, content-diff, visual-diff) with every
|
||||
scroll-entrance animation, header scroll-morph, hover transition, and
|
||||
secondary carousel missing — and users notice immediately on first manual
|
||||
review. `recreation-procedure.md` § Interaction parity exists but is easy to
|
||||
skip (it skipped in 5 of 7 archetypes here, including under parallel
|
||||
sub-agent briefs), and it under-specifies HOW to discover motion.
|
||||
|
||||
## 2. The failure mode that makes the naive fix wrong (field-proven)
|
||||
|
||||
First attempt lifted motion from **static sources** — `@keyframes` + trigger
|
||||
classes from the site's CSS, element inventory from DOM class names
|
||||
(`querySelectorAll('[class*="-animation"]')`), hover rules by parsing
|
||||
`:hover` selectors. This **invents motion** three distinct ways, all caught
|
||||
in user review:
|
||||
|
||||
1. **Dead animation classes.** Sites (esp. component CMSs — the energy-company site is
|
||||
Sitecore) stamp animation classes on many elements; the runtime JS only
|
||||
ever adds the trigger class (`.animate` here) to SOME of them. Evidence:
|
||||
on the energy-company site, of ~8 caption-class families carrying `right-to-left-animation`,
|
||||
only 2 ever fire; 3 whole page types have ZERO firing entrance
|
||||
animations despite fully classed markup. Tagging from static classes
|
||||
animated elements the real site never animates.
|
||||
2. **Hover rules whose scope never matches.** A plausible, syntactically
|
||||
applicable `:hover` rule can be dead at runtime (scoping condition,
|
||||
specificity loser, wrong grid variant). Evidence: full-width teaser
|
||||
captions had a lifted scale rule that never applies on live; media-card
|
||||
hover scales the caption, not the card, contrary to the rule that
|
||||
appeared to match.
|
||||
3. **Approximated mechanisms create impossible states.** Reproducing the
|
||||
header scroll-morph as a cloned fixed overlay bar looked equivalent but
|
||||
allowed bar + original header visible simultaneously — a state that
|
||||
cannot exist on live, which morphs its SINGLE header in place. Users see
|
||||
a "double rendered" header. Mechanisms must be cloned from the observed
|
||||
state machine, not re-invented to a similar visual effect.
|
||||
|
||||
**Division of labor that works:** static CSS supplies exact VALUES
|
||||
(keyframes, durations, easings, colors); only a runtime trace decides WHAT
|
||||
runs, WHERE, and HOW the mechanism behaves.
|
||||
|
||||
## 3. The instrument: `motion-observe.mjs`
|
||||
|
||||
Ship as `skills/replica/scripts/motion-observe.mjs`, sibling of
|
||||
stitch-shot, reusing `live-session.mjs` hardening (UA/headers, headed
|
||||
fallback, consent dismissal, pacing). Reference implementation:
|
||||
`scripts/replica/motion-observe.mjs` in this repo (~170 lines, playwright).
|
||||
|
||||
What it does, per live URL:
|
||||
|
||||
1. **Instrument before any scrolling:**
|
||||
- `animationstart`/`animationend` capture-phase listeners → log
|
||||
`{animationName, elementPath (5 ancestors, incl. data-tpl/component
|
||||
marker), textSnippet (to map elements to prototype counterparts),
|
||||
scrollY}`.
|
||||
- `transitionstart` listeners → `{propertyName, elementPath, computed
|
||||
transitionDuration, scrollY}` (capped, e.g. 400 entries).
|
||||
- `MutationObserver` on `documentElement` (attributes:class,
|
||||
oldValue) → log classes ADDED per element (capped). This exposes the
|
||||
trigger mechanism (e.g. `.animate`, `slick-current`,
|
||||
`has-scrolled-up/down`) and its thresholds.
|
||||
2. **Scroll traversal:** auto-scroll to bottom in ~400px steps (~180ms
|
||||
apart), then back UP with dense sampling near the top (e.g. 300, 200,
|
||||
150, 120, 90, 60, 30, 0) — scroll-chrome behavior differs by direction
|
||||
and near-top state.
|
||||
3. **Chrome state timeline:** at each up-step (and sparsely on the way
|
||||
down) record the header's `{className, position, height, transform,
|
||||
transition}` plus `main`/`body` paddingTop (detects layout-compensation
|
||||
vs accepted content jump).
|
||||
4. **Widget pokes (`--click <selector>`, repeatable):** scroll the widget
|
||||
into view, click, then sample 4 frames at 200ms: track transform +
|
||||
transition, dot/indicator li classes + computed size/color/transition.
|
||||
Captures slide mechanics (fade vs translate, duration) and indicator
|
||||
animation (e.g. slick magic-dots: `li { transition: left .2s,
|
||||
transform .2s }`).
|
||||
5. Output one JSON: `{headerTimeline, widgetSamples, events: {animations,
|
||||
transitions, classMutations}}`.
|
||||
|
||||
Complementary probe (a dozen lines, can live in the same script behind
|
||||
`--hover <selector>` flags): **per-module hover-diff** — scrollIntoView,
|
||||
read computed transform/colors, hover, wait ~300ms, read again, park the
|
||||
pointer. Only a measured change justifies a hover rule in the prototype.
|
||||
|
||||
## 4. Skill-text changes
|
||||
|
||||
### `skills/replica/reference/recreation-procedure.md` § Interaction parity
|
||||
Rewrite around the evidence rule:
|
||||
|
||||
> Motion is OBSERVED at runtime, never inferred from static classes or CSS
|
||||
> rules. Run `motion-observe.mjs` per archetype live URL (full down+up
|
||||
> scroll; `--click` each carousel/widget control; `--hover` each distinct
|
||||
> card/teaser/button family). Implement ONLY behaviors that measurably
|
||||
> fired, with the recorded trigger mechanism, durations and thresholds.
|
||||
> Static source CSS is then the authority for exact keyframe/easing VALUES
|
||||
> of those fired animations. A behavior implemented without a runtime trace
|
||||
> naming it is a fidelity bug (same severity as an unregistered design
|
||||
> change).
|
||||
|
||||
Also add the mechanism-cloning rule: scroll-chrome and widgets are
|
||||
reproduced as the SAME state machine observed live (same element morphing,
|
||||
same class-state transitions, same restore thresholds) — never as a
|
||||
different mechanism with a similar look (the cloned-header-bar lesson).
|
||||
|
||||
### `skills/replica/SKILL.md` Phase 4
|
||||
Make interaction parity a REQUIRED gate output per archetype (like
|
||||
content-diff), not a post-pass suggestion: the archetype's ledger entry must
|
||||
include a **motion inventory** — for each fired animation/transition/chrome
|
||||
state: source evidence (observe-JSON pointer), implementation location, and
|
||||
a note for behaviors present in live markup but observed dead (these are
|
||||
recorded as NOT implemented, which is the correct replica of a dead class).
|
||||
|
||||
### Sub-agent briefs (parallel archetype fan-out)
|
||||
The brief template must carry the evidence rule + instrument invocation
|
||||
verbatim; this is the step agents skipped when unprompted.
|
||||
|
||||
## 5. Implementation pattern (what the method's output looks like)
|
||||
|
||||
One shared motion layer per project, not per-page forks:
|
||||
|
||||
- `css/motion.css`: lifted keyframes verbatim; trigger rules reusing the
|
||||
LIVE class names (keeps capture instruments symmetric — stitch-shot's
|
||||
animation-freezing already keys on `*-animation`); hover rules
|
||||
(hover-diff-verified only); chrome-morph classes; indicator transitions.
|
||||
- `js/motion.js`: an IntersectionObserver that adds the live trigger class
|
||||
(threshold ~0.15, once) to a per-module tagging map (runtime-fired
|
||||
selectors only); the chrome state machine on scroll (direction +
|
||||
thresholds as measured); widget drivers (autoplay interval, arrows, dots)
|
||||
mirroring observed mechanics.
|
||||
|
||||
Gate-safety is by construction: entrance animations only run when the
|
||||
trigger class is added (live has no pre-animate hidden state — verify this
|
||||
per site; if a site DOES hide pre-animate, stitch-shot's forcing covers it);
|
||||
chrome morph is inert at y=0; hovers need a pointer; stitch-shot clears
|
||||
timers so autoplay stays at t=0.
|
||||
|
||||
## 6. Verification protocol (both directions)
|
||||
|
||||
1. **No pixel regression:** re-run pixel-compare per touched archetype at
|
||||
the gate breakpoints; the number must return to (±noise of) the gated
|
||||
value. Energy-company-site evidence: press-hub 1.01% gated → 1.06% with invented motion
|
||||
(drift!) → 1.01% exact after evidence-only rewrite. The drift itself is
|
||||
a smell test: motion code that changes t=0 is wrong.
|
||||
2. **Behavior match:** headless run against the PROTOTYPE asserting, per
|
||||
page: tagged-element count == live fired count; chrome state at
|
||||
{top, scrolled-down, scrolled-up, back-to-top} == the live headerTimeline
|
||||
states; zero pageerrors. (This is the motion analog of the anchor probe;
|
||||
trivial to script from the observe-JSON.)
|
||||
|
||||
## 7. Pitfalls log (encode as bullets in the reference doc)
|
||||
|
||||
- Sites 429 bursts / bot-walls: observation needs the same live-session
|
||||
hardening + pacing as the gate captures; one observation run per page,
|
||||
reuse the JSON.
|
||||
- Autoplay widgets may pause off-viewport — poke them explicitly with
|
||||
`--click` rather than waiting for autoplay events.
|
||||
- Element→prototype mapping: match by text snippet captured in the event
|
||||
log, not by class names (prototype classes are clean re-authored names).
|
||||
- Indicator "magic dots": the live mechanism may animate `left`/`transform`
|
||||
while an equivalent rendered effect in the recreation animates
|
||||
width/height — equivalence of the RENDERED effect is the bar, but the
|
||||
duration/easing must be the measured ones.
|
||||
- Wobble/stagger patterns: delays may be child-order dependent (energy-company site: 2nd
|
||||
child first, 0.5s steps, 1st child last) — read them from the CSS rules
|
||||
of the FIRED animation, they're not guessable.
|
||||
- `prefers-reduced-motion`: mirror the live site's handling (energy-company site: none) —
|
||||
do not "improve" by adding it; that's an inconsistency-register item.
|
||||
|
||||
## 8. Suggested plugin deliverables checklist
|
||||
|
||||
- [ ] `skills/replica/scripts/motion-observe.mjs` (port of this repo's
|
||||
`scripts/replica/motion-observe.mjs`, + `--hover` flag,
|
||||
live-session.mjs integration)
|
||||
- [ ] `recreation-procedure.md` § Interaction parity rewritten (evidence
|
||||
rule + mechanism-cloning rule + pitfalls)
|
||||
- [ ] `SKILL.md` Phase 4: motion inventory as required gate output;
|
||||
progress.json schema gains `motion: {observed, implemented, dead[]}`
|
||||
- [ ] Sub-agent brief template carries the section verbatim
|
||||
- [ ] Optional: behavior-match assertion script (§ 6.2)
|
||||
@@ -1128,6 +1128,6 @@ Update `stardust/eds-conversion-log.md` (or create one) with: final block invent
|
||||
|
||||
- `davids-model.md` — David's Model (aem.live) distilled: the 15 rules (`D#N`), each mapped to the contract or gate in this skill that enforces it, plus the component-model shape compatibility notes.
|
||||
- `da-deploy-protocol.md` — the curl-based DA Source API deploy contract (auth, source PUT, preview/publish, asset-before-preview ordering).
|
||||
- `IMPROVEMENTS.md` — running log of friction/gaps and the numbered findings (#NN) that the stardust `diff` skill's `eds` profile cites.
|
||||
- `../../notes/deploy-improvements-archive.md` — the frozen ledger (findings #1–#80) that the `(#NN)` citations in this document and in the deploy/diff scripts point to; new findings go to `skills/stardust/reference/learnings.md`.
|
||||
- `scripts/ew-editability-probe.mjs` — the Experience Workspace editability gate (Step 8 § contract): instrument → decorate → count survivors; `--simulate-editor` edit-mode drift; URL and `--content` harness modes; reads `@ew-exempt` JSDoc tags.
|
||||
- Experience Workspace sources the contract was verified against (read them when the mechanism seems to have changed): da.live `blocks/canvas/editor-utils/editor-utils.js` (`getInstrumentedHTML` — what is stamped), `blocks/canvas/ew-editor-wysiwyg/ew-editor-wysiwyg.js`, `blocks/shared/prose2aem.js` (cells keep their `<p>`); da-nx `nx/public/plugins/quick-edit/quick-edit.js` (`setBody` → `loadPage` → `restoreBlockIndices`), `src/prose.js` (`createEditor` swap shape), `src/images.js`, `src/dom-index.js`, `src/selection.js` (cursor math on `textContent` length).
|
||||
|
||||
Reference in New Issue
Block a user