)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"275f5b741ec4cf283e567dc35725c5c8e53798fe","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"ffb769f2_671eb8b0","updated":"2022-02-08 03:01:29.000000000","message":"Inline things can be in a followup.","commit_id":"fe3fdc55b031bf883db62cfbbf8c34e03ee45e58"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b6ae36d7c09111fb3f4731c62b00b99d4e9bdd89","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"b47f5159_2574e033","updated":"2022-02-08 00:27:05.000000000","message":"Looks OK to me.","commit_id":"fe3fdc55b031bf883db62cfbbf8c34e03ee45e58"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"40657e966279eaeaf353ba2b229772b8d824eaf0","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"db188059_1d153f53","updated":"2022-02-08 21:43:51.000000000","message":"Looks good","commit_id":"98fcf304975d01b9b826b5abfb0e95e3584d9a1c"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7ac60d3611939cd3094c97f6884fcbfd59195061","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"d92ae8bb_ca3692fb","updated":"2022-02-10 23:21:11.000000000","message":"Update looks good and looks to address gmann\u0027s comments","commit_id":"faa1ad516f60d2f054f0972b3cf0debcf47df9ab"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"7d8511a6edde52179211acc0c6c6834c621aa7a9","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"bcc3dbb0_9e4c22f8","updated":"2022-02-17 11:23:18.000000000","message":"i have some nits in line but nothing deserving of a respin\nso this look good to me to proceed with","commit_id":"faa1ad516f60d2f054f0972b3cf0debcf47df9ab"}],"placement/lib.py":[{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7ac60d3611939cd3094c97f6884fcbfd59195061","unresolved":true,"context_lines":[{"line_number":47,"context_line":"def _fix_one_forbidden(traits):"},{"line_number":48,"context_line":"    forbidden \u003d [trait for trait in traits if trait.startswith(\u0027!\u0027)]"},{"line_number":49,"context_line":"    required \u003d traits - set(forbidden)"},{"line_number":50,"context_line":"    forbidden \u003d set(trait.lstrip(\u0027!\u0027) for trait in forbidden)"},{"line_number":51,"context_line":"    conflicts \u003d forbidden \u0026 required"},{"line_number":52,"context_line":"    return required, forbidden, conflicts"},{"line_number":53,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"81e289cd_b06e65ab","line":50,"updated":"2022-02-10 23:21:11.000000000","message":"I got curious about the behavior of parsing forbidden traits for /allocation_candidates and AFAICT it is using lstrip() as well. This is called by placement.lib.dict_by_request() which is called by placement.handlers.list_allocation_candidates().\n\nSo it seems like if we fixed the parsing of things like !!!FOO we\u0027d need to do it here too to make the behavior consistent.\n\nAnd finding this makes me think it would be good to commonize how different APIs parse forbidden traits and make them call the same methods.","commit_id":"faa1ad516f60d2f054f0972b3cf0debcf47df9ab"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"a56befc5f36b9d437be2c5d0f77bd9bd01f07c0c","unresolved":true,"context_lines":[{"line_number":47,"context_line":"def _fix_one_forbidden(traits):"},{"line_number":48,"context_line":"    forbidden \u003d [trait for trait in traits if trait.startswith(\u0027!\u0027)]"},{"line_number":49,"context_line":"    required \u003d traits - set(forbidden)"},{"line_number":50,"context_line":"    forbidden \u003d set(trait.lstrip(\u0027!\u0027) for trait in forbidden)"},{"line_number":51,"context_line":"    conflicts \u003d forbidden \u0026 required"},{"line_number":52,"context_line":"    return required, forbidden, conflicts"},{"line_number":53,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"f8d43e3e_a7efc7c6","line":50,"in_reply_to":"81e289cd_b06e65ab","updated":"2022-02-17 10:10:26.000000000","message":"Actually my series commonize most of the trait parsing, except parsing traits out of root_required query param, as that param did not get any-trait support so I did not change that code path. But now both the GET A_C and GET RP uses the same parsing logic from placement/utils. So it is better now.","commit_id":"faa1ad516f60d2f054f0972b3cf0debcf47df9ab"}],"placement/util.py":[{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b6ae36d7c09111fb3f4731c62b00b99d4e9bdd89","unresolved":true,"context_lines":[{"line_number":307,"context_line":"    This method currently does no format validation of trait strings, other"},{"line_number":308,"context_line":"    than to ensure they\u0027re not zero-length."},{"line_number":309,"context_line":""},{"line_number":310,"context_line":"    This method only accept query parameter value without \u0027in:\u0027 prefix support"},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"    :param val: A traits query parameter value: a comma-separated string of"},{"line_number":313,"context_line":"                trait names."}],"source_content_type":"text/x-python","patch_set":6,"id":"7adf9ffe_3018ea73","line":310,"range":{"start_line":310,"start_character":21,"end_line":310,"end_character":27},"updated":"2022-02-08 00:27:05.000000000","message":"accepts","commit_id":"fe3fdc55b031bf883db62cfbbf8c34e03ee45e58"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"beec578dea3a6a18ae6769a8de7fea54f985dfbb","unresolved":false,"context_lines":[{"line_number":307,"context_line":"    This method currently does no format validation of trait strings, other"},{"line_number":308,"context_line":"    than to ensure they\u0027re not zero-length."},{"line_number":309,"context_line":""},{"line_number":310,"context_line":"    This method only accept query parameter value without \u0027in:\u0027 prefix support"},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"    :param val: A traits query parameter value: a comma-separated string of"},{"line_number":313,"context_line":"                trait names."}],"source_content_type":"text/x-python","patch_set":6,"id":"114ca4f6_2bf5ab08","line":310,"range":{"start_line":310,"start_character":21,"end_line":310,"end_character":27},"in_reply_to":"7adf9ffe_3018ea73","updated":"2022-02-08 14:51:22.000000000","message":"Done","commit_id":"fe3fdc55b031bf883db62cfbbf8c34e03ee45e58"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b6ae36d7c09111fb3f4731c62b00b99d4e9bdd89","unresolved":true,"context_lines":[{"line_number":315,"context_line":"                            prefixed by \u0027!\u0027) as a valid form when notifying"},{"line_number":316,"context_line":"                            the caller that the provided value is not properly"},{"line_number":317,"context_line":"                            formed."},{"line_number":318,"context_line":"    :return: A set of trait names or trait name prefixed with \u0027!\u0027"},{"line_number":319,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the val parameter is not in the"},{"line_number":320,"context_line":"            expected format."},{"line_number":321,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":6,"id":"df7cfaeb_af3d6ace","line":318,"range":{"start_line":318,"start_character":43,"end_line":318,"end_character":47},"updated":"2022-02-08 00:27:05.000000000","message":"names","commit_id":"fe3fdc55b031bf883db62cfbbf8c34e03ee45e58"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"beec578dea3a6a18ae6769a8de7fea54f985dfbb","unresolved":false,"context_lines":[{"line_number":315,"context_line":"                            prefixed by \u0027!\u0027) as a valid form when notifying"},{"line_number":316,"context_line":"                            the caller that the provided value is not properly"},{"line_number":317,"context_line":"                            formed."},{"line_number":318,"context_line":"    :return: A set of trait names or trait name prefixed with \u0027!\u0027"},{"line_number":319,"context_line":"    :raises `webob.exc.HTTPBadRequest` if the val parameter is not in the"},{"line_number":320,"context_line":"            expected format."},{"line_number":321,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":6,"id":"1e11021e_b96e993e","line":318,"range":{"start_line":318,"start_character":43,"end_line":318,"end_character":47},"in_reply_to":"df7cfaeb_af3d6ace","updated":"2022-02-08 14:51:22.000000000","message":"Done","commit_id":"fe3fdc55b031bf883db62cfbbf8c34e03ee45e58"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"b6ae36d7c09111fb3f4731c62b00b99d4e9bdd89","unresolved":true,"context_lines":[{"line_number":435,"context_line":"            msg \u003d ("},{"line_number":436,"context_line":"                f\"Invalid query string parameters: Expected \u0027required\u0027 \""},{"line_number":437,"context_line":"                f\"parameter value of the form: {expected_form}. \""},{"line_number":438,"context_line":"                f\"Got any empty trait in: {val}\")"},{"line_number":439,"context_line":"            raise webob.exc.HTTPBadRequest(msg)"},{"line_number":440,"context_line":""},{"line_number":441,"context_line":"        # NOTE(gibi): we need to wrap each required trait into a one element"}],"source_content_type":"text/x-python","patch_set":6,"id":"20c847fb_40c9c252","line":438,"range":{"start_line":438,"start_character":22,"end_line":438,"end_character":25},"updated":"2022-02-08 00:27:05.000000000","message":"an?","commit_id":"fe3fdc55b031bf883db62cfbbf8c34e03ee45e58"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"beec578dea3a6a18ae6769a8de7fea54f985dfbb","unresolved":false,"context_lines":[{"line_number":435,"context_line":"            msg \u003d ("},{"line_number":436,"context_line":"                f\"Invalid query string parameters: Expected \u0027required\u0027 \""},{"line_number":437,"context_line":"                f\"parameter value of the form: {expected_form}. \""},{"line_number":438,"context_line":"                f\"Got any empty trait in: {val}\")"},{"line_number":439,"context_line":"            raise webob.exc.HTTPBadRequest(msg)"},{"line_number":440,"context_line":""},{"line_number":441,"context_line":"        # NOTE(gibi): we need to wrap each required trait into a one element"}],"source_content_type":"text/x-python","patch_set":6,"id":"ca634c68_56a00ed7","line":438,"range":{"start_line":438,"start_character":22,"end_line":438,"end_character":25},"in_reply_to":"20c847fb_40c9c252","updated":"2022-02-08 14:51:22.000000000","message":"Done","commit_id":"fe3fdc55b031bf883db62cfbbf8c34e03ee45e58"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"af8324d5631836fe3ec8052192994f9a42e00492","unresolved":true,"context_lines":[{"line_number":423,"context_line":"        all_traits \u003d [substr.strip() for substr in val.split(\u0027,\u0027)]"},{"line_number":424,"context_line":""},{"line_number":425,"context_line":"        forbidden_traits \u003d {"},{"line_number":426,"context_line":"            trait[1:] for trait in all_traits if trait.startswith(\u0027!\u0027)}"},{"line_number":427,"context_line":""},{"line_number":428,"context_line":"        if not all("},{"line_number":429,"context_line":"                trait"}],"source_content_type":"text/x-python","patch_set":7,"id":"243ae464_c4177630","line":426,"range":{"start_line":426,"start_character":12,"end_line":426,"end_character":21},"updated":"2022-02-09 14:25:59.000000000","message":"This is actually a change in API behavior.\n\nIn the past the leading \u0027!\u0027 was removed with lstrip(\u0027!\u0027) [1][2]. Therefore placement allowed and striped more than one leading \u0027!\u0027. Now trait[1:] only strips one leading \u0027!\u0027 and the rest is parsed as a trait name. \n\nSo in the past !!!FOO meant forbidden FOO, but after this patch it result in HTTP400 as !!FOO is not a valid trait name.\n\n\n[1] https://github.com/openstack/placement/blob/master/placement/objects/resource_provider.py#L940\n[2] https://github.com/openstack/placement/blob/7e0ad4956fa96620d6988b4038e3dc42cd8103fe/placement/lib.py#L50","commit_id":"98fcf304975d01b9b826b5abfb0e95e3584d9a1c"},{"author":{"_account_id":8556,"name":"Ghanshyam Maan","display_name":"Ghanshyam Maan","email":"gmaan.os14@gmail.com","username":"ghanshyam"},"change_message_id":"78884a24f7a43605ce2300cbf91b21a87798220a","unresolved":true,"context_lines":[{"line_number":423,"context_line":"        all_traits \u003d [substr.strip() for substr in val.split(\u0027,\u0027)]"},{"line_number":424,"context_line":""},{"line_number":425,"context_line":"        forbidden_traits \u003d {"},{"line_number":426,"context_line":"            trait[1:] for trait in all_traits if trait.startswith(\u0027!\u0027)}"},{"line_number":427,"context_line":""},{"line_number":428,"context_line":"        if not all("},{"line_number":429,"context_line":"                trait"}],"source_content_type":"text/x-python","patch_set":7,"id":"349ec742_98beaa76","line":426,"range":{"start_line":426,"start_character":12,"end_line":426,"end_character":21},"in_reply_to":"243ae464_c4177630","updated":"2022-02-09 17:09:56.000000000","message":"Yeah, as you mentioned in current code !!FOO is accepted as valid trait and there is no error at the down layer too. So user it this way are getting success case which will be changed to error and break them. It is bad interface but success case for user. We should not change it without microversion. We have ton of such cases in Nova APIs too and we cannot change them just saying \"you were not meant to use this interface that way even it is allowed and we have not documented it too\". That is main purpose of microversion that we avoid breaking the success case of APIs usage. \n\nIf this end up with error at the end/down layer then yes it become failure case and then we can fix it without microverion.","commit_id":"98fcf304975d01b9b826b5abfb0e95e3584d9a1c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"4d5cf7b6c8e6556d46f13348f9b66e84cde45d35","unresolved":true,"context_lines":[{"line_number":423,"context_line":"        all_traits \u003d [substr.strip() for substr in val.split(\u0027,\u0027)]"},{"line_number":424,"context_line":""},{"line_number":425,"context_line":"        forbidden_traits \u003d {"},{"line_number":426,"context_line":"            trait[1:] for trait in all_traits if trait.startswith(\u0027!\u0027)}"},{"line_number":427,"context_line":""},{"line_number":428,"context_line":"        if not all("},{"line_number":429,"context_line":"                trait"}],"source_content_type":"text/x-python","patch_set":7,"id":"f035fdf1_5df52d9b","line":426,"range":{"start_line":426,"start_character":12,"end_line":426,"end_character":21},"in_reply_to":"349ec742_98beaa76","updated":"2022-02-10 10:01:41.000000000","message":"OK, Then I will replace this with lstrip to keep the legacy behavior.","commit_id":"98fcf304975d01b9b826b5abfb0e95e3584d9a1c"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"0ea0ca3abf2ef150bf3b1d8609676c162035da60","unresolved":false,"context_lines":[{"line_number":423,"context_line":"        all_traits \u003d [substr.strip() for substr in val.split(\u0027,\u0027)]"},{"line_number":424,"context_line":""},{"line_number":425,"context_line":"        forbidden_traits \u003d {"},{"line_number":426,"context_line":"            trait[1:] for trait in all_traits if trait.startswith(\u0027!\u0027)}"},{"line_number":427,"context_line":""},{"line_number":428,"context_line":"        if not all("},{"line_number":429,"context_line":"                trait"}],"source_content_type":"text/x-python","patch_set":7,"id":"fbb47f61_3df1602b","line":426,"range":{"start_line":426,"start_character":12,"end_line":426,"end_character":21},"in_reply_to":"f035fdf1_5df52d9b","updated":"2022-02-10 10:10:42.000000000","message":"Restored the legacy buggy behavior. 😢","commit_id":"98fcf304975d01b9b826b5abfb0e95e3584d9a1c"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"7d8511a6edde52179211acc0c6c6834c621aa7a9","unresolved":true,"context_lines":[{"line_number":324,"context_line":""},{"line_number":325,"context_line":"    # then reformat that structure to the old format"},{"line_number":326,"context_line":"    legacy_traits \u003d set()"},{"line_number":327,"context_line":"    for any_traits in required:"},{"line_number":328,"context_line":"        # a legacy request does not have any-trait support so every internal"},{"line_number":329,"context_line":"        # set expressing OR relationship should exactly contain one trait"},{"line_number":330,"context_line":"        assert len(any_traits) \u003d\u003d 1"}],"source_content_type":"text/x-python","patch_set":8,"id":"0e4044a5_6609ba82","line":327,"range":{"start_line":327,"start_character":8,"end_line":327,"end_character":18},"updated":"2022-02-17 11:23:18.000000000","message":"nit in generally i find useing any_traits as a variable name kind of confusing\n\ni know we are using that as the name of the feature but i would just have used traits here.","commit_id":"faa1ad516f60d2f054f0972b3cf0debcf47df9ab"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"7d8511a6edde52179211acc0c6c6834c621aa7a9","unresolved":true,"context_lines":[{"line_number":399,"context_line":"                f\"since microversion 1.39. Got: {val}\")"},{"line_number":400,"context_line":"            raise webob.exc.HTTPBadRequest(msg)"},{"line_number":401,"context_line":""},{"line_number":402,"context_line":"        any_traits \u003d set(substr.strip() for substr in val[3:].split(\u0027,\u0027))"},{"line_number":403,"context_line":""},{"line_number":404,"context_line":"        if not all(trait for trait in any_traits):"},{"line_number":405,"context_line":"            msg \u003d ("}],"source_content_type":"text/x-python","patch_set":8,"id":"68327cfe_73291678","line":402,"range":{"start_line":402,"start_character":8,"end_line":402,"end_character":18},"updated":"2022-02-17 11:23:18.000000000","message":"nit: any_traits again i find confusing here and in the previous patches too.\nall_traits or just traits would be more intuitive. any_traites to me invokes the idea of a regex or matcher that matches any valid trait rather then a collection of tratis \n\nanyway this is just a minor nit but everytime i read any_traits uses as a variable name i do a double take and it drops me out of the code flow.\n\nthat is not enough to respine this but in general it might be nice to clean that up if outers agree at some point in a followup.","commit_id":"faa1ad516f60d2f054f0972b3cf0debcf47df9ab"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7ac60d3611939cd3094c97f6884fcbfd59195061","unresolved":true,"context_lines":[{"line_number":429,"context_line":"        # bump. See"},{"line_number":430,"context_line":"        # https://review.opendev.org/c/openstack/placement/+/826491/7/placement/util.py#426"},{"line_number":431,"context_line":"        forbidden_traits \u003d {"},{"line_number":432,"context_line":"            trait.lstrip(\u0027!\u0027) for trait in all_traits if trait.startswith(\u0027!\u0027)}"},{"line_number":433,"context_line":""},{"line_number":434,"context_line":"        if not all("},{"line_number":435,"context_line":"                trait"}],"source_content_type":"text/x-python","patch_set":8,"id":"6bcdc98c_cee61191","line":432,"updated":"2022-02-10 23:21:11.000000000","message":"Note to self: the previous (and undefined) behavior is shown here:\nhttps://review.opendev.org/c/openstack/placement/+/826491/8/placement/objects/resource_provider.py#b940","commit_id":"faa1ad516f60d2f054f0972b3cf0debcf47df9ab"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"7d8511a6edde52179211acc0c6c6834c621aa7a9","unresolved":false,"context_lines":[{"line_number":429,"context_line":"        # bump. See"},{"line_number":430,"context_line":"        # https://review.opendev.org/c/openstack/placement/+/826491/7/placement/util.py#426"},{"line_number":431,"context_line":"        forbidden_traits \u003d {"},{"line_number":432,"context_line":"            trait.lstrip(\u0027!\u0027) for trait in all_traits if trait.startswith(\u0027!\u0027)}"},{"line_number":433,"context_line":""},{"line_number":434,"context_line":"        if not all("},{"line_number":435,"context_line":"                trait"}],"source_content_type":"text/x-python","patch_set":8,"id":"23a77cae_2fe7482a","line":432,"in_reply_to":"6bcdc98c_cee61191","updated":"2022-02-17 11:23:18.000000000","message":"well undefeind is not entirely ture ! is not a legal charter in a trait.\nit is reseved solely for use with forbiden traits.\nwe coudl quible over details but \nhttps://specs.openstack.org/openstack/nova-specs/specs/rocky/implemented/placement-forbidden-traits.html#rest-api-impact\nonly allowed a singel ! as prefix and states\"\"\"\nA malformed trait will result in a 400 Bad Request response (this is already the case).\n\"\"\"\nhttps://specs.openstack.org/openstack/nova-specs/specs/pike/implemented/resource-provider-traits.html#rest-api-impact\n\ndefiend the alow chacters in a trait as \n\n\"\"\"\nTRAIT \u003d {\n  \"type\": \"string\",\n  \u0027minLength\u0027: 1, \u0027maxLength\u0027: 255,\n  \"pattern\": \"^[A-Z0-9_]+$\"\n}\nCUSTOM_TRAIT \u003d {\n  \"type\": \"string\",\n  \u0027minLength\u0027: 1, \u0027maxLength\u0027: 255,\n  \"pattern\": \"^CUSTOM_[A-Z0-9_]+$\"\n}\n\"\"\"\n\nso by defintion repeated \"!\" is malformed\n\nso we shoudl return a 400 to be complent with the spec in this case.\n\nanyway im not trying to reopen that now but !!!!!FOO is not a valid forbiden trait or trait.\n\ni still hope we will fix this without a microversion eventually but we can discuss that at the ptg or otherwise outside of this review.","commit_id":"faa1ad516f60d2f054f0972b3cf0debcf47df9ab"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"7d8511a6edde52179211acc0c6c6834c621aa7a9","unresolved":false,"context_lines":[{"line_number":494,"context_line":"        # the query param is repeated we only consider the last one from the"},{"line_number":495,"context_line":"        # request"},{"line_number":496,"context_line":"        values \u003d values[-1:]"},{"line_number":497,"context_line":""},{"line_number":498,"context_line":"    for value in values:"},{"line_number":499,"context_line":"        rts, fts \u003d normalize_traits_qs_param("},{"line_number":500,"context_line":"            value, allow_forbidden, allow_any_traits)"}],"source_content_type":"text/x-python","patch_set":8,"id":"255c44ed_fac4cd79","line":497,"updated":"2022-02-17 11:23:18.000000000","message":"i still think its fundementally a bug that we preserve this broken behavior\nbut again we can disuss that in the future but if we dont fix this its a really stong argument for raising the min microversion.\nbut ya that is out of scope of this review","commit_id":"faa1ad516f60d2f054f0972b3cf0debcf47df9ab"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"7d8511a6edde52179211acc0c6c6834c621aa7a9","unresolved":true,"context_lines":[{"line_number":496,"context_line":"        values \u003d values[-1:]"},{"line_number":497,"context_line":""},{"line_number":498,"context_line":"    for value in values:"},{"line_number":499,"context_line":"        rts, fts \u003d normalize_traits_qs_param("},{"line_number":500,"context_line":"            value, allow_forbidden, allow_any_traits)"},{"line_number":501,"context_line":"        required_traits +\u003d rts"},{"line_number":502,"context_line":"        forbidden_traits |\u003d fts"}],"source_content_type":"text/x-python","patch_set":8,"id":"918331b4_a7136d59","line":499,"range":{"start_line":499,"start_character":7,"end_line":499,"end_character":16},"updated":"2022-02-17 11:23:18.000000000","message":"nit until i read how this is used i did not know what these stood for","commit_id":"faa1ad516f60d2f054f0972b3cf0debcf47df9ab"}]}
