Commit Graph
13 Commits
Author SHA1 Message Date
Paul HittandClaude Opus 5.5 c38dbe528b Add the Today tab beside Messages
Headlines, Markets ("Prices are delayed. Not advice."), Weather for
the cities picked on the phone, Site of the day with the file's own
note, the blog when there is a post, and the way into the directory.
The tab asks the relay when it opens and when the app comes back to
it; offline it shows the cached copy with "From <date>", and a 404
shows only the directory and "Today's page is not offered by this
relay." Links open in the browser on a tap, with the host shown.

The dev key (kid a9a94e74) is compiled into debug builds only, from
src/debug; release has its own empty copy, and TodayKeys.PRODUCTION is
empty until the release step. Eight tabs fit a 360dp phone with the
labels one size smaller.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 08:57:48 -04:00
Paul HittandClaude Opus 5.5 04ef16c423 Ship the small-web directory and send a site to a chat
directory-v1.json (DESIGN 5) ships as an asset: 2,964 sites in 90
categories, browsed by category and searched on the phone with no
network. A site sent to a chat is an ordinary text through the 1:1
send path, the URL as the words and an lnk built from the entry: the
title, and desc present and empty (DESIGN 18). Nothing is fetched to
make it, and with link previews off the URL goes alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 08:57:47 -04:00
Paul HittandClaude Opus 5.5 cb44ee6604 Read the Today file from the home relay, verified and cached
TodayFile checks a Today envelope (SPEC 8.11) before reading a field
of it: size, version, a pinned kid, the Ed25519 signature over the body
bytes, then a body with a real date and a made time. Lists are cut to
their bounds, strings are cut on character boundaries, and a link that
is not http or https drops its entry.

TodayFeed asks the home relay for /today.json through the default
client, so a bridge carries it: no Authorization, cookie, id or query,
and If-None-Match only when it is the hash of the copy held (DESIGN
19). At most once an hour from the relay's last answer, five minutes
after a failed connection. Redirects are not followed. The last good
envelope is kept on disk and re-verified when read; a 404 clears it,
and an older signed file never replaces a newer one.

The signed sample flamenet.io's builder made is a test fixture, and
LiveTodayTest checks a relay on this machine when FN_LIVE_TODAY_RELAY
names one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 08:57:47 -04:00
Paul HittandClaude Opus 5.5 511607062a Fill Home's add screen with the scanned address, not template text
Scanning a code on Home filled the add field with the literal text
${card.fnid}@${card.relay}: the line in 130edd7 was written with ${'$'}
escapes, so the template was never evaluated. Every scan on Home gave
the same unusable string.

homePrefill() turns a scanned code into the address, bound by the fnid
as the audit asked, and Home uses it. The test pins both the address
and the absence of the escaped template in MainActivity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 08:57:47 -04:00
Paul HittandClaude Opus 5.5 41dbfeb19d Point links at the extant2000 GitLab group
The messenger repositories move from gitlab.com/paulhitt to
gitlab.com/extant2000. Old web and git URLs redirect; the relay's container
image path does not, so docker-compose.yml names the new registry path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 14:38:57 -04:00
Paul HittandClaude Opus 5.5 d53f6a81bb Merge branch 'fix/echo-peer-survives-errors' into 'main'
The echo peer outlives a failed call instead of exiting

See merge request paulhitt/flamenet-messenger-android!157

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 10:14:57 -04:00
Paul HittandClaude Opus 5.5 df56cf2e6e The echo peer outlives a failed call instead of exiting
Peer's autoreply loop had no catch, so one failed poll or send to the relay
ended the process. The on-device reply case then waited out its 90 seconds
for an echo from a peer that was gone, which fits the one missed echo seen
in five full runs on 2026-09-28 (its log was lost, so not proven).

Each poll and each echo is now caught, logged to stderr with a timestamp
("poll failed, still answering: ..."), and the loop carries on. The
closing JSON adds an `errors` count. instrumented.sh already prints the
echo peer's log when a run fails, so a recurrence will say why.

Checked against a relay address that refuses connections: the old peer
exits 1 on the first poll with no result; the new one runs its full 8 s,
logs 4 failed polls and prints {"echoed":0,"errors":4}. Against relay1: 0
errors. Full on-device suite with the new peer: 10 of 10.

Harness only: interop/ is not shipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 10:11:30 -04:00
Paul HittandClaude Opus 5.5 fdee288111 Merge branch 'fix/await-the-email-field' into 'main'
On-device suite green: sign-up tap, fresh peers, group id, and the chat scroll crash

