Publish desktop generation before its MTP reference

This commit is contained in:
fy59 2026-09-17 19:37:43 +02:00
parent 908c38546c
commit d87d7cd302
2 changed files with 70 additions and 8 deletions

View file

@ -73,6 +73,47 @@ class SyncErrorClassificationTest(unittest.TestCase):
)
self.assertEqual(observed, ["request-v1.json"])
def test_desktop_generation_directory_precedes_reference(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
generation = (
"desktop-objects/generations/"
"gen_11111111-1111-4111-8111-111111111111"
)
(root / generation).mkdir(parents=True)
(root / generation / "manifest.json").write_text("manifest")
for name in (
"request-v1.json",
"desktop-archive-acknowledgements-v1.json",
"desktop-consumption-ack-v1.json",
"desktop-generation-v1.json",
):
(root / name).write_text("{}")
observed = []
def inspect(_adapter, _operation, _peer, outbox, _deadline):
observed.append(
sorted(
str(path.relative_to(outbox))
for path in outbox.rglob("*")
if path.is_file()
)
)
return True
with mock.patch.object(sync_peer_worker, "run_adapter", side_effect=inspect):
sync_peer_worker.push_desktop_generation(
Path("adapter"),
"peer",
root,
generation,
sync_peer_worker.time.monotonic() + 60,
)
self.assertEqual(len(observed), 2)
self.assertEqual(observed[0], [generation + "/manifest.json"])
self.assertNotIn("desktop-generation-v1.json", observed[0])
self.assertIn("desktop-generation-v1.json", observed[1])
if __name__ == "__main__":
unittest.main()

View file

@ -145,6 +145,29 @@ def push_adapter(
run_adapter(adapter, "push", peer, outbox, deadline)
def push_desktop_generation(
adapter: Path,
peer: str,
root: Path,
relative_path: str,
deadline: float,
) -> None:
"""Commit immutable bytes before making their correlated reference visible."""
push_adapter(adapter, peer, root, [relative_path], deadline)
push_adapter(
adapter,
peer,
root,
[
"request-v1.json",
"desktop-archive-acknowledgements-v1.json",
"desktop-consumption-ack-v1.json",
"desktop-generation-v1.json",
],
deadline,
)
def wait_file(path: Path, deadline: float, pump=None) -> None:
while not path.is_file():
if time.monotonic() >= deadline:
@ -331,17 +354,15 @@ def main() -> int:
}
publish_json(args.transport_root / "desktop-generation-v1.json", ref)
if args.mode == "mtp":
push_adapter(
# CONTRACT: the immutable generation must be fully visible before its
# mutable run-correlated reference. Publishing both in one MTP walk
# lets Android observe the reference while artifacts are still being
# transferred, turning a complete generation into a false rejection.
push_desktop_generation(
args.mtp_adapter,
args.expected_peer,
args.transport_root,
[
"request-v1.json",
"desktop-archive-acknowledgements-v1.json",
"desktop-consumption-ack-v1.json",
"desktop-generation-v1.json",
ref["relative_path"],
],
ref["relative_path"],
deadline,
)
emit(