Skip to content

refactor(update): decompose command by responsibility - #97634

Closed
cervantesh wants to merge 1 commit into
NousResearch:mainfrom
cervantesh:codex/update-cmd-decomposition
Closed

cervantesh wants to merge 1 commit into
NousResearch:mainfrom
cervantesh:codex/update-cmd-decomposition

Conversation

@cervantesh

@cervantesh cervantesh commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Note

Superseded on current main. PR #102117 independently landed the same structural objective and is present in main@1e69c12b64dba4090eddffeae27f5a147068d34b. Rebasing this branch would combine two incompatible decompositions rather than preserve a useful patch. This PR is retained as historical design, review, and evidence provenance; its architecture and exact-head receipts do not describe current main.

What does this PR do?

Decomposes the 11,250-physical-line hermes_cli/update_cmd.py implementation into focused modules by existing operational responsibility while retaining update_cmd.py as a 504-line compatibility facade.

This is a behavior-preserving refactor with two explicit safety contracts:

  1. historical imports, mutable facade state, logger identity, and monkeypatch targets continue to reach moved consumers; and
  2. a live self-updating process protects the complete executing updater graph from cross-generation module mixing after the source tree changes.

Related issue

Closes #97633

Current integration frame

  • Base: main@48c0c3a873bc5adaf20c632b5b7630a4fac000b4
  • Exact head: d205375a3a63c440fefc14e0a777700f24a8d12e
  • Visible history: one atomic commit authored by cervantesh
  • Delivery state: ready for review after all exact-head required checks passed

The previous four-commit review frame (7c23c6d866, dc78338bb5, 17cdb78a4e, 49db219ea0) has been superseded by the single commit above. This folds the abort-recovery facade bridge into the extraction itself, so there is no longer an intermediate active object with an incomplete ABI. The earlier SHAs remain recorded in the review discussion for archaeology; no CI claim is made for them.

Responsibility boundaries

Module Responsibility
update_orchestrator.py top-level update/check orchestration
update_source.py Git/source selection and mutation
update_zip.py ZIP update and replacement paths
update_dependencies.py Python/Node dependency synchronization
update_runtime_refresh.py post-source runtime/module refresh
update_process_guard.py process, venv-holder, and mutation gates
update_gateway_posix.py POSIX/systemd/launchd restart mechanics
update_gateway_windows.py Windows restart and launcher mechanics
update_fleet_restart.py fleet restart orchestration
update_reconciliation.py restart outcomes and fleet reconciliation
update_backup.py pre-update backup
update_desktop.py Desktop update handling
update_notices.py modified-file and user notices

Following andrexibiza's review on #96235, this refactor uses 2,000 physical lines as a review-specific maintainability guard, not as a claimed repository policy. Every extracted production module remains below that guard; the largest is update_orchestrator.py at 1,934 physical lines. The already-large tests/hermes_cli/test_backup.py remains outside that production-module decomposition boundary.

Behavioral authorship and refactor provenance

This PR authors the decomposition. It does not claim authorship of the updater behaviors that it relocates from update_cmd.py into bounded owners. For the specific recovery and reconciliation behaviors called out in the review, the relevant reporting, implementation, and integration lineage is:

Those merged commits already exist in this branch's main ancestry, so they should not be cherry-picked again. This PR preserves their shipped behavior while changing its module ownership. The single commit at this PR's head, authored by @cervantesh, represents the decomposition and compatibility work only.

Live merge-order interlocksThese are complementary changes, not work absorbed by this refactor:

Neither PR's implementation is duplicated here.

Mechanical-equivalence audit

Compared with the exact current base:

  • 181 / 181 updater functions have a destination; none are missing;
  • 175 function bodies are attribute-free AST-identical;
  • the six non-identical functions are the declared compatibility/extraction adaptations: _m, _holder_value_flags, _resolve_pre_update_backup_mode, _run_pre_update_backup, _check_and_apply_config_migration, and _cmd_update_impl;
  • 226 / 226 historical top-level names remain available through hermes_cli.update_cmd; and
  • _cmd_update_impl resolves to hermes_cli.update_orchestrator.

Review-driven regressions

