/get advertised 0.9 on the evening 0.11 shipped

The install page told people "Version 0.9 brings editing, search, forwarding
and pinning" -- three releases behind, on the page somebody reads while
deciding whether to install, and stale in public for weeks.

Nothing connected the two. The publish gate checks that /releases mentions
the build being published and stops there, so the changelog was right and
the page selling the download was wrong. The test now compares the version
/get advertises against the newest Android release in the same file the gate
already treats as the truth, and it is checked by putting 0.9 back:

  /get advertises 0.9 but the newest Android release is 0.11.
  Somebody deciding whether to install is reading a stale number.

The copy names what 0.11 actually fixes, in the words somebody would use:
messages that failed to send to a contact who had reinstalled, blamed on the
server when it was this phone declining to send.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Paul Hitt
2026-09-08 07:55:39 -04:00
co-authored by Claude Opus 5
parent be0740745e
commit 1e5d2dc5ff
2 changed files with 48 additions and 5 deletions
+7 -5
View File
@@ -62,11 +62,13 @@
something and chosen a password is a worse way to learn it.
</p>
<p class="fineprint">
<strong>Installed an earlier build? Replace it.</strong> Version 0.9
brings editing, search, forwarding and pinning, and fixes an
&ldquo;unsend&rdquo; that did not unsend &mdash; it cleared the message
from your phone and left it on theirs. Installing over the top keeps your
account and your conversations. <a href="/releases">What changed</a>.
<strong>Installed an earlier build? Replace it.</strong> Version 0.11
fixes messages that could fail to send to someone who had reinstalled
&mdash; with an error that blamed the server, when it was your own phone
declining to send to keys it could no longer check. It also stops a photo
sent as a file from carrying where it was taken. Installing over the top
keeps your account and your conversations.
<a href="/releases">What changed</a>.
</p>
<p class="fineprint">
<!-- Said before somebody waits for something they cannot install. The
@@ -264,6 +264,47 @@ final class PublicPagesTests: XCTestCase {
"\(name).leaf has \(groups) groups. The point is that the TOP level "
+ "stays small; put the feature inside an existing group.")
}
/// ⚠️ **The install page names a version, and it went stale in public.**
/// `/get` was still telling people "Version 0.9 brings editing, search,
/// forwarding and pinning" on the evening 0.11 was published — three
/// releases behind, on the page somebody reads *while deciding to install*.
///
/// Nothing connected the two: the publish gate checks that `/releases`
/// mentions the build, and stops there. This closes the loop by comparing
/// the version `/get` advertises against the newest Android release in the
/// changelog, which is the file the gate already treats as the truth.
func testTheInstallPageNamesTheCurrentBuild() throws {
let page = try String(contentsOf: views.appendingPathComponent("get.leaf"),
encoding: .utf8)
// Parsed here rather than through the module: this file is
// deliberately free of the server, and the changelog is the same file
// the Android publish gate already treats as the truth.
let data = try Data(contentsOf: root.appendingPathComponent("Resources/releases.json"))
let releases = try JSONSerialization.jsonObject(with: data) as? [[String: Any]] ?? []
let newest = releases.lazy.compactMap { release -> String? in
let platforms = release["platforms"] as? [[String: Any]] ?? []
return platforms.first { ($0["name"] as? String)?.lowercased() == "android" }?
.first(where: { $0.key == "version" })?.value as? String
}.first
guard let newest else {
return XCTFail("no Android release in releases.json to compare against")
}
// Every "Version 0.x" the page states has to be the current one.
var stated: [String] = []
var cursor = page.startIndex
while let hit = page.range(of: "Version ", range: cursor ..< page.endIndex) {
cursor = hit.upperBound
let number = String(page[hit.upperBound...].prefix(while: { $0.isNumber || $0 == "." }))
if !number.isEmpty { stated.append(number) }
}
XCTAssertFalse(stated.isEmpty, "the install page no longer names a version at all")
for version in stated {
XCTAssertEqual(
version, newest,
"/get advertises \(version) but the newest Android release is \(newest). "
+ "Somebody deciding whether to install is reading a stale number.")
}
}