Stable Asura series IDs: strip rotating build hash (#6)

Asura series slugs carry a site-wide build hash (-059befe1) that rotates on every redeploy, silently orphaning all asura bookmarks (old-hash URLs 302 to new-hash ones, so detect() yields keys that never match stored rows).

Backend:
- migrateAsuraKeys in OpenStore: one-off idempotent migration rewriting hashed asura keys to the stable hashless ID, merging collisions to newest updated_at; losers deleted before winner rewrite (PK-collision safe) — regression tests included
- poller latestChapterFrom: build hash made optional in chapter-scoping regex so latest_chapter survives redeploys

Userscript:
- stripBuildHash(/-[0-9a-f]{8}$/) applied to seriesId in both asura detect branches; URLs keep full slug (stale hashes 302)
- load-time migration rewrites cached + retry-queued asura keys to the stripped form so a queued PUT cannot resurrect an orphaned row

Docs: AGENTS.md + CLAUDE.md URL-shape notes; design spec at docs/superpowers/specs/2026-07-28-asura-stable-series-id-design.md

Verified: go test -count=1 ./... green (new rotation + collision tests), node --check green, regex verified against live asurascans.com slugs.

Deploy order: backend first (migration runs at OpenStore). Orphan rows created by not-yet-updated userscripts self-heal on next backend restart.

Reviewed-on: #6
Co-authored-by: Sulthan Zaki <sultankiki05@gmail.com>
Co-committed-by: Sulthan Zaki <sultankiki05@gmail.com>
This commit was merged in pull request #6.
This commit is contained in:
2026-07-28 07:21:10 +07:00
committed by sulthan
parent 6dce9fc481
commit 206c447f36
7 changed files with 432 additions and 6 deletions
+11 -2
View File
@@ -99,8 +99,17 @@ Bromite userscript (isolated world, per-site adapters, localStorage cache)
### Live URL shapes (verified 2026-07-26, may drift — re-check against live pages before trusting)
- **asurascans.com**: series `/comics/<slug>` (slug carries a trailing hash-like suffix, e.g. `-f886a8af`), chapter `/comics/<slug>/chapter/<n>`. Astro-rendered; chapter links are present in raw server HTML (no client-side-only render blocking a server fetch).
- **demonicscans.org**: series `/manga/<slug>` (slug may URL-encode punctuation, e.g. `%2527` for `'`), chapter `/title/<slug>/chapter/<n>/<page>` (the older `chaptered.php?manga=<id>&chapter=<n>` form still exists as a redirect and is what series-page chapter-list anchors link through).
- **asurascans.com**: series `/comics/<slug>` (slug carries a trailing
site-wide build-hash suffix, e.g. `-059befe1`, that **rotates on every
redeploy**), chapter `/comics/<slug>/chapter/<n>`. `seriesId` must strip
the hash (`/-[0-9a-f]{8}$/`, `stripBuildHash` in the userscript,
`asuraBuildHash` in the backend); URLs keep the full slug — stale-hash
URLs 302 to current ones. Astro-rendered; chapter links present in raw
server HTML.
- **demonicscans.org**: series `/manga/<slug>` (slug may URL-encode punctuation, e.g. `%2527` for `'`), chapter `/title/<slug>/chapter/<n>/<page>` (older `chaptered.php?manga=<id>&chapter=<n>` form still exists as redirect, what series-page chapter-list anchors link through).
Encodings (incl. triple-encoded punctuation like `%25252D`) are identical
on /manga/ and /title/ pages, so decode-once seriesIds match — verified
2026-07-28.
## Commands (once code exists)