mirror of
https://github.com/adobe/skills.git
synced 2026-09-19 08:06:09 +08:00
0d97a20ae1
Replace every reference to a real customer, test or donor site — in skill text, reference docs, script comments, the deploy IMPROVEMENTS log, the notes folder and the changelog — with a generic sector descriptor. Numbers, dates, finding IDs and technical content are unchanged; scripts changed in comment lines only (node --check / bash -n clean). Kept: vendor/platform names, Adobe's own properties, fictional sample brands, design-vocabulary brand references, and the eval suite's live crawl target. notes/improvement-plan-2026-08-rwe-centene.md renamed to notes/improvement-plan-2026-08-replica-deploy.md. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
22 KiB
22 KiB
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.mjsdiscover() doesn't recurse<sitemapindex>— would queue 6 XML files and fail each. - site B: wait-mode vocabulary mismatch — recipe
fast|medium|specvs crawl.mjsfast|medium|slow;--wait specsilently falls to medium. - site B: extract crash between Phase 2 and 3 leaves
state=extractedbut no_brand-extraction.json; no--consolidate-onlyresume 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.mjsnever setsprefers-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-
divstage 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 syntheticformless:trueentry 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.mjsadvisory noise — functional alpha ramps (scrim stops, hairline families) flagged as undocumented colors; allow adivergence.functional_ramps[]declaration. - site E: side-tab detector fires on a CSS-triangle play glyph (
border-leftwith 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.mjsrequiresstate.json.migrate.pageMap[], but the SKILL § State contract never enumeratespageMap(only in migration-procedure.md) — addpageMap[]{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.mjsdoesn't runsanitise.jsinternally (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) — usewhile IFS= read -r f. - site F:
header:off/footer:offmetadata is unsupported on vanilla aem-boilerplate (footer.js fetches/offand 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)
- Make
crawl.mjsand all bundled.mjsself-resolve playwright (§1 #1, #2 — 6 sites each). Add acreateRequire(process.cwd())shim to crawl.mjs and the prototype/migrate/diff fixtures soimport 'playwright'resolves from the project's node_modules; document the--no-save --legacy-peer-depsinstall 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. - 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--prepwrite-back); OR add prepare-migration/--prepas an explicit step inskills/stardust/SKILL.mdpipeline + direct's command sequence. Why: hands-off core pipeline dead-ends at migrate on 4 of 6 sites. - Make
bootstrap-authorkit.mjssafe and pinned (§1 #13 — 2 sites, blocking). PinAUTHORKIT_REFto a known-good static-fragment commit by default (notmain); make the port transactional with rollback; bundle a known-goodpostlcp.jsas 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. - Emit the
_provenancecontract fromcrawl.mjs(§1 #3 — 4 sites, high). One-line writer change threadingresp.status()+wait. File:skills/extract/scripts/crawl.mjs. Why: strict contract reading rejects every page the reference crawler produces. - 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. - Fix the
resolvesprobe 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. - 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. - 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 indecorate(); 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)
- 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. - Reconcile the asset-rewrite vs portability contradiction (§1 #7 — 3 sites, med): depth-relative rewrite in
asset-bundling.md+migrate/SKILL.md § Phase 3. - Add the Phase 2.5 section to
extract/SKILL.mdand rebuild the skill cache on change (§1 #10 — 3 sites, med). - Extend Mode-A / captured-verbatim bypass to data-detectors and declared
DESIGN.json.components[], and let the impeccable hook read areflexRejectAudit.bypassedmarker (§1 #11, #9 — 3 sites each, low). - Normalize
content-diffmatch keys (whitespace + typographic punctuation) (§1 #16 — 2 sites, low). File:skills/diff/scripts/content-diff.mjs. - 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. - 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-onlyresume seam (§3, various — mostly high-value where they gate capture completeness). - Single-site deploy gotchas: sanitise-in-deploy-batch, band/quote-as-
<p>, index folder-URL verify, zshwhile readPUT loop, vanilla-EDS header/footer:off + stock-nav-split docs, forms-block note,<p>-not-inside-<a>rule (§3). - 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).
- Docs/hygiene: inline PRODUCT.md spec (drop dead impeccable
teach.mdref), brand-review-template impeccable waiver, refero untrusted-description parser note (§3).