Independent review identified three concrete proof requirements, all represented in the current atomic object:

  • abort-recovery facade exports and compatibility propagation are present in the same commit as the extraction;
  • moved backup failure paths keep using the historical facade logger; and
  • test_purge_protects_executing_modules now includes hermes_cli.update_fleet_restart, matching the complete production _STALE_PURGE_PROTECTED execution graph.

The modified-skill notice remains evaluated per source file, and source-inspection tests follow Git network calls and runtime allowlists to their extracted owners.

Exact-head validation

Gate Result Evidence
Focused updater/compatibility matrix 154 passed locally exact tree at d205375a3a
AST function mapping 181/181; 175 identical; 6 declared adaptations exact base/head audit
Historical facade surface 226/226; none missing exact base/head audit
Static quality Ruff passed; compileall exit 0; diff-check exit 0 local exact-head validation
Production-module structural guard no extracted production module at or above 2,000 physical lines local exact-head audit
Full CI, E2E, Windows, macOS, Ruff, ty, security and required-check aggregation passed CI 33708334479
Docker amd64/arm64 passed Docker 33708333779
Nix flake check passed Nix 33708333814

A broader local Windows diagnostic completed with 719 passed, 54 skipped, 24 failed after updater tests spawned live gateway processes from the test worktree. The exact processes were inventoried and removed. A representative isolated failure reproduces unchanged on the exact base main@48c0c3a873, so it is not attributed to this refactor and is not used as a green acceptance claim.

Historical operational evidence

The earlier evidence package remains useful provenance for the design and before/after harnesses, but its SHAs are historical and are not presented as validation of the current head:

Behavior-preserving update command decomposition

The infographic is a navigation aid; the current exact-head audits and hosted checks are authoritative for this refresh.

Checklist

  • Current main updater behavior is composed into the extracted owners.
  • Historical imports and patch targets remain compatible.
  • The active history is one self-consistent commit.
  • update_fleet_restart is pinned in the frozen execution-graph regression.
  • Merged behavior provenance and live merge-order interlocks are explicit.
  • Focused local tests pass on the exact head.
  • Full hosted CI and required checks pass on the exact head.
  • Docker amd64/arm64 and Nix pass on the exact head.
  • The PR diff contains only the declared refactor and its regression guards.
  • No user-facing configuration, tool schema, or CLI contract changes.

@alt-glitch alt-glitch added type/refactor Code restructuring, no behavior change P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard area/install-update Installer, updater, packaging, wheels, doctor platform/windows Native Windows-specific behavior or breakage sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows labels Aug 29, 2026
@cervantesh
cervantesh force-pushed the codex/update-cmd-decomposition branch from 9f1f78e to cd38939 Compare August 29, 2026 04:04
@cervantesh
cervantesh marked this pull request as ready for review August 29, 2026 04:14

@andrexibiza andrexibiza left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head cd38939500c7aac9110a0cff0d68b244414d65f4, including the actual 20-file diff, the behavior-critical extracted modules/facade, compatibility and stale-module regressions, the public verification ledger, the closing issue, current open updater work, and the exact-head upstream workflows.

This is strong structural work. The decomposition is not just file motion with a hopeful re-export layer: update_cmd.py remains the historical patch surface, seeds the extracted consumers from _COMPAT_CONSUMERS, and installs a module-level __setattr__ bridge so later monkeypatches of historical globals propagate to the moved call sites. The regressions exercise that in more than one shape (_read_project_version, get_hermes_home, and a fleet-restart subprocess consumer), which addresses the highest-risk compatibility failure mode of this kind of extraction.

The other important side of this refactor is the running updater's generation boundary. update_runtime_refresh._STALE_PURGE_PROTECTED includes the full 15-module extracted updater graph, and test_purge_protects_executing_modules proves those exact module objects remain pinned while stale non-executing Hermes modules are evicted and rebuilt from the post-update checkout. That is the right invariant: do not let the process executing generation N accidentally import a generation N+1 sibling halfway through its own mutation/restart transaction.

