Commit Graph
936 Commits
Author SHA1 Message Date
jackandClaude Fable 5 8899cb7f9e Add field correctness diagnostics: store invariant audit, drop and bounds proofs
ConversationStore.auditInvariants() verifies the per-conversation and
store-level message-ID indexes, caps, timestamp ordering, unread-set
membership, and selection validity - wired to the existing read-receipt
cleanup cadence, loud (.error) on violation, sampled heartbeat when
healthy (~2.8ms per audit at 5k messages, benchmarked and floored).
Router drops log both outcomes (marked failed / skipped by no-downgrade
guard); relay cap evictions, age sweeps, and jittered reconnect delays
log their counts; mirrored republishes get a sampled proof line. 11 new
invariant tests corrupt store state through DEBUG-only hooks since the
single-writer lockdown makes those states unreachable via intents.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 19:28:47 +02:00
jackandClaude Fable 5 22be3d6392 Resurrect dead Noise vector tests; add CI perf floors; make tests hermetic
Package.swift's .process("Noise") resource claim silently excluded all
of bitchatTests/Noise/ from compilation since Oct 2025 - including a
complete official-vector runner (cacophony + snow XX transcripts,
transport messages, handshake hash, byte-identical to upstream).
Narrowing the resource to the JSON file and loading via Bundle.module
brings 51 Noise tests back to life, with a guard asserting each
vector's protocol name matches the app's.

CI gains a performance floor gate: perf-floors.json carries deliberately
generous floors (~25% of measured throughput) that catch algorithmic
regressions without flaking on runner variance; PERF lines reach the
gate via an O_APPEND side-channel file since swift test --parallel
swallows passing tests' stdout.

Tests are now hermetic: FavoritesPersistenceService uses an in-memory
keychain under test (fixes the securityd hang that blocked pipeline
benchmarks locally) and read-receipt persistence uses a wiped scratch
UserDefaults suite instead of .standard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 15:53:34 +02:00
jackandClaude Fable 5 8a867a17a1 Remove noise service exposure; single-owner selection state
Transport callers no longer reach the raw NoiseEncryptionService:
getNoiseService() is deleted in favor of narrow purpose-named Transport
methods (session public key, identity fingerprint, static/signing keys,
sign/verify, callback installation). VerificationService now reaches
crypto through the transport, so it can no longer pin a stale service
across a panic reset. myPeerID/myNickname become private(set); the
existing setNickname mutator is the sole nickname path.

ConversationStore is now the sole owner of private-chat selection:
PrivateChatManager.selectedPeer is a published read-only mirror, and
startChat/endChat mutate through the store intent. The bridge method
and its five call sites are deleted, removing a latent bug where a
stale manager selection pushed back into the store could resurrect a
just-removed conversation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 15:29:07 +02:00
jackandClaude Fable 5 ed86ed1065 Surface router drops as failed status; bound relay pending subscriptions; jitter backoff
MessageRouter outbox drops (attempt cap, TTL expiry in flush and
cleanup, per-peer overflow eviction) now invoke onMessageDropped, wired
to mark the message .failed in the ConversationStore - guarded so a
late failure never downgrades an already delivered/read status.

