)]}'
{"ironic/common/exception.py":[{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"78016ac18b989bc40056a63646841cbeae3394b0","unresolved":true,"context_lines":[{"line_number":939,"context_line":"class NodeMaintenanceAlreadyExists(Conflict):"},{"line_number":940,"context_line":"    _msg_fmt \u003d _(\"Node %(node)s already has an active maintenance entry of \""},{"line_number":941,"context_line":"                 \"type %(type)s at %(scope)s scope asserted by project \""},{"line_number":942,"context_line":"                 \"%(project)s.\")"},{"line_number":943,"context_line":""},{"line_number":944,"context_line":""},{"line_number":945,"context_line":"class NodeMaintenanceNotFound(NotFound):"}],"source_content_type":"text/x-python","patch_set":1,"id":"80877bb0_0eafb097","line":942,"updated":"2026-08-13 17:07:26.000000000","message":"This was an explicit design decision, just highlighting some operator pain it might cause:\n\nI have fix_my_node.bash, it looks like this (pseudocode):\n```\n1) set maintenance on node\n2) attempt to run repair on node\n3) unset maintenance if #2 succeeds\n```\n\nIn the previous model, I could run this as many times as I wanted, and the second run -- even after a fail -- would continue because setting maint on a node with maint already set is a noop. After this change, however, subsequent runs of this script would throw a NodeMaintenanceAlreadyExists.\n\nJust tossing this out here so we can be 100% sure we want to break people like this. I think it\u0027s OK, but I\u0027m on the fence.","commit_id":"5323ee20e5d266812b3652e0a37e57cd972a12f5"}],"ironic/common/maintenance.py":[{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"78016ac18b989bc40056a63646841cbeae3394b0","unresolved":true,"context_lines":[{"line_number":75,"context_line":"        user\u003dcontext.user_id, project\u003dcontext.project_id)"},{"line_number":76,"context_line":""},{"line_number":77,"context_line":""},{"line_number":78,"context_line":"def get_entries(context, node, types\u003dNone):"},{"line_number":79,"context_line":"    \"\"\"Return the node\u0027s active maintenance entries, oldest first."},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    :param context: a request context."}],"source_content_type":"text/x-python","patch_set":1,"id":"56319cb8_26e96778","line":78,"updated":"2026-08-13 17:07:26.000000000","message":"nit throughout: since this is new code, can we do type annotations?","commit_id":"5323ee20e5d266812b3652e0a37e57cd972a12f5"},{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"78016ac18b989bc40056a63646841cbeae3394b0","unresolved":true,"context_lines":[{"line_number":111,"context_line":"    if existing:"},{"line_number":112,"context_line":"        entry \u003d existing[0]"},{"line_number":113,"context_line":"        if entry.reason !\u003d reason:"},{"line_number":114,"context_line":"            entry.reason \u003d reason"},{"line_number":115,"context_line":"            entry.save()"},{"line_number":116,"context_line":"            _record_history(context, node, entry, \u0027reason updated\u0027)"},{"line_number":117,"context_line":"        return entry"}],"source_content_type":"text/x-python","patch_set":1,"id":"0d3fc54b_9e6b81d7","line":114,"updated":"2026-08-13 17:07:26.000000000","message":"I validated this matches existing behavior: most recently set reason always wins.","commit_id":"5323ee20e5d266812b3652e0a37e57cd972a12f5"}],"ironic/common/release_mappings.py":[{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"78016ac18b989bc40056a63646841cbeae3394b0","unresolved":true,"context_lines":[{"line_number":1053,"context_line":"            \u0027Node\u0027: [\u00271.44\u0027, \u00271.43\u0027, \u00271.42\u0027, \u00271.41\u0027],"},{"line_number":1054,"context_line":"            \u0027NodeHistory\u0027: [\u00271.3\u0027, \u00271.2\u0027, \u00271.1\u0027, \u00271.0\u0027],"},{"line_number":1055,"context_line":"            \u0027NodeInventory\u0027: [\u00271.1\u0027, \u00271.0\u0027],"},{"line_number":1056,"context_line":"            \u0027NodeMaintenance\u0027: [\u00271.0\u0027],"},{"line_number":1057,"context_line":"            \u0027Conductor\u0027: [\u00271.6\u0027, \u00271.5\u0027, \u00271.4\u0027],"},{"line_number":1058,"context_line":"            \u0027Chassis\u0027: [\u00271.4\u0027, \u00271.3\u0027],"},{"line_number":1059,"context_line":"            \u0027Deployment\u0027: [\u00271.1\u0027, \u00271.0\u0027],"}],"source_content_type":"text/x-python","patch_set":1,"id":"ae6fcef8_b3deed4e","line":1056,"updated":"2026-08-13 17:07:26.000000000","message":"this has to be with the migration","commit_id":"5323ee20e5d266812b3652e0a37e57cd972a12f5"}],"ironic/db/sqlalchemy/api.py":[{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"78016ac18b989bc40056a63646841cbeae3394b0","unresolved":true,"context_lines":[{"line_number":3524,"context_line":"        values.setdefault(\u0027uuid\u0027, uuidutils.generate_uuid())"},{"line_number":3525,"context_line":"        # The moment the entry was asserted, which survives a later"},{"line_number":3526,"context_line":"        # in-place update of its reason as updated_at would not."},{"line_number":3527,"context_line":"        values.setdefault(\u0027asserted_at\u0027, timeutils.utcnow())"},{"line_number":3528,"context_line":"        entry \u003d models.NodeMaintenance()"},{"line_number":3529,"context_line":"        entry.update(values)"},{"line_number":3530,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"08eff3a1_d25ce7bf","line":3527,"updated":"2026-08-13 17:07:26.000000000","message":"Does asserted_at give us any value over just using created_at? Is there some Ironic convention against using created_at here?","commit_id":"5323ee20e5d266812b3652e0a37e57cd972a12f5"}],"ironic/objects/node_maintenance.py":[{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"78016ac18b989bc40056a63646841cbeae3394b0","unresolved":true,"context_lines":[{"line_number":18,"context_line":""},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"@base.IronicObjectRegistry.register"},{"line_number":21,"context_line":"class NodeMaintenance(base.IronicObject,"},{"line_number":22,"context_line":"                      object_base.VersionedObjectDictCompat):"},{"line_number":23,"context_line":"    \"\"\"One active maintenance entry on a node."},{"line_number":24,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"1ae013a1_6f29791b","line":21,"updated":"2026-08-13 17:07:26.000000000","message":"I believe with this change, even though we missed it in the spec, we need to consider notifications.\n\nSetting a node to maintenance can trigger one, but we don\u0027t have a specific notification payload for nodemaintenance.\n\nWe should explicitly observe the notifcation behavior before and after this change and evaluate if we need to add a specific notification object around NodeMaintenance so the extra metadata is made available to operators.","commit_id":"5323ee20e5d266812b3652e0a37e57cd972a12f5"}]}
