Files
amethyst/amethyst
Claude 52ad5b9bbb fix: stop comparing a class name R8 renames, and scope the contract per flavor
Audit of what still reflects now that obfuscation is on. Two live defects, both
invisible in a debug build:

1. AmethystAppFunctions.requireInProcessSigner() compared
   `signer::class.qualifiedName` against the fully-qualified name of
   NostrSignerExternal, with a comment explaining that this avoided an import.
   R8 renames that class — `NostrSignerExternal -> nbc` in the release mapping —
   so the comparison never matched and the external-signer branch stopped
   running the moment obfuscation was enabled. A user on Amber invoking a write
   AppFunction from Gemini would fall through to the write attempt instead of
   the typed "not supported here" message. It is a plain `is` check now; the
   class is already imported directly by two other files in this source set.

2. The reflection contract listed AmethystCastOptionsProvider unscoped, but that
   class only exists in the play flavor, and the release workflow runs the
   verifier for playRelease AND fdroidRelease. Absent from a mapping reads as
   "R8 deleted it", so the next release would have failed on fdroid. Measured,
   not guessed: the old contract reports 2 of 21 checks failed against a real
   fdroidRelease mapping. Contract lines may now open with @play / @fdroid, the
   verifier derives the flavor from the mapping directory, and an unrecognised
   directory still checks everything.

Also from the audit:

  - Deleted 16 keep rules that matched nothing: libscrypt (com.lambdaworks),
    NetCipher (info.guardianproject), LazySodium and the whole JNA block.
    None of those artifacts appear in mapping.txt, usage.txt or seeds.txt —
    quartz replaced libsodium with LibSodiumInstance and Tor runs through arti
    now. Two of them were `-keep class * implements …` wildcards.

  - Added NwcErrorCode to the contract. Its constant names are the NIP-47 wire
    strings: the response parser calls NwcErrorCode.valueOf() on a string
    another wallet wrote, inside a try/catch that falls back to null. The
    blanket enum rule covers it today, which is exactly why it needs recording
    before that rule is retired.

  - Added AmethystAppFunctions (@play), so the one package keep that had no
    contract line is no longer unverified.

Everything else that reflects is either a library that ships its own consumer
rules (appfunctions, kotlinx-serialization companions, WorkManager, lifecycle
ViewModel constructors, Startup, Cast, AppSearch) or names a class R8 cannot
rename: quic's JdkCertificateValidator probes the *platform* trust manager for
the 3-arg checkServerTrusted, and every setClassName() target is a
manifest-declared component that AAPT2 already generates a keep for.

Verified: 21/21 on a fresh playRelease, 19/19 + 2 skipped on fdroidRelease,
both from full assembles.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DEoxktEZyTrAS33vVZBiwm
2026-09-19 15:50:02 +00:00
..