)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"4a2e462b67719d373a72069f442922ca89a435f1","unresolved":true,"context_lines":[{"line_number":5,"context_line":"CommitDate: 2026-03-02 21:31:21 -0800"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"obj-reconstructor: use Timestamp.internal when sending out fragment requests."},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Change-Id: I946636249c61897b82e18451bf7a116261d190ab"},{"line_number":10,"context_line":"Signed-off-by: Jianjian Huo \u003cjhuo@nvidia.com\u003e"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"24faf4f8_6b073b9c","line":8,"updated":"2026-03-04 10:19:25.000000000","message":"please add\n\n``Closes-Bug: #2143206 ``","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"b0813c687a1928753f799c6ad519eb71e395cdac","unresolved":false,"context_lines":[{"line_number":5,"context_line":"CommitDate: 2026-03-02 21:31:21 -0800"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"obj-reconstructor: use Timestamp.internal when sending out fragment requests."},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Change-Id: I946636249c61897b82e18451bf7a116261d190ab"},{"line_number":10,"context_line":"Signed-off-by: Jianjian Huo \u003cjhuo@nvidia.com\u003e"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"7f420c34_1943dc9e","line":8,"in_reply_to":"24faf4f8_6b073b9c","updated":"2026-03-05 20:18:18.000000000","message":"Done","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"04b93f94e3bde4db6cc7db9cdf282bba032c756e","unresolved":true,"context_lines":[{"line_number":10,"context_line":"timestamp in the fragment preferences it sent to remote nodes. If the"},{"line_number":11,"context_line":"data timestamp has an offset then the abbreviated normal format would"},{"line_number":12,"context_line":"not match when looking for fragments on the remote nodes. As a result,"},{"line_number":13,"context_line":"remote nodes could send a different (newer) set of fragments."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"If this happened, the Related-Bug could result in the reconstructor"},{"line_number":16,"context_line":"rebuilding a corrupt fragment at the requested data timestamp using"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":5,"id":"9c6e67a5_8fc0840c","line":13,"updated":"2026-03-05 19:12:33.000000000","message":"Or, would fail to respond with the non-durable that *would have* matched -- potentially meaning we\u0027d fail to reconstruct even though we know the data *should* be durable.","commit_id":"1f488b2842eb27c9b1caad44caffb18f8f95a228"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"391defa9a44e8cdc000689c477ed8a3a6e3e6d9e","unresolved":true,"context_lines":[{"line_number":10,"context_line":"timestamp in the fragment preferences it sent to remote nodes. If the"},{"line_number":11,"context_line":"data timestamp has an offset then the abbreviated normal format would"},{"line_number":12,"context_line":"not match when looking for fragments on the remote nodes. As a result,"},{"line_number":13,"context_line":"remote nodes could send a different (newer) set of fragments."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"If this happened, the Related-Bug could result in the reconstructor"},{"line_number":16,"context_line":"rebuilding a corrupt fragment at the requested data timestamp using"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":5,"id":"4fb3cc98_96f36d1a","line":13,"in_reply_to":"402fa02f_c5025cf9","updated":"2026-03-06 11:25:17.000000000","message":"If I\u0027m understanding the concern correctly, remote nodes *will* return non-durables that do not match the frag prefs timestamp.\n\n\u003e When a frag_prefs arg is provided, including an empty list, there is no\n        requirement for there to be a durable file at the same timestamp as a\n        data file that is chosen to construct the disk file\n        \nhttps://github.com/openstack/swift/blob/3fea9f474b5e6a4b703190409f0bea15db8cdf21/swift/obj/diskfile.py#L3708-L3710\n\nThe issue with a frag pref mismatch is that the remote node will return whatever it has that is *newest*, which may not be what the reconstructor is expecting.","commit_id":"1f488b2842eb27c9b1caad44caffb18f8f95a228"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"95ed57fb2b04000fc36bd3b9b178e56c2312b93f","unresolved":true,"context_lines":[{"line_number":10,"context_line":"timestamp in the fragment preferences it sent to remote nodes. If the"},{"line_number":11,"context_line":"data timestamp has an offset then the abbreviated normal format would"},{"line_number":12,"context_line":"not match when looking for fragments on the remote nodes. As a result,"},{"line_number":13,"context_line":"remote nodes could send a different (newer) set of fragments."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"If this happened, the Related-Bug could result in the reconstructor"},{"line_number":16,"context_line":"rebuilding a corrupt fragment at the requested data timestamp using"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":5,"id":"402fa02f_c5025cf9","line":13,"in_reply_to":"9c6e67a5_8fc0840c","updated":"2026-03-05 20:26:22.000000000","message":"good point! this is another case this patch fixed. and I think that would include durable frags responses as well.","commit_id":"1f488b2842eb27c9b1caad44caffb18f8f95a228"}],"/PATCHSET_LEVEL":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"14c726a798a3a42485074c105a3c401441052eb4","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"ad36e005_0004b2f2","updated":"2026-03-03 15:42:39.000000000","message":"This should probably merge straight to master, IIUC it is a pre-existing bug that has just been highlighted by the addition of jitter to timestamps.\n\nI think we are also going to want something like, as a follow-on:\n\n```\ndiff --git a/swift/obj/reconstructor.py b/swift/obj/reconstructor.py\nindex c946a025b..e8eb8d3b8 100644\n--- a/swift/obj/reconstructor.py\n+++ b/swift/obj/reconstructor.py\n@@ -107,6 +107,7 @@ class ResponseBucket(object):\n         self.durable \u003d False\n         # etag of the first response associated with the Bucket\n         self.etag \u003d None\n+        self.timestamp \u003d None\n \n \n class RebuildingECDiskFileStream(object):\n@@ -460,6 +461,7 @@ class ObjectReconstructor(Daemon):\n             return None\n \n         bucket \u003d buckets[timestamp]\n+        bucket.timestamp \u003d timestamp\n         bucket.num_responses +\u003d 1\n         if bucket.etag is None:\n             bucket.etag \u003d etag\n@@ -582,7 +584,9 @@ class ObjectReconstructor(Daemon):\n             bucket \u003d self._handle_fragment_response(\n                 node, policy, partition, fi_to_rebuild, path, buckets,\n                 error_responses, resp)\n-            if bucket and len(bucket.useful_responses) \u003e\u003d policy.ec_ndata:\n+            if (bucket\n+                    and len(bucket.useful_responses) \u003e\u003d policy.ec_ndata\n+                    and bucket.timestamp \u003d\u003d local_timestamp):\n                 useful_bucket \u003d bucket\n                 break\n \n```","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"cf20ccbde9108ff430dfc6fc93448f98875a7754","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"2a006f68_603fa737","updated":"2026-03-05 16:59:05.000000000","message":"great catch @Jianjian 👍","commit_id":"1f488b2842eb27c9b1caad44caffb18f8f95a228"}],"test/probe/test_reconstructor_rebuild.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"14c726a798a3a42485074c105a3c401441052eb4","unresolved":true,"context_lines":[{"line_number":556,"context_line":"        #"},{"line_number":557,"context_line":"        # This exercises the X-Backend-Fragment-Preferences mechanism:"},{"line_number":558,"context_line":"        # the reconstructor sends frag_prefs asking remote nodes for"},{"line_number":559,"context_line":"        # fragments at the durable timestamp. If frag_prefs lookup fails"},{"line_number":560,"context_line":"        # (e.g. due to Timestamp mismatch when jitter is present), remote"},{"line_number":561,"context_line":"        # nodes may serve the newer non-durable fragment instead, causing"},{"line_number":562,"context_line":"        # reconstruction to use wrong-version data."},{"line_number":563,"context_line":""},{"line_number":564,"context_line":"        # setUp already did 1st PUT object (let\u0027s call it object v1) and"},{"line_number":565,"context_line":"        # it\u0027s durable on all nodes"}],"source_content_type":"text/x-python","patch_set":2,"id":"fbeff067_2812712e","line":562,"range":{"start_line":559,"start_character":46,"end_line":562,"end_character":51},"updated":"2026-03-03 15:42:39.000000000","message":"this comment is describing a bug; that should be made more obvious i.e. this test is verifying that the bad thing does *not* happen, rather than suggesting that it might happen.","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e1559d9e897ec14c631f6bb754cc5dc519df443f","unresolved":false,"context_lines":[{"line_number":556,"context_line":"        #"},{"line_number":557,"context_line":"        # This exercises the X-Backend-Fragment-Preferences mechanism:"},{"line_number":558,"context_line":"        # the reconstructor sends frag_prefs asking remote nodes for"},{"line_number":559,"context_line":"        # fragments at the durable timestamp. If frag_prefs lookup fails"},{"line_number":560,"context_line":"        # (e.g. due to Timestamp mismatch when jitter is present), remote"},{"line_number":561,"context_line":"        # nodes may serve the newer non-durable fragment instead, causing"},{"line_number":562,"context_line":"        # reconstruction to use wrong-version data."},{"line_number":563,"context_line":""},{"line_number":564,"context_line":"        # setUp already did 1st PUT object (let\u0027s call it object v1) and"},{"line_number":565,"context_line":"        # it\u0027s durable on all nodes"}],"source_content_type":"text/x-python","patch_set":2,"id":"e7202c36_d2bc9510","line":562,"range":{"start_line":559,"start_character":46,"end_line":562,"end_character":51},"in_reply_to":"fbeff067_2812712e","updated":"2026-03-05 16:55:38.000000000","message":"Done","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"14c726a798a3a42485074c105a3c401441052eb4","unresolved":true,"context_lines":[{"line_number":571,"context_line":"        # durable v1 fragments on every primary."},{"line_number":572,"context_line":"        v1_chunk_size \u003d len(b\u0027test\u0027 * 16 * 2 ** 10)"},{"line_number":573,"context_line":"        v1_total_bytes \u003d int(3.5 * 2 ** 20)"},{"line_number":574,"context_line":"        v2_total_bytes \u003d (v1_total_bytes // v1_chunk_size + 1) * v1_chunk_size"},{"line_number":575,"context_line":"        internal_client \u003d self.make_internal_client()"},{"line_number":576,"context_line":"        v2_body \u003d ProbeBody(total\u003dv2_total_bytes)"},{"line_number":577,"context_line":"        internal_client.upload_object("}],"source_content_type":"text/x-python","patch_set":2,"id":"69d2fde8_4fcf4d63","line":574,"updated":"2026-03-03 15:42:39.000000000","message":"the outcome is very different is v2_total_bytes \u003c v1_total_bytes\n\nAs written, the reconstructed frag is larger than the expected, so the receiving object server WILL put and commit a durable data file, then ssync sender will raise an exception when it reads more than expected from the RebuildingECDiskFileStream.\n\nIf v2_total_bytes \u003c v1_total_bytes then the receiving object server never commits the frag.","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e1559d9e897ec14c631f6bb754cc5dc519df443f","unresolved":false,"context_lines":[{"line_number":571,"context_line":"        # durable v1 fragments on every primary."},{"line_number":572,"context_line":"        v1_chunk_size \u003d len(b\u0027test\u0027 * 16 * 2 ** 10)"},{"line_number":573,"context_line":"        v1_total_bytes \u003d int(3.5 * 2 ** 20)"},{"line_number":574,"context_line":"        v2_total_bytes \u003d (v1_total_bytes // v1_chunk_size + 1) * v1_chunk_size"},{"line_number":575,"context_line":"        internal_client \u003d self.make_internal_client()"},{"line_number":576,"context_line":"        v2_body \u003d ProbeBody(total\u003dv2_total_bytes)"},{"line_number":577,"context_line":"        internal_client.upload_object("}],"source_content_type":"text/x-python","patch_set":2,"id":"b224bc69_5010d75a","line":574,"in_reply_to":"69d2fde8_4fcf4d63","updated":"2026-03-05 16:55:38.000000000","message":"Done","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"14c726a798a3a42485074c105a3c401441052eb4","unresolved":true,"context_lines":[{"line_number":578,"context_line":"            v2_body, self.account,"},{"line_number":579,"context_line":"            self.container_name.decode(\u0027utf8\u0027),"},{"line_number":580,"context_line":"            self.object_name.decode(\u0027utf8\u0027),"},{"line_number":581,"context_line":"            {\u0027x-backend-no-commit\u0027: \u0027True\u0027})"},{"line_number":582,"context_line":""},{"line_number":583,"context_line":"        # proxy GET should still return v1 (the durable version)"},{"line_number":584,"context_line":"        headers, etag \u003d self.proxy_get()"}],"source_content_type":"text/x-python","patch_set":2,"id":"bf14a93a_30f2e02f","line":581,"range":{"start_line":581,"start_character":14,"end_line":581,"end_character":33},"updated":"2026-03-03 15:42:39.000000000","message":"might be worth a comment to draw attention to this header resulting in a non-durable - it wasn\u0027t obvious to me at first because I was looking for node failures to be the cause.","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e1559d9e897ec14c631f6bb754cc5dc519df443f","unresolved":false,"context_lines":[{"line_number":578,"context_line":"            v2_body, self.account,"},{"line_number":579,"context_line":"            self.container_name.decode(\u0027utf8\u0027),"},{"line_number":580,"context_line":"            self.object_name.decode(\u0027utf8\u0027),"},{"line_number":581,"context_line":"            {\u0027x-backend-no-commit\u0027: \u0027True\u0027})"},{"line_number":582,"context_line":""},{"line_number":583,"context_line":"        # proxy GET should still return v1 (the durable version)"},{"line_number":584,"context_line":"        headers, etag \u003d self.proxy_get()"}],"source_content_type":"text/x-python","patch_set":2,"id":"337c4469_fcd50bca","line":581,"range":{"start_line":581,"start_character":14,"end_line":581,"end_character":33},"in_reply_to":"bf14a93a_30f2e02f","updated":"2026-03-05 16:55:38.000000000","message":"I see it now at line 569","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"14c726a798a3a42485074c105a3c401441052eb4","unresolved":true,"context_lines":[{"line_number":612,"context_line":"        # frag_prefs lookup works, remote nodes return v1 fragments and"},{"line_number":613,"context_line":"        # reconstruction produces v1 data. If the lookup fails, remote"},{"line_number":614,"context_line":"        # nodes fall back to \"newest\" (v2) and reconstruction produces"},{"line_number":615,"context_line":"        # wrong data."},{"line_number":616,"context_line":"        rebuilt_hdrs, rebuilt_etag \u003d self.direct_get("},{"line_number":617,"context_line":"            fail_node, self.opart)"},{"line_number":618,"context_line":"        self.assertEqual(orig_frag_etag, rebuilt_etag,"}],"source_content_type":"text/x-python","patch_set":2,"id":"b672ef37_64869827","line":615,"updated":"2026-03-03 15:42:39.000000000","message":"nit: ``If the lookup fails`` might be better written as ``If the lookup does not find a match`` to avoid any suggestion that there is a bug in lookup.","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"14c726a798a3a42485074c105a3c401441052eb4","unresolved":true,"context_lines":[{"line_number":611,"context_line":"        # asking remote nodes for fragments at v1\u0027s timestamp. If the"},{"line_number":612,"context_line":"        # frag_prefs lookup works, remote nodes return v1 fragments and"},{"line_number":613,"context_line":"        # reconstruction produces v1 data. If the lookup fails, remote"},{"line_number":614,"context_line":"        # nodes fall back to \"newest\" (v2) and reconstruction produces"},{"line_number":615,"context_line":"        # wrong data."},{"line_number":616,"context_line":"        rebuilt_hdrs, rebuilt_etag \u003d self.direct_get("},{"line_number":617,"context_line":"            fail_node, self.opart)"},{"line_number":618,"context_line":"        self.assertEqual(orig_frag_etag, rebuilt_etag,"}],"source_content_type":"text/x-python","patch_set":2,"id":"666ded85_db1af48c","line":615,"range":{"start_line":614,"start_character":47,"end_line":615,"end_character":20},"updated":"2026-03-03 15:42:39.000000000","message":"this is a bug, so we should call it out as such until it is fixed:\n\n```\nXXX If the lookup does not find a match, remote\nnodes fall back to returning their \"newest\" frag (v2). The reconstructor does not check that returned frags match the preferred frag and consequently uses it to reconstruct the wrong data for the frag it is rebuilding.\n```","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e1559d9e897ec14c631f6bb754cc5dc519df443f","unresolved":false,"context_lines":[{"line_number":611,"context_line":"        # asking remote nodes for fragments at v1\u0027s timestamp. If the"},{"line_number":612,"context_line":"        # frag_prefs lookup works, remote nodes return v1 fragments and"},{"line_number":613,"context_line":"        # reconstruction produces v1 data. If the lookup fails, remote"},{"line_number":614,"context_line":"        # nodes fall back to \"newest\" (v2) and reconstruction produces"},{"line_number":615,"context_line":"        # wrong data."},{"line_number":616,"context_line":"        rebuilt_hdrs, rebuilt_etag \u003d self.direct_get("},{"line_number":617,"context_line":"            fail_node, self.opart)"},{"line_number":618,"context_line":"        self.assertEqual(orig_frag_etag, rebuilt_etag,"}],"source_content_type":"text/x-python","patch_set":2,"id":"e3ddbec6_11491660","line":615,"range":{"start_line":614,"start_character":47,"end_line":615,"end_character":20},"in_reply_to":"666ded85_db1af48c","updated":"2026-03-05 16:55:38.000000000","message":"Done","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e1559d9e897ec14c631f6bb754cc5dc519df443f","unresolved":false,"context_lines":[{"line_number":612,"context_line":"        # frag_prefs lookup works, remote nodes return v1 fragments and"},{"line_number":613,"context_line":"        # reconstruction produces v1 data. If the lookup fails, remote"},{"line_number":614,"context_line":"        # nodes fall back to \"newest\" (v2) and reconstruction produces"},{"line_number":615,"context_line":"        # wrong data."},{"line_number":616,"context_line":"        rebuilt_hdrs, rebuilt_etag \u003d self.direct_get("},{"line_number":617,"context_line":"            fail_node, self.opart)"},{"line_number":618,"context_line":"        self.assertEqual(orig_frag_etag, rebuilt_etag,"}],"source_content_type":"text/x-python","patch_set":2,"id":"231eab4c_3df5a473","line":615,"in_reply_to":"b672ef37_64869827","updated":"2026-03-05 16:55:38.000000000","message":"Done","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"14c726a798a3a42485074c105a3c401441052eb4","unresolved":true,"context_lines":[{"line_number":618,"context_line":"        self.assertEqual(orig_frag_etag, rebuilt_etag,"},{"line_number":619,"context_line":"                         \u0027Rebuilt fragment does not match original v1 \u0027"},{"line_number":620,"context_line":"                         \u0027fragment; reconstruction has incorrectly \u0027"},{"line_number":621,"context_line":"                         \u0027used newer non-durable version data\u0027)"},{"line_number":622,"context_line":""},{"line_number":623,"context_line":"        # the rebuilt frag should be durable"},{"line_number":624,"context_line":"        self.assertIn(\u0027X-Backend-Durable-Timestamp\u0027, rebuilt_hdrs)"}],"source_content_type":"text/x-python","patch_set":2,"id":"56083f14_d6f0dc1b","line":621,"updated":"2026-03-03 15:42:39.000000000","message":"it would be good to also verify that the rebuilt frag has the v1 timestamp","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e1559d9e897ec14c631f6bb754cc5dc519df443f","unresolved":false,"context_lines":[{"line_number":618,"context_line":"        self.assertEqual(orig_frag_etag, rebuilt_etag,"},{"line_number":619,"context_line":"                         \u0027Rebuilt fragment does not match original v1 \u0027"},{"line_number":620,"context_line":"                         \u0027fragment; reconstruction has incorrectly \u0027"},{"line_number":621,"context_line":"                         \u0027used newer non-durable version data\u0027)"},{"line_number":622,"context_line":""},{"line_number":623,"context_line":"        # the rebuilt frag should be durable"},{"line_number":624,"context_line":"        self.assertIn(\u0027X-Backend-Durable-Timestamp\u0027, rebuilt_hdrs)"}],"source_content_type":"text/x-python","patch_set":2,"id":"6c0d503e_d3d74a8d","line":621,"in_reply_to":"56083f14_d6f0dc1b","updated":"2026-03-05 16:55:38.000000000","message":"Done","commit_id":"0fe71bd40210db1e25096d5471ad1b30a3ae67c9"}],"test/unit/obj/test_reconstructor.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e1559d9e897ec14c631f6bb754cc5dc519df443f","unresolved":false,"context_lines":[{"line_number":5213,"context_line":"                             self.policy)"},{"line_number":5214,"context_line":"            self.assertIn(\u0027X-Backend-Fragment-Preferences\u0027, called_header)"},{"line_number":5215,"context_line":"            self.assertEqual("},{"line_number":5216,"context_line":"                [{\u0027timestamp\u0027: self.obj_timestamp.internal, \u0027exclude\u0027: []}],"},{"line_number":5217,"context_line":"                json.loads(called_header[\u0027X-Backend-Fragment-Preferences\u0027]))"},{"line_number":5218,"context_line":"            self.assertIn(\u0027X-Backend-Replication\u0027, called_header)"},{"line_number":5219,"context_line":"        # no error and warning"}],"source_content_type":"text/x-python","patch_set":3,"id":"5f9879a4_87493b41","line":5216,"updated":"2026-03-05 16:55:38.000000000","message":"this does not fail if the bug fix is reverted (because we do not yet have jitter in Timestamps until the following patches). We should have a test that sets the Timestamp offset explicitly.","commit_id":"886790163c0663421460f7a7497a367c9a524cb9"}]}
