docs: drop dated self-corrections

Remove dates and "this used to say X" framing from prose and comments.
What the tree does now is the only thing that matters; the history is in
git.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Paul Hitt
2026-09-09 09:30:32 -04:00
co-authored by Claude Opus 5
parent 1e0bf0ba1f
commit 41cdef5e07
11 changed files with 31 additions and 36 deletions
+1 -1
View File
@@ -93,7 +93,7 @@ unit-tests:
import glob, re, sys
# Floors, not exact counts. Set around 90% of the suite as it stands
# (539 / 403 / 75 / 145 on 2026-09-06) so a module that loses most of its
# (539 / 403 / 75 / 145) so a module that loses most of its
# tests to a bad filter is caught, without a gate that has to be edited
# every time somebody adds one.
MINIMUMS = {"engine": 480, "client": 360, "obfs4": 68, "app": 130}
+13 -13
View File
@@ -136,10 +136,10 @@ From `E2E/E2EInbox.swift`, which is the real feature list.
| Buddy list, add by username | yes |
| Remove, block, unblock | yes |
| Member lookup | look up before adding; adding is gated on it |
| Buddy commands | — retired; not a feature any more (owner, 2026-08-25) |
| Buddy commands | — retired; not a feature any more (owner) |
| Voice calls (WebRTC, DTLS-SRTP, TURN) | P2P-first; no TURN deployed |
| Notifications list, read state | yes |
| Services (AIM/ICQ via `flamenet-oscar`) | — retired; not a goal for this app (owner, 2026-09-04) |
| Services (AIM/ICQ via `flamenet-oscar`) | — retired; not a goal for this app (owner) |
**History at rest was marked and it has been built the whole time, the
third stale row in this file.** Every read goes to disk: `Session.history` calls
@@ -386,7 +386,7 @@ the messenger rather than staying separate apps.
| Local vault: add, organise, delete | index, folders, both storage modes, bulk delete with its report |
| Files screen: set up, unlock, browse, add, folders, delete, promote | **verified on a device**: set up, encrypt, lock, cold-start reload, link via SAF |
| The security lattice (labels, clearance) | encoding and clearance in Kotlin, pinned to independently-computed vectors. **Not Bell–LaPadula**: the -property is deliberately unenforced on both clients; see android#15 |
| Share a file into a chat or group | both directions; **proven live 2026-09-04**: a Restricted document crossed two vaults through a real relay with its label intact |
| Share a file into a chat or group | both directions; **proven live**: a Restricted document crossed two vaults through a real relay with its label intact |
| Wallet engine: BIP-39, Base58, SLIP-0010 | pinned to the published vectors |
| Wallet engine: address derivation and signing | BIP-44 path, Base58 address, and the engine's own RFC 8032 signs, no API-33 floor |
| Wallet: BIP-39 seed, create and restore | create, import, restore, sealed at rest, with the phrase shown once and explained |
@@ -637,7 +637,7 @@ the live tests already cover and the door is what was missing.
It found two real gaps on its first run: sign-out was reachable only from the
contact list rather than from Account, and several controls sat below the fold.
## Cross-platform, 2026-08-25
## Cross-platform
iOS → Android is proven, through both UIs. The iOS app signed up on
`relay1`, added the Android account as a contact, and sent; the Android
@@ -664,7 +664,7 @@ believing a slow or flaky XCUITest run.
Point `-derivedDataPath` at a directory ending `.noindex`. Spotlight will
otherwise index every build product, which is a large share of the above.
## §19 on Android, 2026-08-25
## §19 on Android
Pinning, verification, identity-change acceptance, key-log enforcement and head
gossip now exist and are tested. What each one is worth:
@@ -692,7 +692,7 @@ explicitly: a shrinking head, two roots at one size, a tampered proof node, a
served key absent from the log, an inclusion proof for somebody else's leaf,
and a rewritten log that cannot be reconciled with a pinned root.
**Exercised against `relay1`**, 2026-08-25, `LiveKeyLogTest`, opt-in via
**Exercised against `relay1`**, `LiveKeyLogTest`, opt-in via
`FN_LIVE_FLEET`. Against the real 231-leaf log: a key the relay published verifies; a substituted key is refused; a second check reconciles the
pinned head with a grown tree using proofs the relay generated; a root we never
saw at our pinned size is a fork; and the send path itself refuses on a bad pin
@@ -733,7 +733,7 @@ A relay that is unreachable pins **nothing** rather than pinning "no
address". Baking that in would be permanent, and the next successful lookup
would then read as the address changing, the alarm, for a network blip.
## Sealed sender, 2026-08-25
## Sealed sender
The relay no longer learns who sent a message. Verified against relay1:
a sealed submission is accepted unauthenticated, the stored row carries
@@ -785,7 +785,7 @@ Two peer processes on one account race for the inbox. The one that polls
first takes the message and the other reports zero, which reads as "nothing was
sent". Run a single `autoreply` at a time.
## Signing, on both sides (2026-08-25)
## Signing, on both sides
**iOS was pinned to the wrong Apple team, and that, not a missing membership,
is what made TestFlight unreachable.** `project.yml` carried
@@ -805,11 +805,11 @@ profile; nothing in this repository can do it, and nothing here should try.
**Android needs none of that.** The release `signingConfig` reads
`~/.flamenet-android-signing.properties`, present on the build Mac since
2026-08-23, so `:app:assembleRelease` produces a signed APK that can go
so `:app:assembleRelease` produces a signed APK that can go
straight to a tester. That asymmetry is why Android reaches testers first, and
it has nothing to do with which app is more finished.
## Two reproducible symptoms in the iOS pair (2026-08-25)
## Two reproducible symptoms in the iOS pair
Found running `TwoSimulatorUITests` against `relay1`. **Both reproduce with the
machine idle**, so neither is the load artifact they were first taken for.
@@ -836,7 +836,7 @@ Both concern sending **to** the second account. Suggestive, not a diagnosis.
The next run needs the thread dump (added) plus the relay's own view of what is
queued for that device.
### Narrowed 2026-08-25: it is the RECEIVE side, and only when both sides opened first
### Narrowed: it is the RECEIVE side, and only when both sides opened first
The headless peer tool settles the direction. `qz89925` (user 402), a real
account driven from a shell, was sent to by the iOS app:
@@ -915,7 +915,7 @@ screen to work against before running it.
### Reproduced cheaply, and now fixed, verified against relay1
2026-08-25, two `:interop:peer` accounts, no simulators, no UI. Neither polls
two `:interop:peer` accounts, no simulators, no UI. Neither polls
before sending, which is the simultaneous-initiation case.
**Before** (retired-session retention alone):
@@ -959,7 +959,7 @@ peer q1.json send <h2> c; peer q2.json send <h1> d # the exchange t
peer q1.json poll; peer q2.json poll
```
## iOS TestFlight readiness, checked 2026-08-25
## iOS TestFlight readiness, checked
Verified against the BUILT PRODUCT, not the source tree, the difference matters,
and caught one thing that would have bounced the upload.
+6 -9
View File
@@ -30,16 +30,13 @@ The app's own unit tests need the Android SDK but still no emulator
**[PARITY.md](PARITY.md) is the definition of done for this app, read that,
not this.** Every row there names the iOS file it came from so it can be
re-checked rather than trusted. Headlines as of 2026-08-28: messaging, groups,
attachments, voice notes, stories, calls, sealed sender, key transparency and
the encrypted vault are built and tested; a cross-platform round trip against
iOS was verified on 2026-08-26.
re-checked rather than trusted. Headlines: messaging, groups, attachments,
voice notes, stories, calls, sealed sender, key transparency and the encrypted
vault are built and tested, and a cross-platform round trip against iOS is
verified.
This file said "Nothing here is an app yet" until 2026-08-28, above a
tree containing the finished app, the README described the repository as it
was when the engine landed and nothing updated it as the app grew around it. If
a claim here ever disagrees with PARITY.md or with the tree, believe those, and
fix this.
If a claim here ever disagrees with PARITY.md or with the tree, believe those,
and fix this.
## Why the engine came first, and is held to the vectors
+1 -1
View File
@@ -12,7 +12,7 @@ hours.
is covered by the JVM unit suites plus on-device instrumentation, alongside the shared 253-check relay conformance suite and
cross-platform interop tests that run the real engine on both sides.
An internal adversarial audit on 2026-08-29 found and fixed a family of
An internal adversarial audit found and fixed a family of
sender-attribution flaws: the ratchet authenticates a *device*, and the user id
inside a sealed envelope is a claim its author chooses, the two were not bound.
Devices now bind to their user on first proven use, control traffic (delivery
+2 -2
View File
@@ -34,7 +34,7 @@ android {
// lower than the installed one, so a code that goes backwards makes a
// release uninstallable for everybody already on the higher number.
// The code is one ahead of the name, deliberately. 0.11 was built
// on 2026-09-07 and never published; the build that followed it went out
// and never published; the build that followed it went out
// as versionCode 12 before the name was settled on. Going back to code
// 11 would make the release uninstallable for anyone already on 12, see
// the paragraph above, so the code keeps climbing and the NAME is what
@@ -64,7 +64,7 @@ android {
// This app's OWN key, not the one every Flamenet Android app shares.
// `.flamenet-android-signing.properties` was made for Flamenet Files, and
// because the path is app-agnostic this app silently inherited it, every
// release before 2026-08-25 went out as `CN=Flamenet Files`. Nobody chose
// release before that went out as `CN=Flamenet Files`. Nobody chose
// that for a messenger; it fell out of the layout.
//
// It matters because an Android signing key is permanent: once a device
@@ -56,9 +56,8 @@ fun CallScreenBody(
modifier =
Modifier
.fillMaxSize()
// Back to the theme's own background: the gradient this used to
// avoid painting over went with the purple theme (reverted
// 2026-09-08), so there is nothing left to clash with.
// The theme's own background: there is no gradient here to
// clash with.
.background(MaterialTheme.colorScheme.background)
.padding(horizontal = Kit.margin)
.testTag("call-screen"),
@@ -705,8 +705,7 @@ fun ColumnScope.AccountScreen(
SectionBand()
SettingsSection { StoryAudienceSection(model, phase) }
// Wallet and Files are NOT here any more, they are bar destinations as of
// 2026-09-07, in the same place iOS puts them.
// Wallet and Files are bar destinations, in the same place iOS puts them.
SectionBand()
SettingsSection { AppLockSection() }
@@ -64,7 +64,7 @@ object KitIcon {
val Alerts: ImageVector = Icons.Outlined.NotificationsNone
val Account: ImageVector = Icons.Outlined.PersonOutline
// The two that joined the bar on 2026-09-07. iOS draws `folder.fill` and
// Files and Wallet. iOS draws `folder.fill` and
// `wallet.bifold.fill`; these are the Material shapes closest to them, so
// the same destination reads the same on both phones.
val Files: ImageVector = Icons.Outlined.FolderOpen
@@ -570,8 +570,8 @@ private fun BottomNav(
// clear.
Screen.CALLS -> model.missedCallsUnseen(phase)
// Alerts left the bar 2026-08-28 and iOS never had one; its
// unread count badges Account on both phones now.
// There is no Alerts tab, and iOS never had one; its
// unread count badges Account on both phones.
Screen.ACCOUNT -> unreadNotes
else -> 0
@@ -6,7 +6,7 @@ import kotlin.test.assertEquals
import kotlin.test.assertTrue
/**
* The multi-device fan-out rule (found 2026-08-29 in live two-device testing).
* The multi-device fan-out rule (found in live two-device testing).
*/
class BundleMergeTest {
private fun stub(id: String) =
@@ -119,7 +119,7 @@ class MailboxStateTest {
}
/**
* The pin falls back to the pre-2026-08-30 global entry, so a phone already
* The pin falls back to the older global entry, so a phone already
* holding one keeps it rather than starting trust-on-first-use again, and a
* per-relay entry, once written, wins.
*/