I also checked the review-driven backup correction rather than relying on the PR narrative. The moved backup failure sites now resolve logging through the historical facade (_u().logger) instead of an unbound extracted-module name, while the existing fail-soft backup behavior remains intact. The public ledger is unusually good about its proof boundaries: 161/161 functions mapped, 155 AST-identical, six adaptations enumerated, 195/195 historical names present, zero missing propagation entries in the static audit, 56 focused tests, cross-platform focused runs, Linux updater and Windows-live before/after comparators, and native systemd/launchd/SCM restart-boundary equivalence. It also explicitly says what those witnesses do not prove rather than laundering them into a broader claim.

Exact-head CI for cd389395... is green on the tested composition: CI 33232923520, Docker 33232923216, and Nix 33232923194 all completed successfully. Within CI, Python tests, E2E, native Windows/macOS lanes, Ruff/ty, blocking Ruff, Windows footguns, attribution, OSV, supply-chain checks, and the final required-check aggregator are green.

Interlock / ownership check

I do not see this as superseding the open updater behavior work. It creates the ownership/routing boundary those PRs should compose through. In particular, #97547 (receipt completion classification), #97366 (multi-venv dependency/runtime ownership), #97350/#97450 (fleet-probe row expectations), #97056 (exact commit target semantics), #96853 (systemd generation boundary), and #96235 (aborted-restart generation recovery) are complementary behavior changes whose contributor credit and semantics must survive whichever merge order wins. #93042 is also still the provenance owner for the intentionally-unlanded canary/rollout transaction; this refactor must not turn that historical carrier into an implicit implementation claim.

The practical merge-order rule is straightforward: if one of those behavior PRs lands first, this decomposition must rebase and absorb the landed semantics into the corresponding extracted owner; if this lands first, those PRs should be rebased/ported onto the extracted modules rather than re-growing update_cmd.py. That is the other side of the shape here: a successful godfile extraction is incomplete if subsequent work keeps treating the compatibility facade as the implementation owner.

One release-gate blocker: the exact landing composition has moved

The branch and all of the cited exact-head evidence are pinned to base ee742fe1bc828f6456659f67d27bdbeacdebbdd4. The PR's current synthetic merge object is still 029f74da78f3485efdddeb22b480da5b80fde561, whose commit message is literally Merge cd389395... into ee742fe....

Current main is now 7eee066c30eda38b50bc8942a06a9c4b67b5d8ce. I compared ee742fe...7eee066... and found no direct path collision with this PR's hermes_cli/update_*, hermes_cli/_update_compat.py, or changed tests/hermes_cli/test_* paths, so I do not see evidence of a semantic conflict and I am not asking for a redesign. But the exact landing object has not been certified: the green workflows and before/after evidence prove ee742fe + cd389395, not 7eee066 + cd389395.

