)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"eee260ff21a9e75b3fd9873c759bfa909340d0e8","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"2807d485_02d57c6e","updated":"2022-01-21 18:35:11.000000000","message":"Need extra tests for the any-trait support of this DB call","commit_id":"25f3c1fd2c9f632256bb77ba55b0f31985614bd0"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"1104bfdf0ee58a8647d152aae04400bb37b69ba3","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"768db2d7_a95d2f54","updated":"2022-01-22 08:41:35.000000000","message":"recheck","commit_id":"25f3c1fd2c9f632256bb77ba55b0f31985614bd0"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"d9b00655e8cd3a4da67f0b719897a56adbf0e0bf","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"cc93a4c9_66affbcd","updated":"2022-02-08 00:06:38.000000000","message":"Looks reasonable as far as I can tell, not being a SQL expert. Code is very well documented and code comments match what code is doing.","commit_id":"5947bc352484607b8f5196190d535fed5f083151"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"cbba0d53a33eb51b68cb481c7dd38837923c7ef8","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":9,"id":"32d95daa_c83f9142","updated":"2022-02-08 21:45:11.000000000","message":"Looks good now","commit_id":"c19481a5f3d89d940b085b20567198026fe101ae"}],"placement/objects/research_context.py":[{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"d9b00655e8cd3a4da67f0b719897a56adbf0e0bf","unresolved":true,"context_lines":[{"line_number":768,"context_line":"    :param ctx: Session context to use"},{"line_number":769,"context_line":"    :param rp_ids: a set of resource provider IDs"},{"line_number":770,"context_line":"    :param required_traits: A list of set of trait internal IDs where the"},{"line_number":771,"context_line":"       traits in each nested set is OR\u0027d while the items in the outer list are"},{"line_number":772,"context_line":"       AND\u0027d together. The RPs in the tree should COLLECTIVELY fulfill this"},{"line_number":773,"context_line":"       trait request."},{"line_number":774,"context_line":"    :param forbidden_traits: A list of trait internal IDs that a resource"}],"source_content_type":"text/x-python","patch_set":8,"id":"89c77ce6_bbca0db7","line":771,"range":{"start_line":771,"start_character":33,"end_line":771,"end_character":35},"updated":"2022-02-08 00:06:38.000000000","message":"are","commit_id":"5947bc352484607b8f5196190d535fed5f083151"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"99b76b1cf8e9990ee75628b431be7c265278e56e","unresolved":false,"context_lines":[{"line_number":768,"context_line":"    :param ctx: Session context to use"},{"line_number":769,"context_line":"    :param rp_ids: a set of resource provider IDs"},{"line_number":770,"context_line":"    :param required_traits: A list of set of trait internal IDs where the"},{"line_number":771,"context_line":"       traits in each nested set is OR\u0027d while the items in the outer list are"},{"line_number":772,"context_line":"       AND\u0027d together. The RPs in the tree should COLLECTIVELY fulfill this"},{"line_number":773,"context_line":"       trait request."},{"line_number":774,"context_line":"    :param forbidden_traits: A list of trait internal IDs that a resource"}],"source_content_type":"text/x-python","patch_set":8,"id":"6095a940_bcf0f82d","line":771,"range":{"start_line":771,"start_character":33,"end_line":771,"end_character":35},"in_reply_to":"89c77ce6_bbca0db7","updated":"2022-02-08 14:51:17.000000000","message":"Done","commit_id":"5947bc352484607b8f5196190d535fed5f083151"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8f3cb90a979c6dcec75a4ab9afc79257168e4ac6","unresolved":true,"context_lines":[{"line_number":730,"context_line":"    # of the required traits and none of the forbidden traits"},{"line_number":731,"context_line":"    rp_tuples_with_trait \u003d _get_trees_with_traits("},{"line_number":732,"context_line":"        rg_ctx.context, provs_with_inv.rps, rg_ctx.required_trait_map.values(),"},{"line_number":733,"context_line":"        rg_ctx.forbidden_trait_map.values())"},{"line_number":734,"context_line":"    provs_with_inv.filter_by_rp(rp_tuples_with_trait)"},{"line_number":735,"context_line":"    LOG.debug(\"found %d providers under %d trees after applying \""},{"line_number":736,"context_line":"              \"traits filter - required: %s, forbidden: %s\","}],"source_content_type":"text/x-python","patch_set":9,"id":"b44c35f3_e3654678","line":733,"updated":"2022-02-17 05:54:09.000000000","message":"right so this is adapting to only using the ids not the names  +1","commit_id":"c19481a5f3d89d940b085b20567198026fe101ae"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"eba985c9d2fac681e49b2cf14a99969814d9028f","unresolved":true,"context_lines":[{"line_number":788,"context_line":"        required_traits \u003d [{trait} for trait in required_traits]"},{"line_number":789,"context_line":""},{"line_number":790,"context_line":"    # TODO(gibi): if somebody can formulate the below three SQL query to a"},{"line_number":791,"context_line":"    # single one then probably that will improve performance"},{"line_number":792,"context_line":""},{"line_number":793,"context_line":"    # Get the root of all rps in the rp_ids as we need to return every rp from"},{"line_number":794,"context_line":"    # rp_ids that is in a matching tree but below we will filter out rps by"}],"source_content_type":"text/x-python","patch_set":9,"id":"61826b5d_56b0b200","line":791,"updated":"2022-02-09 08:58:21.000000000","message":"Note for reviewers: I run some perfload measurements locally on this change compared to the current master and I see 6% - 18% performance degradation in the nested perfload run. Even locally I see big variance in the perfload runs so I don\u0027t really trust these numbers.","commit_id":"c19481a5f3d89d940b085b20567198026fe101ae"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8f3cb90a979c6dcec75a4ab9afc79257168e4ac6","unresolved":true,"context_lines":[{"line_number":802,"context_line":""},{"line_number":803,"context_line":"    # First filter out the rps from the rp_ids list that provide forbidden"},{"line_number":804,"context_line":"    # traits. To do that we collect those rps that provide any of the forbidden"},{"line_number":805,"context_line":"    # traits and with the outer join and the null check we filter them out"},{"line_number":806,"context_line":"    # of the result"},{"line_number":807,"context_line":"    rptt_forbidden \u003d sa.alias(_RP_TRAIT_TBL, name\u003d\"rptt_forbidden\")"},{"line_number":808,"context_line":"    rp_to_trait \u003d sa.outerjoin("}],"source_content_type":"text/x-python","patch_set":9,"id":"3c588444_54f49cd4","line":805,"updated":"2022-02-17 05:54:09.000000000","message":"i suspect the outer join is hurting performance here\n\nwe should likely do this with a subquery instead\n\ne.g.\n\nselect rp.id, rp.root_provider_id from resource_providres as rp\nwhere rp.id not in (select resouce_provider_id from resource_providers_traits\nwhere trait_id not in ($forbidden_traits))\n\nthat should be much cheaper then an outer join. and have the same effect as lins 806 to 822 below","commit_id":"c19481a5f3d89d940b085b20567198026fe101ae"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"30fb3b50ab4439a3fa5263385e2f2c04f97b725a","unresolved":true,"context_lines":[{"line_number":802,"context_line":""},{"line_number":803,"context_line":"    # First filter out the rps from the rp_ids list that provide forbidden"},{"line_number":804,"context_line":"    # traits. To do that we collect those rps that provide any of the forbidden"},{"line_number":805,"context_line":"    # traits and with the outer join and the null check we filter them out"},{"line_number":806,"context_line":"    # of the result"},{"line_number":807,"context_line":"    rptt_forbidden \u003d sa.alias(_RP_TRAIT_TBL, name\u003d\"rptt_forbidden\")"},{"line_number":808,"context_line":"    rp_to_trait \u003d sa.outerjoin("}],"source_content_type":"text/x-python","patch_set":9,"id":"0d5d4d42_0f047c6b","line":805,"in_reply_to":"3c588444_54f49cd4","updated":"2022-02-17 10:06:33.000000000","message":"Actually the current perfload setup is not really convincing that there is significant performance issue. As I noted I run some perfload locally and it produced 6 - 18% performance degradation compared to master, but even on master I saw 10% variance in subsequent perfload runs on my local machine. So right now it is hard to say how much performance we really lost here due to noise.","commit_id":"c19481a5f3d89d940b085b20567198026fe101ae"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8f3cb90a979c6dcec75a4ab9afc79257168e4ac6","unresolved":true,"context_lines":[{"line_number":829,"context_line":""},{"line_number":830,"context_line":"    # shortcut if no traits required the good_rp_ids.values() contains all the"},{"line_number":831,"context_line":"    # good roots"},{"line_number":832,"context_line":"    if not required_traits:"},{"line_number":833,"context_line":"        return {"},{"line_number":834,"context_line":"            (rp_id, root_id)"},{"line_number":835,"context_line":"            for rp_id, root_id in original_rp_ids.items()"}],"source_content_type":"text/x-python","patch_set":9,"id":"ff2ae106_5ad3232d","line":832,"updated":"2022-02-17 05:54:09.000000000","message":"we should actully move this check up and do an early return because the query i ahve above i think is sufficnet in this case\n\nselect rp.id, rp.root_provider_id from resource_providres as rp\nwhere rp.id not in (select resouce_provider_id from resource_providers_traits\nwhere trait_id not in ($forbidden_traits))","commit_id":"c19481a5f3d89d940b085b20567198026fe101ae"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8f3cb90a979c6dcec75a4ab9afc79257168e4ac6","unresolved":true,"context_lines":[{"line_number":836,"context_line":"            if root_id in good_rp_ids.values()"},{"line_number":837,"context_line":"        }"},{"line_number":838,"context_line":""},{"line_number":839,"context_line":"    # now get the traits provided by the good rps per tree"},{"line_number":840,"context_line":"    rptt \u003d sa.alias(_RP_TRAIT_TBL, name\u003d\"rptt\")"},{"line_number":841,"context_line":"    rp_to_trait \u003d sa.join("},{"line_number":842,"context_line":"        rpt, rptt, rpt.c.id \u003d\u003d rptt.c.resource_provider_id)"}],"source_content_type":"text/x-python","patch_set":9,"id":"b0975fc6_ab7b547b","line":839,"updated":"2022-02-17 05:54:09.000000000","message":"if we do not early then in the implcit else we should make a single query that include the required traits\n\nselect rp.id, rp.root_provider_id from resource_providres as rp\nwhere rp.id not in (select resouce_provider_id from resource_providers_traits\n    where trait_id not in ($forbidden_traits))\nand rp.id in (select distinct resouce_provider_id from resource_providers_traits\n    group by resouce_provider_id, trait_id having\n    (trait_id \u003d\u003d $required_traits_group_1_trait1 and trait_id \u003d\u003d  \n        $required_traits_group_1_trait2 and …) or (trait_id \u003d\u003d      \n        $required_traits_group_1_trait2) or …\n    )   \n)\n\ni think that extended query now takes care of forbidden traits and required traits groups by using group by and a having clause but it does not ensure all required traits are in the same tree.\n\nwith that said im not sure that the having clause is vlaid.\ni tought there was a way to do that in sql but im a bit rusty.\n\nif you use the python based filtering you have below to validate that tree has all the required traits  and the query works that should have done most of the heavy lifting.\n\nthat should help with performance since you will have less work to do although the current algorightm does not seam to hanel root_requries. just required traits.\nis that an oversight or is that done else where.\n\ni might see if i can come up with a better query since i think it will not like the having clause as written both i touht there was a  way to say “ only select X if there is a row with id X and  collume Y has all of (…)\n\nyou can defintly do it with joins or a chain of subquiese whci i might try and write out tomorow \n\ni.e.\nselect rp.id, rp.root_provider_id from resource_providres as rp\nwhere rp.id not in (select resouce_provider_id from resource_providers_traits\n    where trait_id not in ($forbidden_traits))\nand\n  (rp.id in (select resouce_provider_id from resource_providers_traits where\n    trait_id \u003d\u003d $required_traits_group_1_trait1)\n  and rp.id in (select resouce_provider_id from resource_providers_traits where \n     trait_id \u003d  $required_traits_group_1_trait2) and …\n  )\nor \n  (rp.id in (select resouce_provider_id from resource_providers_traits where \n    trait_id \u003d $required_traits_group_1_trait2) or …\n  )\n\n\nbut i think there is a cleaner way.","commit_id":"c19481a5f3d89d940b085b20567198026fe101ae"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"90722240fe314d5a9c644dd70375305d461c5e60","unresolved":true,"context_lines":[{"line_number":836,"context_line":"            if root_id in good_rp_ids.values()"},{"line_number":837,"context_line":"        }"},{"line_number":838,"context_line":""},{"line_number":839,"context_line":"    # now get the traits provided by the good rps per tree"},{"line_number":840,"context_line":"    rptt \u003d sa.alias(_RP_TRAIT_TBL, name\u003d\"rptt\")"},{"line_number":841,"context_line":"    rp_to_trait \u003d sa.join("},{"line_number":842,"context_line":"        rpt, rptt, rpt.c.id \u003d\u003d rptt.c.resource_provider_id)"}],"source_content_type":"text/x-python","patch_set":9,"id":"4daf2247_10eacb17","line":839,"in_reply_to":"ad053835_9f6d16c2","updated":"2022-02-22 14:52:50.000000000","message":"the inner join will require the query optimiser to do more work to get to the optimal execution plan so your milage might vary form dbms to dbms but i agree that we should proably defer this to a followup \n\nmy sugestion for refactors where prometed by gibis orginal concern that this was going to degrade perfromace but gibi i belive has changed his mind sine the local delta they observed was within the noise of there testign env.\nso for now i think we can proceed with this as written.","commit_id":"c19481a5f3d89d940b085b20567198026fe101ae"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"30fb3b50ab4439a3fa5263385e2f2c04f97b725a","unresolved":true,"context_lines":[{"line_number":836,"context_line":"            if root_id in good_rp_ids.values()"},{"line_number":837,"context_line":"        }"},{"line_number":838,"context_line":""},{"line_number":839,"context_line":"    # now get the traits provided by the good rps per tree"},{"line_number":840,"context_line":"    rptt \u003d sa.alias(_RP_TRAIT_TBL, name\u003d\"rptt\")"},{"line_number":841,"context_line":"    rp_to_trait \u003d sa.join("},{"line_number":842,"context_line":"        rpt, rptt, rpt.c.id \u003d\u003d rptt.c.resource_provider_id)"}],"source_content_type":"text/x-python","patch_set":9,"id":"ffcca612_a09e6287","line":839,"in_reply_to":"b0975fc6_ab7b547b","updated":"2022-02-17 10:06:33.000000000","message":"\u003e although the current algorightm does not seam to hanel root_requries. just\n\u003e required traits.\n\u003e is that an oversight or is that done else where.\n\nThe any-trait syntax was not planned to be implemented for root_requires (no mention in the spec). I\u0027ve documented this in the later patch [1].\nAlso this particular DB function is not intended to filter root_required. It is done in [2].\n\n[1] https://review.opendev.org/c/openstack/placement/+/826719/11/doc/source/user/provider-tree.rst\n[2] https://github.com/openstack/placement/blob/91b85ba7abf8e89fc565cb5af53c1753d6a98895/placement/objects/research_context.py#L834\n\nI can try an alternative SQL solution but I need help formulating thath.","commit_id":"c19481a5f3d89d940b085b20567198026fe101ae"},{"author":{"_account_id":7166,"name":"Sylvain Bauza","email":"sbauza@redhat.com","username":"sbauza"},"change_message_id":"691b82861783018c126902cfacd6aa0f2e0cbd9d","unresolved":true,"context_lines":[{"line_number":836,"context_line":"            if root_id in good_rp_ids.values()"},{"line_number":837,"context_line":"        }"},{"line_number":838,"context_line":""},{"line_number":839,"context_line":"    # now get the traits provided by the good rps per tree"},{"line_number":840,"context_line":"    rptt \u003d sa.alias(_RP_TRAIT_TBL, name\u003d\"rptt\")"},{"line_number":841,"context_line":"    rp_to_trait \u003d sa.join("},{"line_number":842,"context_line":"        rpt, rptt, rpt.c.id \u003d\u003d rptt.c.resource_provider_id)"}],"source_content_type":"text/x-python","patch_set":9,"id":"ad053835_9f6d16c2","line":839,"in_reply_to":"ffcca612_a09e6287","updated":"2022-02-22 10:17:58.000000000","message":"Again, I think the execution plan would be the same so the performance could not be better.","commit_id":"c19481a5f3d89d940b085b20567198026fe101ae"}],"placement/tests/functional/db/test_allocation_candidates.py":[{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"d9b00655e8cd3a4da67f0b719897a56adbf0e0bf","unresolved":true,"context_lines":[{"line_number":915,"context_line":"        custom_foo \u003d trait_obj.Trait.get_by_name(self.ctx, \u0027CUSTOM_FOO\u0027)"},{"line_number":916,"context_line":"        tb.set_traits(cn1_c1, \u0027CUSTOM_FOO\u0027)"},{"line_number":917,"context_line":""},{"line_number":918,"context_line":"        required_traits \u003d {}"},{"line_number":919,"context_line":"        forbidden_traits \u003d {custom_foo.id}"},{"line_number":920,"context_line":"        rp_ids \u003d {cn1.id, cn1_c1.id}"},{"line_number":921,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"7ef2054c_e2199edc","line":918,"range":{"start_line":918,"start_character":26,"end_line":918,"end_character":28},"updated":"2022-02-08 00:06:38.000000000","message":"[]?","commit_id":"5947bc352484607b8f5196190d535fed5f083151"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"99b76b1cf8e9990ee75628b431be7c265278e56e","unresolved":false,"context_lines":[{"line_number":915,"context_line":"        custom_foo \u003d trait_obj.Trait.get_by_name(self.ctx, \u0027CUSTOM_FOO\u0027)"},{"line_number":916,"context_line":"        tb.set_traits(cn1_c1, \u0027CUSTOM_FOO\u0027)"},{"line_number":917,"context_line":""},{"line_number":918,"context_line":"        required_traits \u003d {}"},{"line_number":919,"context_line":"        forbidden_traits \u003d {custom_foo.id}"},{"line_number":920,"context_line":"        rp_ids \u003d {cn1.id, cn1_c1.id}"},{"line_number":921,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"681cb264_392e8eca","line":918,"range":{"start_line":918,"start_character":26,"end_line":918,"end_character":28},"in_reply_to":"7ef2054c_e2199edc","updated":"2022-02-08 14:51:17.000000000","message":"Done","commit_id":"5947bc352484607b8f5196190d535fed5f083151"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"d9b00655e8cd3a4da67f0b719897a56adbf0e0bf","unresolved":true,"context_lines":[{"line_number":1066,"context_line":"                |"},{"line_number":1067,"context_line":"              CN1_C1_GC1 CUSTOM_C"},{"line_number":1068,"context_line":""},{"line_number":1069,"context_line":"        And each node has one extra custom traits with its own name so the test"},{"line_number":1070,"context_line":"        can easily forbid on or more RPs directly from the tree."},{"line_number":1071,"context_line":""},{"line_number":1072,"context_line":"        We use the formula (CUSTOM_A or CUSTOM_B) and CUSTOM_C) in this test."}],"source_content_type":"text/x-python","patch_set":8,"id":"e9f6b6e3_5b96ce85","line":1069,"range":{"start_line":1069,"start_character":43,"end_line":1069,"end_character":49},"updated":"2022-02-08 00:06:38.000000000","message":"trait?","commit_id":"5947bc352484607b8f5196190d535fed5f083151"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"99b76b1cf8e9990ee75628b431be7c265278e56e","unresolved":false,"context_lines":[{"line_number":1066,"context_line":"                |"},{"line_number":1067,"context_line":"              CN1_C1_GC1 CUSTOM_C"},{"line_number":1068,"context_line":""},{"line_number":1069,"context_line":"        And each node has one extra custom traits with its own name so the test"},{"line_number":1070,"context_line":"        can easily forbid on or more RPs directly from the tree."},{"line_number":1071,"context_line":""},{"line_number":1072,"context_line":"        We use the formula (CUSTOM_A or CUSTOM_B) and CUSTOM_C) in this test."}],"source_content_type":"text/x-python","patch_set":8,"id":"3867f4ef_fbb3938e","line":1069,"range":{"start_line":1069,"start_character":43,"end_line":1069,"end_character":49},"in_reply_to":"e9f6b6e3_5b96ce85","updated":"2022-02-08 14:51:17.000000000","message":"Done","commit_id":"5947bc352484607b8f5196190d535fed5f083151"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"d9b00655e8cd3a4da67f0b719897a56adbf0e0bf","unresolved":true,"context_lines":[{"line_number":1067,"context_line":"              CN1_C1_GC1 CUSTOM_C"},{"line_number":1068,"context_line":""},{"line_number":1069,"context_line":"        And each node has one extra custom traits with its own name so the test"},{"line_number":1070,"context_line":"        can easily forbid on or more RPs directly from the tree."},{"line_number":1071,"context_line":""},{"line_number":1072,"context_line":"        We use the formula (CUSTOM_A or CUSTOM_B) and CUSTOM_C) in this test."},{"line_number":1073,"context_line":"        Then we do the following cases where forbidden traits remove RPs:"}],"source_content_type":"text/x-python","patch_set":8,"id":"5fa451ab_b8623aed","line":1070,"range":{"start_line":1070,"start_character":26,"end_line":1070,"end_character":28},"updated":"2022-02-08 00:06:38.000000000","message":"one?","commit_id":"5947bc352484607b8f5196190d535fed5f083151"},{"author":{"_account_id":9708,"name":"Balazs Gibizer","display_name":"gibi","email":"gibizer@gmail.com","username":"gibi"},"change_message_id":"99b76b1cf8e9990ee75628b431be7c265278e56e","unresolved":false,"context_lines":[{"line_number":1067,"context_line":"              CN1_C1_GC1 CUSTOM_C"},{"line_number":1068,"context_line":""},{"line_number":1069,"context_line":"        And each node has one extra custom traits with its own name so the test"},{"line_number":1070,"context_line":"        can easily forbid on or more RPs directly from the tree."},{"line_number":1071,"context_line":""},{"line_number":1072,"context_line":"        We use the formula (CUSTOM_A or CUSTOM_B) and CUSTOM_C) in this test."},{"line_number":1073,"context_line":"        Then we do the following cases where forbidden traits remove RPs:"}],"source_content_type":"text/x-python","patch_set":8,"id":"82ff9e82_c176383e","line":1070,"range":{"start_line":1070,"start_character":26,"end_line":1070,"end_character":28},"in_reply_to":"5fa451ab_b8623aed","updated":"2022-02-08 14:51:17.000000000","message":"Done","commit_id":"5947bc352484607b8f5196190d535fed5f083151"}]}
