)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"519d7cd169460d41e0594c81d4710308f8fc4f1b","unresolved":true,"context_lines":[{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Extra POST to handoff on mixed primary 404"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Change-Id: I43644f242d1cca416844dbd556d40f4e8cd869f9"},{"line_number":10,"context_line":"Signed-off-by: Clay Gerrard \u003cclay.gerrard@gmail.com\u003e"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"1cadd980_54d75d22","line":9,"updated":"2025-08-06 17:32:54.000000000","message":"commit should reference Bug #2119675 “POST returns 404 on handoff” : https://bugs.launchpad.net/swift/+bug/2119675","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5c808e34d20a7025de1c7bd12efa9547f87f9b69","unresolved":false,"context_lines":[{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Extra POST to handoff on mixed primary 404"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Change-Id: I43644f242d1cca416844dbd556d40f4e8cd869f9"},{"line_number":10,"context_line":"Signed-off-by: Clay Gerrard \u003cclay.gerrard@gmail.com\u003e"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"74297fa3_9775b380","line":9,"in_reply_to":"1cadd980_54d75d22","updated":"2025-10-06 19:32:24.000000000","message":"Done","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"}],"/PATCHSET_LEVEL":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"519d7cd169460d41e0594c81d4710308f8fc4f1b","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"627d602f_c405f949","updated":"2025-08-06 17:32:54.000000000","message":"Having written the bug report I think that other status_map test with the \"only 3 nodes in the whole cluster\" should actually be updated to assert [404, 404, 202] \u003d\u003e 503 \n\n... then there\u0027s some other tests that show:\n\n * [404, 404, 202] \u003d\u003e [404, 404] \u003d\u003e 404\n * [404, 404, 202] \u003d\u003e [202, 202] \u003d\u003e 202\n * [404, 404, 202] \u003d\u003e [202, 404] \u003d\u003e 503 (???)","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c6a3536f40a8aaf829febca47c5e36de67f39c9f","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"c2020b54_8493bd61","updated":"2025-08-04 22:25:27.000000000","message":"my favorite part of this change so far is the debug logging!\n\n```\nAug  4 21:49:04 saio proxy-server: Primary nodes returned mixed results on POST: {404: [\u0027127.0.0.3:6030/sdb3\u0027, \u0027127.0.0.4:6040/sdb4\u0027], 202: [\u0027127.0.0.1:6010/sdb1\u0027]}, trying handoffs: [\u0027127.0.0.2:6020/sdb2\u0027] (txn: tx3ebbb5cfa0034f4788e02-0068912ad0)\n```\n\nI think it kind of works and does what I want... but I found some edge cases that could use tightening up.  Some of the churn in probetests might not be worth \"cleaning up\"","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5c808e34d20a7025de1c7bd12efa9547f87f9b69","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"eccfa6e3_2d9a61ae","updated":"2025-10-06 19:32:24.000000000","message":"Looks I left some notes suggesting we could add negative probe test(s) for POST after DELETE returning 404/503\n\nbut I took care of the two XXX in the impl WRT reusing handoffs and found quorum calculation, fixed the other test.unit.proxy.test_server test to show [202, 404, 404] w/o handoff \u003d\u003e 503 and added the closes-bug to the commit message\n\nThis could probably merge, but maybe could also still be better: I\u0027d appreciate some review.","commit_id":"73ea48d3a048de91598e4de8b175f69244cc8e79"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"a5007c2e6dc997da01e5859b87e8a21c8db65a51","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"9052d9fe_2ce14b7e","updated":"2025-10-31 21:01:10.000000000","message":"With this patch, a few cases when handoff returns 202 are now correctly handled and POSTs are able to return 202 now, that\u0027s awesome! IMHO, in additional, there are two more cases we also need to return them correctly, they are:\n\n   [202 404 404] + [404 404] \u003d 503 (instead of 404)\n   [202 404 404] + [202 404] \u003d 202 (instead of 404)\n   \nI pushed up my test cases and fixes at here: https://review.opendev.org/c/openstack/swift/+/965863/","commit_id":"86f255751f35918b0305a89a2c5baf1f109bd571"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"a03da7d8dcf129275181e150ea2d850727e4114c","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"89c062ed_f1201e97","updated":"2025-11-04 00:12:15.000000000","message":"so the updated test in proxy.controller.test_obj turns a 404 \u003d\u003e 202 (for multi-replica policy by using handoffs under mixed results)\n\nthe new test also shows a 202 case (when there\u0027s more than one primary 404)\n\n... but there\u0027s no new *negative* tests\n\n... and apparently the 404\u003d\u003e503 change in proxy.test_server is misleading (I know it has something to do with fake-rings that don\u0027t have enough nodes/devices to talk to handoffs)","commit_id":"86f255751f35918b0305a89a2c5baf1f109bd571"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5e9930e79389e042ab761d947a75fb3856179639","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"65fdc8e9_2c26b5c9","updated":"2025-11-04 00:25:43.000000000","message":"added some new tests that seem to be working OMM\n\nthe fix for quorum makes things WAY easier to reason about, nice save by Jian\n\nI think the `if final_resp.status \u003d\u003d 404 \u0026 found_count \u003e 0` is about as good as we can do.  It\u0027s at least the best I could today.","commit_id":"06c6fb1e569013f8fb77d9a1942e39bec86c1e54"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"9c0899b6820210a38f106a9ff6795bd8eda42c46","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"a5d684f9_bc94238c","in_reply_to":"65fdc8e9_2c26b5c9","updated":"2025-11-04 15:29:01.000000000","message":"I will add my name into co-author then since you like my test cases and quorum fix, ;-)","commit_id":"06c6fb1e569013f8fb77d9a1942e39bec86c1e54"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"1ebf476fc6895fbd5997fe6abe82719f7d3116d8","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"e518e49e_dac79386","updated":"2025-11-04 16:02:29.000000000","message":"Flake8 seems happy OMM\n\n```\n(vagrant-swift-all-in-one) cgerrard@NVStation:~/Workspace/vagrant-swift-all-in-one/swift$ for f in $(git show --name-only | grep \".py$\"); do echo $f; flake8 $f; done\nswift/proxy/controllers/base.py\nswift/proxy/controllers/obj.py\ntest/probe/brain.py\ntest/probe/common.py\ntest/probe/test_object_handoff.py\ntest/unit/proxy/controllers/test_obj.py\ntest/unit/proxy/test_server.py\n```\n\nThanks @jhuo@nvidia.com","commit_id":"ef8b2a5f32adcc99fcbe9e377da90d081d3f7469"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"9c0899b6820210a38f106a9ff6795bd8eda42c46","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"52aa6f34_d2605c74","updated":"2025-11-04 15:29:01.000000000","message":"Tests all passed on my local vasio.","commit_id":"ef8b2a5f32adcc99fcbe9e377da90d081d3f7469"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"6dd5044b725e59d2f195e931129b7ea7684afce3","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"08621cf1_4176d11a","updated":"2025-12-03 19:23:33.000000000","message":"This patch is working well on prod.","commit_id":"ef8b2a5f32adcc99fcbe9e377da90d081d3f7469"}],"swift/proxy/controllers/base.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c6a3536f40a8aaf829febca47c5e36de67f39c9f","unresolved":true,"context_lines":[{"line_number":2153,"context_line":"            node_count, node_iterator, body)"},{"line_number":2154,"context_line":"        statuses, reasons, resp_headers, bodies \u003d zip(*[("},{"line_number":2155,"context_line":"            resp.status, resp.reason, resp.getheaders(), body)"},{"line_number":2156,"context_line":"            for resp, body, _ in results])"},{"line_number":2157,"context_line":"        return self.best_response(req, statuses, reasons, bodies,"},{"line_number":2158,"context_line":"                                  \u0027%s %s\u0027 % (self.server_type, req.method),"},{"line_number":2159,"context_line":"                                  overrides\u003doverrides, headers\u003dresp_headers)"}],"source_content_type":"text/x-python","patch_set":2,"id":"321e5ff9_42d05189","line":2156,"updated":"2025-08-04 22:25:27.000000000","message":"this is intended to be a functionally equivalent method extraction - if I did it in it\u0027s own change I would consider changing the signature of best_response to accept the new results list and DRY out the (rather dense) parameter regrouping.","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"a5007c2e6dc997da01e5859b87e8a21c8db65a51","unresolved":true,"context_lines":[{"line_number":2105,"context_line":"                    {\u0027method\u0027: method, \u0027path\u0027: path})"},{"line_number":2106,"context_line":"        return None, None, None"},{"line_number":2107,"context_line":""},{"line_number":2108,"context_line":"    def _make_requests(self, req, ring, part, method, path, headers,"},{"line_number":2109,"context_line":"                       query_string\u003d\u0027\u0027, node_count\u003dNone, node_iterator\u003dNone,"},{"line_number":2110,"context_line":"                       body\u003dNone):"},{"line_number":2111,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":4,"id":"648cd106_853d5609","line":2108,"updated":"2025-10-31 21:01:10.000000000","message":"This new internal function looks equivalent as the previous logic in ``make_requests``, and it\u0027s going to be reused by the new ``_post_extra_handoffs``, good abstraction.","commit_id":"d0516f130128cc5b8f5d143d124dfb21a0771bfa"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5e9930e79389e042ab761d947a75fb3856179639","unresolved":false,"context_lines":[{"line_number":2105,"context_line":"                    {\u0027method\u0027: method, \u0027path\u0027: path})"},{"line_number":2106,"context_line":"        return None, None, None"},{"line_number":2107,"context_line":""},{"line_number":2108,"context_line":"    def _make_requests(self, req, ring, part, method, path, headers,"},{"line_number":2109,"context_line":"                       query_string\u003d\u0027\u0027, node_count\u003dNone, node_iterator\u003dNone,"},{"line_number":2110,"context_line":"                       body\u003dNone):"},{"line_number":2111,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":4,"id":"e2123717_7107f859","line":2108,"in_reply_to":"648cd106_853d5609","updated":"2025-11-04 00:25:43.000000000","message":"Acknowledged","commit_id":"d0516f130128cc5b8f5d143d124dfb21a0771bfa"}],"swift/proxy/controllers/obj.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c6a3536f40a8aaf829febca47c5e36de67f39c9f","unresolved":true,"context_lines":[{"line_number":818,"context_line":"                             handoff_nodes):"},{"line_number":819,"context_line":"        \"\"\""},{"line_number":820,"context_line":"        Send POST requests to handoff nodes when primary nodes return mixed"},{"line_number":821,"context_line":"        results."},{"line_number":822,"context_line":""},{"line_number":823,"context_line":"        :param req: the POST Request"},{"line_number":824,"context_line":"        :param obj_ring: the object ring"}],"source_content_type":"text/x-python","patch_set":2,"id":"a92f6e83_237147cf","line":821,"updated":"2025-08-04 22:25:27.000000000","message":"I\u0027m not sure AI doc-strings are really that helpful... maybe better than nothing?","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c6a3536f40a8aaf829febca47c5e36de67f39c9f","unresolved":true,"context_lines":[{"line_number":861,"context_line":"            if not node:"},{"line_number":862,"context_line":"                continue"},{"line_number":863,"context_line":"            status_primary_map[resp.status].append(node_to_string(node))"},{"line_number":864,"context_line":"        found_count \u003d len(status_primary_map[202])"},{"line_number":865,"context_line":"        missing_count \u003d len(status_primary_map[HTTP_NOT_FOUND])"},{"line_number":866,"context_line":"        # XXX found_count \u003c missing_count is inprecise"},{"line_number":867,"context_line":"        if found_count and found_count \u003c missing_count:"}],"source_content_type":"text/x-python","patch_set":2,"id":"ea4f4466_e10cde1d","line":864,"updated":"2025-08-04 22:25:27.000000000","message":"There\u0027s probably some case to be made that we should use some kind of \"is_success\" for counting found - but I think using the literal status in logging is better\n\n... maybe good enough to s/202/HTTP_ACCEPTED/g","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5e9930e79389e042ab761d947a75fb3856179639","unresolved":false,"context_lines":[{"line_number":861,"context_line":"            if not node:"},{"line_number":862,"context_line":"                continue"},{"line_number":863,"context_line":"            status_primary_map[resp.status].append(node_to_string(node))"},{"line_number":864,"context_line":"        found_count \u003d len(status_primary_map[202])"},{"line_number":865,"context_line":"        missing_count \u003d len(status_primary_map[HTTP_NOT_FOUND])"},{"line_number":866,"context_line":"        # XXX found_count \u003c missing_count is inprecise"},{"line_number":867,"context_line":"        if found_count and found_count \u003c missing_count:"}],"source_content_type":"text/x-python","patch_set":2,"id":"e8a003e2_ce2fc70b","line":864,"in_reply_to":"ea4f4466_e10cde1d","updated":"2025-11-04 00:25:43.000000000","message":"Done","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c6a3536f40a8aaf829febca47c5e36de67f39c9f","unresolved":true,"context_lines":[{"line_number":862,"context_line":"                continue"},{"line_number":863,"context_line":"            status_primary_map[resp.status].append(node_to_string(node))"},{"line_number":864,"context_line":"        found_count \u003d len(status_primary_map[202])"},{"line_number":865,"context_line":"        missing_count \u003d len(status_primary_map[HTTP_NOT_FOUND])"},{"line_number":866,"context_line":"        # XXX found_count \u003c missing_count is inprecise"},{"line_number":867,"context_line":"        if found_count and found_count \u003c missing_count:"},{"line_number":868,"context_line":"            # XXX during connection-timeout we\u0027ve probably already tried some"}],"source_content_type":"text/x-python","patch_set":2,"id":"9041c422_d0d8fd9a","line":865,"updated":"2025-08-04 22:25:27.000000000","message":"currently as best I can tell POST doesn\u0027t return any x-backend-[data-]timestamp:\n\n```\nvagrant@saio:~$ curl http://127.0.0.3:6030/sdb3/655/AUTH_test/container-7863cd35-c195-400a-99f0-e9d73e98ae6e/object2-f2327c87-3614-412b-a40a-f2340d7d20ec -v\n*   Trying 127.0.0.3:6030...\n* Connected to 127.0.0.3 (127.0.0.3) port 6030 (#0)\n\u003e GET /sdb3/655/AUTH_test/container-7863cd35-c195-400a-99f0-e9d73e98ae6e/object2-f2327c87-3614-412b-a40a-f2340d7d20ec HTTP/1.1\n\u003e Host: 127.0.0.3:6030\n\u003e User-Agent: curl/7.81.0\n\u003e Accept: */*\n\u003e \n* Mark bundle as not supporting multiuse\n\u003c HTTP/1.1 404 Not Found\n\u003c Content-Type: text/html; charset\u003dUTF-8\n\u003c X-Backend-Timestamp: 1754345794.45674\n\u003c Content-Length: 70\n\u003c Date: Mon, 04 Aug 2025 22:19:28 GMT\n\u003c \n* Connection #0 to host 127.0.0.3 left intact\n\u003chtml\u003e\u003ch1\u003eNot Found\u003c/h1\u003e\u003cp\u003eThe resource could not be found.\u003c/p\u003e\u003c/html\u003evagrant@saio:~$ \nvagrant@saio:~$ curl -XPOST http://127.0.0.3:6030/sdb3/655/AUTH_test/container-7863cd35-c195-400a-99f0-e9d73e98ae6e/object2-f2327c87-3614-412b-a40a-f2340d7d20ec -H \u0027x-timestamp: 1754345794.95674\u0027 -H \u0027x-object-meta-color: blue\u0027 -v\n*   Trying 127.0.0.3:6030...\n* Connected to 127.0.0.3 (127.0.0.3) port 6030 (#0)\n\u003e POST /sdb3/655/AUTH_test/container-7863cd35-c195-400a-99f0-e9d73e98ae6e/object2-f2327c87-3614-412b-a40a-f2340d7d20ec HTTP/1.1\n\u003e Host: 127.0.0.3:6030\n\u003e User-Agent: curl/7.81.0\n\u003e Accept: */*\n\u003e x-timestamp: 1754345794.95674\n\u003e x-object-meta-color: blue\n\u003e \n* Mark bundle as not supporting multiuse\n\u003c HTTP/1.1 404 Not Found\n\u003c Content-Type: text/html; charset\u003dUTF-8\n\u003c Content-Length: 70\n\u003c Date: Mon, 04 Aug 2025 22:19:37 GMT\n\u003c \n* Connection #0 to host 127.0.0.3 left intact\n\u003chtml\u003e\u003ch1\u003eNot Found\u003c/h1\u003e\u003cp\u003eThe resource could not be found.\u003c/p\u003e\u003c/html\u003evagrant@saio:~$ \n```\n\n... so we can\u0027t say early if this the rouge 202 is from a stale primary - hopefully an additional 404 from a handoff would sort things the right way tho.","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c6a3536f40a8aaf829febca47c5e36de67f39c9f","unresolved":true,"context_lines":[{"line_number":876,"context_line":"                    [node_to_string(n) for n in handoff_nodes])"},{"line_number":877,"context_line":"                handoff_results \u003d self._post_extra_handoffs("},{"line_number":878,"context_line":"                    req, obj_ring, partition, headers, results, handoff_nodes)"},{"line_number":879,"context_line":"                results.extend(handoff_results)"},{"line_number":880,"context_line":"        statuses, reasons, resp_headers, bodies \u003d zip(*[("},{"line_number":881,"context_line":"            resp.status, resp.reason, resp.getheaders(), body)"},{"line_number":882,"context_line":"            for resp, body, _node in results])"}],"source_content_type":"text/x-python","patch_set":2,"id":"a750a77c_39f59884","line":879,"updated":"2025-08-04 22:25:27.000000000","message":"there\u0027s probably an argument to be made that if this is just adding some 503s it\u0027s not worth messing up the original primary quorum.  But I think in a healthy cluster you\u0027d expect worse case we\u0027re just adding more 404s to be extra sure.","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5e9930e79389e042ab761d947a75fb3856179639","unresolved":false,"context_lines":[{"line_number":876,"context_line":"                    [node_to_string(n) for n in handoff_nodes])"},{"line_number":877,"context_line":"                handoff_results \u003d self._post_extra_handoffs("},{"line_number":878,"context_line":"                    req, obj_ring, partition, headers, results, handoff_nodes)"},{"line_number":879,"context_line":"                results.extend(handoff_results)"},{"line_number":880,"context_line":"        statuses, reasons, resp_headers, bodies \u003d zip(*[("},{"line_number":881,"context_line":"            resp.status, resp.reason, resp.getheaders(), body)"},{"line_number":882,"context_line":"            for resp, body, _node in results])"}],"source_content_type":"text/x-python","patch_set":2,"id":"a26c62cb_6bb7ff8a","line":879,"in_reply_to":"a750a77c_39f59884","updated":"2025-11-04 00:25:43.000000000","message":"it turned out adding the 503s didn\u0027t matter than much to best_response because it goes `for hstatus in (200, 300, 400): if len(resp w/ hstatus) \u003e quorum: return`\n\nso as soon as you get \"enough\" 404 no amount of 503s will \"trump\" the 404 response.\n\n... now that\u0027s only the case because we\u0027re overriding the quorum to be node/replica based instead of response length based; but we HAVE to do that to get the 202 behavior we want AFAICT.","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"a5007c2e6dc997da01e5859b87e8a21c8db65a51","unresolved":true,"context_lines":[{"line_number":897,"context_line":"                          if r[0].status \u003d\u003d HTTP_NOT_FOUND]"},{"line_number":898,"context_line":"        # _make_requests will not make requests per header and *recycle*"},{"line_number":899,"context_line":"        # the nodes in the node_iter leading to 409!?"},{"line_number":900,"context_line":"        failed_headers \u003d failed_headers[:len(handoff_nodes)]"},{"line_number":901,"context_line":"        handoff_results \u003d self._make_requests("},{"line_number":902,"context_line":"            req, obj_ring, partition, \u0027POST\u0027,"},{"line_number":903,"context_line":"            req.swift_entity_path, failed_headers,"}],"source_content_type":"text/x-python","patch_set":4,"id":"c370cae2_b98aeb66","line":900,"updated":"2025-10-31 21:01:10.000000000","message":"nice, when POSTing to handoff nodes, this reuses those headers which previous 404 requests used, so the container updates are still properly distributed across container servers, even though they  are talking to different object servers.","commit_id":"d0516f130128cc5b8f5d143d124dfb21a0771bfa"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5e9930e79389e042ab761d947a75fb3856179639","unresolved":true,"context_lines":[{"line_number":897,"context_line":"                          if r[0].status \u003d\u003d HTTP_NOT_FOUND]"},{"line_number":898,"context_line":"        # _make_requests will not make requests per header and *recycle*"},{"line_number":899,"context_line":"        # the nodes in the node_iter leading to 409!?"},{"line_number":900,"context_line":"        failed_headers \u003d failed_headers[:len(handoff_nodes)]"},{"line_number":901,"context_line":"        handoff_results \u003d self._make_requests("},{"line_number":902,"context_line":"            req, obj_ring, partition, \u0027POST\u0027,"},{"line_number":903,"context_line":"            req.swift_entity_path, failed_headers,"}],"source_content_type":"text/x-python","patch_set":4,"id":"c5ba4e06_629f022d","line":900,"in_reply_to":"c370cae2_b98aeb66","updated":"2025-11-04 00:25:43.000000000","message":"I\u0027m not 100% this is fully correct yet now that I\u0027ve reminding myself how the base controller _make_request gets passed a \"nodes\" list and will consume handoffs if the response is Timeout/503\n\n... but *maybe* the backend indexes will line up correctly with the observed responses - we have to cook up *some* headers maybe this is good enough.","commit_id":"d0516f130128cc5b8f5d143d124dfb21a0771bfa"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"a5007c2e6dc997da01e5859b87e8a21c8db65a51","unresolved":true,"context_lines":[{"line_number":926,"context_line":"                continue"},{"line_number":927,"context_line":"            status_primary_map[resp.status].append(node_to_string(node))"},{"line_number":928,"context_line":"        found_count \u003d len(status_primary_map[202])"},{"line_number":929,"context_line":"        missing_count \u003d len(status_primary_map[HTTP_NOT_FOUND])"},{"line_number":930,"context_line":"        if found_count and found_count \u003c self._quorum_size("},{"line_number":931,"context_line":"                obj_ring.replica_count):"},{"line_number":932,"context_line":"            handoff_nodes \u003d list(itertools.islice("}],"source_content_type":"text/x-python","patch_set":4,"id":"a3600a7c_315a25a7","line":929,"updated":"2025-10-31 21:01:10.000000000","message":"here it doesn\u0027t account for other non-404 error responses (e.g., 503, timeout stub responses), only counts 202 and 404, potentially missing scenarios where we should retry handoffs","commit_id":"d0516f130128cc5b8f5d143d124dfb21a0771bfa"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5e9930e79389e042ab761d947a75fb3856179639","unresolved":false,"context_lines":[{"line_number":926,"context_line":"                continue"},{"line_number":927,"context_line":"            status_primary_map[resp.status].append(node_to_string(node))"},{"line_number":928,"context_line":"        found_count \u003d len(status_primary_map[202])"},{"line_number":929,"context_line":"        missing_count \u003d len(status_primary_map[HTTP_NOT_FOUND])"},{"line_number":930,"context_line":"        if found_count and found_count \u003c self._quorum_size("},{"line_number":931,"context_line":"                obj_ring.replica_count):"},{"line_number":932,"context_line":"            handoff_nodes \u003d list(itertools.islice("}],"source_content_type":"text/x-python","patch_set":4,"id":"31566545_a06818be","line":929,"in_reply_to":"a3600a7c_315a25a7","updated":"2025-11-04 00:25:43.000000000","message":"I had to rediscover why this was correct by changing it\n\nBasically any Timeout/503 will have already been retried inside the original make_requests - but 404 does NOT get retried.  In retrospect maybe I should have taken the approach of trying to conditionally bury a retry for 404s into POST?  DELETEs don\u0027t need it b/c they\u0027ll still write a tombstone on 404.","commit_id":"d0516f130128cc5b8f5d143d124dfb21a0771bfa"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"a5007c2e6dc997da01e5859b87e8a21c8db65a51","unresolved":true,"context_lines":[{"line_number":941,"context_line":"        statuses, reasons, resp_headers, bodies \u003d zip(*[("},{"line_number":942,"context_line":"            resp.status, resp.reason, resp.getheaders(), body)"},{"line_number":943,"context_line":"            for resp, body, _node in results])"},{"line_number":944,"context_line":"        return self.best_response(req, statuses, reasons, bodies,"},{"line_number":945,"context_line":"                                  \u0027Object POST\u0027, headers\u003dresp_headers)"},{"line_number":946,"context_line":""},{"line_number":947,"context_line":"    @public"}],"source_content_type":"text/x-python","patch_set":4,"id":"ef0393e0_7d90b5ed","line":944,"updated":"2025-10-31 21:01:10.000000000","message":"with ``best_response``,\n``[202, 404, 404] + [404, 404]`` still returns ``404``, but it should be ``503`` instead:\n\nIf object is deleted after the original PUT and the 202 replica hasn\u0027t received/processed the delete request yet, since we don\u0027t have ``x-backend-data-timestamp`` from a datafile/tombstone, we can\u0027t know if the deleted timestamp is newer than PUT, so better to return 503 for this POST.\n\nIf object only lives on the first replica (two other primaries were down during PUT), then POST should return 503. it\u0027s only one replica, no quorum yet. This is also the expected behavior which existing test cases have in ``test_POST_insufficient_primaries_others_fail_handoffs_fail`` and ``test_POST_all_primaries_fail_insufficient_handoff_succeeds``, which they return ``503`` on a single replica success ``(202, 503, 503, 503, 503, 503)``. \n\n\nand with ``best_response``,\n``[202, 404, 404] + [202, 404]`` returns ``404``, but it should be ``202``, since we achieved the original 2/3 quorum.","commit_id":"d0516f130128cc5b8f5d143d124dfb21a0771bfa"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5e9930e79389e042ab761d947a75fb3856179639","unresolved":false,"context_lines":[{"line_number":941,"context_line":"        statuses, reasons, resp_headers, bodies \u003d zip(*[("},{"line_number":942,"context_line":"            resp.status, resp.reason, resp.getheaders(), body)"},{"line_number":943,"context_line":"            for resp, body, _node in results])"},{"line_number":944,"context_line":"        return self.best_response(req, statuses, reasons, bodies,"},{"line_number":945,"context_line":"                                  \u0027Object POST\u0027, headers\u003dresp_headers)"},{"line_number":946,"context_line":""},{"line_number":947,"context_line":"    @public"}],"source_content_type":"text/x-python","patch_set":4,"id":"9efd06a8_152b84cb","line":944,"in_reply_to":"ef0393e0_7d90b5ed","updated":"2025-11-04 00:25:43.000000000","message":"\u003e [202, 404, 404] + [404, 404] still returns 404, but it should be 503 instead:\n\nI\u0027ve decided that best_response SHOULD return 404 - but that for POST we want to just override the \"quorum 404\" when staring at an existence proof 202\n\n\u003e [202, 404, 404] + [202, 404] returns 404, but it should be 202\n\nthis was for sure just a bug/misunderstanding of the quorum calculation in best_response; fixed.  well spotted Jian KUDOS!","commit_id":"d0516f130128cc5b8f5d143d124dfb21a0771bfa"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5e9930e79389e042ab761d947a75fb3856179639","unresolved":true,"context_lines":[{"line_number":902,"context_line":"            req, obj_ring, partition, \u0027POST\u0027,"},{"line_number":903,"context_line":"            req.swift_entity_path, missing_headers,"},{"line_number":904,"context_line":"            node_count\u003dlen(handoff_nodes),"},{"line_number":905,"context_line":"            node_iterator\u003dnode_iter)"},{"line_number":906,"context_line":"        return handoff_results"},{"line_number":907,"context_line":""},{"line_number":908,"context_line":"    def _collect_status_map(self, results):"}],"source_content_type":"text/x-python","patch_set":6,"id":"f95d4594_4cc533fe","line":905,"updated":"2025-11-04 00:25:43.000000000","message":"_make_requests is such a weird beast.\n\nWhen there ARE handoff_nodes we get `len(handoff_results) \u003d\u003d len(missing_headers)` ... but if handoff_nodes is *empty* (short rings?) we get len(obj_ring.replica_count) made up 503!?\n\nit doesn\u0027t matter because we fix quorum size to not grow the more 503 we add, so 2x404 is still quorum (and then we override 503 if there was any found_count)","commit_id":"06c6fb1e569013f8fb77d9a1942e39bec86c1e54"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"9c0899b6820210a38f106a9ff6795bd8eda42c46","unresolved":true,"context_lines":[{"line_number":935,"context_line":"        found_count \u003d len(primary_status_map[HTTP_ACCEPTED])"},{"line_number":936,"context_line":"        if found_count and found_count \u003c quorum:"},{"line_number":937,"context_line":"            # ... but quorum is going to be wrong if we make extra requests"},{"line_number":938,"context_line":"            quorum \u003d self._quorum_size(obj_ring.replica_count)"},{"line_number":939,"context_line":"            # the make_requests machinery will make extra requests to handoffs"},{"line_number":940,"context_line":"            # for Timeout/503 primaries, we only have to make up for the 404s"},{"line_number":941,"context_line":"            extra_requests \u003d len(primary_status_map[HTTP_NOT_FOUND])"}],"source_content_type":"text/x-python","patch_set":6,"id":"9ddd54fa_f1993279","line":938,"updated":"2025-11-04 15:29:01.000000000","message":"This is correct! when it comes to EC, there is ``ec_ndata+1`` for data durability. however this is metadata POST, the same copy of it will be applied into each EC fragment, so we can use the same ``_quorum_size`` to calculate quorum as replication based policy. Took me a while to think through this.","commit_id":"06c6fb1e569013f8fb77d9a1942e39bec86c1e54"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"1ebf476fc6895fbd5997fe6abe82719f7d3116d8","unresolved":false,"context_lines":[{"line_number":935,"context_line":"        found_count \u003d len(primary_status_map[HTTP_ACCEPTED])"},{"line_number":936,"context_line":"        if found_count and found_count \u003c quorum:"},{"line_number":937,"context_line":"            # ... but quorum is going to be wrong if we make extra requests"},{"line_number":938,"context_line":"            quorum \u003d self._quorum_size(obj_ring.replica_count)"},{"line_number":939,"context_line":"            # the make_requests machinery will make extra requests to handoffs"},{"line_number":940,"context_line":"            # for Timeout/503 primaries, we only have to make up for the 404s"},{"line_number":941,"context_line":"            extra_requests \u003d len(primary_status_map[HTTP_NOT_FOUND])"}],"source_content_type":"text/x-python","patch_set":6,"id":"cda88f3c_28fba1ff","line":938,"in_reply_to":"9ddd54fa_f1993279","updated":"2025-11-04 16:02:29.000000000","message":"Acknowledged","commit_id":"06c6fb1e569013f8fb77d9a1942e39bec86c1e54"}],"test/probe/brain.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c6a3536f40a8aaf829febca47c5e36de67f39c9f","unresolved":true,"context_lines":[{"line_number":221,"context_line":"    def post_object(self, container_name, object_name, headers\u003dNone):"},{"line_number":222,"context_line":"        return client.post_object(self.url, self.token, container_name,"},{"line_number":223,"context_line":"                                  object_name, headers\u003dheaders)"},{"line_number":224,"context_line":""},{"line_number":225,"context_line":"    def delete_container(self, container_name):"},{"line_number":226,"context_line":"        return client.delete_container(self.url, self.token, container_name)"},{"line_number":227,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"544a3238_71c182ca","line":224,"updated":"2025-08-04 22:25:27.000000000","message":"the amount of drive-by extending of test infra primitives is very distracting.  Consider:\n\n1) inline\n2) prefactor\n3) get some by-in from other reviews it\u0027s sufficiently trivial and obvious to ignore","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"}],"test/probe/common.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c6a3536f40a8aaf829febca47c5e36de67f39c9f","unresolved":true,"context_lines":[{"line_number":368,"context_line":"    \"\"\""},{"line_number":369,"context_line":""},{"line_number":370,"context_line":"    def _make_name(self, prefix):"},{"line_number":371,"context_line":"        return (\u0027%s%s\u0027 % (prefix, uuid4())).encode()"},{"line_number":372,"context_line":""},{"line_number":373,"context_line":"    def _load_rings_and_configs(self):"},{"line_number":374,"context_line":"        self.ipport2server \u003d {}"}],"source_content_type":"text/x-python","patch_set":2,"id":"46d9ab30_684db4b9","line":371,"updated":"2025-08-04 22:25:27.000000000","message":"obviously useful for more than EC - presumably added to subclass to avoid complicating some other diff with unrelated churn until it\u0027s actually needed in a replicated probe test.","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"}],"test/probe/test_object_handoff.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c6a3536f40a8aaf829febca47c5e36de67f39c9f","unresolved":true,"context_lines":[{"line_number":643,"context_line":"            self.url, self.token, self.container_name,"},{"line_number":644,"context_line":"            object_name, service, policy\u003dpolicy)"},{"line_number":645,"context_line":""},{"line_number":646,"context_line":"    def test_main(self):"},{"line_number":647,"context_line":"        object1_name \u003d self._make_name(\u0027object1-\u0027)"},{"line_number":648,"context_line":"        object1_brain \u003d self._get_brain(object1_name)"},{"line_number":649,"context_line":"        # stop 1 primary"}],"source_content_type":"text/x-python","patch_set":2,"id":"c01e39b5_483134a0","line":646,"updated":"2025-08-04 22:25:27.000000000","message":"this is really just the happy path - the negative test would confirm we still return 404 even if a single primary misses a DELETE request (even at the expense of an extra handoff request that does nothing but confirm the 404)","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5e9930e79389e042ab761d947a75fb3856179639","unresolved":false,"context_lines":[{"line_number":643,"context_line":"            self.url, self.token, self.container_name,"},{"line_number":644,"context_line":"            object_name, service, policy\u003dpolicy)"},{"line_number":645,"context_line":""},{"line_number":646,"context_line":"    def test_main(self):"},{"line_number":647,"context_line":"        object1_name \u003d self._make_name(\u0027object1-\u0027)"},{"line_number":648,"context_line":"        object1_brain \u003d self._get_brain(object1_name)"},{"line_number":649,"context_line":"        # stop 1 primary"}],"source_content_type":"text/x-python","patch_set":2,"id":"85a3a00e_1c847934","line":646,"in_reply_to":"c01e39b5_483134a0","updated":"2025-11-04 00:25:43.000000000","message":"Done","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c6a3536f40a8aaf829febca47c5e36de67f39c9f","unresolved":true,"context_lines":[{"line_number":672,"context_line":"        # restart primaries"},{"line_number":673,"context_line":"        object2_brain.start_primary_half()"},{"line_number":674,"context_line":"        # POST still works"},{"line_number":675,"context_line":"        object2_brain.post_object(headers\u003d{\u0027X-Object-Meta-Test\u0027: \u0027test2\u0027})"},{"line_number":676,"context_line":"        headers \u003d object2_brain.head_object()"},{"line_number":677,"context_line":"        self.assertEqual(headers[\u0027X-Object-Meta-Test\u0027], \u0027test2\u0027)"},{"line_number":678,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"7dd4e28d_37ab8602","line":675,"updated":"2025-08-04 22:25:27.000000000","message":"master will raise ClientException(404)","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"}],"test/unit/proxy/controllers/test_obj.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c6a3536f40a8aaf829febca47c5e36de67f39c9f","unresolved":true,"context_lines":[{"line_number":1458,"context_line":"            expected_status \u003d 404"},{"line_number":1459,"context_line":"        with mocked_http_conn(*codes):"},{"line_number":1460,"context_line":"            resp \u003d req.get_response(self.app)"},{"line_number":1461,"context_line":"        self.assertEqual(expected_status, resp.status_int,"},{"line_number":1462,"context_line":"                         \u0027replicas \u003d %s\u0027 % self.replicas())"},{"line_number":1463,"context_line":""},{"line_number":1464,"context_line":"    def test_POST_insufficient_primaries_others_fail_handoffs_404(self):"}],"source_content_type":"text/x-python","patch_set":2,"id":"c65bcb3f_f449176c","line":1461,"updated":"2025-08-04 22:25:27.000000000","message":"There\u0027s another test that was asserting [202, 404, 404] \u003d\u003e 404\n\nhttps://github.com/NVIDIA/swift/blob/master/test/unit/proxy/test_server.py#L4024\n\nIn additional to providing too few stub responses it ALSO provides a ring with only 3 devices (!!?) ... which ends up not making any requests because of `if not handoff_nodes` - if we tried to give _make_requests an empty list it will (helpfully?) fill-in those stub 503s","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5c808e34d20a7025de1c7bd12efa9547f87f9b69","unresolved":false,"context_lines":[{"line_number":1458,"context_line":"            expected_status \u003d 404"},{"line_number":1459,"context_line":"        with mocked_http_conn(*codes):"},{"line_number":1460,"context_line":"            resp \u003d req.get_response(self.app)"},{"line_number":1461,"context_line":"        self.assertEqual(expected_status, resp.status_int,"},{"line_number":1462,"context_line":"                         \u0027replicas \u003d %s\u0027 % self.replicas())"},{"line_number":1463,"context_line":""},{"line_number":1464,"context_line":"    def test_POST_insufficient_primaries_others_fail_handoffs_404(self):"}],"source_content_type":"text/x-python","patch_set":2,"id":"087f52e8_b9c15fc6","line":1461,"in_reply_to":"c65bcb3f_f449176c","updated":"2025-10-06 19:32:24.000000000","message":"Done","commit_id":"9d31ac648f7f73d182b0fda67739a0a6166b8f02"}],"test/unit/proxy/test_server.py":[{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"a5007c2e6dc997da01e5859b87e8a21c8db65a51","unresolved":true,"context_lines":[{"line_number":4144,"context_line":"            test_status_map((200, 200, 202, 202, 500), 202)"},{"line_number":4145,"context_line":"            test_status_map((200, 200, 202, 500, 500), 503)"},{"line_number":4146,"context_line":"            test_status_map((200, 200, 202, 404, 500), 503)"},{"line_number":4147,"context_line":"            test_status_map((200, 200, 202, 404, 404), 503)"},{"line_number":4148,"context_line":"            test_status_map((200, 200, 404, 500, 500), 503)"},{"line_number":4149,"context_line":"            test_status_map((200, 200, 404, 404, 404), 404)"},{"line_number":4150,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"289689a7_de6fe7ae","line":4147,"updated":"2025-10-31 21:01:10.000000000","message":"this is weird, here POST returns 503, because ``_make_requests`` padded with 2 stub 503 responses, so\nstatuses passed to best_response: (202, 404, 404, 503, 503) and POST returns 503 because no status achieved quorum among all 5 responses.","commit_id":"d0516f130128cc5b8f5d143d124dfb21a0771bfa"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"a03da7d8dcf129275181e150ea2d850727e4114c","unresolved":true,"context_lines":[{"line_number":4144,"context_line":"            test_status_map((200, 200, 202, 202, 500), 202)"},{"line_number":4145,"context_line":"            test_status_map((200, 200, 202, 500, 500), 503)"},{"line_number":4146,"context_line":"            test_status_map((200, 200, 202, 404, 500), 503)"},{"line_number":4147,"context_line":"            test_status_map((200, 200, 202, 404, 404), 503)"},{"line_number":4148,"context_line":"            test_status_map((200, 200, 404, 500, 500), 503)"},{"line_number":4149,"context_line":"            test_status_map((200, 200, 404, 404, 404), 404)"},{"line_number":4150,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"47316fd9_1b6257a0","line":4147,"in_reply_to":"289689a7_de6fe7ae","updated":"2025-11-04 00:12:15.000000000","message":"\u003e padded with 2 stub 503 responses,\n\nwait, what?  why is it padded with extra 503?!?\n\nI think was the test that convinced me that (202, 404, 404) was a 503?","commit_id":"d0516f130128cc5b8f5d143d124dfb21a0771bfa"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"5e9930e79389e042ab761d947a75fb3856179639","unresolved":false,"context_lines":[{"line_number":4144,"context_line":"            test_status_map((200, 200, 202, 202, 500), 202)"},{"line_number":4145,"context_line":"            test_status_map((200, 200, 202, 500, 500), 503)"},{"line_number":4146,"context_line":"            test_status_map((200, 200, 202, 404, 500), 503)"},{"line_number":4147,"context_line":"            test_status_map((200, 200, 202, 404, 404), 503)"},{"line_number":4148,"context_line":"            test_status_map((200, 200, 404, 500, 500), 503)"},{"line_number":4149,"context_line":"            test_status_map((200, 200, 404, 404, 404), 404)"},{"line_number":4150,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"6b0a4e7e_ad0b74a2","line":4147,"in_reply_to":"47316fd9_1b6257a0","updated":"2025-11-04 00:25:43.000000000","message":"well it definitely is NOW!","commit_id":"d0516f130128cc5b8f5d143d124dfb21a0771bfa"}]}
