gabriel / musehub public
fix patch task/proposal-models-v2 #10 / 19
AI Agent gabriel · 127 days ago · May 8, 2026 · Diff

fix: add ghost guard to wire_push_presign (Layer 5)

wire_push_presign was checking DB only for 'already_stored', so ghost rows (DB present, storage absent) told the client to skip re-uploading. The client never sent those bytes; Phase-C then rejected the push.

Fix: for each DB-present object, call backend.exists() before placing it in already_stored. Ghost objects are demoted to the upload path (presigned URL or stream_these) so the client re-uploads the actual bytes.

Same ghost guard pattern as wire_push_confirm (Layer 2).

6 new tests: P5.1–P5.6.

sha256:4feba6d72278319d9831dd3d18b610e5976562d1e474b8630d55bdf2de1ba04b sha
+61 ~22 symbols
sha256:492e9ff5013f39703e875496ca3c5eb6abecb84db36032b07832591b5449e869 snapshot
+61
symbols added
~22
symbols modified
0
dead code introduced
Semantic Changes 83 symbols
+ SFRAME_ERROR variable variable SFRAME_ERROR L45–45
+ _body_iter function async_function _body_iter L93–94
+ _collect_frames function async_function _collect_frames L97–104
+ _commit_pack_frame function function _commit_pack_frame L80–83
+ _end_frame function function _end_frame L76–77
+ _fw variable variable _fw L46–46
+ _header_frame function function _header_frame L69–73
+ _insert_ghost_row function async_function _insert_ghost_row L133–142
+ _now function function _now L53–54
+ _o_frame function function _o_frame L86–90
+ _pack function function _pack L61–62
+ _push_stream_raw function function _push_stream_raw L107–130
+ _uid function function _uid L57–58
+ _wrap function function _wrap L65–66
+ AsyncMock import import AsyncMock L26–26
+ AsyncSession import import AsyncSession L32–32
+ MagicMock import import MagicMock L26–26
+ MuseWireFrameWriter import import MuseWireFrameWriter L34–34
+ SFRAME_COMMIT_PACK import import SFRAME_COMMIT_PACK L37–37
+ SFRAME_END import import SFRAME_END L37–37
+ SFRAME_HEADER import import SFRAME_HEADER L37–37
+ SFRAME_OBJECT import import SFRAME_OBJECT L37–37
+ annotations import import annotations L22–22
+ blob_id import import blob_id L35–35
+ create_repo import import create_repo L43–43
+ datetime import import datetime L25–25
+ db import import db L36–36
+ fake_id import import fake_id L35–35
+ func function import func L30–30
+ msgpack import import msgpack L28–28
+ patch import import patch L26–26
+ pg_insert import import pg_insert L31–31
+ pytest import import pytest L29–29
+ select import import select L30–30
+ timezone import import timezone L25–25
+ zlib import import zlib L24–24
+ test_P5_1_presign_ghost_guard_demotes_ghost function async_function test_P5_1_presign_ghost_guard_demotes_ghost L150–178
+ test_P5_2_fixed_presign_demotes_ghost_to_upload function async_function test_P5_2_fixed_presign_demotes_ghost_to_upload L186–210
+ test_P5_3_fixed_presign_keeps_present_object function async_function test_P5_3_fixed_presign_keeps_present_object L218–238
+ test_P5_4_fixed_presign_mixed_batch function async_function test_P5_4_fixed_presign_mixed_batch L246–278
+ test_P5_5_push_with_all_genuine_objects_passes function async_function test_P5_5_push_with_all_genuine_objects_passes L286–308
+ test_P5_6_ghost_still_rejected_by_phase_c function async_function test_P5_6_ghost_still_rejected_by_phase_c L316–342
~ GHOST_OBJECTS_INVESTIGATION.md .md 19 symbols added, 21 symbols modified
+ Current Status (2026-05-08) section Current Status (2026-05-08) L7–26
+ Completed section Completed L9–16
+ Failing Now section Failing Now L16–26
+ code@L17 variable variable code@L17 L17–21
+ Layer 5 — Has/Wants Dance + wire_push_presign DB-only check section Layer 5 — Has/Wants Dance + wire_push_presign DB-only check L340–450
+ First principles section First principles L387–405
+ code@L389 variable variable code@L389 L389–399
+ Fix section Fix L433–450
+ code[python]@L437 variable variable code[python]@L437 L437–447
+ Layer 5 tests section Layer 5 tests L405–433
+ code@L408 variable variable code@L408 L408–412
+ code@L414 variable variable code@L414 L414–418
+ code@L421 variable variable code@L421 L421–425
+ code@L428 variable variable code@L428 L428–432
+ The two questions section The two questions L361–387
+ code[python]@L366 variable variable code[python]@L366 L366–376
+ What we observed section What we observed L342–353
+ code@L344 variable variable code@L344 L344–348
+ Why not in local object store? section Why not in local object store? L353–361

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:4feba6d72278319d9831dd3d18b610e5976562d1e474b8630d55bdf2de1ba04b --body "your comment"