Skip to content

bug(deploy): the code-sync path installs three components' requirements without the constraint rewrite — the same abort #14272 fixed for ansible #14275

Description

@mrveiss

Problem

The code-sync / self-update path — the mechanism CLAUDE.md designates as the only way system
updates may reach a host — installs three components' requirements without rewriting their
relative constraint includes.

autobot-slm-backend/services/role_registry.py:

:251  ai-stack    cd {BASE}/autobot-ai-stack   && pip install -r requirements.txt
:286  npu-worker  cd {BASE}/autobot-npu-worker && pip install -r requirements.txt
:301  tts-worker  cd {BASE}/autobot-tts-worker && pip install -r requirements.txt

Both worker requirements files carry a relative constraint:

autobot-npu-worker/requirements.txt:6   -c ../constraints/shared.txt
autobot-tts-worker/requirements.txt:6   -c ../constraints/shared.txt

Only backend's post_sync_cmd (:129) delegates to
scripts/build-filtered-requirements.sh, and its own comment at :124 says why:

A bare pip install -r requirements.txt would error on the [missing constraint file]

Three siblings do exactly that bare install.

Why this matters now

#14272 fixed the ai-stack's ansible deploy path. This is its other path, and the one an
operator actually reaches from the maintenance UI. A code-sync of npu-worker or tts-worker
plausibly reproduces the same abort:

ERROR: Could not open constraint file: '/constraints/shared.txt'

It depends on whether {BASE}/autobot-npu-worker/../constraints/shared.txt exists on the host —
i.e. whether the deployed layout preserves the repo's sibling relationship. The ansible path did
not, which is what #14272 was.

Secondary drift on the ai-stack entry

role_registry.py's ai-stack entry has source_paths: ["autobot-ai-stack/"], but that repo
directory holds only a placeholder README.md — the real files live under
autobot-infrastructure/shared/docker/ai-stack/. Its post_sync_cmd also expects
requirements.txt while the ansible role deploys requirements-ai.txt. So that entry may be
inert rather than live, which is its own problem: a sync path that silently syncs nothing looks
identical to one that works.

Fix

Acceptance criteria

  • A code-sync of npu-worker and of tts-worker installs with the shared pins applied, proven on
    a host rather than by diff.
  • A new post_sync_cmd cannot pip-install a requirements file carrying a relative include
    without the rewrite — asserted by a test that reads role_registry.py, not only YAML.
  • The ai-stack entry either syncs the files that actually exist, or is gone.

Context

Found reviewing PR #14273 (#14272), which fixed the ansible half. Same defect, different deploy
trigger — and the trigger the operator uses.

Activity

  1. github-actions commented on Aug 15, 2026

    @github-actions
    Contributor

    PR #14276 (merged to Dev_new_gui) references this issue with a close keyword.

    fix(deploy): code-sync updates the install instead of discarding it (#14275)

    If this issue is fully resolved, close it manually. If work remains, no action is needed.

  2. mrveiss commented on Aug 15, 2026

    @mrveiss
    OwnerAuthor

    Closing — delivered and verified in base

    PR #14276 merged into Dev_new_gui.

    Evidence, read from the base tip:

    _rsync_source_path has a delete flag : False
    returns False on a missing source    : True
    bare `pip install -r` remaining      : 0
    tests/services/…14275                : 14 passed
    

    What this changes for an operator

    Code-sync is an update procedure. It costs downtime; it no longer costs the installation.

    • The rsync onto a node's target_path no longer deletes. The venv, the ansible-generated src/
      symlinks and the deployed app files survive, so the service restarts instead of needing a
      re-provision. The two rsyncs that write the checkout into the sync cache keep the delete flag —
      they carry the full tree, and I verified that before assuming they shared the defect.
    • source_paths for ai-stack points at the real sources. It pointed at a directory holding one
      README, so a sync copied that README over the live install and reported success.
    • A source path missing from the checkout fails instead of returning True, "skipped".
    • All four components install with venv/bin/pip — the interpreter their unit actually runs.
      slm-backend was also running alembic from system Python, migrating with a different
      interpreter than the service.
    • A failed post-sync command stops the sync before the restart and before the DB record. It
      used to be logged at WARNING and ignored, so a failed pip install produced a green sync with
      nothing installed.

    Four defects found in my own work along the way

    Three were the same shape — asserting on source text rather than behaviour — and each survived
    the mutation it existed to catch:

    1. "HOST_STATE_EXCLUDES" in source stayed true after the excludes left the argv; the import
      line
      still named them.
    2. Reading rsync_artifact_excludes() directly could not see a second exclude set added back.
    3. "returncode" in body and "return False" in body stayed true after
      if proc.returncode != 0: became if False: — both words survive in the dead branch.

    The fourth was worse: I applied HOST_STATE_EXCLUDES here because it is the canonical vocabulary
    api/code_sync.py protects — canonical for that layout. On this path data/, config/ and
    .env.example are tracked source (autobot-backend/, autobot-frontend/,
    autobot-slm-backend/), so excluding them would have made the update silently incomplete: the
    exact failure this issue is about, reintroduced by its own fix.

    Recorded as [assert behaviour, not source text] in the session's memory, since four instances in
    one PR is a habit rather than an accident.

    Still open

    #14279 — the AI stack's spacy build failure on Python 3.14 — is a separate cause in the same
    provisioning run and is not addressed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions