842 Commits

Author SHA1 Message Date
Taksh Kothari
9ee0b7fb48
Merge dfc2b8dcd115736110a8290b2dbb2604a1cfc6cf into 4f828b5643ff87a5064c8d384d0a4cb64001d2b2 2026-08-26 12:41:59 -04:00
callebtc
4f828b5643
Merge pull request #916 from permissionlesstech/codex/fix-wear-shape-and-font-scaling
Improve Wear layouts for round screens
2026-08-26 18:19:15 +02:00
callebtc
7cf5286bfb Fix slow Wear scroll intent detection 2026-08-26 17:28:17 +02:00
callebtc
a125da48aa Polish Wear shape-aware layout implementation 2026-08-26 16:46:13 +02:00
callebtc
3ed46222ba Fade Wear chat at screen contour 2026-08-26 11:56:00 +02:00
callebtc
898cfde066 Restore Wear chat edge fading 2026-08-26 11:39:16 +02:00
callebtc
33c1ebfc60
Merge pull request #909 from Chessing234/fix/panic-wipe-destroy-db-on-failure
fix: destroy conversation database files when panic wipe throws
2026-08-25 14:37:58 +02:00
Taksh
1a9f6befd4 fix: destroy conversation database files when panic wipe throws
If SQLite clearAll fails mid-panic, in-memory state was already cleared
but a process restart could reload encrypted history from disk (#699).
Fall back to deleting the database files before reporting failure.
2026-08-25 07:40:04 +05:30
callebtc
ed617f0f1b Fix Wear chat autoscroll and focal scaling 2026-08-24 21:13:07 +02:00
callebtc
34f94882f5 Restore Wear chat content space 2026-08-24 20:57:24 +02:00
callebtc
45915fab8f Tune Wear header boundary by screen shape 2026-08-24 20:15:17 +02:00
callebtc
f744038318 Preserve width for Wear Material cards 2026-08-24 20:08:44 +02:00
callebtc
4a1de47ed6 Cover transformed Wear header boundary 2026-08-24 20:04:46 +02:00
callebtc
5d66b69129 Clip Wear messages below the chat header 2026-08-24 20:01:46 +02:00
callebtc
7788328917 Keep Wear chat rows clear of controls 2026-08-24 19:58:03 +02:00
callebtc
2e41dabd07 Add round-screen responsive Wear insets 2026-08-24 19:54:20 +02:00
callebtc
5852fca9b5 Fix Wear content clipping on watch shapes 2026-08-24 19:38:26 +02:00
callebtc
eab894ce78
Merge pull request #743 from aharshit123456/fix/geohash-signature-verification-733
fix: verify Schnorr signatures on incoming geohash Nostr events
2026-08-24 19:17:25 +02:00
GitHub Action
d55754d824 Automated update of relay data - Sun Aug 23 06:09:25 UTC 2026 2026-08-23 06:09:25 +00:00
callebtc
09b481f1ef
Merge pull request #876 from qutad/feat/announce-capability-bits
feat: Add announce capability bit assignments
2026-08-17 21:05:02 +02:00
callebtc
db97c60af1 Merge remote-tracking branch 'origin/main' into feat/announce-capability-bits 2026-08-17 20:40:43 +02:00
callebtc
2318b51630
Merge pull request #897 from permissionlesstech/codex/fix-command-processor-test-brace
Fix CommandProcessor test syntax
2026-08-17 20:38:39 +02:00
callebtc
03d1da5423 Fix CommandProcessor test syntax 2026-08-17 20:13:19 +02:00
callebtc
646044cd81 Clarify capability authentication scope 2026-08-17 19:14:05 +02:00
callebtc
35ed4417f0
Merge pull request #841 from phuctoan123/codex-fix-geohash-join-channel-routing
Fix geohash join channel routing
2026-08-17 19:09:26 +02:00
callebtc
9167013ac4
Merge pull request #863 from areebahmeddd/fix/preserve-wire-payload
feat: preserve original bytes during re-encoding of packets with foreign encoders
2026-08-17 19:08:01 +02:00
GitHub Action
b028270cc4 Automated update of relay data - Sun Aug 16 06:08:32 UTC 2026 2026-08-16 06:08:32 +00:00
Taksh
dfc2b8dcd1 Narrow the failure marker and fix the self-cancelling restart
Two problems Codex found in the first push.

"SOCKS connection error" is not a circuit failure. arti-build logs that
wrapper for every error out of handle_socks_connection, including local
protocol faults raised before a circuit is attempted — "Invalid SOCKS
handshake", "Unsupported SOCKS version", "Unsupported SOCKS command".
Anything on the device that speaks SOCKS badly to the local port would
have read as a dead Tor. Drop it. "Failed to connect through Tor" is
logged only on client.connect() failure, and "Failed to obtain exit
circuit" is arti's own detail for that error, which is what #610 shows —
so the reported lines are still matched.

The restart path cancels itself. restartArti stops Arti first, and
stopArtiInternal cancels retryJob and inactivityJob. Both existing
recovery paths call restartArti from inside one of those jobs, so the
coroutine is cancelled between the stop and the start and Arti never
comes back. That is already true on main for the start-failure and
bootstrap-inactivity paths; routing a post-bootstrap outage into it would
have turned a wrong indicator into a stopped Tor, which is worse.

Run restarts from a separate restartJob that the stop path leaves alone,
and cancel it explicitly when the user turns Tor off so a pending
recovery cannot resurrect it.
2026-08-16 09:25:11 +05:30
Taksh
e65fce66d0 Cover the circuit-health thresholds
Uses the log lines from the report verbatim. Pins both directions: a
same-instant burst and occasional failures far apart leave the indicator
alone, while four failures still going after twenty seconds downgrade it.
Also covers reset and a backwards clock jump.
2026-08-16 08:01:14 +05:30
Taksh
71dd9dfca3 Stop reporting Tor as connected once its circuits fail
Arti's bootstrap milestones only fire on the way up. "We have found that
guard [scrubbed] is usable." latches the session to RUNNING at 100% and
calls stopInactivityMonitoring(), and from there nothing downgrades the
status except a deliberate stop or a state-file lock conflict.

So when the network goes away after bootstrap, Arti logs a continuous
stream of "Failed to connect through Tor" / "SOCKS connection error"
while the header keeps showing the connected colour, which is gated on
running && bootstrapPercent >= 100. isProxyEnabled() agrees, so requests
keep being routed into a SOCKS port that cannot reach an exit.

Track circuit failures after bootstrap and drop the published status
below 100% once they both accumulate and persist. Individual failures are
a normal part of Tor, so a burst inside one instant — which is what the
report shows, three threads failing in the same millisecond — is ignored;
it takes four failures still going twenty seconds later.

Downgrading to BOOTSTRAPPING rather than ERROR keeps running = true, so
callers fail closed through awaitSelectedRoute instead of leaking to
clearnet, the inactivity watchdog re-arms now that bootstrapPercent is
below 100, and the existing backoff retry gets to re-establish the
session. A successful re-bootstrap clears the tally and restores RUNNING.

The policy is kept free of Android and coroutine dependencies so the
thresholds are directly testable.

Refs #610
2026-08-16 08:01:14 +05:30
wollow
22f87a493a Add announce capability bit assignments 2026-08-13 15:11:54 +03:00
callebtc
5156f7de89 Restore PRIVACY_POLICY.md 2026-08-12 01:55:05 +02:00
callebtc
93e9594bad
Merge pull request #873 from permissionlesstech/codex/bump-version-2.0.1
Prepare Android 2.0.1 release
v2.0.1
2026-08-11 21:09:03 +02:00
callebtc
16a22316b2 Disable nondeterministic Compose group mapping 2026-08-11 20:42:26 +02:00
callebtc
c549bdb03f Bump Android release to 2.0.1 2026-08-11 20:08:57 +02:00
callebtc
c9938a36ea
Merge pull request #872 from permissionlesstech/codex/fix-reproducible-aab-mapping
Fix reproducible R8 mapping output
2026-08-11 19:57:31 +02:00
callebtc
6c5d7d1ef0 Fix reproducible R8 mapping output 2026-08-11 19:33:44 +02:00
callebtc
1a0d8713e4
Merge pull request #871 from permissionlesstech/watch-release-0.1.0
Prepare Wear 0.1.0 reproducible release
v2.0.0
2026-08-11 18:14:29 +02:00
callebtc
c9a4e68157 Serialize reproducible release modules 2026-08-11 15:38:15 +02:00
callebtc
7e8ea63230 Prepare reproducible Wear 0.1.0 release 2026-08-11 15:19:39 +02:00
callebtc
47e725a4d8
Merge pull request #870 from permissionlesstech/bump-version-2.0.0
Bump phone app to 2.0.0
2026-08-11 15:12:58 +02:00
callebtc
920eed52d7 Bump phone app to 2.0.0 2026-08-11 12:13:16 +02:00
callebtc
fcb4562bd5
Merge pull request #812 from moehamade/fix/apk-download-and-rate-limit
fix: make APK sharing local-first and rate-limit safe
2026-08-11 09:51:39 +02:00
Kane Waldo
4007bae1e2 Fix syntax error in CommandProcessorTest 2026-08-11 09:20:39 +07:00
Moe Hamade
8f21ad5be3 fix(apk): keep the local APK shareable across a restart mid-download
Codex is right about this one. The downloader observer builds Downloading
out of whatever status it replaces, reading shareableFallback from an
existing Downloading or a current Ready. A ViewModel restored onto work
that is already active starts from Loading, so neither cast matches and
the fallback is null. WorkManager keeps a download running across process
death, so this is the ordinary case: background the app during a 42 MB
transfer over Tor, come back, and the row drops to "Prepare App for
Sharing" while Share via Hotspot and Share via Quick Share disappear
entirely. The installed APK never moved - it was on disk and shareable a
moment earlier - and it stays hidden until the download ends.

checkStatus() could not repair it because its guard conflated two things:
not letting a resolved status overwrite active work, which is right, and
not looking at local state at all during a download, which is not. Both
orderings lost. If the observer arrived first the guard returned early. If
checkStatus() arrived first it suspended on disk IO, the observer flipped
the state underneath it, and the re-check discarded the status it had just
resolved.

Resolves the local artifact either way and decides inside the same state
update, where the active download is visible: the download keeps the
status it owns, and adopts the artifact only when it is carrying none.
Metadata is still skipped while work is active, so this costs no extra API
budget.

Verified on a Pixel 9a by starting a download, force-stopping mid-transfer
and reopening: the row holds "App Ready for Offline Sharing" with both
sharing rows present, where it previously showed neither.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 15:49:22 +03:00
Moe Hamade
52f14cc5b5 fix(apk): stop a reset header alone from marking a 403 rate limited
GitHub sends X-RateLimit-Reset on every REST response, an ordinary 403
included, and it always points at the current window. Feeding it through
retryAtMillis() therefore produced a non-null deadline for any 403, and
the classifier accepted that as proof of a limit. A permissions failure
with the quota untouched came back as RateLimited, so the caller persisted
a cooldown on that route and served stale metadata until a reset window
the failure had nothing to do with.

Classification now looks only at signals that actually mean this request
was the one refused: a spent quota, or an explicit Retry-After. Nothing
real is lost, because GitHub marks a primary limit with
X-RateLimit-Remaining: 0 and a secondary limit with Retry-After. The reset
header keeps its job of supplying the deadline once a limit is
established some other way.

ApkDownloadSourceTest already claimed this contract - its name is "403 is
only treated as a limit when response headers say so" - but its
permissions case passed no reset header at all, which is the one input
that hides the bug. Adds the case it was missing, which fails without this
change, and pins the secondary-limit path so tightening the reset header
cannot blind the client to a Retry-After.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 15:16:51 +03:00
Moe Hamade
7b86bafbac fix(apk): give the persisted store sole ownership of rate-limit cooldowns
The cooldown was tracked in two places. ApkRateLimitStore persisted it per
scope and per route, and the ViewModel kept a second copy in
downloadRetryAtMillis plus a retryAtMillis on Resumable and Error, frozen
into WorkManager output data on the way through. The copy was the weaker
of the two: it lived in memory, so a cold start lost it, and the deadline
it froze belonged to whichever route earned it, which is exactly the drift
the per-route store exists to prevent.

It also could not expire on its own. downloadRetryBlocked was computed
with System.currentTimeMillis() during composition, so nothing recomposed
when the deadline passed; scheduleRetryUnlock papered over that with a
viewModelScope delay that died with the process. Meanwhile the disabled
row and icon gave the user no countdown to read, so a tap simply did
nothing.

Drops the copy. The store is consulted where the request is actually made
and the UI stays enabled, which costs a worker that fails in well under a
tenth of a second without touching the network.

RateLimitedWithWait goes with it. Its "try again in %2$s min" was computed
at failure time and baked into static text that never ticked down, so it
was wrong within a minute; RateLimited says "try again later" and stays
true. Removing it leaves nothing pre-formatted, so Resumable and Error now
carry an ApkFailureMessage of string id plus arguments and the row
resolves it during composition. Failure text follows the device locale
rather than the locale the worker happened to run under.

Anchors the GitHub cooldown at the moment it is judged. now was sampled
before awaitRoute(), which can hold a request for the full 60-second route
timeout, so a relative Retry-After interpreted against it could land in
the past and let the very next check reach GitHub - the loop this branch
set out to close. Reads the clock again once the route is ready and once
the response arrives, and uses each where it applies.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 14:57:32 +03:00
Moe Hamade
000a8acdb9 fix: build each shared HTTP client once instead of racing to replace it
routedHttpClient() and webSocketClient() both did a plain check-then-set
on their AtomicReference: read, and if empty build a client and store it.
Two threads arriving together each saw an empty reference, each built a
full OkHttpClient, and the loser's client was dropped on the floor with
its connection pool and dispatcher threads already allocated. Nothing
closed it, so the leak lasted until the process died.

Moves construction inside a lock and re-checks the reference there, so
the second thread returns the first thread's client rather than building
its own. reset() takes the same lock, which is what makes the pairing
airtight: a build can no longer interleave with a reset and store a
client for the route that was just discarded. The fast path stays outside
the lock, so a warm client still costs a single volatile read.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 14:53:42 +03:00
GitHub Action
55fd6ad9bd Automated update of relay data - Sun Aug 9 06:17:04 UTC 2026 2026-08-09 06:17:04 +00:00
Toan Wizard
ca992d169c
Merge branch 'main' into codex-fix-geohash-join-channel-routing 2026-08-04 09:30:27 +07:00