Skip to content

Remove the paid-era claim path - #4

Merged
StaticHumStudio merged 1 commit into
masterfrom
chore/remove-paid-era-claim-path
Aug 22, 2026
Merged

Remove the paid-era claim path#4
StaticHumStudio merged 1 commit into
masterfrom
chore/remove-paid-era-claim-path

Conversation

@StaticHumStudio

Copy link
Copy Markdown
Owner

What

Removes the paid-era claim path completely, and the purchase settle gate that existed
only to serve it.

Gone: the one-time "You paid for this" dialog and its email helper,
PaidEraClaimPolicy, PaidEraClaimPrefs, the compiled-in PROMPT_CUTOFF_MILLIS,
purchaseQuerySettled, and PurchaseGatePolicy. 675 lines out, 40 in.

Kept: the direct contact row in Settings, which is now the entire support channel.

Why

The claim path existed for people who bought Nine Lives while it cost money. That
population is one person, and they were refunded on 2026-08-21. A refund unwinds the
transaction. They stand where any free user stands.

But the stronger reason is that the mechanism could not work correctly even in
principle. The app cannot tell who paid. Play does not expose buyer identity for a
paid-app order. So the prompt guessed from firstInstallTime against a cutoff date,
and told every pre-cutoff install "You paid for this" before inviting them to email
for a free code.

The Play reviewer installs fresh during review. With any cutoff later than the
submission date, the reviewer qualifies. The build gating the relaunch would have
shown a reviewer a false claim plus an off-platform offer of something transactional.

Making the date safe meant compiling in a value that had to stay ahead of a submission
date nobody knows at build time, and keeping it correct forever after. That is a lot
of standing risk carried on behalf of somebody who has their money back.

Yes, this deletes today's PR #3

PurchaseGatePolicy and the ERROR classification fix shipped hours ago. The gate's
only consumer was the claim prompt, so removing the prompt orphans it. Keeping a
public flow documented as "every consumer MUST carry its own bound" with zero
consumers is a trap for whoever adds the next one without reading that.

Deleting six hours of work is cheaper than shipping a dialog that lies to a reviewer.

Testing

416 tests, 0 failures. assembleDebug clean. The drop from 427 is exactly the 11
tests belonging to the two deleted policy classes.

Device, before and after, same scenario on SM-S948U. A deletion proves itself by
absence, so this is a contrast rather than a screenshot of nothing.

211, earlier tonight this branch
t=5s claim dialog on screen onboarding only
t=10s / 20s dialog no prompt
t=40s dialog no prompt

t=40s is checked deliberately. During the earlier ERROR canary the 35s backstop
released the prompt by then. There is no backstop now because there is no gate.

Logcat filtered for PaidEraClaim|paid for this returned zero lines.

The Play build was checked separately. com.ninelivesaudio.app versionCode 211,
installer com.android.vending, launched without clearing data. Home rendered, no
FATAL EXCEPTION, no ANR. That build still contains the claim path, which is correct,
since 211 is what is on Play and this ships in 212.

Evidence: /home/static/nine-lives-evidence/2026-08-21-claim-path-removed/

Comments

Every comment describing the removed pieces was rewritten rather than left to
contradict the code, and the argument above is written into EntitlementPrefs and
SettingsScreen. Anyone considering rebuilding a claim prompt has to meet the reason
it died first.

🤖 Generated with Claude Code

The claim path existed to catch people who bought Nine Lives while it cost
money. That population is one person, and they were refunded on 2026-08-21.
A refund unwinds the transaction. They stand where any free user stands, and
if they want the unlock it costs what it costs everyone.

So this deletes the machinery built for them, and it was more machinery than
the problem deserved:

- the one-time "You paid for this" dialog and its email helper
- PaidEraClaimPolicy, PaidEraClaimPrefs, and their tests
- the compiled-in PROMPT_CUTOFF_MILLIS date
- purchaseQuerySettled, the gate that existed only to keep that dialog from
  acting on a provisional reading of what a user owns
- PurchaseGatePolicy and its tests, which existed only to classify for that gate

WHY IT HAD TO GO, not just why it was unnecessary. The app cannot tell who
paid, because Play does not expose buyer identity for a paid-app order. The
prompt guessed from firstInstallTime against a cutoff date. That guess told
every pre-cutoff install "You paid for this" and invited them to email for a
free code.

The Play reviewer installs fresh during review. With any cutoff later than the
submission date, the reviewer qualifies, and the build gating the relaunch
shows the reviewer a false claim plus an off-platform offer. Making the date
safe meant compiling in a value that had to stay ahead of a submission date
nobody knows at build time, and keeping it correct forever after.

That is a lot of standing risk to carry for somebody who has their money back.

WHAT SURVIVES. The direct contact row in Settings, which is the whole channel
now and is enough. Anyone who believes they bought this writes in and gets
answered by hand with a promo code. It scales to the population it serves, and
it cannot lie to anyone because a human reads it first.

Reactive for one person beats machinery on every install. Same call Jeff made
on 2026-08-20 when a refund beat a date-gated grandfather writer, applied one
level up.

Comments that described the removed pieces are rewritten rather than left to
contradict the code, including the reasoning above, so nobody rebuilds this
without meeting the argument against it first.

416 tests, 0 failures. assembleDebug clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@StaticHumStudio
StaticHumStudio merged commit 8442cb8 into master Aug 22, 2026
1 check passed
@StaticHumStudio
StaticHumStudio deleted the chore/remove-paid-era-claim-path branch August 22, 2026 03:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant