Repository navigation
fix(code-sync): delete files removed from source through the updater, and check drift across every file (#16310, #16322) - #16351
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Two corrections to the description, posted as a comment so editing the description doesn't cancel in-flight CI:
CI runs everything else. ansible-lint wasn't run locally, and no repo code was executed by hand, per the repo rule. The two moved tests are cited in the description at their new |
Second-session review of 32d73ea: changes requested (1 blocking)Read from the PR head and base BlockingB1. The delete step can't run under
Non-blocking
Verified
|
✅ SSOT Configuration Compliance: Passing🎉 No new hardcoded values of either class — Known backlog in |
|
Coordinator's independent review of round 12, Checked by running the real step, not by reading assertions:
Confirmed by reading:
Low, not pursued in this PR:
|
Second-session delta review,
|
|
Round 13, The three notes from Helper-02's round-12 delta review:
Two guards for single-node installs (raised by the owner: on an all-in-one host every component's directory is on one filesystem). New file
Line numbers in |
Second-session delta review,
|
|
CI red at The template passes each Fix: the helpers only read, so type their parameter as |
|
CI red at Fix: |
|
Delta
The approval covers the code only. CI was still queued at this head, so merging still needs it green. |
api/__init__.py eagerly imports every router, and .agents (the first one) imports config.settings -- so every api.x module's own import transitively constructed Settings(), whose external_url field called _get_local_ip() (a real socket.connect, #2758's local-IP probe) as a plain class-body default. That ran unconditionally at import time, which is exactly the effect the import-hermeticity sweep (#16198) is built to catch, and is what all 51 SLM api.* modules in import_hermeticity_known_offenders.py were actually inheriting from one shared cause. Converted external_url to a computed, cached property: the env-var override is still checked first, and the socket probe only runs on the first actual access of settings.external_url, cached afterward since the machine's outbound IP does not change during the process's lifetime. No call site changes -- all ~10 readers access it as a plain attribute, unaffected by the property.
…ps (#16262) Review from the delta on 3426b6e: @computed_field makes the property participate in settings.model_dump()/.json() -- a future dump or serialization path would re-run the socket probe this fix exists to defer, the same class of hidden side effect being removed. Nothing today calls those (checked: no model_dump/.json()/jsonable_encoder/ whole-object logging of settings anywhere in autobot-slm-backend), but keeping it dump-visible "for consistency" was speculative -- plain @cached_property gives every current reader (~10 call sites, plain attribute access) identical behavior without that exposure.
CI's own scoped sweep (run 34758956096, head 331c10f) reported these 4 baseline entries examined and no longer failing after the config.py fix: api, api._resume_plan, api.code_sync, api.venv_reconcile. Removed exactly those, per the baseline's own shrink-only rule -- not guessed, not assumed from the root-cause analysis alone, but read directly from the guard's own pass/fail verdict on this exact head. The other 47 previously-listed api.* entries were not examined by this PR-scoped sweep (their files are outside this diff's changed-file set) and are left untouched; whether they also clear is for whichever PR's diff next reaches them, or a full sweep, to determine.
…ers (#16262) Full-population sweep, dispatched specifically to probe every listed module rather than the PR-scoped subset (workflow_dispatch run 34760508167 on this branch): "47 baseline entries were examined and no longer fail that way." Removed exactly those 47, read directly from the run's own verdict -- the same evidence discipline as the earlier 4-entry shrink, just against the full population this time. Combined with that earlier shrink, all 51 of the SLM's api.* entries (including the package's own __init__) are now gone from the baseline; the two remaining entries (autobot-backend api.multimodal/api.vision) are an unrelated write-outside-tree effect, not touched by this fix. Closes #16262
|
Delta review, head moved twice since the last verdict (b6fd5ac → 49e3dea → now cb0a3b5): approve. Two new commits, both checked against their own evidence:
CI at cb0a3b5: 0 fail, 0 pending. |
Closes #16322. Refs #16310 (AC5 needs host evidence from a real GUI update). Refs #16262 (fixed the root cause -- config.py's external_url socket probe at import time -- and shrunk 4 of the 51 known-offender baseline entries this PR's own diff reached; the remaining 47 need a full sweep or other PRs to clear before #16262 itself closes).
Thinking Path
npu_workers.yamlleft by a fixed cwd bug. The owner ruled: no manual patches, and a drift check that covers every file..deployed_commitmid-update (CRITICAL: one-click update never redeploys the SLM control plane — self-update skip reads code_source HEAD (advanced by the pull) not the deployed commit #12202). That would have made self-update skip the real sync on every host. A normal Update All also runs a playbook that restarts the SLM part-way through, so Python never sees a success to act on..deployed_commitrealpathcontainmentbackendrole only throughtasks_from: env_only/unit_only, nevermain.yml. That's the CRITICAL(deploy): Update-All uses inline tasks and applies only backend/env_only — every fix landing in an Ansible role is inert on hosts (#12777 faulthandler, #12907 consolidation, #12886 TTS all merged but never delivered) #12959 trap. So deletion is wired after every sync taskupdate-all-nodes.ymlactually runs, and the tests prove reachability, not just ordering.shelltask usingset -euo pipefailwith noexecutable, so it ran under/bin/sh, which is dash on Ubuntu. dash rejectspipefail("Illegal option"), so every run fell intorescueand nothing was ever deleted. The tests ran the step withbash -c, so CI couldn't see it. Round 12 fixes B1 and all six non-blocking findings.What Changed
Planner (runs on the controller, never on the target):
autobot-slm-backend/services/sync_deletions.py: pure planning.-M --diff-filter=DR)ls-treepluslog -M --diff-filter=AR, 2 git calls in total)_commit_known) returnsbootstrap_requiredinstead of an error, so it no longer rescues forever in silenceservices/host_state_filter.py:HOST_STATE_EXCLUDESplusgit check-ignore.services/git_subprocess.py: onerun_gitchokepoint with-c core.quotePath=false.scripts/sync_deletion_planner.py, which also reportsbootstrap_required.Ansible:
ansible/roles/_shared/tasks/sync_deletions.yml, oneblock/rescue/always:.deployed_commitonlydelegate_to: localhost, and switch to bootstrap mode when the planner asksansible.builtin.copy, read withIFS= read -r. There's no heredoc any more, so a path named like the terminator can't end the list.realpath -mon the target, and keep anything outside the rootrm -f --, run underexecutable: /bin/bashrescuewarns and never writes the marker.alwaysremoves both temp files, the one on the controller and the one on the target.Wiring on the update path (
playbooks/update-all-nodes.yml): the pass runs right after the sync task of every component the updater touches. Each one is pinned by its exact target directory.:319:375:326:384autobot_sharedon the SLM (PLAY 1):333:393libs, workspace packages (PLAY 1, new in round 12):342:408autobot-plugins, workspace packages (PLAY 1, new in round 12):349:417:774:804autobot_shared:782:838:1233:1255:1306:1329:1454:1475:1614:1632:1666:1688copytasksroles/slm_agent/tasks/main.yml, which both plays import in fullThe provisioning paths (
provision-fleet-roles.yml,ansible/site.yml,deploy-slm-manager.yml) keep themain.ymlwiring. That's two call sites of one shared task file, not two mechanisms.The marker
.autobot_sync_deletions_commitis excluded from all 6 delete-style syncs, and it's inHOST_STATE_EXCLUDES.AC3:
services/slm_frontend_build.py_remove_legacy_previous, called from the publish step (_swap→_publish_build→build_slm_frontend).AC4:
roles/backend/tasks/npu_workers_cleanup.yml, included on the update path inupdate-all-nodes.ymland frommain.yml. It removes the nestednpu_workers.yamlonly when both copies exist and their sha256 checksums match, and otherwise reports.DELIVERED["backend"]intests/test_update_all_applies_roles_12959.pyincludesnpu_workers_cleanup.Drift covering every file:
services/full_tree_drift.pyandGET /code-sync/drift/full, with verdictsmodified,removed_from_source(plus its commit),build_bundleandhost_state:<category>FullTreeDriftPanel.vueon the Code Sync page, filterable by verdict, with its own error stateopenapi.json/api.tscome from the repo's types botConsolidation: the Python apply calls are gone from
api/code_sync.py, now 6084 lines instead of 6094, with both ceiling files lowered.Verification
tests/services/sync_deletions_test.py:bootstrap_required, while known and same commits never ask for itscripts/sync_deletion_planner_test.pytests/services/full_tree_drift_test.pyrepo_tests/sync_deletions_ansible_wiring_16310_test.py:.deployed_commitis never toucheddeploy_artifactsnpu_workersgating, and its delivery on the update path/bin/shdefault if none is declared), from a list file, including a candidate named like the old heredoc terminatorrepo_tests/sync_deletions_target_pinning_and_shell_safety_16310_test.py, new in round 12:sync_deletions_target_dir, so removing any one failsexecutable: /bin/bash, with a guard-the-guard testalways:, never only inrescue:test_site_yml_frontend_play_applies_only_existing_rolesisxfail(strict=True)for site.yml's Frontend play references a nonexistent rolefrontend_app#16342, a pre-existing brokenfrontend_appreference.FullTreeDriftPanel.test.tscovers the three verdict kinds, the filter, and the panel's own error state.--strip-components=4and slm-agent's per-file copies./var/lib/...,/var/log/...).servicesstub (fixed by moving two tests undertests/services/), a hostile filename containing/, and an empty commit missing--allow-empty. CI runs everything else. ansible-lint and--syntax-checkweren't run locally, and no repo code was executed by hand, per the repo rule.slm_manager's oldsynchronize … delete: trueinto this mechanism is deploy: consolidate slm_manager's delete:true synchronize into the git-aware deletion pass #16338.Model Used
Claude Opus 5 as coordinator. A senior-backend-engineer subagent did the implementation over twelve rounds. Each round was reviewed by independent code-reviewer subagents, and round 12 answers a second-session review by another Claude session (Helper-02).
🤖 Generated with Claude Code