The apps' six 0.32 features travel inside ordinary sealed envelopes, so the relay sees nothing new about anyone. It gains two public routes and one fix.
GET /today.json (SPEC §8.12) serves one signed file, the same bytes for everybody, read from FN_TODAY_FILE or fetched from FN_TODAY_SOURCE every 15 minutes (10 second deadline, 512 KB cap). Nothing is served until the file verifies against a key in FN_TODAY_KEYS, and a file that fails never replaces the last good one; FN_TODAY_CACHE keeps that copy across a restart. 404 {"error":"not_offered"} with no source set, 503 until something verifies; a 200 carries an ETag and honours If-None-Match. The route reads no credentials and no query string and writes no new log lines. With none of these variables set, a relay behaves as it does today and answers 404.
/hi and /es/hi: the static page a hello link (https://flamenetmessenger.com/hi#<address>, §6.34) opens. The address is in the fragment, which browsers never send; Public/hi.js checks it on the device with the same host rule as both apps (ASCII only, no spaces, 400 characters at most) and offers "Open in Flamenet Messenger", copy, and the install links. The script makes no request.
The iPhone badge counts announced envelopes only. Before this, delivery keys, receipts and answers waiting in the same mailbox made one message read as 2. Each envelope now carries one bit, set from the send's silent flag; the badge counts undelivered announced envelopes.
docs/CONFIGURATION.md says a closed relay opens one outbound connection, for the Today file, when FN_TODAY_SOURCE is set. The /metadata row about the silent flag now says it is kept as one bit on the waiting envelope. Both in the owner's approved English wording.
Citations of the Today file use §8.12.
How it was tested
All local; every relay was started on 127.0.0.1.
swift test at the tip: 802 Swift Testing tests in 84 suites and 61 XCTest tests, 0 failures, plus a clean swift build.
flamenet-e2e relay.mjs from a fresh clone at d07ed14, as the conformance job runs it: 265 passed, 0 failed, 2 skipped. No Swift interop driver was built for this run, as on the CI runner.
Earlier in the test pass, against this code: relay.mjs 272 of 272 (the iOS key-log section on the Swift driver) and relay-today.mjs 20 of 20; Public/hi.js against all 45 hello-link fragment cases, with the Kelvin-sign case refused, and red against a copy using toLowerCase.
Scripts/check-doc-pages.py with the engine at d07ed14: all 9 generated pages current.
The iOS end-to-end run used this relay with a development-signed Today file: the app loaded it, kept it when the relay stopped, and the hello link added a contact without sending anything until confirmed.
CI changes in this branch
.e2e-ref moves to flamenet-e2e d07ed14 (docs/spec-0-32), and spec.leaf and engine.leaf are regenerated from it with Scripts/build-doc-pages.sh (pandoc 3.11). The other seven generated pages come out unchanged.
Before this can go green
Push flamenet-e2e docs/spec-0-32 first. conformance and doc-pages check out the pinned commit from gitlab.com.
conformance-head and doc-pages-head (advisory) stay red until the spec branch is merged to e2e main.
Not done, and needs the owner
Not deployed anywhere. A deploy is the owner's call.
Drafts that must not go out unapproved: the /metadata line about the Today file (English and Spanish), shown only on a relay that offers the file, and the Spanish /metadata row about the silent flag, which waits for a native speaker. Each carries an HTML comment marking it as a draft. Approve or remove them before deploying.
The production Today signing key does not exist yet, and no relay has FN_TODAY_* set. Until both happen, /today.json answers 404 and the apps show "Today's page is not offered by this relay."
The regenerated spec and engine pages publish the 0.32 spec once deployed.
For the reviewer
Migration AddEnvelopeAnnounced adds a NOT NULL column with a default false to the envelopes table, in one ADD (a catalogue change on Postgres, accepted by SQLite because of the default). Rows already waiting take false, so they can only be left out of the badge until collected. Read it with the production SQLite relay in mind before deploying.
The relay cannot delete a story's blob on request from the uploader; a story taken down in the apps leaves its blob until the retention purge.
<h2 id="what-this-adds">What this adds</h2> <p>The apps' six 0.32 features travel inside ordinary sealed envelopes, so the relay sees nothing new about anyone. It gains two public routes and one fix.</p> <ul> <li><code>GET /today.json</code> (SPEC §8.12) serves one signed file, the same bytes for everybody, read from <code>FN_TODAY_FILE</code> or fetched from <code>FN_TODAY_SOURCE</code> every 15 minutes (10 second deadline, 512 KB cap). Nothing is served until the file verifies against a key in <code>FN_TODAY_KEYS</code>, and a file that fails never replaces the last good one; <code>FN_TODAY_CACHE</code> keeps that copy across a restart. 404 <code>{"error":"not_offered"}</code> with no source set, 503 until something verifies; a 200 carries an ETag and honours If-None-Match. The route reads no credentials and no query string and writes no new log lines. With none of these variables set, a relay behaves as it does today and answers 404.</li> <li><code>/hi</code> and <code>/es/hi</code>: the static page a hello link (<code>https://flamenetmessenger.com/hi#<address></code>, §6.34) opens. The address is in the fragment, which browsers never send; <code>Public/hi.js</code> checks it on the device with the same host rule as both apps (ASCII only, no spaces, 400 characters at most) and offers "Open in Flamenet Messenger", copy, and the install links. The script makes no request.</li> <li>The iPhone badge counts announced envelopes only. Before this, delivery keys, receipts and answers waiting in the same mailbox made one message read as 2. Each envelope now carries one bit, set from the send's silent flag; the badge counts undelivered announced envelopes.</li> <li>docs/CONFIGURATION.md says a closed relay opens one outbound connection, for the Today file, when <code>FN_TODAY_SOURCE</code> is set. The /metadata row about the silent flag now says it is kept as one bit on the waiting envelope. Both in the owner's approved English wording.</li> <li>Citations of the Today file use §8.12.</li> </ul> <h2 id="how-it-was-tested">How it was tested</h2> <p>All local; every relay was started on 127.0.0.1.</p> <ul> <li><code>swift test</code> at the tip: 802 Swift Testing tests in 84 suites and 61 XCTest tests, 0 failures, plus a clean <code>swift build</code>.</li> <li>flamenet-e2e <code>relay.mjs</code> from a fresh clone at d07ed14, as the conformance job runs it: 265 passed, 0 failed, 2 skipped. No Swift interop driver was built for this run, as on the CI runner.</li> <li>Earlier in the test pass, against this code: <code>relay.mjs</code> 272 of 272 (the iOS key-log section on the Swift driver) and <code>relay-today.mjs</code> 20 of 20; <code>Public/hi.js</code> against all 45 hello-link fragment cases, with the Kelvin-sign case refused, and red against a copy using <code>toLowerCase</code>.</li> <li><code>Scripts/check-doc-pages.py</code> with the engine at d07ed14: all 9 generated pages current.</li> <li>The iOS end-to-end run used this relay with a development-signed Today file: the app loaded it, kept it when the relay stopped, and the hello link added a contact without sending anything until confirmed.</li> </ul> <h2 id="ci-changes-in-this-branch">CI changes in this branch</h2> <p><code>.e2e-ref</code> moves to flamenet-e2e d07ed14 (docs/spec-0-32), and <code>spec.leaf</code> and <code>engine.leaf</code> are regenerated from it with <code>Scripts/build-doc-pages.sh</code> (pandoc 3.11). The other seven generated pages come out unchanged.</p> <h2 id="before-this-can-go-green">Before this can go green</h2> <ul> <li>Push flamenet-e2e docs/spec-0-32 first. <code>conformance</code> and <code>doc-pages</code> check out the pinned commit from gitlab.com.</li> <li><code>conformance-head</code> and <code>doc-pages-head</code> (advisory) stay red until the spec branch is merged to e2e main.</li> </ul> <h2 id="not-done-and-needs-the-owner">Not done, and needs the owner</h2> <ul> <li>Not deployed anywhere. A deploy is the owner's call.</li> <li>Drafts that must not go out unapproved: the /metadata line about the Today file (English and Spanish), shown only on a relay that offers the file, and the Spanish /metadata row about the silent flag, which waits for a native speaker. Each carries an HTML comment marking it as a draft. Approve or remove them before deploying.</li> <li>The production Today signing key does not exist yet, and no relay has <code>FN_TODAY_*</code> set. Until both happen, <code>/today.json</code> answers 404 and the apps show "Today's page is not offered by this relay."</li> <li>The regenerated spec and engine pages publish the 0.32 spec once deployed.</li> </ul> <h2 id="for-the-reviewer">For the reviewer</h2> <ul> <li>Migration <code>AddEnvelopeAnnounced</code> adds a NOT NULL column with a default false to the envelopes table, in one ADD (a catalogue change on Postgres, accepted by SQLite because of the default). Rows already waiting take false, so they can only be left out of the badge until collected. Read it with the production SQLite relay in mind before deploying.</li> <li>The relay cannot delete a story's blob on request from the uploader; a story taken down in the apps leaves its blob until the retention purge.</li> </ul> <p>Generated with <a href="https://claude.com/claude-code">Claude Code</a></p>
Superseded by #256, which is this branch merged into main with its 14 conflict hunks resolved. Wave 2 landed on main while this sat and rewrote the same send path, so this PR could not merge.
The resolution worth knowing about: wave 2 extracted the write, the wake and the push into Delivery.write, and this branch carried the announced column wave 2 knew nothing about. The model, the migration and badgeCount would all have merged cleanly and every badge would have read zero, because nothing on the surviving path set the column. Delivery.Item carries it now.
Superseded by #256, which is this branch merged into main with its 14 conflict hunks resolved. Wave 2 landed on main while this sat and rewrote the same send path, so this PR could not merge.
The resolution worth knowing about: wave 2 extracted the write, the wake and the push into Delivery.write, and this branch carried the `announced` column wave 2 knew nothing about. The model, the migration and badgeCount would all have merged cleanly and every badge would have read zero, because nothing on the surviving path set the column. Delivery.Item carries it now.
Three more branches in this repository were read in the same pass and are now deleted, with what was in them:
12-plain-comparison (2026-08-31, 3 commits). Its Apple claim fix is already in main by another path: comparison.leaf says "Apple's design was examined by academics outside the company" and the "proved correct" wording it corrected is nowhere in main. Its other half edited Resources/Views/spec.leaf, which is GENERATED, and #256 has since regenerated all nine doc pages from the current spec. Its lede counted four messengers; main's counts six.
accuracy/plain-mode-who-each-page-is-about (2026-09-04). Lifting its two files onto main was tried and reverted: both are older than main's, and comparison.leaf in particular would have gone back to "Four messengers" and to claiming that only Flamenet Messenger runs on a server you host, which main no longer says. The one idea worth keeping is that privacy.leaf's "Unencrypted conversations" section reads as if the apps can send a readable message. That is a real accuracy point about a public page and is better written against today's text than merged from a six-week-old copy.
chore/nzbdav-vacuum-timer (2026-09-10). A weekly SQLite compaction timer for nzbdav, which is the media stack and has nothing to do with the relay. Wrong repository.
The eight docs/spec-6-* and spec-page branches are deleted too: every one of them hand-edited the generated spec page, and #256 regenerated it from flamenet-e2e d0274ca0. Sections 6.9 and 6.15 through 6.19 are all present in the regenerated page.
Three more branches in this repository were read in the same pass and are now deleted, with what was in them:
`12-plain-comparison` (2026-08-31, 3 commits). Its Apple claim fix is already in main by another path: comparison.leaf says "Apple's design was examined by academics outside the company" and the "proved correct" wording it corrected is nowhere in main. Its other half edited `Resources/Views/spec.leaf`, which is GENERATED, and #256 has since regenerated all nine doc pages from the current spec. Its lede counted four messengers; main's counts six.
`accuracy/plain-mode-who-each-page-is-about` (2026-09-04). Lifting its two files onto main was tried and reverted: both are older than main's, and comparison.leaf in particular would have gone back to "Four messengers" and to claiming that only Flamenet Messenger runs on a server you host, which main no longer says. The one idea worth keeping is that privacy.leaf's "Unencrypted conversations" section reads as if the apps can send a readable message. That is a real accuracy point about a public page and is better written against today's text than merged from a six-week-old copy.
`chore/nzbdav-vacuum-timer` (2026-09-10). A weekly SQLite compaction timer for nzbdav, which is the media stack and has nothing to do with the relay. Wrong repository.
The eight `docs/spec-6-*` and spec-page branches are deleted too: every one of them hand-edited the generated spec page, and #256 regenerated it from flamenet-e2e d0274ca0. Sections 6.9 and 6.15 through 6.19 are all present in the regenerated page.
Pull request closed
This pull request cannot be reopened because the branch was deleted.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What this adds
The apps' six 0.32 features travel inside ordinary sealed envelopes, so the relay sees nothing new about anyone. It gains two public routes and one fix.
GET /today.json(SPEC §8.12) serves one signed file, the same bytes for everybody, read fromFN_TODAY_FILEor fetched fromFN_TODAY_SOURCEevery 15 minutes (10 second deadline, 512 KB cap). Nothing is served until the file verifies against a key inFN_TODAY_KEYS, and a file that fails never replaces the last good one;FN_TODAY_CACHEkeeps that copy across a restart. 404{"error":"not_offered"}with no source set, 503 until something verifies; a 200 carries an ETag and honours If-None-Match. The route reads no credentials and no query string and writes no new log lines. With none of these variables set, a relay behaves as it does today and answers 404./hiand/es/hi: the static page a hello link (https://flamenetmessenger.com/hi#<address>, §6.34) opens. The address is in the fragment, which browsers never send;Public/hi.jschecks it on the device with the same host rule as both apps (ASCII only, no spaces, 400 characters at most) and offers "Open in Flamenet Messenger", copy, and the install links. The script makes no request.FN_TODAY_SOURCEis set. The /metadata row about the silent flag now says it is kept as one bit on the waiting envelope. Both in the owner's approved English wording.How it was tested
All local; every relay was started on 127.0.0.1.
swift testat the tip: 802 Swift Testing tests in 84 suites and 61 XCTest tests, 0 failures, plus a cleanswift build.relay.mjsfrom a fresh clone at d07ed14, as the conformance job runs it: 265 passed, 0 failed, 2 skipped. No Swift interop driver was built for this run, as on the CI runner.relay.mjs272 of 272 (the iOS key-log section on the Swift driver) andrelay-today.mjs20 of 20;Public/hi.jsagainst all 45 hello-link fragment cases, with the Kelvin-sign case refused, and red against a copy usingtoLowerCase.Scripts/check-doc-pages.pywith the engine at d07ed14: all 9 generated pages current.CI changes in this branch
.e2e-refmoves to flamenet-e2e d07ed14 (docs/spec-0-32), andspec.leafandengine.leafare regenerated from it withScripts/build-doc-pages.sh(pandoc 3.11). The other seven generated pages come out unchanged.Before this can go green
conformanceanddoc-pagescheck out the pinned commit from gitlab.com.conformance-headanddoc-pages-head(advisory) stay red until the spec branch is merged to e2e main.Not done, and needs the owner
FN_TODAY_*set. Until both happen,/today.jsonanswers 404 and the apps show "Today's page is not offered by this relay."For the reviewer
AddEnvelopeAnnouncedadds a NOT NULL column with a default false to the envelopes table, in one ADD (a catalogue change on Postgres, accepted by SQLite because of the default). Rows already waiting take false, so they can only be left out of the badge until collected. Read it with the production SQLite relay in mind before deploying.Generated with Claude Code
assigned to @paulhitt
Superseded by #256, which is this branch merged into main with its 14 conflict hunks resolved. Wave 2 landed on main while this sat and rewrote the same send path, so this PR could not merge.
The resolution worth knowing about: wave 2 extracted the write, the wake and the push into Delivery.write, and this branch carried the
announcedcolumn wave 2 knew nothing about. The model, the migration and badgeCount would all have merged cleanly and every badge would have read zero, because nothing on the surviving path set the column. Delivery.Item carries it now.Three more branches in this repository were read in the same pass and are now deleted, with what was in them:
12-plain-comparison(2026-08-31, 3 commits). Its Apple claim fix is already in main by another path: comparison.leaf says "Apple's design was examined by academics outside the company" and the "proved correct" wording it corrected is nowhere in main. Its other half editedResources/Views/spec.leaf, which is GENERATED, and #256 has since regenerated all nine doc pages from the current spec. Its lede counted four messengers; main's counts six.accuracy/plain-mode-who-each-page-is-about(2026-09-04). Lifting its two files onto main was tried and reverted: both are older than main's, and comparison.leaf in particular would have gone back to "Four messengers" and to claiming that only Flamenet Messenger runs on a server you host, which main no longer says. The one idea worth keeping is that privacy.leaf's "Unencrypted conversations" section reads as if the apps can send a readable message. That is a real accuracy point about a public page and is better written against today's text than merged from a six-week-old copy.chore/nzbdav-vacuum-timer(2026-09-10). A weekly SQLite compaction timer for nzbdav, which is the media stack and has nothing to do with the relay. Wrong repository.The eight
docs/spec-6-*and spec-page branches are deleted too: every one of them hand-edited the generated spec page, and #256 regenerated it from flamenet-e2e d0274ca0. Sections 6.9 and 6.15 through 6.19 are all present in the regenerated page.Pull request closed