)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"f055e07d61ae6411ff1e421494112aa7690a00d5","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"900d7e50_60746da3","updated":"2025-08-25 16:47:36.000000000","message":"I think I like the idea -- at the very least, though, it could use some docstring improvements.","commit_id":"0bdc807484e0c5b8089c1012196357dd8df28197"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"066638123a499fa66b0d6c50b675a641b64cab6a","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"a258403e_4f253e44","updated":"2025-08-25 03:35:34.000000000","message":"recheck","commit_id":"0bdc807484e0c5b8089c1012196357dd8df28197"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"47473adca6581b50f290444e5beeb92c71e394b8","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":4,"id":"a3c12aee_f232f63e","updated":"2025-10-08 22:05:06.000000000","message":"I am personally not a big fan of this structure where we are storing functions in multiple dicts keyed by their names, what if later on they need a refactor although i know this is the ringbuilder cli, yet if we can avoid using a dict -\u003e single @command decorate + flags with something like when i asked a code generator to reduce the space complexity of this code change it came up with something like:\n```\nfrom enum import Flag, auto\nfrom functools import wraps\n\nclass CmdFlag(Flag):\n    READ_ONLY      \u003d auto()\n    NO_BACKUP      \u003d auto()\n    RING_FILE      \u003d auto()\n    BUILDER_EXEMPT \u003d auto()\n\n# Global registry of available commands (name -\u003e function)\nCOMMANDS \u003d {}\n\ndef command(*, name\u003dNone, flags\u003dCmdFlag(0)):\n    \"\"\"\n    Decorator to declare a CLI command and its flags.\n\n    Example:\n      @command(flags\u003dCmdFlag.READ_ONLY)\n      def default(): ...\n\n      @command(flags\u003dCmdFlag.READ_ONLY | CmdFlag.RING_FILE | CmdFlag.BUILDER_EXEMPT)\n      def version(): ...\n    \"\"\"\n    # business rule: read-only implies no backup\n    if CmdFlag.READ_ONLY in flags:\n        flags |\u003d CmdFlag.NO_BACKUP\n\n    def deco(func):\n        cmd_name \u003d name or func.__name__\n        # Attach metadata directly to the function\n        func._cmd_name \u003d cmd_name\n        func._cmd_flags \u003d flags\n\n        # Keep the original signature/name for help/tracebacks\n        @wraps(func)\n        def wrapper(*args, **kwargs):\n            return func(*args, **kwargs)\n\n        # Register and make it a staticmethod-friendly attribute if used in a class\n        COMMANDS[cmd_name] \u003d wrapper\n        return staticmethod(wrapper)\n    return deco\n\ndef has_flag(func, flag: CmdFlag) -\u003e bool:\n    return bool(getattr(func, \"_cmd_flags\", CmdFlag(0)) \u0026 flag)\n\n# ---- Usage ----\n\nclass Commands:\n    @command(flags\u003dCmdFlag.BUILDER_EXEMPT)\n    def create():\n        # ...\n        # if not has_flag(Commands.create.__func__, CmdFlag.NO_BACKUP):\n        #   make_backup()\n        pass\n\n    @command(flags\u003dCmdFlag.READ_ONLY)\n    def default():\n        # ...\n        pass\n\n    @command(flags\u003dCmdFlag.READ_ONLY | CmdFlag.RING_FILE | CmdFlag.BUILDER_EXEMPT)\n    def version():\n        # ...\n        pass\n\n    @command(flags\u003dCmdFlag.READ_ONLY)\n    def search():\n        # ...\n        pass\n\n    @command(flags\u003dCmdFlag.READ_ONLY)\n    def list_parts():\n        # ...\n        pass\n\n    @staticmethod\n    def unknown():\n        print(\u0027Unknown command:\u0027, argv[2])\n        exit(EXIT_ERROR)\n```\n\nThe structure looks easier on the eyes and if i need to consume it somehwere else i can write something like:\n```\nif has_flag(underlying, CmdFlag.RING_FILE):\n    # open ring file path\n    \nelse:\n    # open builder file path or whatever else the logic requires\n \n\n\nif not has_flag(underlying, CmdFlag.NO_BACKUP):\n     performing backup code\n```\n\nLet me know if you like the aforementioned structure for the cli change?\n\nIT is quite important to note that before you are using 4 seperate dicts while now wit the suggested change `COMMANDS` our (a better name for the dict) will be just 1 dict with (n\u003d4) entries. The proposed design reduces memory usage by 3 dictionaries.","commit_id":"0897bc57e0bfc031b78f4beabe30a942b15474bf"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ae7093d60301a1fdf965587a294e7c130d1bd035","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"ac2c7b05_00c61b8c","updated":"2025-10-13 16:55:52.000000000","message":"I think the fundamental problem is we\u0027re trying to conditionally opt into (or out of) some common behaviors and we don\u0027t have a clear taxonomy of \"command types\" that want which behaviors.\n\nI think this is *sort of* trying to classify the commands - but it seems a little on the nose.  `@command.i_want_this_specific_behavior` IMHO isn\u0027t *that* much better than `def my_command(): this_specific_behavior()`\n\nThe biggest \"win\" from a code maintenance perspective is since \"most\" commands want some common prep-helpers having the command decorators essentially be a blacklist means we get a \"fail closed\" behavior if a developer forgets `def new_command(): do_backups()` instead of `@command.skip_backups`.\n\n\u003e ring functions in multiple dicts keyed by their names\n\nI don\u0027t think the difference of 3 dicts vs a flag enum makes much of functional/maintenance difference if we take this approach.  The point is each function is has to decide if it wants to be \"in\" or \"out\" of each specific \"if wants_specific_common_behavior\" list.\n\nI think the reaction is correct \"each command shouldn\u0027t opt-into each dict\" but the reaction/suggested-solution doesn\u0027t go far enough.  A \"declarative\" taxonomy where each command is decorated as a *single* type that implies the behaviors it wants would be more work to discover - but also easier to reason about the addition of new commands:\n\ni.e. a \"ring_command\" should imply \"read_only\" which should imply \"no_backup\"\n\ne.g. our ops need a `swift-ring-builder /path/to/ring.gz devices` command!  calling write_builder just to defalt/read-only is silly\n\n-1 because I\u0027m not sure we should decorate commands that can optionally write back to the .builder as \"read only\"","commit_id":"0897bc57e0bfc031b78f4beabe30a942b15474bf"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"38b2f6869864ef26f931d220effe1da148a8c2e5","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"0431a13c_c9be603c","updated":"2025-09-09 04:25:23.000000000","message":"recheck","commit_id":"0897bc57e0bfc031b78f4beabe30a942b15474bf"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"fe10398c4f83dafc36f7f50223a8f2f334e4e57a","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":4,"id":"5cce32f2_0db53afd","in_reply_to":"a3c12aee_f232f63e","updated":"2025-10-09 00:17:22.000000000","message":"Interesting! Well enum Flag\u0027s seem to be introduced in py3. So it is something we can now use.\n\nThe core of this approach is taken from how we do StoragePolicy\u0027s, it has similar decorators. But I do like the way the flag and commands are working.\n\nI\u0027ll have a play and try and intergrate the flag code so see how it shakes out. Thanks Ash","commit_id":"0897bc57e0bfc031b78f4beabe30a942b15474bf"}],"swift/cli/ringbuilder.py":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"f055e07d61ae6411ff1e421494112aa7690a00d5","unresolved":true,"context_lines":[{"line_number":547,"context_line":"    @classmethod"},{"line_number":548,"context_line":"    def ring_command(cls, func):"},{"line_number":549,"context_line":"        \"\"\""},{"line_number":550,"context_line":"        Decorator to mark a command readonly"},{"line_number":551,"context_line":"        \"\"\""},{"line_number":552,"context_line":"        cls.ring_file_commands[func.__name__] \u003d func"},{"line_number":553,"context_line":"        return func"}],"source_content_type":"text/x-python","patch_set":3,"id":"6322fa3b_92b11ebf","line":550,"updated":"2025-08-25 16:47:36.000000000","message":"Too much copy/paste ;-)","commit_id":"0bdc807484e0c5b8089c1012196357dd8df28197"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"ab49f5fd78e7017994ecc2e9cc948187dfd4aa84","unresolved":false,"context_lines":[{"line_number":547,"context_line":"    @classmethod"},{"line_number":548,"context_line":"    def ring_command(cls, func):"},{"line_number":549,"context_line":"        \"\"\""},{"line_number":550,"context_line":"        Decorator to mark a command readonly"},{"line_number":551,"context_line":"        \"\"\""},{"line_number":552,"context_line":"        cls.ring_file_commands[func.__name__] \u003d func"},{"line_number":553,"context_line":"        return func"}],"source_content_type":"text/x-python","patch_set":3,"id":"84a741b3_b9980e1d","line":550,"in_reply_to":"6322fa3b_92b11ebf","updated":"2025-08-26 05:05:12.000000000","message":"Done","commit_id":"0bdc807484e0c5b8089c1012196357dd8df28197"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"f055e07d61ae6411ff1e421494112aa7690a00d5","unresolved":true,"context_lines":[{"line_number":555,"context_line":"    @classmethod"},{"line_number":556,"context_line":"    def builder_exempt(cls, func):"},{"line_number":557,"context_line":"        \"\"\""},{"line_number":558,"context_line":"        Decorator to mark a command readonly"},{"line_number":559,"context_line":"        \"\"\""},{"line_number":560,"context_line":"        cls.builder_exempt_commands[func.__name__] \u003d func"},{"line_number":561,"context_line":"        return func"}],"source_content_type":"text/x-python","patch_set":3,"id":"ffa96235_000fc7a0","line":558,"updated":"2025-08-25 16:47:36.000000000","message":"Here, too.","commit_id":"0bdc807484e0c5b8089c1012196357dd8df28197"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"ab49f5fd78e7017994ecc2e9cc948187dfd4aa84","unresolved":false,"context_lines":[{"line_number":555,"context_line":"    @classmethod"},{"line_number":556,"context_line":"    def builder_exempt(cls, func):"},{"line_number":557,"context_line":"        \"\"\""},{"line_number":558,"context_line":"        Decorator to mark a command readonly"},{"line_number":559,"context_line":"        \"\"\""},{"line_number":560,"context_line":"        cls.builder_exempt_commands[func.__name__] \u003d func"},{"line_number":561,"context_line":"        return func"}],"source_content_type":"text/x-python","patch_set":3,"id":"69e9154d_2d56458f","line":558,"in_reply_to":"ffa96235_000fc7a0","updated":"2025-08-26 05:05:12.000000000","message":"Done","commit_id":"0bdc807484e0c5b8089c1012196357dd8df28197"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"f055e07d61ae6411ff1e421494112aa7690a00d5","unresolved":true,"context_lines":[{"line_number":587,"context_line":"            exit(EXIT_ERROR)"},{"line_number":588,"context_line":"        backup_dir \u003d pathjoin(dirname(builder_file), \u0027backups\u0027)"},{"line_number":589,"context_line":"        try:"},{"line_number":590,"context_line":"            mkdir(backup_dir)"},{"line_number":591,"context_line":"        except OSError as err:"},{"line_number":592,"context_line":"            if err.errno !\u003d EEXIST:"},{"line_number":593,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":3,"id":"4effc4c5_ac7d49c3","line":590,"updated":"2025-08-25 16:47:36.000000000","message":"Off-topic: Kinda weird that `create` tries to create `backup_dir` after `main` already should have...","commit_id":"0bdc807484e0c5b8089c1012196357dd8df28197"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"ab49f5fd78e7017994ecc2e9cc948187dfd4aa84","unresolved":true,"context_lines":[{"line_number":587,"context_line":"            exit(EXIT_ERROR)"},{"line_number":588,"context_line":"        backup_dir \u003d pathjoin(dirname(builder_file), \u0027backups\u0027)"},{"line_number":589,"context_line":"        try:"},{"line_number":590,"context_line":"            mkdir(backup_dir)"},{"line_number":591,"context_line":"        except OSError as err:"},{"line_number":592,"context_line":"            if err.errno !\u003d EEXIST:"},{"line_number":593,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":3,"id":"4795dc64_e6136512","line":590,"in_reply_to":"4effc4c5_ac7d49c3","updated":"2025-08-26 05:05:12.000000000","message":"Yeah, good point.. might remove it as a drive-by 😊","commit_id":"0bdc807484e0c5b8089c1012196357dd8df28197"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"f055e07d61ae6411ff1e421494112aa7690a00d5","unresolved":true,"context_lines":[{"line_number":1403,"context_line":"        exit(EXIT_SUCCESS)"},{"line_number":1404,"context_line":""},{"line_number":1405,"context_line":"    @staticmethod"},{"line_number":1406,"context_line":"    @CommandDecorator.readonly"},{"line_number":1407,"context_line":"    @CommandDecorator.ring_command"},{"line_number":1408,"context_line":"    @CommandDecorator.builder_exempt"},{"line_number":1409,"context_line":"    def write_builder():"}],"source_content_type":"text/x-python","patch_set":3,"id":"483094ad_1a857e92","line":1406,"updated":"2025-08-25 16:47:36.000000000","message":"I\u0027m not sure so `write_builder` should be called `readonly` -- though OTOH, it definitely doesn\u0027t touch `backup_dir`...","commit_id":"0bdc807484e0c5b8089c1012196357dd8df28197"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"ab49f5fd78e7017994ecc2e9cc948187dfd4aa84","unresolved":false,"context_lines":[{"line_number":1403,"context_line":"        exit(EXIT_SUCCESS)"},{"line_number":1404,"context_line":""},{"line_number":1405,"context_line":"    @staticmethod"},{"line_number":1406,"context_line":"    @CommandDecorator.readonly"},{"line_number":1407,"context_line":"    @CommandDecorator.ring_command"},{"line_number":1408,"context_line":"    @CommandDecorator.builder_exempt"},{"line_number":1409,"context_line":"    def write_builder():"}],"source_content_type":"text/x-python","patch_set":3,"id":"56fd4421_f35c4197","line":1406,"in_reply_to":"483094ad_1a857e92","updated":"2025-08-26 05:05:12.000000000","message":"OK so added a new no_backup and readonly also adds to this list.\n\nNot really using the readonly list anymore, but still want to keep it, because it feels like a useful group.","commit_id":"0bdc807484e0c5b8089c1012196357dd8df28197"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"f055e07d61ae6411ff1e421494112aa7690a00d5","unresolved":true,"context_lines":[{"line_number":1781,"context_line":"    else:"},{"line_number":1782,"context_line":"        command \u003d argv[2]"},{"line_number":1783,"context_line":""},{"line_number":1784,"context_line":"    if command not in Commands.read_only_commands:"},{"line_number":1785,"context_line":"        backup_dir \u003d pathjoin(dirname(builder_file), \u0027backups\u0027)"},{"line_number":1786,"context_line":"        try:"},{"line_number":1787,"context_line":"            mkdir(backup_dir)"}],"source_content_type":"text/x-python","patch_set":3,"id":"69be8fdd_c960cd90","line":1784,"updated":"2025-08-25 16:47:36.000000000","message":"OK, cool -- so that\u0027s a new guard.","commit_id":"0bdc807484e0c5b8089c1012196357dd8df28197"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ae7093d60301a1fdf965587a294e7c130d1bd035","unresolved":true,"context_lines":[{"line_number":703,"context_line":"    @CommandDecorator.readonly"},{"line_number":704,"context_line":"    @CommandDecorator.ring_command"},{"line_number":705,"context_line":"    @CommandDecorator.builder_exempt"},{"line_number":706,"context_line":"    def version():"},{"line_number":707,"context_line":"        \"\"\""},{"line_number":708,"context_line":"swift-ring-builder \u003cring_file\u003e version"},{"line_number":709,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":4,"id":"e10af815_9b5ca7e2","line":706,"updated":"2025-10-13 16:55:52.000000000","message":"why isn\u0027t `ring_command` sufficient to illicit all the behaviors we want - I think this should be a \"less is more\" sort of thing - if you have to declare multiple command decorators I think we\u0027ve lost the thread.","commit_id":"0897bc57e0bfc031b78f4beabe30a942b15474bf"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ae7093d60301a1fdf965587a294e7c130d1bd035","unresolved":true,"context_lines":[{"line_number":824,"context_line":"        exit(EXIT_SUCCESS)"},{"line_number":825,"context_line":""},{"line_number":826,"context_line":"    @staticmethod"},{"line_number":827,"context_line":"    def add():"},{"line_number":828,"context_line":"        \"\"\""},{"line_number":829,"context_line":"swift-ring-builder \u003cbuilder_file\u003e add"},{"line_number":830,"context_line":"    [r\u003cregion\u003e]z\u003czone\u003e-\u003cip\u003e:\u003cport\u003e[R\u003cr_ip\u003e:\u003cr_port\u003e]/\u003cdevice_name\u003e_\u003cmeta\u003e"}],"source_content_type":"text/x-python","patch_set":4,"id":"b7034291_231f4ec2","line":827,"updated":"2025-10-13 16:55:52.000000000","message":"I think it would be ok to replace ALL the `@staticmethod` decorators with a `Command.cmd_type` decorator - where MOST just become `Command.modify_builder`","commit_id":"0897bc57e0bfc031b78f4beabe30a942b15474bf"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ae7093d60301a1fdf965587a294e7c130d1bd035","unresolved":true,"context_lines":[{"line_number":1249,"context_line":"        builder.save(pathjoin(backup_dir, \u0027%d.\u0027 % ts + basename(builder_file)))"},{"line_number":1250,"context_line":"        builder.get_ring().save("},{"line_number":1251,"context_line":"            ring_file, format_version\u003doptions.format_version)"},{"line_number":1252,"context_line":"        builder.save(builder_file)"},{"line_number":1253,"context_line":"        exit(status)"},{"line_number":1254,"context_line":""},{"line_number":1255,"context_line":"    @staticmethod"}],"source_content_type":"text/x-python","patch_set":4,"id":"b33bc315_8edfb699","line":1252,"updated":"2025-10-13 16:55:52.000000000","message":"is this the ONLY command that actually *wants* the backups directory?!","commit_id":"0897bc57e0bfc031b78f4beabe30a942b15474bf"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ae7093d60301a1fdf965587a294e7c130d1bd035","unresolved":true,"context_lines":[{"line_number":1311,"context_line":"        orig_version \u003d builder.version"},{"line_number":1312,"context_line":"        report \u003d dispersion_report(builder, search_filter\u003dsearch_filter,"},{"line_number":1313,"context_line":"                                   verbose\u003doptions.verbose,"},{"line_number":1314,"context_line":"                                   recalculate\u003doptions.recalculate)"},{"line_number":1315,"context_line":"        if builder.version !\u003d orig_version:"},{"line_number":1316,"context_line":"            # we\u0027ve already done the work, better go ahead and save it!"},{"line_number":1317,"context_line":"            builder.save(builder_file)"}],"source_content_type":"text/x-python","patch_set":4,"id":"1dc60424_a8a7bbb3","line":1314,"updated":"2025-10-13 16:55:52.000000000","message":"this doesn\u0027t feel very \"read-only-y\"","commit_id":"0897bc57e0bfc031b78f4beabe30a942b15474bf"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ae7093d60301a1fdf965587a294e7c130d1bd035","unresolved":true,"context_lines":[{"line_number":1367,"context_line":"        exit(EXIT_SUCCESS)"},{"line_number":1368,"context_line":""},{"line_number":1369,"context_line":"    @staticmethod"},{"line_number":1370,"context_line":"    def write_ring():"},{"line_number":1371,"context_line":"        \"\"\""},{"line_number":1372,"context_line":"swift-ring-builder \u003cbuilder_file\u003e write_ring"},{"line_number":1373,"context_line":"    Just rewrites the distributable ring file. This is done automatically after"}],"source_content_type":"text/x-python","patch_set":4,"id":"f7d1a8bd_60a75c39","line":1370,"updated":"2025-10-13 16:55:52.000000000","message":"am I to understand we never backup *rings* - just builders?\n\nI think a `Commands.builder_read_only` might differentiate from `Commands.read_only`... I think *all* `Commands.ring_file` are read only","commit_id":"0897bc57e0bfc031b78f4beabe30a942b15474bf"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ae7093d60301a1fdf965587a294e7c130d1bd035","unresolved":true,"context_lines":[{"line_number":1786,"context_line":"    else:"},{"line_number":1787,"context_line":"        command \u003d argv[2]"},{"line_number":1788,"context_line":""},{"line_number":1789,"context_line":"    if command not in Commands.no_backup_commands:"},{"line_number":1790,"context_line":"        backup_dir \u003d pathjoin(dirname(builder_file), \u0027backups\u0027)"},{"line_number":1791,"context_line":"        try:"},{"line_number":1792,"context_line":"            mkdir(backup_dir)"}],"source_content_type":"text/x-python","patch_set":4,"id":"804732a4_73328595","line":1789,"updated":"2025-10-13 16:55:52.000000000","message":"`not in no_backup` is sort of gross.","commit_id":"0897bc57e0bfc031b78f4beabe30a942b15474bf"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ae7093d60301a1fdf965587a294e7c130d1bd035","unresolved":true,"context_lines":[{"line_number":1794,"context_line":"            if err.errno !\u003d EEXIST:"},{"line_number":1795,"context_line":"                raise"},{"line_number":1796,"context_line":""},{"line_number":1797,"context_line":"    if argv[0].endswith(\u0027-safe\u0027):"},{"line_number":1798,"context_line":"        try:"},{"line_number":1799,"context_line":"            with lock_parent_directory(abspath(builder_file), 15):"},{"line_number":1800,"context_line":"                getattr(Commands, command, Commands.unknown)()"}],"source_content_type":"text/x-python","patch_set":4,"id":"28afc1fc_e5b15814","line":1797,"updated":"2025-10-13 16:55:52.000000000","message":"does this entrypoint still exist?","commit_id":"0897bc57e0bfc031b78f4beabe30a942b15474bf"}]}
