Repository navigation
Umbrella: post-sync actions are unordered, duplicated, unexplained, and absent from the sync record #17452
Description
The bar as it renders today
A node's post-sync bar rendered 22 buttons in this order (owner report):
1 Restart postgresql 9 Restart autobot-celery 17 Build (Frontend UI)
2 Restart redis-stack-server 10 Restart autobot-celery-beat 18 Restart autobot-chromadb
3 Install deps (AI Stack) 11 Install deps (TTS Worker) 19 Install deps (Browser Automation)
4 Restart autobot-ai-stack 12 Restart autobot-tts-worker 20 Restart autobot-playwright
5 Restart ollama 13 Install deps (Shared Library) 21 Run migrations (SLM Backend)
6 Restart ollama <-- dup 14 Build (SLM Frontend) 22 Restart autobot-slm-backend
7 Install deps (NPU Worker) 15 Run migrations (Backend API)
8 Restart autobot-npu-worker 16 Restart autobot-backend autobot-celery
Four distinct defects, one surface.
1. There is no execution order. get_node_actions (autobot-slm-backend/api/roles.py:576)
walks the node's roles and extends a list per role, so the output order is role iteration order.
Restart autobot-celery is at 9 while Install deps (Shared Library) is at 13 and
Run migrations (Backend API) at 15 — clicking left to right restarts a service before the code and
schema it will load are in place.
2. The same unit is scheduled twice, in two ways that need different detection:
ollamaat 5 and 6, identical labels — the unit is owned by bothautobot-llm-cpuand
autobot-llm-gpu(SLM role shape has two sources of truth: role_registry.DEFAULT_ROLES vs autobot-infrastructure/*/manifest.yml #16025), so a node holding both roles gets one restart action from each.autobot-celeryat 9 and inside 16, different labels. Any comparison of what the reader sees
— label, command,(role, category)— misses this one.
3. Nothing says WHY an action is needed. PostSyncAction (roles.py:108-116) carries
role_name, display_name, category, label, command, systemd_service — and no field for
the change that triggered it. The owner's words: "it just displays there is package update, not
saying what is needing this update and how to do it." A reader sees Install deps (AI Stack) with
no way to know requirements-ai.txt changed, let alone which requirement.
4. The automated path and this bar are two surfaces that disagree. sync_orchestrator.py DOES
run post-sync automatically and in the right order per role
(_run_post_sync_cmd → _restart_systemd_service, lines 216-245). But it logs to the application
logger only, there is no durable per-action record, and nothing cross-role orders it — so the bar is
a parallel manual surface that re-derives the same work and loses the ordering. The owner asks for
these actions to be part of the code-sync process and its logs, not a separate button bar.
Tasks
- Task 1: order the plan and restart each unit once → the ordering/dedupe fix
- Subtask 1.1:
autobot-slm-backend/api/_post_sync_plan.py— category rank + unit dedupe - Subtask 1.2:
autobot-slm-backend/api/roles.py— call it fromget_node_actions - Subtask 1.3:
PostSyncActionBadges.vue— number the badges, document that the order is the server's
- Subtask 1.1:
- Task 2: carry the trigger, so an action says what needs it
- Subtask 2.1:
PostSyncActiongains a trigger (changed path / requirement / reason) - Subtask 2.2: the producer fills it from what the sync actually changed
- Subtask 2.3: the badge shows it, and the tooltip explains how
- Subtask 2.1:
- Task 3: make post-sync part of the sync record
- Subtask 3.1: a durable per-action record on the sync run (started, exit, output tail)
- Subtask 3.2: cross-role ordering and unit dedupe in
sync_orchestrator, reusing Task 1's policy - Subtask 3.3: surface the record where the run is shown, so the bar is a fallback rather than the only view
Task 1 is independent. Tasks 2 and 3 both depend on it: Task 3 reuses its ordering policy rather
than growing a second one, and Task 2's UI shows the trigger on badges Task 1 orders.
Why one umbrella
All four come from the same place — a per-role classifier whose output is concatenated with no
node-level plan. Fixing them separately would put four different node-level policies in four
places, which is the defect one level up.
Activity
guard(paths): parse the imports and the sys.path argument, do not gre…
fix(deploy): the pre-flight unshallow could not import autobot_shared…
fix(orchestration): order post-sync actions and restart each unit once (