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:
@@ -57,6 +57,13 @@ func TestLatestChapterFrom(t *testing.T) {
|
||||
site: "asura", seriesURL: asuraURL, body: asuraCrossSeriesFixture,
|
||||
wantOK: true, wantNum: 181, wantLabel: "Chapter 181",
|
||||
},
|
||||
{
|
||||
name: "asura scoping survives a build-hash rotation",
|
||||
site: "asura",
|
||||
seriesURL: "https://asurascans.com/comics/chronicles-of-the-demon-faction-059befe1",
|
||||
body: asuraCrossSeriesFixture,
|
||||
wantOK: true, wantNum: 181, wantLabel: "Chapter 181",
|
||||
},
|
||||
{
|
||||
name: "asura with an unparseable series url",
|
||||
site: "asura", seriesURL: "https://asurascans.com/", body: asuraSeriesFixture,
|
||||
|
||||
Reference in New Issue
Block a user