Imported from FahadBinHussain/aura (
AGENTS.md). Install upstream withnpx skills add FahadBinHussain/aura. Copyright stays with the author.
aura - project notes
layout
web/= the Next.js app (this is also the Vercel project's Root Directory)winui/,wpf/= desktop app variants;.github/workflows/build.ymlbuilds ONLY the WinUI app (dotnet publish + GitHub releaselatesttag) - it does not touch the web app.pnpmis the package manager (web/pnpm-lock.yamlis tracked - dependabot watches it).
security: next.js advisory GHSA-2xp9-vwfh-vxw4 (2026-09-06)
- unauthenticated RCE in the image optimization API when AVIF files are
optimized (libheif/sharp), critical 9.5. affected: next
>=10 <15.5.24and>=16.0.0 <16.3.3; patched: 15.5.24 / 16.3.3. - this repo was affected: lockfile pinned
next@16.2.6. it is RELEVANT here becauseweb/next.config.tsenables the optimizer (images.remotePatterns-> picsum.photos), so the/_next/imageendpoint is live on production. - fix: bump
"next"inweb/package.jsonto^16.3.3(lockfile resolves to 16.3.8 as of 2026-09-06), commit5861ed2. when upgrading next, the build regeneratesweb/next-env.d.ts- commit it with the bump. - dependabot alert clears on the next scan after the lockfile push.
backiee site reversing (2026-10-02)
- plain fetchers get 403; a browser UA works. in-app,
BackieeNetworkClient(HttpClient UAMozilla/5.0 ... Aura/1.0+ curl fallback) is the only sanctioned fetch path - use it for all backiee URLs. - category slugs are FLAT:
sitemap-categories.xmllists exactly 19/categories/<slug>pages, no nested subcategory URLs. api/wallpaper/list.php?action=paging_list&category=<slug>filters correctly (ThemeCatmatches the slug) - categories grid reuses this viaBackieeWallpaperSection.ForCategory().- per-category "Popular searches" chips link to
/search/<term>- this is the only subcategory-like level; search has NO api (action=search-> 550,args=ignored), it is server-rendered HTML with?page=Npagination (rel=next,data-pagination), scraped byBackieeHtmlParser. - list markup (both
/categories/<slug>and/search/<term>pages):a.wall-link[href=/wallpaper/<slug>/<id>]>.wall-body > h3title,picture > img.wall-cover[src]thumb,.flag-pillquality badge,.stat-pill(heart, download) counts in that order. - category cards on
/categories:a.category-card> imgstatic/wallpapers/categories/<slug>.jpg(url is derivable from slug), accent--category-accent: #hex, name inh3. - chips on category pages:
a.detail-chip[href=/search/<term>].
drill-down + infinite scroll, verified live (2026-10-06)
end-to-end on the installed CI build (UIA + vision, see automata
windows-ui-automation): Home -> Categories (19 cards) -> Abstract
(Abstract wallpapers title, 30-card grid, 13 labeled chips) -> digital+art
chip (24 search cards, orange active pill, server HTML ?page=N).
- chips had a blank-label bug (WinUI:
Foreground = nulllocal value beats the theme style setter) - fixed inApplyChipStyleviaClearValue(Control.ForegroundProperty), commit6fd48cb. - pagination (
CategoryWallpapersPage):MainScrollViewer.ViewChanged->offset >= ScrollableHeight * 0.4(_loadMoreThreshold) -> +30 items per server page (_itemsPerPage = 30; apipage=0..Nverified disjoint by curl). it also auto-fires when the window is restored/resized while near the bottom, and works with the window minimized. - load-more failure handling (fixed 2026-10-06): an exception in
LoadMoreWallpapersused to set_hasMoreItems = falsepermanently and silently - the error line only rendered when the grid was empty - so ONE transient network failure killed scroll-load for the rest of the page session (observed live: first bottom-jump fetched nothing, no bar, no message; only re-navigation recovered). now a failed page keeps_hasMoreItemsarmed (retry happens on the next scroll/resize/restore near the bottom; no storm possible becauseViewChangedonly fires on real view changes) and ALWAYS showsErrorTextBlockwith the message, cleared on the next successful page._currentPageonly increments on success, so a retry re-requests the same page.LatestWallpapersPagehad the identical catch with NO error UI at all - same contract there plus a newErrorTextBlockoverlay (same id/style as the category page). live-verified on the CI build (2026-10-06, hosts-blockedbackiee.com): failed jump showed the error line at 60 items within 2.4s (the old code showed nothing there), and after restoring the network the next bottom-jump retried the SAME page and cleared the line (60 -> 90, error absent). retry needs a REAL view change: a second jump from an already-bottom position is a no-op that fires noViewChanged(scroll away + back / resize / window restore are the triggers).
merged global/local categories, verified live (2026-10-06)
commit 544d27b (CI run 37437947067 green, installed over the local build).
one Categories page merges every platform's categories behind a scope button;
everything below was driven shell-only (UIA patterns, zero synthetic input)
against the installed build:
ScopeButton/ScopeButtonTextBlock: startsGlobal= 25 cards (19 backiee categories + 4K + Harvest Rain + Backgrounds + Places + Curated); flyout itemsGlobal (all platforms) | Backiee | AlphaCoders | Pixabay | Pexels; pickBackiee-> labelLocal · Backiee+ 19 cards, pickGlobal-> 25 again.- a merged card with >1 source opens a platform chooser (
Nature=Backiee | Pixabay | Pexels,Space= 2 sources); a card with exactly 1 source takes the direct-navigate fast path (Sources.Count == 1). - chooser ->
Pixabay= titlePixabay, empty grid, and a LOUDStatusInfoBarerror (Pixabay support needs a Pixabay API key. Add it in Settings > API Keys, then try again.) - never a silent empty state; chooser ->Backiee= titleNature wallpapers+ 30-card grid. - UIA ids for future checks: titles
PageTitleTextBlock(backiee/alphacoders) vsTitleTextBlock(public sources), gridsCategoriesGridView/WallpapersGridView, errorsStatusInfoBar(read its child Texts - its own Name is empty).Nature(3 sources) andSpace(2) are the merged canaries. - flyout menus need the offscreen-visible window protocol (while minimized
the popup is never even created) - recipe in automata
windows-ui-automationAGENTS.md.
all-9-platform categories, reversed + ported (2026-10-06)
the Categories page now scopes over every implemented site (supersedes the
25-card state above): Global = 112 merged cards; per-scope counts: backiee
19, alphacoders 63, pixabay 20, wallpaperhub 17, artstation 5, pexels 3,
wallhaven 3, bing 1, simple desktops 1. CategoryPlatforms (9 entries) is the
scope menu; every other platform contributes PublicWallpaperService.GetModes()
as its category cards. per-site reversal evidence + curl recipes live in
automata-private/<site>/AGENTS.md (8 new folders + wall.alphacoders.com
extended). key facts the code depends on:
- wallhaven:
categoriesbitmask order = general/anime/people (proven by reading the per-resultcategoryfield:100->only general,010->anime,001->people) -> modes General/Anime/People; legacy Latest/Random/Toplist still resolve with 111. the mode switch is lowercased (slideshow passes lowercase modes). - pixabay: categories = the site's curated Collections index, live-loaded (see the dated section below) - the old 20-API-category list, the API calls, and the API key requirement are GONE.
- wallpaperhub: the 17 collections (id+title) =
WallpaperHubCollections, LIVE-LOADED from the site's own Collections index (see the dated section below) - a mode that matches a collection title routes to/collections/<id>and parsespageProps.collectionWallpapers(identical{entity:...}wrappers asinitWallpapers); anything else =/wallpapers(initWallpapers). both SSR shapes serve everything at page 1.?tags=is SSR-ignored - never build fetch URLs on it. - alphacoders: uniform
https://alphacoders.com/<slug>-wallpapers?page=N(4kspecial ->/resolution/4k-wallpapers; plain4k-wallpapers= 404). the category list is LIVE-LOADED from the site's real category pagehttps://alphacoders.com/tag/is-category(24 desktop rows over the index's 2 pages;GetCategoryIndexAsyncSetCategories, same loud contract as backiee - a failed fetch = a loud error line, never a silent empty list) - the merged grid ANDAlphaCodersGridPagetitles both readAlphaCodersService.Categories; deep-linked categories leave the 3 quick buttons unselected instead of faking 4K. the old 63-entry homepage-curated table was REMOVED 2026-10-08 (see the dated section below).
- artstation: the subject-matter taxonomy is POST + CSRF (anonymous =
Invalid CSRF Token; GET filter params silently ignored - all baselines stay 47230), but the site's own Channels directory is anonymous-open - that is the category source now (see the dated section below). live indexapi/v2/community/channels/channels.json(GetChannelsIndexAsync+SetChannels, 64 published channels) + drillcommunity/channels/projects.json?channel_id=&sorting=trending&per_page=45(GetChannelProjectsAsync, same card shape as the search endpoint minusis_adult_content- the adult flag there ishide_as_adult).ArtStationGridPagetakeschannel:<id>as its navigation parameter; sorting buttons exit channel mode (and neither chip is highlighted while in it). - bing + simple desktops: proven zero taxonomy => one honest entry each
(
Daily/Minimal) so no scope ever renders an empty grid; their fetchers ignore the mode. (SUPERSEDED 2026-10-09: both are now rejected from the category page entirely via the dynamic exclusion list - see the dated section; their grid chips keep the entries.) - pexels: categories = the site's own Wallpapers discover index, live loaded (see the dated pexels section below - the old read "API has no categories at all (Curated/Nature/Space stay), the website is Cloudflare-walled" is SUPERSEDED: the site passes with curl + the full browser header set).
- chips overflow fix: up to 17-20 mode chips per platform ->
ModeButtonsPanelnow sits in a horizontalScrollViewer(Auto horizontal bar, Disabled vertical, ZoomMode Disabled). - category card thumbnails (fixed 2026-10-07): only backiee cards ever got
real art -
BuildMergedleft every other platform's card on the shared placeholder forever (the reported bug: "cards after the first backiee ones show the same placeholder"). nowFillThumbnailsAsync(fire-and-forget right afterApplyScope) gives every non-backiee card ONE representative wallpaper = page 1's first item of its own drill-down fetch (alphaGetWallpapersByCategoryAsync(key,1,1)/ArtStationService GetChannelProjectsAsync/PublicWallpaperService.GetWallpapersAsync) throughWallpaperItem.LoadImageAsync, session-cached in a staticConcurrentDictionary. three traps found live:AlphaCodersService's scrape cache is STATIC (list + lastPage + currentCategory) and NOT thread-safe: the first build fetched through a 4-wide gate and exactly the 4 simultaneous cards came back empty (plus cross-category image mixups) while every sequential scrape - the grid page, curl - worked. alpha fills therefore run through their ownAlphaCodersThumbGate = 1(alone); other platforms share the 4-wide gate because each news its own service instance per fetch.WallpaperItem'sGetOutputStreamAt/AsStreamForWrite/FlushAsyncstream path threw WIC0x88982F50with an EMPTYex.Messageon 3/93 loads (an empty reason in the error bar) -> rewritten toBackieeCategory's provenstream.WriteAsync(bytes.AsBuffer())+Seek(0)+SetSourceAsync(its 19/19 pattern); empty reasons now coalesce to<Type> hresult=0x<code>so the bar can never go blank.- loud contract: the bar lists EVERY platform with >= 1 failed card as
<platform> category thumbnails: <n>/<total> failed - <first reason>; a keyless install shows exactly 1 line (the Pexels API key - pixabay needs no key since the 2026-10-08 collections rework; since the 2026-10-09 pexels discover re-source even pexels FILLS need no key - the chip photos come from the CDN - so a keyless install shows no fill line at all: the loud key error surfaces on the first pexels DRILL instead). the fill failure paths never touch the session cache, so the next Categories open retries them. verified menuless + vision on the local build (2026-10-07): the complaint cardsAura Farming..Cyberpunkall real, alpha 0/63 failed, 0 duplicates except one honest source overlap -animalandcatpages serve the SAME first thumb (thumbbig-20658.webp, curl-verified), so those two cards legitimately show one photo. second instance (2026-10-08): pixabaypeopleandtravelboth serve photo id10506740first (identical bytes, verified live) - pixabay's per-request random url prefix makes the first-hit URLs LOOK different while serving the same image, so compare hit ids (or file hashes), never url strings. duplicate thumbs are honest source overlap, not a cache bug, unless hit ids differ.
7 more keyless platforms ported, verified live (2026-10-08)
the picker listed 28 platforms; 9 were implemented, now 16: the new 7 =
DesktopNexus, Digital Blasphemy, HDwallpapers, Pixiv, Cara, Wallpaper Cave,
Wallpaper Engine. the 2 dead domains (Kuvva, Vladstudio) were removed from
the picker entirely on 2026-10-08, so it lists 26. Global categories =
149 merged cards (was 112).
per-site reversal evidence + curl recipes live in
automata-private/<site>/AGENTS.md (7 new folders). key facts:
- single source of truth =
PublicWallpaperService.GetSupportedPlatformNames(): it drives the picker's not-implemented dialog (ShowNotImplementedMessage),CategoryPlatforms,BuildMerged's platform loop, andNavigateToSource's routing (default case =IsSupportedPlatform->PublicWallpaperGridPage). that last one was the 4th hardcoded list - acase "Pixabay": ... case "WallpaperHub":switch arm - which made every new platform's card drill die withNo drill-down page exists for X categories. no hardcoded platform lists remain. - honest caps: Digital Blasphemy full = 640x480 preview (membership originals),
Wallpaper Engine full = preview_url (file url needs auth), Cara thumb == full
(single full-size image), Wallpaper Cave titles =
<h1> #<n>(no per-item titles exist), DesktopNexus grid/preview+ full/original, HDW full =/previews/<slug>-<id>.jpg(droppingthumb_from the cdn url is 404). - content policy: pixiv
restrict=safepinned on every request + per-itemxRestrict != 0skipped; steam parts tagged Questionable/Mature/Adult/ NSFW/18+ dropped (2/30 on page 1); cara has no filter - no NSFW modes added. - pximg referer:
WallpaperItem.GetRefererForreturnshttps://www.pixiv.net/for i.pximg.net (alphacoders referer = 403 there) - proven live, pixiv tiles render real art. - cara needs curl, not .NET: cara.app + images.cara.app return 403 to
SocketsHttpHandler's TLS fingerprint (http/1.1 AND http/2; curl + same UA =
200) ->
Services/CurlClient.csis cara's ONLY transport (html viaGetStringAsync, images viaWallpaperItem.IsCaraUrl), single method not a fallback, failure = curl exit code + stderr in the loud bar.BackieeNetworkClient's curl part now delegates to CurlClient (identical invocation, unchanged behavior). - steam split regex fails one-typo-silent: a verbatim
Regex.Splitliteral one backslash short after the colon matches nothing -> 0 items, no exception, clean bar. the parse harness missed it by mirroring patterns; the check that works is decoding the@"..."literal out of the C# SOURCE (""->") and asserting IsMatch against a captured body. - the other 9 listed platforms stay unimplemented ON PURPOSE: 7 are WAF/anti-bot-walled (Dribbble, Newgrounds, Peakpx, CGSociety, Behance, ArtFol, CharacterDesignReferences) and 2 need credentials (Unsplash = API key with hosting-terms caveat, DeviantArt = OAuth). the dead 2 were dropped from the list (see above), and Artgram left this list the same day (see the Artgram section below). the picker dialog text derives from SupportedPlatforms, so it always matches reality.
- verification recipe (menuless, zero focus steal, ~9 min):
C:\tmp\aura-platformcheck.ps1(probes stay in C:\tmp, never committed). it: waits for a window handle that HOSTS UIA text and is still the main window (the splash/transient window hands you a stale handle whose tree reads empty forever), drills the picker for Pixiv via a 900x3600 resize (the picker's ItemsRepeater realizes only the visible 16/28 otherwise), then drills 6 single-source cards (source grep proved none of Explore/Trending/Soulslike/All/Free/Latest is shared -> the chooser MenuFlyout never opens), waits 180s of thumbnail fill reading BOTH ErrorTextBlock and StatusInfoBar (an ERR line masks the IB fill lines if you return early), deep-scrolls via ScrollItemPattern and restores to top, captures viaautomata-private\window-capture\Capture-WindowBackground.ps1(moved fromtools\on 2026-10-08) for rule-15 vision checks. assert items>=5 per drill, bar clean, cards>=100. the known open silent death (exit=0) fired on 2 of 7 runs - paced re-runs pass; root cause still open (see the menuless section below).
17th platform: Artgram, reversed + ported (2026-10-08, same day)
Artgram had been triaged as WAF-blocked - that was wrong: a live re-probe found
the gallery fully anonymous-reachable (reversal + curl recipes in
automata-private/www.artgram.co/AGENTS.md). ported as platform 17; all
derived lists (picker dialog, categories, drill routing) follow
SupportedPlatforms automatically. Global categories = 150 merged cards:
Artgram's Trending and Latest MERGE into the existing Wallpaper Engine /
HDwallpapers cards (same mode titles), so only Oldest adds a card.
- images:
fsn1.your-objectstorage.compresigned urls, 1h expiry, minted per page render - covers (512x512) go on the grid and FullPhotoUrl; opening an item runsPublicWallpaperDetailPage.UpgradeArtgramImageAsync(), which refetches the art's detail page, swaps FullPhotoUrl to the artworks/ original (render/set/download all flip together via GetBestImageUrl) and postsArtgram original image loaded.- failure keeps the cover and posts the reason as a Warning InfoBar. public-source items open the PUBLIC detail page (Views/PublicSources/PublicWallpaperDetailPage) - the AlphaCodersWallpaperDetailPagenever sees artgram items (its DebugBigThumbTextBlock hook read ABSENT in the first verify run for exactly that reason). - verification recipe impact:
aura-platformcheck.ps1's drill listExplore, Trending, Soulslike, All, Free, Latestis no longer chooser-free - Trending now has 2 sources (Wallpaper Engine + Artgram) and Latest 2 (HDwallpapers + Artgram): clicking either would OPEN the chooser MenuFlyout (forbidden while the user works). swap both forOldest(Artgram-only) in future full runs. verified menuless the same day: cards=150, Oldest drill items=20 (viewport-realized; grid is virtualized) title=Artgrambar clean, detail upgrade Success line exact, both backs OK, 90s fill clean, focus restored. - known limit: the slideshow never opens detail pages, so it shows Artgram's 512 covers (documented, not silently broken).
alphacoders categories now live from the real category page (2026-10-08)
user audit: the 63-card AlphaCoders set was derived from the homepage's
curated slug links, not the site's own category taxonomy. fixed at the source:
AlphaCodersService holds NO static category list now -
CategoriesPage.LoadCategoriesAsync fetches
https://alphacoders.com/tag/is-category (runs alongside the backiee load)
through GetCategoryIndexAsync + SetCategories and parses its 24 <h3>
rows across 2 pages - the index PAGINATES (?page=1 = 20 rows + a
?page=2 link, ?page=2 = 4 more: Dark/Technology/Religious/Humor with no
further link, ?page>=3 = 200 but 0 rows) and the loader walks pages until
the first empty one (hard cap 10; blowing the cap = a thrown error -> the loud
bar, never a silently truncated list) (name = row text, first letter of each word up-cased - "video game" ->
"Video Game", the page's own "TV Show" casing survives; browse key = the h3
slug -> <slug>-wallpapers?page=N, which is exactly the row's own "Desktop
Wallpapers" cell href). the -phone/pfp/gif cells can never parse (h3-anchored
regex). fetch failure = a loud error bar line (same contract as backiee), and
the error bar now also shows under the Local - AlphaCoders scope (visibility
conditions extended to it).
- counts: per-scope AlphaCoders = 24 (was 63), Global = 113 merged
cards (was 150 at the 63-era; 110 when only page 1 loaded - Dark,
Religious, Humor add cards,
Technologymerges into the hdwallpapers one). the grid page's4k/harvest/rainquick buttons are page chips, not category rows - unaffected (4kstill resolves to the resolution page). - menuless canary:
Batmanis gone (not a real category) - drillVehiclefor the alpha single-source check. verified menuless three times: 113 cards, 24/24 real names on the grid, 0 legacy names,Vehicletitle + 15 items, bar clean, stable under a 60s watch. - the back-lands-on-Home anomaly observed TWICE now: the 2026-10-08 alpha run
and the 2026-10-09 pexels run 3 (both at the LAST back of a drill sequence:
scope reads
ABSENT,Select Your Wallpaper Sourcepresent, cards=-1; re-navigating to Categories works) - not reproduced between them, root cause unknown.
wallpaper cave thumbs hit an AVIF wall (2026-10-08)
wallpapercave.com/mwp/<file> now transcodes to image/avif
unconditionally (Accept: image/jpeg does NOT negotiate it back; file magic
ftypavif), and WinUI has no AVIF decoder (its decoder list: TGA/QOI/GIF/
JPEG/TIFF/PBM/BMP/Webp/PNG) - so every Wallpaper Cave card decode-failed and
the loud bar showed Wallpaper Cave category thumbnails: 8/8 failed - Image cannot be loaded. Available decoders: ... at ~35s into every fill. fix =
ImageUrl now uses the site's OWN desktop <source>
https://wallpapercave.com/dwp1x/<file> (JPEG, 12/12 verified across 4
albums); FullPhotoUrl stays /wp/ (JPEG original). re-verified menuless:
bar clean through the full 60s fill watch.
pixabay categories re-sourced to the real collections page (2026-10-08)
user audit: pixabay's 20 "categories" were the API's filter values (docs
category str row), not the site's own browsable categories. the real surface
= https://pixabay.com/collections/ ("Curated Collections" by Pixabay) -
63 collections over 2 pages (?pagi=1 = 40 + ?pagi=2 = 23; TRAP:
?pagi>=3 SILENTLY WRAPS to page 1 - the pager on page 2 even links to
?pagi=3 - so GetPixabayCollectionsIndexAsync stops at the first page with
no NEW slugs, hard cap 10 + thrown error past it). CategoriesPage
live-loads it (runs alongside the alpha + backiee loads) via
SetPixabayCollections, same loud contract, error-bar visibility extended to
the Local - Pixabay scope; the drill fetcher scrapes each collection's own
page (?pagi=N, ~15 tiles; data-pk id, img alt as title, __340.jpg
tile -> _1280.jpg full - SINGLE underscore, __1280/__640/bare = 403).
- the API is GONE from the pixabay path (it cannot filter by collection):
pixabay needs NO API key anymore. the Settings key box was removed (saving
now clears any legacy stored key via the empty second slot), the keyless
bar-line count drops to exactly 1 (Pexels),
GetDescriptionand the README say so. - transport = curl, like cara: Cloudflare fingerprints the TLS client -
the SAME headers pass through curl.exe and 403 through SocketsHttpHandler
(http/1.1
RequestVersionExactincluded), so html fetches route throughCurlClient.GetStringAsyncwithSec-Fetch-Mode: navigate+Sec-Fetch-Site: noneREQUIRED (plain curl = 403; the... Aura/1.0UA passes with them). the CDN (cdn.pixabay.com) and/api/pass .NET - only the HTML pages route through curl. - Cloudflare rate-limits rapid pixabay fetches (~4+ back to back = 403
challenge, loud as curl exit 22 in the bar, retried next open - failures
are never cached): the thumb fill got its own
PixabayThumbGate = 1(like alpha's) and the full 61-card pixabay fill then ran 0 challenges. - counts: per-scope Pixabay = 63 (was 20), Global = 159 merged cards
(was 113; collection names like Food/Fashion/Sports merge with other
platforms' cards, adding 46 net). public-grid drill titles stay the
PLATFORM name (
Pixabay), not the collection name. - menuless canary:
Halloween(pixabay-only; 15-item drill, alt-text captions render). verified menuless 2026-10-08 (probeC:\tmp\aura-pixabaycollectioncheck.ps1): 159 cards, 14/14 sampled collection names, 0 old API-category names, Halloween + alphaVehicledrills OK, bar clean through the whole fill + a 90s watch, no flip. vision (zengate,C:\tmp\zengate-vision.ps1): real Halloween artwork tiles, no broken/placeholder tiles. - the slideshow's
latestmode = the site's own newest wallpaper results (fix 2026-10-10):/images/search/wallpaper/?order=latest&pagi=Nvia the same curl transport. ~100 tiles/page,?pagi=99serves older DISTINCT ids (NO wrap like the collections index), every tile ships a schema.org ImageObject JSON-LD block (contentUrl= full_1280,acquireLicensePage= item href,name= title; parse independent per-key, no key-order contract). TRAP: the visible<img>is eager on only ~19 tiles (the rest rendersrc=/static/img/blank.gifwith the URL living ONLY in the JSON-LD)- the collection-page tile-img parse matches 19/100 here. before this fix,
mode=latest(Latest basis + the All fast path) fell into the collection-name lookup and threwNo pixabay collection named 'latest' is loadedon EVERY start; it only surfaced when the user added pixabay to the desktop platform list (their original 8-platform config had no pixabay, so no probe ever hit it). full facts inautomata-private\pixabay.com\AGENTS.mdunder "latest wallpaper search".
- the collection-page tile-img parse matches 19/100 here. before this fix,
wallpaperhub categories live from the collections index (2026-10-08)
user audit: the 17 wallpaperhub "categories" were a hand-reversed static table.
fixed at the source: PublicWallpaperService now live-loads
https://www.wallpaperhub.app/collections on every Categories open
(GetWallpaperHubCollectionsIndexAsync + SetWallpaperHubCollections, runs
alongside the backiee/alpha/pixabay loads, same loud contract, error-bar
visibility extended to the Local - WallpaperHub scope).
- index facts: 17 collections, ONE page today -
?page=Nis IGNORED (page 2 re-serves the same rows), so the loader walks pages until the first one brings no NEW ids (hard cap 10, thrown error past it = the loud bar, never a silently truncated list). card markup =<h3>name</h3>...href="/collections/<id>"(the row's View link); the parse matched 17/17 against the old static table (0 mismatches - titles/ids unchanged). - no curl: wallpaperhub accepts .NET's SocketsHttpHandler fingerprint (IWR 200) - unlike pixabay/cara, the index AND the drill fetches stay on the plain HttpClient.
- the static
WallpaperHubCollectionsarray is GONE (replaced by a locked live snapshot).GetModesreads the snapshot property; an empty list (load failed) = no wallpaperhub cards + the loud error line, and the drill fetcher'sFirstOrDefaultmiss falls through to the/wallpapersroute exactly as before. - menuless canary:
Windows 11(single-source card; collection has 6 items, grid title = platform nameWallpaperHub). verified 2026-10-08 (probeC:\tmp\aura-wallpaperhubindexcheck.ps1): 159 cards, 17/17 live names on the grid,Windows 116 items + alphaVehicle15 items, bar clean through the whole fill + a 90s watch, no flip. vision (zengate): 4 real Windows 11 tiles (bloom/logo/glow/sunrise), mode chips = live collection titles, zero errors.
artstation categories live from the channels directory (2026-10-09)
user audit: the channel picker on artstation's search sidebar (Abstract, Anatomy, Animals & Wildlife, ... "All channels") IS the site's category taxonomy - reversed and ported as artstation's categories, replacing the 5 honest query entries.
- endpoints (all anonymous, plain HttpClient - no curl): list
GET api/v2/community/channels/channels.json={total_count, data[]}(64 published channels: 61 global + 1 hashtag + 2 sponsored; fields id, name, uri, state, type) and drillGET api/v2/community/channels/projects.json?channel_id=<id>&page=N&sorting=trending&per_page=45(card shape = search/projects.json minusis_adult_content- adult items carry onlyhide_as_adult, filtered;total_countcaps at 10000; trending page2 can overlap page1 by ~2/45).sortingis RESTRICTED to trending|latest|popular - anything else = 400 with the valid list in the error body. all 64 ids verified 200-with-items in one pass. - discovery: the list endpoint was found in the Angular search bundle - the
/searchdocument 403s without fullSec-Fetch-Mode: navigateheaders, and the JS bundles needReferer+Sec-Fetch-Dest: script. GET filter params onsearch/projects.jsonstay silently ignored (baseline unchanged), and/api/v2/search/channels500s on every shape tried - the community/channels pair above is the real surface. - code:
ArtStationServiceholds a locked live snapshot (ChannelsLock/SetChannels/GetChannelsIndexAsync) like alpha/pixabay/wallpaperhub;SearchProjectsAsyncand the static 5-entryArtStationCategoriestable are GONE. keys =channel:<id>; the thumb fill andArtStationGridPage's OnNavigatedTo parse it STRICT (a non-channel:<id>key throws - loud, never a silent browse-mode grid). grid title =ArtStation <channel name>(snapshot lookup;#<id>label if the snapshot ever lacks it). the 5th live-load block runs with the others and"ArtStation"joined both error-visibility conditions. - counts: per-scope ArtStation = 64 (was 5), Global = 221 merged cards (was 159; 2 channel names merged into existing cards - Abstract among them). the old query names survive on their non-artstation owners (pixiv: Wallpaper/Landscape/Nature, pexels: Space, backiee+alpha+pixabay: Abstract), so none of those cards disappeared.
- menuless canary:
Book Illustration(artstation-only channel, chooser-free) -> titleArtStation Book Illustration, 44 items, bar clean. verified 2026-10-09 with probeC:\tmp\aura-artstationchannelcheck.ps1: 221 cards, 64/64 channel names on the grid, Book Illustration + alphaVehicle+ the pixabayNature videosregression all OK, bar clean through the whole fill + an 18x5s watch, no flip, focus restored. vision (zengate): real book-illustration/fantasy artwork tiles (horned creature, Witcher covers), zero errors.
pixabay tile parse: lazy imgs + video collections (2026-10-09)
found by the artstation probe's long bar watch: a persistent
Pixabay category thumbnails: 1/61 failed - no items returned for "Nature videos" line - earlier probes sampled the bar before the 1-wide pixabay fill
reached that card, so it looked clean. root cause: the shipped tile regex
matched ONE shape - eager src= photo/illustration jpg tiles - while every
collection page mixes shapes:
- only the first ~15 tiles render eagerly; the rest are
src="/static/img/blank.gif" data-lazy="..."(halloween page: 15 eager + 33 lazy of 49 main-grid tiles - every drill silently served ~15/page). - posters:
__340.jpg,__340.png(full =_1280+ SAME extension -_1280.jpgon a png asset = 403), video_tiny.jpg; tile links span/photos/illustrations/vectors/videos. - "Nature videos" is the ONE video collection of 63 -
class="item video-item"tiles whose poster still ships a full ladder:tiny1280x720 -> small 1920 -> medium 2560 ->large3840x2160 (all 200;big= 404). it parsed 0 items = the permanent loud error line. - fix = two-pass regex (eager
src=+ lazydata-lazy=), generic tile href (a future media type degrades to skipping that tile, not a broken SourceUrl), jpg|png, video included; both passes merged and sorted by document index, deduped bydata-pkid.FullPhotoUrl: video_tiny.->_large., photo__340->_1280(extension preserved). - verified: parse == tile-div count on 3 captured pages (50/49/50, was
15/0/0 with the shipped pattern), probe drill
Nature videos= 20 items (viewport realized) titlePixabaybar clean, vision = real nature stills (beach-spit frame = the probed video), full watch bar clean.
categories page lag: off-thread image conversion + parallel opens (2026-10-09)
user report: the Global categories page was "lagging super hard" (stutter while the ~200 card thumbs streamed in, dead time on every open). two causes, both fixed:
WallpaperItem.LoadImageAsync/LoadFullImageAsyncran their CPU on the UI thread: everyawaitin them resumes on the WinUI SynchronizationContext, and ImageSharp'sImage.LoadAsync+SaveAsPngAsyncover MemoryStreams complete synchronously - so each fill did a FULL-resolution decode + FULL- size PNG re-encode inline on the dispatcher (tens to hundreds of ms x ~200 fills per open; a detail page = one big stutter). both now wrap decode + encode inTask.Run(pool thread);LoadImageAsyncalso resizes to <=500 wide BEFORE encoding (DecodePixelWidth = 500discarded the full-res PNG anyway - the encode is thumb-sized now; sources <=500 wide are untouched, so the DecodePixelWidth upscale path behaves exactly as before).BitmapImageis a DependencyObject: created back on the UI thread after the pool hop. the full path ALSO left the oldGetOutputStreamAt/AsStreamForWrite/FlushAsyncWIC form (the 0x88982F50-prone one from the thumb fix above) for the provenWriteAsync+Seek(0)+SetSourceAsyncpattern.- the open awaited the 5 index loads sequentially (alpha -> pixabay ->
wallpaperhub -> artstation -> backiee + 19 eager thumbs) before the first
card could render = every open paid the SUM of all round trips, growing with
every platform added. now
Task.WhenAllover 5 local funcs insideLoadCategoriesAsync, each returning ITS OWNList<string>of errors (one shared list appended from parallel tasks would race), merged after WhenAll; afinallykeeps the progress bar +_isLoadingreset even if WhenAll ever faulted (a stuck_isLoadingwould dead-end the page silently). - verified menuless (re-run of
C:\tmp\aura-artstationchannelcheck.ps1): 221 cards, 64/64 channels, all 3 drills OK, bar clean through the whole fill + an 18x5s watch whose cadence never slipped (UIA reads = the UI-thread canary- the old build starved them during fills), focus restored. one run died with the KNOWN open exit=0 signature mid-drill; the paced re-run passed.
- UI-thread peg on the full grid is PRE-EXISTING, measured A/B 2026-10-09
(during the pexels port, to rule the port out): with ZERO probe walkers on
an idle Categories page, one thread burns ~1 core - and it is the UI thread
(per-thread UserProcessorTime delta + GetWindowThreadProcessId). HEAD
6b88deeat 221 cards: CPU 5.58s/6s, GridCount-style walk 9541 ms, FindText 3132 ms. pexels build at 296 cards: 5.36s/6s, 18098 ms, 7239 ms. Home (small tree) = 0.2s/10s + 13 ms walks. so the peg predates the pexels port and scales with realized card count - it is NOT a pexels regression; what the UI thread actually burns CPU on is NOT yet root-caused (a managed stack dump is the next step; the probe deaths below correlate with walking this pegged thread). measurement gotcha:dotnet build winui\(the folder) resolvesAura.slnwhose default platform is ARM64 and lands inbin\ARM64\Debug\win-arm64\- which does NOT run on this x64 box; buildwinui\Aura.csprojdirectly for the flatbin\Debug\Aura.exethe probes launch.
pexels categories live from the discover index (2026-10-09)
user audit: pexels' categories = the SECTIONS on its own Wallpapers
discover page (https://www.pexels.com/discover/wallpapers/), minus the
"Phone & mobile" section (a size class, not a style - user decision). the
old read "the API has no categories, the website is CF-walled" is REVERSED
- ported: the wall was a bare-curl artifact, and the taxonomy lives in the page's Next.js payload, not the API.
- structure:
__NEXT_DATA__script payload (match on the id alone - the other attrs vary) ->props.pageProps.topics[]= 9 topics x ~10terms[]= 88 terms (resolution phone desktop dark colors aesthetic nature seasonal subjects;darkhas 8, the rest 10). thephonetopic is skipped per user decision -> 78 terms over 8 topics (10/10/8/10/ 10/10/10/10). every term ={term, mediaId, imageUrl, totalResults}and the term is BOTH the card name (the pill's lowercase text) and the API search query. the pill href is/search/<term>/with NO orientation param, so the drill droppedorientation=landscapeto match (vertical wallpaperresolves portrait). one pill (live wallpaper) links to/search/videos/on the site but its PHOTO surface serves hundreds of results - the photo query is what this image app ships (automatawww.pexels.com/AGENTS.mdhas the curl recipe). - transport:
www.pexels.com403s .NET's TLS fingerprint AND bare/minimal curl (UA alone, pixabay's Sec-Fetch pair) - only curl + the FULL browser header set passes (6 headers, side-by-side proof 2026-10-09) -> pexels html routes throughCurlClientlike pixabay/cara, header set lives inPexelsBrowserHeaders. a challenge shell fails the__NEXT_DATA__presence check -> thrown error -> loud bar, never a silently empty list. - code:
PublicWallpaperServiceholds a locked live snapshot (PexelsDiscoverLock/SetPexelsDiscoverTerms/PexelsDiscoverTermsproperty /GetPexelsDiscoverIndexAsync, same pattern as alpha/pixabay/ wallpaperhub/artstation);GetModes(Pexels)reads it; the 6thTask.WhenAllload block inLoadCategoriesAsyncfeeds it and"Pexels"joined both error-visibility conditions. card thumbs = the pill's ownimages.pexels.comphoto (imageUrl + ?h=420&w=420&fit= crop&dpr=1; pill ImageUrls carry NO query string today, so the append is safe) - ZERO API calls: the free tier caps 200 req/hour and 78 search fills per open would eat 40% before any browsing. thumb case lives inLoadRepresentativeThumbnailAsync(aWallpaperItemover the CDN url -> the sharedLoadImageAsync, which already does webp under the app's image Accept);GetPexelsTermImageUrlmiss = loud throw, never a fake placeholder. the drill still searches (/v1/search?query=<term>, key required;/v1/curatedand the orientation param are GONE from the code). - counts: per-scope Pexels = 78 (was 3), Global = 296 merged cards
(was 221 = 221 - 1 Curated + 78 - 2 merges: pixabay already owns
collections named
black wallpaperandaesthetic wallpaper, so those two pexels terms merged into them instead of adding cards). Curated had no other owner and disappeared with the port; Nature/Space survive on backiee/pixiv/desktopnexus/hdwallpapers.GetDescriptionsays discover-loaded + mentions the key for drills. - keyless contract: fills need NO key (CDN pill photos) - a keyless install's fill bar is CLEAN and the loud key error surfaces on the first pexels DRILL instead (see the thumbnail-fix section above).
- menuless canary:
dark academia wallpaper(pexels-only term, chooser-free) -> grid titlePexels, description = the discover line, mode chips = the live terms, search returns 30 (viewport-realized 20). - verified menuless + vision 2026-10-09 with probe
C:\tmp\aura-pexelsdiscovercheck.ps1: 296 cards, 78/78 term names on the grid, Nature/Space present, Curated gone, 5 cross-platform spot checks, all 3 drills (dark academia wallpaper / alpha Vehicle / pixabay Nature videos) OK, bar clean through the fill. vision (zengate, 3 shots): Categories top = real art everywhere, drill = 4 real pexels photos + titlePexels, scrolled pill zone = 9 pexels cards all real artwork, no placeholders, no errors. runs 1+2 died with the known exit=0 (see the death section); run 3 passed end to end after pacing + an adaptive settle that waits for UIA walk latency instead of a fixed sleep.
history rows open the wallpaper's detail page (2026-10-09)
user choice: clicking a Wallpaper History row opens the IN-APP detail page for that wallpaper (never a browser URL). rows store a serializable navigation snapshot at AddEntry time:
- schema (
Services/WallpaperHistoryService.cs):HistoryNavigation {Page, Platform, Wallpaper}whereWallpaperis aHistoryWallpaperDTO - the string/bool fields ofWallpaperItem(ImageUrl, FullPhotoUrl, SourceUrl, Title, Description, ...), explicitly EXCLUDING ImageSource + DownloadCommand (not serializable).AddEntry(..., WallpaperItem? wallpaper, string? page = null, string? platform = null)- optional tail params, so SlideshowService's call is untouched and yieldsNavigation = null(slideshow does not open detail pages - honest, not broken). - page discriminators:
"Public" | "Backiee" | "AlphaCoders" | "ArtStation";HistoryPage.HistoryEntry_Clickswitches on them ->PublicSources.PublicWallpaperDetailPage(+PublicWallpaperNavigationParameter),Backiee.WallpaperDetailPage,AlphaCoders.WallpaperDetailPage,ArtStation.ArtStationDetailPage. null Navigation or an unknown Page = LOUDStatusInfoBar(row 0 in the XAML,StatusInfoBar+ShowStatus), never a silent no-op; a navigate() returning false = loud "could not open" with the reason. the exact null message:No detail page is stored for this entry — it was set by the Slideshow or saved before click-through. Set the wallpaper again from its source page to make it clickable. - rows are
HistoryEntryButton : Button(a Button subclass becauseProtectedCursoris protected) - setsInputSystemCursor.Create(Hand),AutomationProperties.Name= the title (clean UIA: rows findable by their title as a Button), hover swaps toCardBackgroundFillColorSecondary. - the 4 pre-existing entries were BACKFILLED by hand (ids/urls curl-verified
live): backiee 376636, alphacoders 996764 (x2 - desktop + lock screen),
simple-desktops traffic. backiee SourceUrl trap: the default
https://backiee.com/wallpaper/{Id}404s - the real URL needs the category slug (/wallpaper/anime/376636;/wallpaper/376636301s there)- the backfill stores the canonical URL.
- artstation detail refetch = curl-only (CF fingerprint):
/projects/ <hash>.json403s .NET even with full browser headers whileprojects.json/ search / channels all pass .NET; bare curl gets a CF challenge page (looks like JSON), and curl +Accept: application/json,text/plain,image/*,*/*+Sec-Fetch-Mode: cors+Sec-Fetch-Site: same-origin= 200 (side-by-side proof 2026-10-09) ->GetProjectDetailsAsyncroutes throughCurlClientwith exactly that header triple (single method, not a fallback; failure = curl exit code + stderr surfaced loud). same class as pixabay/cara/pexels. before this fix the B4 probe run showedCould not load ArtStation artwork: 403+ empty title. - UIA verify gotcha: x:Name
TitleTextBlockappears TWICE in the backiee/alpha detail name scopes (XAML name-scope collision) - assert titles via a TEXT element with the literal string, not AutomationId. per-page unique markers: backieeSetAsWallpaperButton, alphaDebugBigThumbTextBlock, publicPlatformTextBlock, artstationArtworkImage. - probe (stays in
C:\tmp, never committed):aura-historyclick.ps1- stage A appends aSource=(probe none)no-Navigation row (rerun-safe: the file may already be backfilled) and asserts the loud path; backfill strips it, adds Navigation to nav-less real entries + a tempArtStation (probe temp)row for the 4th switch arm; stage B clicks all 4 rows (assert title + page marker + bar clean + back OK each time); cleanup strips every(probe ...)row; final relaunch leaves History visible. two probe-authoring traps: (1)ConvertFrom-JsonPSCustomObject rejects$e.Nav = ...assignment - useAdd-Member -NotePropertyName; (2) capture BEFORE the back-navigation - a Shot after GoDetail returns shows History, not the detail page (first run wasted 4 captures that way;aura-histdetail-shot.ps1did the visual proof attach-and-capture). - verified end-to-end 2026-10-09 (local
bin\Debugbuild): stage A loud exact message OK; B1 Backiee / B2 AlphaCoders (big thumb resolved live) / B3 Public SimpleDesktops / B4 ArtStation (curl fix) all OK - title + marker + clean bar + back each time; file ends with 4/4 entries carrying Navigation, temp rows gone. vision (zengate): loud red InfoBar text exact; backiee detail = real Santorini artwork + title + Set/Download/ View-on-Web buttons; public detail =Traffic+Simple Desktops+ 2560x1600 image; final History = 4 rows, thumbnails render, no bars. history file:%APPDATA%\Aura\wallpaper_history.json.
backiee view-on-web 404 + selectable detail titles (2026-10-09)
- backiee has NO id-only permalink:
/wallpaper/<id>= 404, and the older AGENTS claim that it 301s is WRONG - it 404s with no redirect (all of/wallpapers/<id>,/wallpaper-detail/<id>,/detail/<id>,/wallpaper/<id>/404 too). but ANY slug in/wallpaper/<slug>/<id>resolves:zzzznope/376636-> 301 -> canonical/wallpaper/anime/376636(200). canonical slug = server-side (title slug or theme cat, not derivable client-side). - the detail APIs (
detail_page_v2root = WallpaperColors/Tags/Comments/ Publisher + related lists; v1detail_pageroot = TagList/ColorList/ Publisher/YouMayList/SelectionList/CommentList) carry no URL for the current wallpaper anywhere - no string in the 108KB response even contains the id. theelsebranches in both detail pages' publishers therefore ALWAYS fired and clobbered every good canonical SourceUrl with the slugless 404 -> View on Web broke for every backiee detail opened (that was the user's 404 screenshot). fix: else branches deleted onViews\Backiee+Views\AlphaCodersWallpaperDetailPage.xaml.cs(alpha page's "DetailApiBaseUrl" is also backiee's detail_page_v2 - copy-paste); API value still used when present. - remaining empty-SourceUrl fallbacks go through
BackieeApiParser.BuildWallpaperUrl(id, themeCat)=https://backiee.com/wallpaper/{themeCat|detail}/{id}- the any-slug 301 resolves to canonical in the browser. call sites: parser fallback (was line 39), both OnNavigatedTo defaults. sweep confirmed no slugless construction left (grepbackiee.com/wallpaper= helper + comments only). - curl-proven:
detail/376636-> 301 canonical,anime/376636-> 200. - selectable titles:
IsTextSelectionEnabled="True"on the LIVETitleTextBlockof all 4 detail pages (Backiee line 35, AlphaCoders line 35 - the line-20 twins are commented out; PublicSources line 45, ArtStation line 14). XamlCompiler ACCEPTED the property (build green) - valid WinUI 3 TextBlock prop, contrary to the silent-exit-1 quirk which applies to properties that don't exist. - menuless proof recipe (no synthetic input, no focus steal): UIA
TextPattern on the title = present;
DocumentRange.Select()thenGetSelection()reads back the full exact title = selection live. UIASetFocus()on a WinUI TextBlock throws "Target element cannot receive focus" (automation peer says not focusable), and with the window ACTIVE but the TextBlock unfocused the highlight renders NOWHERE in PrintWindow captures - so a visual-highlight proof menuless is NOT possible; the highlight appears on real pointer drag (focus goes to the TextBlock then). screenshot proof of selection needs the window already foreground - if fg is the user's app, ABORT loudly, never activate. probes:C:\tmp\aura-selectfix*.ps1(4 = screen-grab attempt).
slideshow died silently on load + next-change status (2026-10-09)
user report: desktop slideshow set to 1 Minutes never changed the wallpaper,
and the page had no "when is it expected to change" status. the log stopped
right after Toggle enabled: True - nothing else ever logged. root causes +
fixes:
- one broken platform silently killed the whole batch: both loaders ran
every platform inside ONE try/catch with an EMPTY catch, and the platform
loop included
platform == "ArtStation" || PublicWallpaperService .IsSupportedPlatform(platform)- butGetWallpapersAsynchas NO ArtStation arm (_ => throw new NotSupportedException) - so ArtStation (3rd in the user's list of 8) threw, the catch swallowed it, the local list was discarded,_desktopWallpapers.Count == 0andStartDesktopSlideshowreturned BEFORE creating the timer: no timer, no next-change time, no countdown, no log line, forever. now each platform loads in its OWN try/catch (failures collected as<platform>: <reason>, logged), and ArtStation routes toArtStationService.GetProjectsAsync(sorting, batch)(https://www.artstation.com/projects.json?sorting=latest|trending- curl-proven; plain .NET passes per the artstation section) instead of the public service. backiee's parse also throws LOUD on a non-array response shape (challenge/error page) instead of an unhandledEnumerateArray. - loud contract (rule: fail loudly, never a dead timer): the empty-batch
return now sets
DesktopLoadError/LockScreenLoadError(exact per-platform reasons) and raises a newErrorsChangedevent; the page renders it in two new per-column InfoBars (DesktopSlideshowInfoBar/LockScreenSlideshowInfoBar- Error + "Slideshow not running" when stopped, Warning + "Slideshow
warning" when running with skipped platforms). apply failures (no image URL,
download refused, Windows refused the change) set
*ApplyErrorwith the wallpaper title + reason and clear on the next successful set; the one-shot tick timers restart infinally(the old code only restarted on success, so one thrown cycle = permanent silent death) and log cycle failures; settings/restore read failures report viaReportRestoreErrorinstead of empty catches.
- Error + "Slideshow not running" when stopped, Warning + "Slideshow
warning" when running with skipped platforms). apply failures (no image URL,
download refused, Windows refused the change) set
- public mode mapping: the dialog's categories are backiee/alpha names -
NormalizePublicModemapsLatest Wallpapers/4K Wallpapers/8K UltraHD/AI Generated/Harvest Wallpapers/Rain Wallpapers/All->latestfor the public platforms (the oldcategory.ToLower()fed wallhaven's toplist default and pexels' literal search query withlatest wallpapers). - status (the user's ask): countdown text never silently hides while
enabled -
Starting slideshow.../Next wallpaper at HH:mm:ss (in 56s)/Changing wallpaper...(<60s overdue) /Overdue - expected at HH:mm:ss/Slideshow is not running. the old code collapsed it when next-change time was MinValue (never started) and hid it >30s past due - exactly the reported blank state. - blank preview card:
SlideshowPage.xamlreferencedms-appx:///Assets/placeholder.pngwhich DOES NOT EXIST (the real asset isplaceholder-wallpaper-1000.png, used everywhere else) - both Image Sources fixed; the card now shows the live wallpaper. - restart guard: page
RestoreSlideshows+MainWindow.RestoreSlideshowsOnStartupAsync skip whenDesktopRunning || DesktopStarting(every Slideshow-page visit used to restart the running slideshow - resetting the countdown and re-adding a history row), and the page's singleton-event subscriptions moved to Loaded/Unloaded with-=first (dead-page handlers used to accumulate onSlideshowService.Instance). - verified menuless with the user's exact config (probe
C:\tmp\aura-slideshowstatus.ps1):Loaded 224 wallpapers from 8 platform(s), 0 platform failures, status line exact8 platforms - Latest Wallpapers (Refresh: 1 Minutes), countdownNext wallpaper at 15:28:58 (in 56s)(vision: verbatim blue line, real preview photo, zero error banners), history gainedDesktop/Slideshowrows at 15:25:39 / 15:26:56 / 15:27:58 / 15:28:59 = exactly 60s apart, 2+next change timelog lines, info bar closed throughout.
history site + category stickers (2026-10-09)
user ask: each Wallpaper History row should also show WHERE the wallpaper
came from (site) and WHICH category it was set from - next to the existing
Desktop/Slideshow pills.
- schema:
HistoryEntrygainedPlatform+Category(nullable - old rows deserialize to null).AddEntrygained a tailstring category = ""; entryPlatform= explicitplatformarg, elsewallpaper.Platform; entryCategory= explicitcategoryarg, elsewallpaper.Category. slideshow calls passwallpaper, category: _desktopCategory(page stays empty soNavigationstays null - the click contract above is untouched). backiee/alpha/artstation detail calls now pass explicitplatform:(the public one already passed_platformName). - items get tagged at the source (
WallpaperItem.Category): backieeThemeCatinBackieeApiParser.CreateWallpaperItem; public mode inGetWallpapersAsync(the per-platform switch arms alreadyawait, so the wrapper assigns the switch result directly - an outerawaitthere is a CS1929); alpha category key inScrapeWallpapersByCategoryAsync(covers the grid AND the slideshow - both go through that scrape). artstation has no per-item category (honest absence, no pill). - old rows (
RecoverSlideshowStickers, one-shot fromMainWindow.RestoreSlideshowsOnStartupAsyncafter both starts):Source == "Slideshow"rows takeCategoryfrom the configured settings and recoverPlatformby matching the local filename id (wallpaper-<id>.<ext>/lockscreen-<id>.<ext>, first-dash split) against the new read-onlySlideshowService.DesktopBatch/LockScreenBatch. rows whose id rolled off the live pages stay empty - never guessed (11/30 stayed empty in the verify run; category filled 30/30). - rendering (
HistoryPage):MakeBadgehelper + pills in order type (gray) / source (SteelBlue Manual, SeaGreen otherwise) / site (MediumPurple, only when it differs from Source - public rows store the site INSource) / category (Chocolate, only when known). old rows go throughDeriveSite:Platform->Navigation.Platform->Navigation.Page(Backiee/AlphaCoders/ArtStation) ->Sourcewhen it is not Manual/Slideshow. - gotchas hit:
Windows.UI.Colorsdoes NOT exist in WinUI 3 (it isMicrosoft.UI.Colors; the helper's parameter type isWindows.UI.Color); this run's XamlCompiler MSB3073 exit-1 was a CASCADE of the two C# errors and went green once they were fixed (a standalone XAML failure would have stayed red - see the quirk section below);HistoryListPanel(StackPanel) has NO UIA peer so it always readsABSENT- probe page detection usesClearHistoryButton;wallpaper_history.jsonis NOT append-ordered (find new rows byTimestamp, never by array position). - verified menuless with probe
C:\tmp\aura-historystickers.ps1(stays in C:\tmp): run 2 full PASS - restore + next-change line OK, missing category 0, missing site no-regression vs baseline, badge counts 37 category / 30 site texts across 7 distinct sites,StatusInfoBarclosed, a new AddEntry row (Garchomp, ArtStation) carried both fields, focus restored. vision (zengate): rows show exactly 4 pills - grayDesktop, greenSlideshow, purple site (ArtStation/Simple Desktops/...), orangeLatest Wallpapers- thumbnails render, zero error banners.
taxonomy-less sites rejected from the category universe (2026-10-09)
user decision: sites with proven zero taxonomy (bing, simple desktops) stay
FULLY supported in the platform picker, but they are REJECTED from every
category surface - a category list built from them would be fake entries
(Daily/Minimal are fetcher modes, not taxonomy). enforcement is one
DYNAMIC list so future rejects are a one-line add:
PublicWallpaperService.CategoryExcludedPlatforms(today{ Bing, SimpleDesktops }) +IsCategoryExcluded(name). consulted inCategoriesPagetwice:CategoryPlatforms(the scope menu - a rejected scope would always render an empty grid) andBuildMerged's GetModes loop (no fake cards).GetModesitself stays factual on purpose: theDaily/Minimalentries still drive each platform's OWN grid chips + default mode (the platform picker is untouched by this rejection).- counts: Global 296 -> 294 (both were single-source; a live-index curl
check found no exact-name merge owner - wallpaperhub's "daily" hit is
description text, pexels'
minimalist wallpaperis its own card); scope menu 17 -> 15 platforms. supersessions: the "one honest entry each" bullet in the all-9-platform section above, and the menuless canary list'sDailyMinimal(those two cards no longer exist). - pending slideshow category-selector feature: the checklist universe must
consult
IsCategoryExcludedtoo - in Category mode bing/SD get no ticks and take the LOUD per-platform skip (supersedes the earlier design call where each resolved its ownDaily/Minimalentry). (SHIPPED 2026-10-10- see the dated section below.)
- verified menuless with probe
C:\tmp\aura-categoryexclusion.ps1(stays in C:\tmp): cards=294,Daily+Minimalgone from the grid, 11 spot names present, alphaVehicledrill 15 items + title + bar clean, back rebuilds 294 with scopeGlobal, 4x5s watch stable (no flip, bar clean). full-grid FindText stays ~4-9s throughout - that is the PRE-EXISTING UI-thread peg (measured 2026-10-09 at 296 cards), not a regression of this change, and it means the probe's settle loop can never gate on "<1.5s walks": it is a paced delay with heartbeats (the first run died silently at the tool timeout because its 30x10s cap had no progress prints - heartbeats added, cap 15).
focus-free verification: menuless protocol (2026-10-07)
- never open a flyout while the user is working: with the window parked
offscreen (-4000,-4000) a
MenuFlyoutrenders clamped at the screen's TOP-LEFT corner, visibly, and it activates (focus steal) - the user called it "dropdown coming in the top left and stealing focus". while minimized the popup is never created at all. so the only acceptable interactive check while the user is at the machine is MENULESS: Global card
Truncated - read the full file at https://github.com/FahadBinHussain/aura/blob/e4a457237a6bd472664cd841fc2a50a88f2002b9/AGENTS.md.
