Instead of computing on-tap, all 9 tones are precomputed in parallel
after a 1-second debounce when the user stops typing. Tone chips only
appear once results are ready. Tapping a chip instantly shows the
precomputed result. Text changes cancel and restart the computation.
https://claude.ai/code/session_01RbCYGrbbapRMike8WQy41F
Replace the sparkle toggle button in the compose toolbar with a
persistent setting in UI/Application Preferences. The new "Propose AI
text improvements" setting (Always/Never) controls whether the tone
chip row appears in the compose screen.
When enabled and the device supports on-device AI, the tone chips show
automatically below the text field. Removes the per-session toggle
button from BottomRowActions.
https://claude.ai/code/session_01RbCYGrbbapRMike8WQy41F
Temporary MockWritingAssistant that returns fake transformed text after
a short delay. Enabled via useMockAi flag in ShortNotePostViewModel.
Allows testing the AI writing help UI on devices without Gemini Nano.
TODO: Set useMockAi = false before shipping.
https://claude.ai/code/session_01RbCYGrbbapRMike8WQy41F
Use ML Kit language identification to detect the post's language before
transforming. Maps detected BCP-47 tags to the 7 supported languages
(English, Japanese, Korean, German, French, Italian, Spanish). Falls
back to English for unsupported languages. Rewriter and proofreader
clients are cached per language+outputType combination.
https://claude.ai/code/session_01RbCYGrbbapRMike8WQy41F
Add on-device AI writing assistance using ML Kit GenAI APIs (Rewriting,
Proofreading) powered by Gemini Nano via Android AICore. Users can tap
the sparkle button in the compose toolbar to access tone chips (Correct,
Rephrase, Shorter, Elaborate, Friendly, Professional, More Direct,
Punchy, + Emoji) that transform their post text. Results appear in a
card with Use/Dismiss actions.
- Play flavor: MLKitWritingAssistant using on-device Gemini Nano
- F-Droid flavor: NoOpWritingAssistant stub (returns unavailable)
- WritingAssistant interface for future DVM/NIP90 integration
- AI button hidden on unsupported devices
Also fixes pre-existing exhaustive when expression in
DecryptAndIndexProcessor for GroupEventResult.Duplicate.
https://claude.ai/code/session_01RbCYGrbbapRMike8WQy41F
- H11: Cache skipped message keys in SecretTree for out-of-order decryption
- L1: Prune sentKeys map when exceeding 10000 entries
- L2: Prune consumed generations below current minimum
- H17: Call markAsRead when chat view is opened
- Key zeroing: Zero old private keys in KeyPackageRotationManager
https://claude.ai/code/session_018gVkmmYgMFtBH7G31pCk9N
ThreadLocal.withInitial is a JVM-only API that doesn't compile on
Kotlin/Native or iOS targets. Replace all usages in commonMain
(FieldP.kt, Point.kt) with a new ScratchLocal expect/actual:
- jvmMain/androidMain: delegates to java.lang.ThreadLocal (same behavior)
- nativeMain: holds value directly (Kotlin/Native coroutines are
cooperative, scratch buffers don't need thread isolation)
https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg
When the app restarts and reconnects to relays, old call offer events
from completed calls could be replayed, causing the phone to ring for
calls that already ended. This was especially noticeable when the user
killed and restarted the app shortly after a call.
Three protections added to CallManager:
1. Track completed call IDs: hangup/reject events mark their call-id as
completed. Subsequent offer events for the same call-id are ignored.
2. Init timestamp guard: events created before the CallManager was
initialized (minus a grace period) are rejected, preventing stale
events from a previous app session from triggering ringing.
3. Completed call IDs survive reset(): the set is intentionally not
cleared when the call state machine resets to Idle, ensuring that
stale offers remain blocked for the lifetime of the CallManager.
https://claude.ai/code/session_0145VKiG8yZMqcMsaBEjNPxv
Three Android-specific optimizations:
1. Use Math.unsignedMultiplyHigh on API 35+ (Android 15): single UMULH
instruction, eliminates the 4-insn signed→unsigned correction that
the fallback path requires. Same optimization as our JVM 18+ path.
2. Use Math.multiplyHigh + correction on API 31-34 (Android 12-14):
avoids the pure-Kotlin 4×32-bit sub-product fallback entirely.
3. Resolve API level check ONCE at class load via static final fields
(HAS_MULTIPLY_HIGH, HAS_UNSIGNED_MULTIPLY_HIGH) instead of checking
Build.VERSION.SDK_INT on every call. These functions are called 16×
per field multiply (~12,000× per signature verify), so eliminating
the per-call branch matters.
Performance tiers on Android:
API 35+ (Android 15): ~same as JVM 18+ (UMULH intrinsic)
API 31-34 (Android 12-14): SMULH + 3 correction insns per product
API 26-30 (Android 8-11): pure-Kotlin fallback (4 sub-products)
https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg
Add precise per-operation cost analysis from comparing our Kotlin
implementation with bitcoin-core/secp256k1's C source:
- doublePoint: 1,516 insns (Kotlin) vs 530 insns (C) = 2.9×
- mul/sqr accounts for 76% of gap (UMULH+MUL+carry vs single MUL)
- add/neg/half accounts for 24% (reduceSelf vs lazy magnitude tracking)
- Update performance numbers to Java 21 results (verify 3.4×, sign 1.1×)
- Document all optimizations implemented during this session
- Note that lazy reduction penalty (4.2× on cheap ops) is the main
remaining algorithmic opportunity, but requires 5×52-bit limb change
https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg
- Add `inline` to hot-path tiny functions: U256.isZero, U256.testBit,
FieldP.reduceSelf, FieldP.neg, MutablePoint.isInfinity. These are
called thousands of times per EC operation; inline eliminates virtual
call overhead (mostly helps Kotlin/Native; JVM JIT already inlines).
- Fix stale comment: G_TABLE_SIZE is 1024 for w=12 (was "64 for w=8")
https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg
Move transitionToEnded() before the signing + relay publish in hangup()
so the UI stops ringing/ringback immediately, matching the pattern
already used by rejectCall(). Add onDestroy safety net in CallActivity
to hang up if the Activity is destroyed while a call is active. Wrap
audio stop methods in try-catch to prevent one failure from blocking
the others.
https://claude.ai/code/session_01Rip2HPCbF48PPFDiB2X5ik
inv() and sqrt() each allocated 11 LongArray(4) (plus 2 for sqrt
verification) on every call. These are now served from a thread-local
Array(11) { LongArray(4) } cache, eliminating 22-24 allocations per
ECDH operation (inv called in toAffine, sqrt called in liftX).
Also reuses chain scratch slots for sqrt's verification step instead
of allocating separate check/ar arrays.
https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg
Eliminates ~80 LongArray allocations per mul/mulDoubleG call by
pre-allocating the P-side Jacobian and affine tables, the doubling
temp, and the batch inversion scratch buffers in PointScratch
(thread-local, allocated once per thread, reused across calls).
Before: mul() allocated 8 MutablePoint (24 LongArray) + 8 MutablePoint
(24 LongArray) + 16 AffinePoint (32 LongArray) + batch temps = ~92
LongArray per call. After: 0 allocations in the table construction path.
Also fixes minor allocation in addMixed degenerate case (use t[5]
scratch instead of new LongArray(4)).
https://claude.ai/code/session_01BhU63WUe9AhikZxRdw3Lpg