NostrRelayManager pending subscriptions gain a per-relay cap (64,
oldest-by-sequence eviction; durable intent still replays from
subscriptionRequestState) and a 10-minute age sweep on the existing
connect path. Reconnect backoff gets injectable +/-20% jitter so
recovering relays don't thundering-herd.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 15:05:44 +02:00
jackandGitHub e74d9a7937 Single-source-of-truth ConversationStore: 2-2.5x ingest, four stores and three sync bridges deleted (#1334)
Single-source-of-truth ConversationStore: 2-2.5x ingest, four stores and three sync bridges deleted
2026-06-11 13:19:24 +01:00
jackandClaude Fable 5 8289a6d05e Republish mirrored conversations on shared-instance status changes
When a private message is mirrored into stable-key and ephemeral-peer
conversations as one shared BitchatMessage instance, the first
conversation's status apply mutated the shared object and the second
skipped as already-equal - state stayed correct but the mirrored
conversation never republished, so a view observing it rendered stale
delivery/read status. The ID-only fan-out now republishes and emits
.statusChanged for every skipped conversation whose message holds the
applied status; genuinely-rejected distinct copies (downgrades) stay
untouched, and duplicate acks still publish nothing.

Found by Codex review on #1334.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 14:09:43 +02:00
jackandClaude Fable 5 38331e62f1 Cut views over to ConversationStore; delete legacy store, bridge, resolver
Feature models observe per-conversation objects directly: PublicChatModel
forwards the active Conversation's objectWillChange, PrivateInboxModel
republishes only for the selected peer's conversation - background
appends no longer invalidate foreground views. LegacyConversationStore,
the coalescing bridge, and IdentityResolver are deleted (resolver
canonicalization proved display-invisible: nothing enumerates direct
conversations, lookups are by exact peer ID, and raw keying is strictly
more robust - documented as a design deviation). Selection state moves
into the store. ChatViewModel.messages/privateChats survive as derived
read views for coordinators that genuinely need them; hot paths use a
new store-direct privateMessages(for:) witness.

Final numbers vs pre-migration baselines:
pipeline.privateIngest 9.7k -> 24.0k msg/s (2.5x)
pipeline.publicIngest  6.8k -> 13.7k msg/s (2.0x)
delivery updates       38k  -> 117-133k/s

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:57:12 +02:00
jackandClaude Fable 5 7fb1f4a219 Route delivery status through the store; delete the location index
ConversationStore maintains an exact messageID -> Set<ConversationID>
map at every mutation point (append/upsert/remove/migrate/trim/clear),
so delivery updates are ID-only lookups that fan out to mirrored
ephemeral/stable copies. ChatDeliveryCoordinator shrinks 327 -> 119
lines: the positional location index, its growth-detection/rebuild
machinery, and the duplicate no-downgrade check are deleted - the rule
now lives in exactly one place. The middle-insertion regression tests
are rewritten against the store since stale positional locations are
structurally impossible now.

delivery updates: 38k -> 262k/s (~6.9x); ingest pipelines unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:26:00 +02:00
jackandClaude Fable 5 99d1d1dccd Cut public message path over to ConversationStore; delete PublicTimelineStore
Mesh and geohash timelines are now store conversations. All public
mutation sites flow through store intents; PublicMessagePipeline keeps
its 80ms UI batching but commits batches via store appends with each
buffered entry carrying its destination conversation (a mid-batch
channel switch now flushes instead of dropping the buffer).
ChatViewModel.messages becomes a cached get-only view of the active
conversation, invalidated through the change subject. The mesh
late-insert threshold is consciously removed: it only ever ordered the
non-rendered messages copy, so strict timestamp insertion makes the
working set agree with rendered order. PublicTimelineStore and the
per-message full-array legacy sync are deleted; the coalescing bridge
mirrors public conversations for the remaining legacy readers.

pipeline.publicIngest: 6.6k -> 9.5k msg/s (+45%); private steady;
store.append 237k/s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:03:07 +02:00
jackandClaude Fable 5 879d8cba12 Cut private message path over to ConversationStore
All private-message mutations now flow through store intents:
coordinators, PrivateChatManager (its @Published dicts deleted - now
read-only views over the store), outbound sends, delivery status, and
chat migration. The O(1) store dedup replaces the full-scan duplicate
check; insertion order is maintained by the store so sanitizeChat's
re-sort is a documented no-op. Both bootstrapper Combine bridges and
the Task.yield store synchronization are deleted.

ChatViewModel.privateChats/unreadPrivateMessages become get-only derived
views (measured: naive rebuild equals a change-invalidated cache within
noise, so the simpler form stays). Feature models still read the legacy
store, fed by a coalescing LegacyConversationStoreBridge (one mirror
per burst, marked for step-5 deletion).

pipeline.privateIngest: 9.6k -> 14.7k msg/s (+53%).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 12:19:11 +02:00
jackandClaude Fable 5 ac3a2f2d34 Add single-writer ConversationStore core (additive)
Per-conversation ObservableObjects with O(1) dedup via an incrementally
maintained message-ID index, binary-search timestamp insertion, folded
cap policies, a no-downgrade delivery rule, and a typed change subject.
All mutation flows through store intents (conversation mutators are
fileprivate). The previous store is renamed LegacyConversationStore
pending deletion in step 5. 16 behavioral tests including per-
conversation publish isolation; store.append benchmarks at ~144k
messages/sec.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 11:02:27 +02:00
jackandClaude Fable 5 45650854e7 Add conversation-store design doc and end-to-end ingest baselines
docs/CONVERSATION-STORE-DESIGN.md records the approved design: a
single-writer ConversationStore of per-conversation ObservableObjects
(per-conversation publishing, incremental ID index, folded caps, typed
change subject) replacing today's four-store/three-bridge topology,
with a five-step migration plan and explicit deletions/non-goals.

New pipeline benchmarks measure the CURRENT architecture end-to-end so
every migration step is judged against real before-numbers:
pipeline.privateIngest ~9.7k msg/s, pipeline.publicIngest ~6.8k msg/s
(200-message passes, stable within 1.5%).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 10:51:24 +02:00
75dd83d9cc Make location notes robust: durable relay subscriptions, failure decay, auto-recovery (#1333)
* Make location notes robust: durable relay subscriptions, failure decay, auto-recovery

Location notes (and geohash chat / DMs) intermittently stopped showing
events because the Nostr relay layer lost subscriptions and blacklisted
relays:

- Replay active subscriptions on every relay (re)connect. Relays drop
  REQs with the socket; previously a drop silently killed the
  subscription on that relay for the rest of the session. Durable
  subscription intent now also survives disconnect()/resetAllConnections
  (background -> foreground).
- Keep failed REQ sends queued instead of dropping them.
- Raise the EOSE fallback from a fixed 2s Timer to a 10s injected
  schedule (Tor needs more than 2s), and settle EOSE trackers when a
  relay disconnects before answering so initial load doesn't stall.
- Decay "permanently failed" relay markings after a 10-minute cooldown;
  previously ~9 minutes of outage (or one DNS hiccup) excluded a relay
  until app restart, with nothing resetting it on macOS.
- Make geo relay selection deterministic (distance, then host) so
  publishers and subscribers with the same directory agree on relays.
- Post .geoRelayDirectoryDidRefresh after a directory fetch and let
  LocationNotesManager auto-resubscribe out of the "no relays" state
  instead of requiring a manual retry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Guard subscription activation on connection identity

A REQ send completion from a dead socket could land after
handleDisconnection cleared the relay's subscriptions and re-mark the
subscription active, making the next connection skip the durable replay
and leave that relay silent. Only mark a subscription active if the
completing socket is still the relay's live connection.

Regression test defers send completions in the mock so the stale
completion deterministically interleaves between disconnect and
reconnect.

Addresses Codex review on #1333.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 09:28:23 +01:00
jackandGitHub 93d01b8fa6 Performance & architecture: 640x hot-path win, zero coordinator back-refs, measured baselines (#1332)
Performance & architecture: 640x hot-path win, zero coordinator back-refs, measured baselines
2026-06-11 09:25:47 +01:00
jackandClaude Fable 5 6c0dbbbd0d Make lifecycle delayed read-pass deterministic in tests
The coordinator scheduled its delayed owner-level read pass via
DispatchQueue.main.asyncAfter, which a busy CI runner's main queue can
delay past any reasonable polling deadline. Scheduling is now an
injected context member (scheduleOnMainAfter); the ChatViewModel witness
keeps the exact asyncAfter behavior while the test mock runs the work
synchronously, eliminating the wall-clock poll entirely.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 09:50:47 +02:00
jackandClaude Fable 5 09087b74cc Add coverage reporting to CI
swift test runs with --enable-code-coverage and each matrix job prints
an llvm-cov per-file + total summary (informational only - no
thresholds, so coverage can never be the reason a build goes red).
Local baseline at introduction: 69.7% lines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 23:07:04 +02:00
jackandClaude Fable 5 cc76086615 Inject notification/favorites singletons through coordinator contexts
NotificationService.shared and FavoritesPersistenceService.shared
accesses across nine coordinators/components consolidate into
ChatViewModel witnesses behind intent-named context members
(notifyPrivateMessage, notifyMention, favoriteRelationship(forNoiseKey:),
allFavoriteRelationships, postLocalNotification, ...). Singleton reach
from coordinators is now zero; nine new tests cover previously
untestable notification/favorites flows.

Also root-causes the long-flaky gift-wrap dedup test: parallel tests
share LocationChannelManager.shared, so channel-switch tests trigger
clearProcessedNostrEvents() on every live ChatViewModel, wiping the
dedup record mid-test. The invariant (forged-signature copies never
poison dedup) now lives as a deterministic NostrInboundPipeline
mock-context test; two Schnorr concurrency probes added along the way
stay as regression guards for the P256K shared-context assumptions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 23:04:20 +02:00
jackandClaude Fable 5 638f3f5005 Split ChatNostrCoordinator into owned components along domain boundaries
The 1,109-line coordinator becomes a 187-line facade wiring three
components, each with its own narrow context protocol:
GeohashSubscriptionManager (384 lines - subscription IDs + relay
lifecycle, the only NostrRelayManager toucher), NostrInboundPipeline
(490 lines - the hot event path, dedup-before-verify ordering preserved
verbatim), and GeoPresenceTracker (192 lines - teleport detection,
sampling LRU, notification cooldowns, now directly tested).

Perf baselines confirm the hot path is unchanged: fresh events
2,131 -> 2,138/sec, duplicates ~1.41M/sec.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 22:28:08 +02:00
jackandClaude Fable 5 6091ee83ad Finish coordinator migration: zero ChatViewModel back-references remain
ChatPeerListCoordinator, ChatComposerCoordinator, ChatOutgoingCoordinator,
and GeoChannelCoordinator complete the migration; every coordinator now
depends on a narrow @MainActor context protocol. GeoChannelCoordinator's
three injected closures collapse into a weak context. New intent op
recordPublicActivity(forChannelKey:) keeps lastPublicActivityAt
single-writer. 15 new mock-context tests; flaky-poll deadline in the
gift-wrap dedup test raised for parallel load.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 22:13:09 +02:00
jackandClaude Fable 5 82736c4991 Migrate five more coordinators to narrow context protocols
ChatTransportEventCoordinator, ChatPeerIdentityCoordinator,
ChatMediaTransferCoordinator, ChatVerificationCoordinator, and
ChatLifecycleCoordinator drop their unowned ChatViewModel back-refs for
narrow @MainActor contexts (20-36 members each), reusing shared
witnesses across protocols. The two remaining raw writers of
sentReadReceipts now route through owner intent ops
(unmarkReadReceiptsSent, syncReadReceiptsForSentMessages), closing the
gaps noted in the previous commit. NoiseEncryptionService stays fully
out of the verification coordinator via installNoiseSessionCallbacks.
26 new mock-context tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 21:54:54 +02:00
jackandClaude Fable 5 707b22878d Convert shared coordinator state to owner-side intent operations
nostrKeyMapping, sentGeoDeliveryAcks/sentReadReceipts dedupe,
isBatchingPublic, geo subscription lifecycle, and private-chat selection
hand-off now mutate through single intent operations on ChatViewModel,
with backing storage locked down via private(set) so the single-writer
property is compiler-enforced. Context protocols downgrade to read-only
access where reads remain. 8 new contract tests.

Known remaining writers outside the protocols: sentReadReceipts is
passed inout to PrivateChatManager.syncReadReceiptsForSentMessages and
un-marked by ChatTransportEventCoordinator on disconnect.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 21:26:21 +02:00
jackandClaude Fable 5 80bed1f395 Add performance baselines; check dedup before verifying Nostr signatures
New PerformanceBaselineTests measure the hot paths (Nostr inbound, BLE
packet pipeline, GCS filters, delivery index, message formatting) with
deterministic fixtures and logged PERF metrics - baselines, not
assertions, so they cannot flake CI.

The suite immediately exposed that every inbound handler ran Schnorr
verification before the dedup lookup, so duplicate events - which
dominate real multi-relay traffic - each paid ~0.5ms of main-actor
crypto for nothing. All five handlers now do cheap rejects (kind, dedup
lookup) first and only record an event as processed AFTER its signature
verifies, so a forged-signature copy can never poison the dedup set and
suppress the genuine event. Gift-wrap verification also moves entirely
off the main actor with an atomic main-actor check-and-record.

Measured: duplicate-event handling 2.2k -> 1.39M events/sec (~640x);
fresh events unchanged (crypto-bound).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 21:11:06 +02:00
jackandClaude Fable 5 4b287f7490 Stop paying for filtered log messages; sample per-event hot-path logs
SecureLogger's public wrappers evaluated their message autoclosure before
the level check inside log(), so every filtered debug message across the
codebase still paid for string interpolation - hundreds of call sites on
the per-packet/per-event hot paths. The wrappers now guard the level
first, and debug() compiles out of release builds entirely. Regression
tests verify filtered messages are never constructed.

The two heaviest per-event debug logs (NostrRelayManager inbound events,
ChatNostrCoordinator geo events) are now sampled every 100th with a
running count, so debug-enabled dev builds stop emitting hundreds of
lines per minute in busy geohashes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 20:55:25 +02:00
jackandGitHub 3caf2d7663 Architecture hardening: Tor reliability, supply-chain CI gate, BLE handler extraction, coordinator contexts (#1331)
Architecture hardening: Tor reliability, supply-chain CI gate, BLE handler extraction, coordinator contexts
2026-06-10 20:24:39 +02:00
jack 14d025cc2a Merge remote-tracking branch 'origin/architecture-hardening' into architecture-hardening 2026-06-10 16:33:02 +01:00
jackandClaude Fable 5 19b28cf49d Rebuild message location index on non-append growth
The incremental index refresh assumed growth meant appended messages,
but PublicMessagePipeline inserts out-of-order arrivals by timestamp:
the count grows while the tail ID stays put, so the inserted message
never entered the index and later delivery updates for it silently
no-op'd (and, with retain-until-ack routing, left it queued for
resend). Detect non-append growth by checking the previously indexed
tail kept its position, and rebuild when it hasn't. Same check on the
per-peer private chat arrays, which re-sort by timestamp.

Found by Codex review on #1331.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 16:32:36 +01:00
jackandGitHub a2825ca288 Merge branch 'main' into architecture-hardening 2026-06-10 17:29:16 +02:00
jackandClaude Fable 5 3a995e20b6 Extract BLE packet handlers and migrate coordinators to narrow contexts
BLEService's per-packet-type orchestration moves into owned, tested
components (BLEAnnounceHandler, BLEPublicMessageHandler,
BLENoisePacketHandler, BLEFileTransferHandler, BLEFragmentHandler),
each taking an environment struct of closures so every queue hop stays
in BLEService and the handlers are synchronously testable. Behavior is
preserved verbatim, including Noise session recovery on decrypt failure
and single-block UI event ordering. handleLeave/handleRequestSync stay
in place as already-thin delegations. BLEService drops to 3393 lines.

Four coordinators (delivery, private conversation, Nostr, public
conversation) drop their unowned/weak ChatViewModel back-references for
narrow @MainActor context protocols, with ChatViewModel conformances as
single shared witnesses for overlapping members. Their true coupling is
now an explicit, reviewable surface, and each gains a mock-context test
suite covering flows previously testable only through the full view
model. Delivery/read acks now also clear the router's retained-send
outbox via the delivery context.

New LargeTopologyTests exercise production-shaped meshes with the
in-memory harness: an 8-peer relay chain with per-hop TTL decay, a
14-peer cyclic mesh with exactly-once delivery, partition/heal, and
topology churn.

App-layer runtime/model files updated alongside.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 16:22:52 +01:00
jackandClaude Fable 5 6bda919dd4 Fix transport reliability gaps: Tor stalls, weak-signal sends, GCS input validation
NostrRelayManager no longer strands work when Tor is slow to bootstrap:
failed readiness waits retry (bounded by nostrTorReadyMaxWaitAttempts)
instead of dropping queued relay connections, parked EOSE callbacks fire
after exhaustion so callers never hang, and sends made before Tor is
ready are queued locally (capped) instead of being dropped on a failed
wait - still strictly fail-closed.

MessageRouter now prefers a connected transport over a merely
window-reachable one, and sends made on a weak reachability signal are
retained in the outbox until a delivery/read ack confirms receipt
(receivers dedup by message ID), with resends bounded by attempt count.

GCS sync filters from the wire are bounds-checked (p in 1...32, m > 1)
at both the packet decode and filter decode layers; oversized Golomb
parameters previously decoded to garbage via silent shift overflow.

BLELinkStateStore is now explicitly pinned to bleQueue: debug builds
trap any access from another queue, enforcing the ownership discipline
the surrounding code already relied on by convention.

CI gains an iOS simulator build job (arm64 only; the vendored Arti
xcframework has no x86_64 simulator slice) so iOS-conditional code
paths are compile-checked - SPM tests only cover the macOS slice.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 16:22:35 +01:00
jackandClaude Fable 5 4093ee6733 Rebuild Arti from audited source with enforced provenance
Vendored arti.xcframework rebuilt from source (Rust 1.96.0, normalized
archive metadata for reproducible hashes). New ARTI-BINARY-PROVENANCE.md
records toolchain, rebuild steps, and a SHA256 manifest for every file
in the xcframework. A new CI workflow turns that policy into a gate:
PRs must keep the binary matching the manifest, and binary changes must
ship with source/lockfile/build-script evidence.

Also raises TorManager.awaitReady's default timeout from 25s to 75s to
match the bootstrap monitor deadline - a shorter wait reported "not
ready" while Arti was still legitimately bootstrapping, silently
stranding queued relay work.

Privacy policy, Tor integration doc, and privacy assessment updated to
match the current implementation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 16:22:15 +01:00
GitHub Action eb2c128cab Automated update of relay data - Sun Jun 7 07:23:10 UTC 2026 2026-06-07 07:23:10 +00:00
3eb4f2bd72 Extract BLE and chat architecture policies (#1324)
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2026-06-02 09:01:59 +02:00
193cfdc06a [codex] Extract BLE service policy helpers (#1321)
* Extract BLE service policy helpers

* Stabilize image media transfer test

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2026-06-01 14:16:44 +02:00
ffa0d7aa4f [codex] Extract BLE link state store (#1310)
* Refactor BLE transport event handling

* Make image output paths unique

* Keep queued Nostr read receipts alive

* Refine BLE ingress fanout

* Rediscover BLE service after invalidation

* Extract BLE notification retry buffer

* Extract BLE inbound write buffer

* Extract BLE fragment assembly buffer

* Tidy secure log handling from device run

* Extract BLE outbound fragment scheduler

* Harden app CI media tests

* Redact BLE message content from logs

* Extract BLE Noise session queues

* Fix BLE read receipt UI updates

* Allow self-authored RSR ingress replies

* Harden read receipt queue test timing

* Extract BLE outbound policy and incoming file storage

* Avoid duplicate BLE link snapshots during send

* Canonicalize Nostr relay URLs

* Extract BLE link state store

* Extract BLE connection scheduler

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2026-05-31 14:24:09 +02:00
9e84f5e822 [codex] Refactor BLE outbound scheduling and Noise queues (#1306)
* Refactor BLE transport event handling

* Make image output paths unique

* Keep queued Nostr read receipts alive

* Refine BLE ingress fanout

* Rediscover BLE service after invalidation

* Extract BLE notification retry buffer

* Extract BLE inbound write buffer

* Extract BLE fragment assembly buffer

* Tidy secure log handling from device run

* Extract BLE outbound fragment scheduler

* Harden app CI media tests

* Redact BLE message content from logs

* Extract BLE Noise session queues

* Fix BLE read receipt UI updates

* Allow self-authored RSR ingress replies

* Harden read receipt queue test timing

* Extract BLE outbound policy and incoming file storage

* Avoid duplicate BLE link snapshots during send

* Canonicalize Nostr relay URLs

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2026-05-31 14:16:11 +02:00
df36b19afe [codex] Refine BLE ingress fanout (#1280)
* Refactor BLE transport event handling

* Make image output paths unique

* Keep queued Nostr read receipts alive

* Refine BLE ingress fanout

* Rediscover BLE service after invalidation

* Extract BLE notification retry buffer

* Extract BLE inbound write buffer

* Extract BLE fragment assembly buffer

* Tidy secure log handling from device run

* Allow self-authored RSR ingress replies

* Harden read receipt queue test timing

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2026-05-31 14:08:30 +02:00
ab0da61533 [codex] Refactor BLE transport event handling (#1266)
* Refactor BLE transport event handling

* Make image output paths unique

* Keep queued Nostr read receipts alive

* Allow self-authored RSR ingress replies

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2026-05-31 13:58:27 +02:00
GitHub Action 3be8fbf1c4 Automated update of relay data - Sun May 31 07:17:57 UTC 2026 2026-05-31 07:17:57 +00:00
764f016d17 [codex] Refactor app runtime and ownership architecture (#1104)
* Refactor app runtime and view model architecture

* Move app ownership into stores and coordinators

* Fix smoke test environment injection

* Stabilize fragmentation package tests

* Fix coordinator build warnings

* Clean up chat view model warnings

* Fix Nostr relay startup coalescing

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
2026-05-30 14:13:26 +02:00
GitHub Action a6cb8872fb Automated update of relay data - Sun May 24 07:05:51 UTC 2026 2026-05-24 07:05:51 +00:00
GitHub Action 3daf02732a Automated update of relay data - Sun May 17 06:57:28 UTC 2026 2026-05-17 06:57:28 +00:00
GitHub Action 0d1cdc7644 Automated update of relay data - Sun May 10 06:54:20 UTC 2026 2026-05-10 06:54:21 +00:00
GitHub Action 43eef0d49c Automated update of relay data - Sun May 3 06:51:02 UTC 2026 2026-05-03 06:51:02 +00:00
GitHub Action bafa461f26 Automated update of relay data - Sun Apr 26 06:37:54 UTC 2026 2026-04-26 06:37:54 +00:00
GitHub Action 602d2316ef Automated update of relay data - Sun Apr 19 06:34:27 UTC 2026 2026-04-19 06:34:27 +00:00
IslamandGitHub c60eff2c11 Move additional files/tests to BitFoundation (#1102) 2026-04-15 12:26:48 -05:00
IslamandGitHub 4cfcefcda6 BitFoundation module to centralize shared components (#1089)
* Run local packages’ tests as well on CI

* BitFoundation module to centralize shared components
2026-04-14 14:10:03 -05:00
GitHub Action 3e137d784c Automated update of relay data - Sun Apr 12 06:32:24 UTC 2026 2026-04-12 06:32:24 +00:00
islam 452e9e74fd Run CI build on all PRs (not just to the main) 2026-04-10 22:31:49 +01:00
jack 3afd74ffc8 Ignore .claude directory 2026-04-05 19:04:18 -05:00