feat: SubscribeStar joins the membership roster (387 D1)
CI / lint (push) Failing after 2s
CI / extension-version (push) Successful in 3s
Build images / sign-extension (push) Successful in 3s
Build images / build-agent (push) Successful in 6s
CI / frontend-build (push) Successful in 21s
CI / backend-lint-and-test (push) Successful in 32s
Build images / build-web (push) Successful in 55s
Build images / smoke-web (push) Skipped
Build images / build-ml (push) Successful in 1m41s
Build images / promote (push) Skipped
CI / integration (push) Successful in 2m12s

The second platform through the seam note 3970 contracted, characterized first from a live capture of the account's /subscriptions page (note 3989). The capture lives in the gitignored captures dir; the committed fixture is hand-built with invented values and was verified tag-for-tag against it - card wrappers, both table heads, and every distinct row shape - before any code depended on it.

What the page is, and the three decisions it forced:

The table IS the status. SubscribeStar has no per-row status word: a creator is either in the active_subscriptions card or the cancelled_subscriptions one. The card's data-identifier is stored verbatim as Membership.status and mapped in MEMBERSHIP_STATUS, keyed on the identifier rather than the table class because the cancelled table's class names the same list differently (for-unsubscribed_users).

The creator's numeric data-user-id is the key, not the slug. A slug re-keys when a creator renames; the old row stops appearing; and a disappearance is exactly what reconciliation reads as a lapse. Keyed on the slug, a rename would have told a paying subscriber they had cancelled. The slug rides as vanity, where the identity join already looks for a handle.

Price is kept as text, never parsed into amount_cents. A bare $ names no currency and a page price is not proven to be the charge - 3970 finding 4. Tier names live behind a per-row modal and are not fetched.

