diff --git a/docs/superpowers/notes/2026-11-02-r8-image-use-findings.md b/docs/superpowers/notes/2026-11-02-r8-image-use-findings.md index 3dd1111..6be7aad 100644 --- a/docs/superpowers/notes/2026-11-02-r8-image-use-findings.md +++ b/docs/superpowers/notes/2026-11-02-r8-image-use-findings.md @@ -38,3 +38,61 @@ craft `clean-ai-response.ts`. Static reading only; no host or gateway contact, n ## Done this round (small and safe) - Prompt tweak (whp `sitesmith-prompts.php`): home hero uses the largest landscape owner photo; other pages prefer a different hero photo while unused photos remain. Prompt and all sitesmith PHP tests pass. + +## Round 9 (branch `sitesmith-images`): what was implemented against the gaps above +Gap numbers refer to the list above. Static + unit/browser tests only; no live model run yet. + +- **Gap 2 (invented `assets/` names) - done, client side.** `craft/src/sitesmith/asset-repair.ts` (`verifyAssetRefs`) runs inside + `useApplyAiResponse().apply()` BEFORE the allow-list cleaner whenever the modal passes the site's fresh upload list + (`SitesmithModal.applyResponse` calls `ss.listAssets()` right before applying, so a stock import since the modal opened counts). + Any `assets/`, `./assets/`, assets-proxy (`filename=`) or origin-qualified reference in an image prop or a CSS `url()` that is + not a real upload is swapped for the nearest-named upload (token/Levenshtein match, >= 0.6) or a labelled `placehold.co` placeholder + (background placeholders are made label-free by the existing cleaner). Proxy URLs of REAL uploads are normalised to `assets/`. + A note ("Sitesmith referred to N images that are not in your uploads ...") goes to the modal note area. A failed list load (null) + checks nothing; an empty list is meaningful (every `assets/` ref is broken). Also runs for regenerate-section. Video props and + non-image props (a PDF link) are never touched. The self-review patch path is NOT repaired (it only sends presentation props). +- **Gap 1 (enforcement) - done for the hero only.** Home hero (scope=page: only when the active page is the home page; scope=site: + the page named Home/Index/... else the first) that has a placeholder, a foreign URL or no image gets the best hero-capable + landscape upload (largest, >= 1200 wide, not logo-like, not already used on the page, only from the ticked uploads). + `HeroSimple` gets `bgType: image`, light text and an overlay >= 0.5; `BackgroundSection` an overlay >= 0.5; an `ImageBlock` + in a split just gets the new `src`. A Section hero with no image slot at all is NOT restructured (adding a photo behind + text designed for a flat colour risks unreadable text); the owner gets a note instead. The "uses none of the uploads on a page" + note that already existed (`missingUploadedImageNote`) is unchanged; no repair CALL was added (cost). + Stands down when the owner opts out in words ("no photo in the hero", "gradient hero") or names an upload file. +- **Gap 5 (same hero everywhere) - done client side.** On a whole-site build a later page whose hero repeats an earlier page's hero + photo is rotated to an unused upload when one exists (else left alone). The plan call still carries no `heroAsset` assignment + (a server-side plan change was not made). +- **Gaps 4/3 (metadata) - done.** whp `sitesmith_asset_traits()` adds a size class (large >= 1600, medium >= 1200, small >= 600, tiny) + and a `role:` hint to each asset row: hero-worthy, hero-capable, too-small-for-full-bleed, portrait, square, logo-like. Transparency is + not read (it is not in the cached metadata), so "logo-like" = SVG, a logo/icon/favicon/wordmark/badge name, or a longest edge <= 500px. + Thumbnails per request 6 -> 10 (`THUMB_MAX_COUNT`; `MAX_READS_PER_CALL` 12 -> 16; the caption call's `max_tokens` 1200 -> 1800). The + cost reservation needs no change: `estimateCallCost()` already charges 1600 tokens per image block actually in the messages, so 4 more + thumbnails add about 6400 prompt tokens to the plan/first call only (site page calls still reuse the turn without thumbnails; + `siteBuildEstimate` therefore rises with the plan call). `THUMB_TOTAL_BYTES` (3 MB) unchanged. Files 11-30 are still listed with + metadata but have NO caption (gap 3 remains partly open: a second batched caption call for them was not added). +- **Gap 7 (low resolution) - done.** Prompt rule (Using the owner's images): never use an image narrower than 1200px as a full-bleed + background; frame it in an ImageBlock beside the text. Client post-check: a hero `bgImage` upload under 1200px wide is swapped for a + better upload, else downgraded (`BackgroundSection`: colour band + the photo framed under the text; `HeroSimple`: its gradient). + Applies to every page's hero, not only the home page; suspended when the owner names the file. +- **Still open from the list:** gap 3 beyond 10 images (captions), gap 4 relevance ordering (mtime order unchanged, 30 listed), gap 6 + (page calls without thumbnails), gap 8 (no-upload placeholders), a server-side `heroAsset` in the site plan, and any repair CALL. + +### Not verified without a real model run +- How often the model now writes invented names / low-res backgrounds (the repair is exercised only with hand-made responses). +- That the `role:` hints and the low-resolution rule actually change the model's choices (prompt effect), and the ~+6400-token cost of + the extra four thumbnails against real per-call spend. +- Visual quality of a substituted hero: overlay 0.5 on a photo behind text that was designed for a flat placeholder colour (dark text + children of a BackgroundSection are not recoloured), and the downgraded "framed under the text" layout. Needs screenshots on the test VM. +- Name-matching false positives on real, messy filenames (IMG_1234.jpg style names never match by design and become placeholders). + +## Using the owner's Pixabay key from Sitesmith later (design hook only; nothing calls Pixabay today) +whp `docs/stock-photos-pixabay.md`: each panel user has their own encrypted key (`StockKeyStore`), searches are user-initiated and cached +24 h, imports copy ONE chosen photo into the site's own `assets/` (so every Pixabay image reaches a page as an ordinary upload; the +allow-list cleaner deliberately allows no Pixabay host). Rules to respect: no automated/bulk fetching, 100 requests/60 s per key, 20 +imports/hour/user, credit/alt text stored with the import. A future hook, in two safe steps: +1. Sitesmith never searches. When a page has NO suitable upload for the hero (home hero would be a placeholder), it emits the existing + "Image suggestions:" lines as a structured `stockQuery` (2-4 words) next to the placeholder; the editor shows "Find a photo for + this: " which opens the Stock tab pre-filled. The owner picks and imports; asset-repair's `usable` list then includes it. +2. Optional later: a user-confirmed "Fill my placeholders" button that runs ONE search per placeholder (max 3 per click, using the + existing search endpoint, so the per-user budgets and cache apply), shows results, and imports only what the owner clicks. The + panel must never import on the model's behalf, and the key stays server-side (the model never sees it).