Required before merge: refresh/rebase onto current main (preserving Miguel Martinez / @cervantesh's three commits and attribution), then rerun the focused compatibility + stale-purge + backup gates and obtain fresh upstream CI/Docker/Nix on that resulting exact head/current-base composition. If the rebase remains mechanical, the existing deeper cross-platform evidence remains valuable provenance; the new exact-current object still needs its own green release receipt.

So: no code-semantic blocker found in the reviewed head; one exact-current-base verification blocker remains. The decomposition itself is careful, unusually well evidenced, and substantially improves the updater's ownership topology without pretending adjacent behavior work is duplicated. Nice work getting a 10k-line mutation/restart surface into reviewable owners while preserving the ugly compatibility reality it has accumulated. 🚀

@cervantesh
cervantesh force-pushed the codex/update-cmd-decomposition branch from cd38939 to a654f00 Compare August 29, 2026 14:30
@cervantesh

cervantesh commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the careful exact-head review. I addressed the landing-composition gate in one bounded refresh.

  • Rebase integrity: the three commits are now based on main@b954547e726eb8df7479178d3db489852904705b at exact head 99daedd99928c26ba0259c54d292fb790228b71a. git range-diff reports all three patches unchanged, and authorship is preserved.
  • Local exact-head gates: the focused compatibility, stale-purge, and backup suite is 56 passed; Ruff, compileall, and diff-check are green; no changed Python file exceeds the review-specific 2,000-line guard.
  • Gateway/SCM control: test_find_windows_gateway_services_rejects_transitional_ancestor passes directly on this exact head. The previously isolated broader local gateway result remains archived; upstream Windows is green on the current composition.
  • Upstream exact-head gates: CI 33259952214, Docker 33259951830, and Nix 33259951818 all completed successfully.
  • Native supervisors: the before/after systemd, launchd, and Windows SCM contracts all compare as equivalent in run 33260176395.
  • Reproducible record: the refreshed evidence package contains the acceptance matrix, commands, raw frames, comparator reports, workflows, and verified SHA-256 manifest.

The PR remains ready for review. I will avoid daily rebase churn and refresh again if relevant updater work lands near a maintainer review/merge window, or if maintainers request it. The SHAs above intentionally define the evidence frame even if unrelated main work lands afterward.

@cervantesh

cervantesh commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

Small evidence clarification after auditing the inherited local failures: the earlier 610/42/42 versus 607/42/42 frame was a historical single-process diagnostic, not the repository's canonical per-file runner or current CI status. Its useful conclusion remains unchanged: candidate and clean base had identical failing node IDs, so those failures were not introduced by this refactor.

A canonical clean-main audit receipt assigned the independently closable test-infrastructure defects to #98037, #98038, #98039, and #98040. None touches this PR diff or changes the behavior-preserving closure predicate. I updated the evidence package, manifest, and infographic accordingly. The product PR head remains 99daedd999; no code or test changes were added here.

@andrexibiza andrexibiza left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewing the materially new exact head 49db219ea01a265cd9b1c4f0ac58368c0eff9f52 against current main@593aa74c6182ce2e5e23bc102daaaae71710c05d. This is not a repeat of my earlier cd389395... review: the branch has been rebuilt on current main and now incorporates the later updater contracts that landed in the meantime.

The final tree is substantially stronger than the earlier frame. I checked the current 21-file diff, the behavior-critical extracted owners and facade, the compatibility propagation table, stale-module generation protection, the exact four-commit chain, the current issue/PR graph, and exact-head hosted CI. The head is mergeable, has no unresolved review threads, and the exact head is green across CI 33702564967, Docker 33702564514, and Nix 33702564513. The current decomposition also correctly follows the moved Git-network inspection sites and carries the newly-landed serve-recovery / reconciliation behavior into the new owner modules rather than silently reverting it.

I do have one release-blocking history/proof defect, plus two concrete follow-ups.

BLOCKER — the active commit chain is not self-consistent / exact-commit green

The first active commit, 7c23c6d8663de920c2c877849b01cf680c451c7c, is based directly on this PR's current base, but it does not carry the abort-recovery facade ABI that current main already requires.

This is not just “no CI ran on an intermediate commit.” There is a concrete broken object:

  • Current-base tests/hermes_cli/test_update_serve_generation_recovery.py calls update_cmd._abort_recovery_is_complete(...) and update_cmd._surviving_pre_update_serve_runtimes(...) directly.
  • At exact commit 7c23c6d..., the new hermes_cli/update_cmd.py facade exports neither name.
  • The moved hermes_cli/update_fleet_restart.py at that same commit directly consumes _abort_recovery_is_complete, _surviving_pre_update_serve_runtimes, _recover_gateway_restart_after_abort, and _warn_stale_serve_runtimes through the compatibility-global model.
  • The later commit 17cdb78a4e558c8fcfc2499f194ba67aa421eae9 is exactly the repair: it imports the abort-recovery names into the facade and adds the corresponding _COMPAT_CONSUMERS propagation entries.

So the branch reaches a correct final tree by passing through an active commit that is not a valid current-main decomposition object. I also checked exact-object CI availability: 7c23c6d..., dc78338..., and 17cdb78... have no check-runs/workflow runs; only the final 49db219... object has the hosted green matrix. Final-head green cannot certify immutable earlier commits.

Required fix: rebuild the visible history so every active commit is self-consistent and receives an exact-commit green verdict. The smallest repair is to fold the 17cdb78... abort-recovery facade bridge into the initial extraction commit (preserving the superseded SHA/provenance in the PR record), then run the repository CI gates on every visible commit. I am not asking for a code redesign; this is a history-integrity / release-proof blocker exposed by a real intermediate-tree regression.

SHOULD-FIX — the generation-protection regression omits one executing owner

Production currently does the right thing: update_runtime_refresh._STALE_PURGE_PROTECTED includes hermes_cli.update_fleet_restart.

But tests/hermes_cli/test_update_stale_module_purge.py::test_purge_protects_executing_modules says it proves the “complete frozen execution graph” and its executing_names set omits hermes_cli.update_fleet_restart. That is exactly the sort of omission this decomposition needs tests to make impossible, because the failure mode is cross-generation module mixing in a live self-updater.

Please add hermes_cli.update_fleet_restart to that asserted frozen graph. The final implementation already satisfies the invariant; the durable regression should actually pin the whole claimed graph.

INTERLOCK / provenance — preserve the updater contracts this refactor is relocating

The rebase correctly absorbed newer behavior, but the PR's lineage text should name the canonical merged owners rather than leaving those changes as anonymous “current main” behavior:

  • #96235 is the historical predecessor from JoaoMarcos44, closed unmerged.
  • #100165 is the merged salvage of that serve-generation recovery, with authorship preserved.
  • #100928 is the merged success-path/reconciliation follow-on, preserving the #100490 reconciliation work and #100493 survivor-warning work plus the field-report/root-cause lineage.

This PR does not supersede those contributions; it relocates their shipped behavior into bounded updater owners. Please say that explicitly so future archaeology does not confuse extraction ownership with behavioral authorship.

There are also two live FILE-LIST collisions that need an explicit merge-order rule:

  • #92934 currently touches hermes_cli/update_cmd.py and tests/hermes_cli/test_update_stale_module_purge.py to preserve hermes_cli.update_receipt across the purge. That is a complementary generation-safety defect, not duplicate work. If #97634 lands first, that fix belongs in update_runtime_refresh.py / the relocated purge test rather than regrowing the facade. If #92934 lands first, this branch must rebase and absorb its protected-module contract into the extracted owner before recertifying.
  • #99450 is a much larger complementary updater-authority change and collides directly with update_cmd.py plus the stale-purge/update test surface. If it lands first, this decomposition must rebase and route its quiesce / restart / reconciliation semantics into the new owners; if this lands first, #99450 needs to port to those owners instead of treating the compatibility facade as the implementation surface.

Finally, #97633's issue body still names an older implementation head/base. The PR↔issue edge exists (Closes #97633), but the closure card should be refreshed to the current exact object after the history repair so the issue does not certify a superseded SHA.

Verdict

Final-tree semantics: no new blocker found. Active-history/release object: blocker remains.

The hard part of this rebase was done well: current-main behavior is actually composed rather than overwritten, the compatibility bridge is explicit, the extracted owners remain bounded, and exact-final-head CI is green. Fix the broken intermediate object, pin update_fleet_restart in the frozen-graph regression, and make the merged provenance/merge-order edges explicit; then this becomes a much cleaner landing object rather than merely a clean final snapshot. 🚀

@cervantesh
cervantesh marked this pull request as draft September 3, 2026 02:03
@cervantesh
cervantesh force-pushed the codex/update-cmd-decomposition branch from c8d7493 to 3e695cd Compare September 3, 2026 02:27
Split the self-update implementation into bounded owner modules while preserving the update_cmd compatibility facade and current runtime behavior. Keep the shipped recovery and reconciliation contracts from NousResearch#100165 and NousResearch#100928 intact, and pin the complete frozen updater execution graph.
@cervantesh
cervantesh force-pushed the codex/update-cmd-decomposition branch from c8d7493 to 3e695cd Compare September 3, 2026 02:29
@cervantesh cervantesh closed this Sep 3, 2026
@cervantesh cervantesh reopened this Sep 3, 2026
@cervantesh

Copy link
Copy Markdown
Contributor Author

@andrexibiza, thank you for the exact-object review. I addressed each item in the current review frame.

Ready-for-review receipt

  • Base: main@48c0c3a873bc5adaf20c632b5b7630a4fac000b4
  • Exact head: d205375a3a63c440fefc14e0a777700f24a8d12e
  • History: one atomic commit, authored by cervantesh

The previous four-commit chain is superseded. The extraction, abort-recovery facade exports, compatibility propagation, relocated source-inspection tests, and frozen-graph regression now coexist in one visible commit, so there is no active intermediate ABI gap. The prior SHAs remain in the review record for archaeology, but are not presented as certified objects.

The frozen execution-graph regression now explicitly includes hermes_cli.update_fleet_restart, matching production protection. The test also records that its literal owner set must stay synchronized when the protected execution graph grows.

The PR and #97633 now identify the shipped behavior provenance: #96235 as the historical unmerged predecessor, #100165 as the merged serve-recovery salvage, and #100928 as the merged success/reconciliation follow-on preserving the #100490 and #100493 lineage. They also state the merge-order rules for #92934 and #99450. Neither live PR's implementation is incorporated or duplicated here.

Current exact-head evidence:

  • focused updater/compatibility matrix: 154 passed locally;
  • structural mapping: 181/181 original functions accounted for, 175 AST-identical and 6 declared extraction adaptations;
  • facade surface: 226/226 historical top-level names preserved;
  • Ruff, compileall, and diff-check: passed;
  • extracted production modules: all below the review-specific 2,000-physical-line guard;
  • CI 33708334479: passed, including Python, E2E, macOS, Windows, lint, security, attribution, and the required-check aggregator;
  • Docker 33708333779: amd64 and arm64 passed;
  • Nix 33708333814: passed.

The PR body and issue closure card now point to this exact frame. With the requested history, regression, provenance, and interlock updates in place—and all required checks green—I am returning the PR to Ready for Review.

@cervantesh

Copy link
Copy Markdown
Contributor Author

Current-main supersession review

I refreshed the integration frame before attempting another rebase. The correct disposition has changed: #102117 merged an independent whole-codebase decomposition and already implements this PR's structural objective on current main@1e69c12b64dba4090eddffeae27f5a147068d34b.

Verified on that exact main:

  • hermes_cli/update_cmd.py is now a 1,353-line compatibility facade over eight focused update_cmd_* owners; every owner is below 1,400 physical lines.
  • The facade retains 225/226 names and 180/181 functions from this PR's original surface. The one missing private helper, _gateway_restart_recovery_profiles, was deliberately removed and had no caller beyond its former lazy re-export.
  • The executing updater graph is protected in production by _STALE_PURGE_PROTECTED.
  • Focused facade, import, stale-generation, recovery, fleet, receipt, and moved-owner tests: 144 passed, 1 Linux-only test deselected on this Windows host.
  • Static validation: Ruff passed and compileall exited 0.
  • Hosted checks for the exact current-main SHA: 49 successful, 41 path-gated/skipped, 0 failed.

I also reviewed what remains unique here. This branch propagates arbitrary reassignment of private facade globals into extracted owners through _COMPAT_CONSUMERS and a module-level __setattr__. Current main deliberately uses owner-aware patch seams instead; commit ba030bc0db updated tests accordingly. I found no production consumer that requires the broader private monkeypatch bridge, so carrying it forward would not preserve a demonstrated user-facing contract.

One non-blocking test-hardening opportunity remains: current production protects all eight split updater owners, while test_purge_protects_executing_modules only directly asserts the package, facade, and main. That is not a current runtime defect and should not keep this large branch alive; if pursued, it should be a small behavior-oriented guard rather than this PR's literal module snapshot.

A rebase preview conflicts in six shared files and would retain both this PR's 13-owner topology and main's update_cmd_* topology. Resolving that would amount to recreating #102117, not refreshing a relevant patch. I am therefore closing this PR as superseded / implemented independently on main, without merging or force-pushing it. The branch, prior reviews, evidence package, and infographic remain available for historical provenance. Git history contains no cherry-pick of this PR's commit into #102117, so the respective authorship records remain distinct.

@cervantesh cervantesh closed this Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/install-update Installer, updater, packaging, wheels, doctor comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have platform/windows Native Windows-specific behavior or breakage sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows type/refactor Code restructuring, no behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor(update): decompose update_cmd.py without changing behavior

3 participants