See merge request paulhitt/flamenet-messenger-android!155

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 09:16:48 -04:00
Paul HittandClaude Opus 5.5 d33bb338de Scroll the chat by request, not by forcing a layout
The chat keeps its newest message in view when it opens and while the
keyboard slides, and both did it with `listState.scrollToItem`, which forces
a layout on the spot. This screen is composed inside the Scaffold's measure
pass, so when the effect ran straight away it asked for a layout in the
middle of one:

  IllegalArgumentException: performMeasureAndLayout called during measure layout
    at LayoutNode.forceRemeasure
    at LazyListState.snapToItemIndexInternal
    at ChatScreens.kt:1740 (the keyboard follow)
    ... LaunchedEffectImpl.onRemembered ... SubcomposeLayout ... Scaffold

It failed ChatFlowTest's send in every full on-device run since 2026-09-18.
The frames that ran the effect inline are the Compose test dispatcher's; the
shipped app posts effects to the next frame, so this has not been seen to
crash a real device. Forcing a synchronous layout from an effect is wrong
either way.

Both now use `requestScrollToItem` (foundation 1.7.6), which the next layout
applies, and the keyboard is what brings that layout. Still instant, still
not animated. The animated follow for new messages is unchanged: it waits
for animation frames before it moves.

TheKeyboardDoesNotHideTheMessagesTest read the source for
`listState.scrollToItem(`; it now requires `requestScrollToItem(` and refuses
`scrollToItem(` in the keyboard effect. Put the old line back and it fails.

Result on relay1: the full on-device suite passes, 10 of 10, and the crash
buffer has no performMeasureAndLayout. App unit tests: 358 debug, 323
release, all green.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 08:13:25 -04:00
Paul HittandClaude Opus 5.5 a44624cfad Find the new group by its hex id, not by a number
aGroupIsCreatedAndListed waited for a row matching `group-\d+`. The relay
mints group ids with randomHexToken(), so the tag is `group-` plus 64 hex
characters, and the pattern only matched when the id happened to start
with a digit: ten times in sixteen. The rest of the time the test failed
with "the group never appeared in the list after Create" while the dump
showed the group in the list ("Test Crew, peer96035270, You", tag
group-eea4ceeb...).

Now `group-[0-9a-f]{16,}`, which matches that tag and still not
`group-name` or `group-member-N`. Checked both patterns against the tag
from the failing run: old no match, new match. On device: passes.

The keyboard was ruled out first: with it fully open (top at y=1517) the
member row and Create sat at y=1201-1377, above it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 07:52:51 -04:00
Paul HittandClaude Opus 5.5 cd5d1d8f44 A fresh peer for each on-device run, not peerjvmone
The suites added `peerjvmone`, one standing account on relay1 whose only
device came online when somebody ran the interop peer by hand. Nobody did.
On relay1 it had no one-time prekeys left, classical or PQ, and 114
messages it would never collect, and every run added more strangers to it.
Adding it and delivering to it failed in some runs and not others.

scripts/instrumented.sh now creates two accounts with the interop peer
before the run and passes them as `contactPeer` and `echoPeer`: one for the
add-and-send cases, one running `autoreply` for the reply case alone, since
an autoreply peer answers the first new account that writes to it. The
peer runs from `:interop:installDist` with plain java, not a second Gradle
build, and the exit trap stops it and waits for it.

The suites no longer fall back to peerjvmone; without the arguments they
say to use the script. The reply case now fails when no echo arrives
instead of logging a warning and passing. FeatureUseTest waited for the
confirm button, which is on screen but disabled until the lookup resolves,
so it tapped a disabled button; it now waits for the lookup result like
the other two suites.

On relay1: 8 of 10. The reply round trip passes. Still red: the group case
("the group never appeared in the list after Create", not yet diagnosed)
and ChatFlowTest's send, which crashes in the app with "performMeasureAndLayout
called during measure layout" at ChatScreens.kt:1740, the keyboard-follow
scroll recorded on 2026-09-18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 07:36:15 -04:00
Paul HittandClaude Opus 5.5 332d3803e9 Version 0.31, build 31
One change since 0.30, android!154: the unsealed-send and changed-address
notices. versionCode and versionName move together, as the comment above
them requires.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 07:14:56 -04:00
Paul HittandClaude Opus 5.5 32a258bc1f Tap "Create an account" before the relay is typed, not after
The on-device sign-up helpers typed the relay and then tapped the
toggle-register button. Typing raises the keyboard, which slides in after
performScrollTo has measured the screen, so the tap landed on the keyboard
and the form stayed on sign-in. The failure read as a missing email field,
and was taken for a race with the relay probe.

Logged on the emulator: after the scroll the toggle sat at y=1878 while the
content ended at y=1517, the top of the keyboard. Every failure dump already
said "This server keeps its own accounts.", so the probe had answered.

Now the toggle is tapped first, while nothing is moving, and the email field
is waited for because the probe decides whether this relay asks for one.
Same change in FeatureUse, CrudSurface, ChatFlow, CrossPlatform and
LiveSignUpFleet. On relay1, every sign-up in the suite now gets through;
the remaining red is the shared peerjvmone fixture, not sign-up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 20:03:54 -04:00