Codex P1: the fixtures assumed the old default-ON preference — on a
clean CI process the coordinator guard drops their frames. Instead of
mutating the shared UserDefaults per test (which races parallel
suites), the live-voice reads are now injectable
(ChatLiveVoiceCoordinator.liveVoiceEnabled), the fixtures opt in per
instance, and the toggle-off test drives the provider directly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codex P1: the manager-path withheld claim landed only in
PrivateChatManager.sentReadReceipts, while the lifecycle read pass
dedups against ChatViewModel's persisted set — enabling receipts
before the next lifecycle pass could send a receipt for a message
read while the setting was off. The withheld branch now records into
the owner's persisted set too (markReceiptHandled, wired in the
bootstrapper); test strengthened to require both sets.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Live push-to-talk defaulted ON in both directions: holding the mic in
a public channel streamed your voice to everyone in radio range before
you released, and inbound bursts auto-played out of the speaker. A
single buried toggle defaulting on was not consent — both behaviors
are now opt-in (PTTSettings.liveVoiceEnabled defaults false), and the
settings copy says exactly what turning it on does.
Recording could also not be aborted one-handed: release always sent,
and the HUD's cancel button required lifting the finger — which sent.
Sliding the finger off the mic button (>60pt) now arms cancel — the
HUD flips from the timer to "release to cancel" — and sliding back
re-arms send. The armed flag resets on every exit path (cancel,
finish, panic), pinned by a new test.
2 new strings + 1 updated, all 30 locales.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Read receipts were unconditional: on chat open and on didBecomeActive,
twice. A receipt is a presence oracle — it says the person is awake,
holding their phone, and opened the app at that exact moment, which is
precisely the metadata the stated threat model says someone should be
able to withhold. Every mainstream messenger ships this switch.
- ReadReceiptSettings (default ON = existing behavior), toggle in the
settings privacy section, reset on panic wipe.
- All four origination paths gated: mesh/nostr routing, direct mesh
receipts, geohash receipts, and PrivateChatManager's read pass.
Withheld receipts are still recorded locally as sent, so re-enabling
the setting never fires a retroactive burst disclosing past reads.
- Only outbound receipts are affected; receipts from others display.
- 2 strings x 30 locales; tests pin the default, the reset, and that
nothing reaches the transport while off.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 09:17:55 +02:00
15 changed files with 1034 additions and 42 deletions