Replace the DM composer with an "Unblock to message" notice bar when
the contact is blocked, so a block also stops outgoing DMs (previously
only incoming DMs/adverts were suppressed). Inline unblock restores the
composer. Adds block_composerNotice l10n string and documents the
outgoing-DM rule in block-contract-as-built.md §4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Offband rebrand renamed the Windows executable meshcore_open.exe ->
offband_meshcore.exe (verified: the #244 build produced offband_meshcore.exe).
Only the Windows distribution doc was stale; the Android package/namespace,
MethodChannel names, and macOS/iOS bundle names are deliberately still
meshcore_open (those renames are deferred per the rebrand plan).
Remove the invented whole-channel-mute (never specified; already exists in
notification settings). Repurpose §6 to the real spec: blocking a channel sender
who can't be resolved to a pubkey adds a GLOBAL name-fallback (hides them in every
channel, not one at a time), which promotes to a pubkey block once the identity is
learned via advert OR DM (§7). Single/invisible-char rename evasion explicitly out
of scope. A4/#171 closed not-planned; behavior lives in A3/#170 + A5/#172 + A7/#174.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ben's UX call: do NOT hide blocked contacts to a settings-only list. Keep them
in Contacts/Discovery with a red block icon + muted styling + inline unblock.
A 'hide blocked entirely' toggle is a post-implementation follow-on.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reply-shape [0xC2][sub][ok] (result byte, not ack/err frame); generic error
frame [0x01][0x06] is NOT 0xC2-prefixed. Overflow at MAX_BLOCKED_KEYS=32 returns
ok=0 (not error) + already-stored returns ok=1 (dedup short-circuit). BLOCK_LIST
truncation detect via START count vs key-frames -> re-request on APP_START
early-END; never derive removals from LIST. DM-drop is silent (no notif/frame) ->
no firmware block counts for UX. No unsolicited pushes. Design confirmed by
PearlMeadow; app half locked to shipped firmware, no open discrepancies.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Align to firmware PR #247 (merged): cap OFFBAND_CAP_BLOCK=0x02, FIRMWARE_VER_CODE
15, 0xC2 CMD_OFFBAND_BLOCK (ADD/REMOVE/LIST/CLEAR), MAX_BLOCKED_KEYS=32, BLOCK_LIST
streamed-dump framing (0xFF count / index / 0xFE end) + APP_START early-END.
Switch sync model to union / always-retain-local (app-local never wiped; portable
across Offband clients, local-only on non-Offband). Global (by-pubkey) app store.
Fold in channel all-matching-pubkeys rule, dual name-key index sourcing (0x8A vs
0x80), promote-and-prune age-out, gaps G1/L1/L2/L3, interop invariant.
Feature #164 / Epic A #165 / Epic B #166; firmware doc #244.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sweep user-facing docs from "MeshCore Open" to "Offband Meshcore":
README, docs/PRIVACY_POLICY, documentation/*, CONTRIBUTING, TESTFLIGHT_GUIDE.
- Prominent README attribution (fork of MeshCore Open by zjs81, MIT) + a
Credits section. LICENSE left untouched (zjs81 copyright retained).
- Removed the upstream donation block (Solana/Monero/BTC) per owner.
- Removed upstream-only pointers that would misdirect (zjs81 Obtainium badge,
meshcoreopen.org); pointed clone/issues at Strycher/meshcore-open; fixed the
stale iOS bundle id -> app.offband.meshcore.
CLAUDE.md (dev-facing instructions) intentionally left as-is.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>