Check the backup payload against the published vector
Both apps were taught one backup shape and nothing checked that they agreed. Each side's tests asserted against what the OTHER was believed to write, transcribed by hand from reading its source, which is a test of one person's reading rather than of interoperability. `backup-payload-v1.json` in flamenet-e2e is now the authority, and the bar it sets is exact: decode the canonical payload, encode it again, and the result must match byte for byte once both are put in a canonical order. The same vector is checked on the iPhone, so the two are compared against one file rather than against each other's source. One real fix came out of writing it. `messageFromShared` wrote `author` unconditionally, so a one-to-one message that carried no author came back claiming user zero sent it, and a round trip through this app changed the file. Storage keeps an author on every message and reads a missing one as 0, so it is now written only when the file carried one. The env var is exported in BOTH ci jobs, the pinned one and the one that runs at vectors HEAD, and added to the gate that checks every vector file exists before the suite runs. A path that silently does not exist puts the tests back where they were and the failure reads as a protocol bug rather than a missing file. `.e2e-ref` moves to the commit that adds the vector. Full suite: 1279 tests, no failures. `ci/lint` accepts the pipeline. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ca679c22f4
commit
fb68878752
@@ -143,10 +143,11 @@ object BackupPayload {
|
||||
.put("at", m.optLong("at"))
|
||||
.put("text", m.optString("text"))
|
||||
m.optString("mid").takeIf { it.isNotEmpty() }?.let { out.put("mid", it) }
|
||||
// The author rides along on one-to-one threads too. The iPhone reads it
|
||||
// only for groups and ignores it elsewhere, which costs nothing and
|
||||
// keeps an Android-to-Android restore whole.
|
||||
if (m.has("author")) out.put("author", m.optLong("author"))
|
||||
// The author rides along on group threads, where it says who spoke.
|
||||
// Only when there is one: this app writes 0 on a one-to-one message,
|
||||
// where the author is whoever is not you, and emitting that would put
|
||||
// a claim in the file that the message came from user zero.
|
||||
m.optLong("author", 0L).takeIf { it != 0L }?.let { out.put("author", it) }
|
||||
m.optJSONObject("att")?.let {
|
||||
out.put("att", attachmentToShared(it, m.optString("kind", Attachment.IMAGE)))
|
||||
}
|
||||
@@ -307,7 +308,9 @@ object BackupPayload {
|
||||
.put("mine", m.optBoolean("mine"))
|
||||
.put("at", m.optLong("at"))
|
||||
.put("text", m.optString("text"))
|
||||
.put("author", m.optLong("author"))
|
||||
// Storage keeps an author on every message and reads a missing one as
|
||||
// 0, so this is written only when the file carried one.
|
||||
m.optLong("author", 0L).takeIf { it != 0L }?.let { out.put("author", it) }
|
||||
m.optString("mid").takeIf { it.isNotEmpty() }?.let { out.put("mid", it) }
|
||||
m.optJSONObject("att")?.let { att ->
|
||||
out.put("kind", att.optString("kind", Attachment.IMAGE))
|
||||
|
||||
Reference in New Issue
Block a user