Refusals, because SubscribeStar offers nothing like Patreon's meta.pagination.total and every conclusion downstream is drawn from absence. The parser raises when: the active card is missing (auth error on a login/age wall, drift otherwise); a row lacks a numeric creator id or a creator link; anything renders after a card's table; or the page carries a page= link. Both cards are paginatable (app#embed_pagination) and the captured account was too small to show what pagination looks like, so possible pagination is a roster FC cannot prove complete. A loud error on a larger account beats a quiet half-list. A missing cancelled card is not drift, and a creator in both tables is reported once, as active.

Fetched from subscribestar.adult, not the .art the capture came from: FC's requests never clear the .art age wall with the 18+ cookie (1259, 1284). Whether /subscriptions on .adult authenticates exactly as .art did in the browser is untested - if not, the sweep records a visible error and C6 shows its unavailable rung.

The seam leak D1 found. Note 3970 promised a second platform would be one builders line plus the client method. The sweep instead called current_user_id() on every client, which only Patreon's has, so SubscribeStar would have raised AttributeError on the first sweep. roster_user_id probes it with getattr, the same way the sweep already probes iter_memberships.

Two existing tests were passing for the wrong reason and now can fail:
- "a platform that has never been characterised says nothing" named SubscribeStar, and stayed green only because active_patron is not a SubscribeStar word. Now uses hentaifoundry, with a positive SubscribeStar test beside it.
- the freshness test gave SubscribeStar a Patreon word, so the vocabulary excluded it and deleting the freshness gate outright would have left it green. It now uses cancelled_subscriptions, making the gate the only thing that excludes it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SHQB1YukL3VyvMK8rcbmV9
This commit is contained in:
2026-09-13 10:53:01 -04:00
co-authored by Claude Opus 5
parent 529d4bff57
commit ef91fcfd26
7 changed files with 532 additions and 9 deletions
+3
View File
@@ -0,0 +1,3 @@
<!DOCTYPE html><html><head><title>My Subscriptions | SubscribeStar.adult</title></head><body><div class="layout"><div class="section-body"><div class="warnings-wrapper"></div><div class="card for-table" data-identifier="active_subscriptions" data-view="app#embed_pagination" id="subscriptions_active"><h2 class="card-title">Active Subscriptions</h2><table class="details_table for-active_subscriptions"><thead><tr><th class="for-name">Profile</th><th class="for-updates">Updates</th><th class="for-date">Subscribed</th><th class="for-renewal">Renewed</th><th class="for-date">Paused</th><th class="for-earnings for-subscription_price">Price</th><th class="for-discord">Discord</th><th class="for-actions for-large_screen">Actions</th></tr></thead><tbody><tr><td class="for-name"><a href="/creator-alpha"><div class="inline_user_name"><img data-view="app#avatar" data-type="avatar" data-user-id="1001" alt="Creator Alpha" src="https://cdn.example.invalid/avatars/1001.jpg" />Creator Alpha</div> </a></td><td class="for-actions has-icons"><button class="details_table-link for-updates-unsubscribe" data-modal="/creator-alpha/unsubscribe" title="Unsubscribe from post updates">Mute updates</button></td><td class="for-date">Jan 2026</td><td class="for-renewal">Mar 2026</td><td class="for-date">-</td><td class="for-earnings for-subscription_price"><span class="subscription_cost">$5</span><span class="for-tiers-list" data-modal="/creator-alpha/tier_details" title="Show tiers"><svg class="icon"><use></use></svg>
</span></td><td class="for-discord"><button class="details_table-link" data-modal="/creator-alpha/discord"><i class="md_icon is-fa_discord"><svg class="icon"><use></use></svg> </i><span>Joined</span></button></td><td class="for-actions is-multiple for-large_screen"><button class="details_table-link" data-modal="/creator-alpha/manage">Manage plan</button></td><tr class="for-actions"><td class="is-inline" colspan="100"><small>Manage options</small><button class="details_table-link" data-modal="/creator-alpha/manage">Manage plan</button></td></tr></tr><tr><td class="for-name"><a href="/creator-beta"><div class="inline_user_name"><img data-view="app#avatar" data-type="avatar" data-user-id="2002002" alt="Creator Beta Studio" src="https://cdn.example.invalid/avatars/2002002.jpg" />Creator Beta Studio</div> </a></td><td class="for-actions has-icons"><button class="details_table-link for-updates-unsubscribe" data-modal="/creator-beta/unsubscribe" title="Unsubscribe from post updates">Mute updates</button></td><td class="for-date">Feb 2025</td><td class="for-renewal">Mar 2026</td><td class="for-date">-</td><td class="for-earnings for-subscription_price"><span class="subscription_cost">$12</span><span class="for-tiers-list" data-modal="/creator-beta/tier_details" title="Show tiers"><svg class="icon"><use></use></svg>
</span></td><td class="for-discord">&mdash;</td><td class="for-actions is-multiple for-large_screen"><button class="details_table-link" data-modal="/creator-beta/manage">Manage plan</button></td><tr class="for-actions"><td class="is-inline" colspan="100"><small>Manage options</small><button class="details_table-link" data-modal="/creator-beta/manage">Manage plan</button></td></tr></tr></tbody></table></div><div class="card for-table" data-identifier="cancelled_subscriptions" data-view="app#embed_pagination" id="subscriptions_cancelled"><h2 class="card-title">Cancelled subscriptions</h2><table class="details_table for-unsubscribed_users"><thead><tr><th class="for-name">Profile</th><th class="for-date">Unsubscribed</th><th class="for-earnings">Price</th><th class="for-actions">Actions</th></tr></thead><tbody><tr><td class="for-name"><a href="/creator-gamma"><div class="inline_user_name"><img data-view="app#avatar" data-type="avatar" data-user-id="3003003" alt="Creator Gamma" src="https://cdn.example.invalid/avatars/3003003.jpg" />Creator Gamma</div> </a></td><td class="for-date">Dec 2025</td><td class="for-earnings">$3</td><td class="for-actions"><button class="details_table-link" data-modal="/creator-gamma/resubscribe">Renew</button></td></tr><tr><td class="for-name"><a href="/creator-delta"><div class="inline_user_name"><img data-view="app#avatar" data-type="avatar" data-user-id="4004" alt="Creator Delta" src="https://cdn.example.invalid/avatars/4004.jpg" />Creator Delta</div> </a></td><td class="for-date">Aug 2025</td><td class="for-earnings">$10</td><td class="for-actions"><button class="details_table-link" data-modal="/creator-delta/resubscribe">Renew</button></td></tr></tbody></table></div></div></div></body></html>