Skip to content

fix(deploy): rewrite the AI stack's constraint path at any depth so provisioning completes (#14272) - #14273

Merged
mrveiss merged 2 commits into
Dev_new_guifrom
issue-14272
Aug 15, 2026
Merged

mrveiss merged 2 commits into
Dev_new_guifrom
issue-14272

Conversation

@mrveiss

@mrveiss mrveiss commented Aug 15, 2026

Copy link
Copy Markdown
Owner

Thinking Path

The error names an absolute path nothing in the repo writes:

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

requirements-ai.txt:25 says -c ../../../../constraints/shared.txt, which is correct where
the file lives
— four levels up from autobot-infrastructure/shared/docker/ai-stack/ is the
repo root. The role copies it to /opt/autobot/autobot-ai-stack/ and pip-installs it in place,
where four levels up is /.

The interesting part is that this was already solved. scripts/build-filtered-requirements.sh
exists for exactly this and says so in its own header — "Without this, pip errors on the missing
constraint file"
(#11117). The backend role and services/role_registry.py both use it. The
ai-stack role never did.

And it would not have worked if it had: the sed matched ^-c \.\./constraints/ — literally two
dots, the backend's depth. A rewrite that only handles the depth it was written against does not
transfer to its next caller.

What Changed

The rewrite is depth-agnostic: (\.\./)+ for both -c and -r, via sed -E.

The ai-stack role now runs the canonical script and installs its output, instead of pip-installing
the copied file raw. One implementation, not a second sed — the backend already shares this script
with role_registry.py, and adding another copy is how the original divergence happened.

Verification

13 tests. Mutation-checked:

mutation result
restore the single-depth \.\./ pattern 7 failed
point the role back at the raw copied file 1 failed
make the copy scan blind to loop:-driven sources 1 failed
(restored) 13 passed

Rewrite probed directly at depths 1 and 4:

-c ../constraints/shared.txt          -> -c /opt/autobot/code_source/constraints/shared.txt
-c ../../../../constraints/shared.txt -> -c /opt/autobot/code_source/constraints/shared.txt

Two defects in my own tests, both worth recording

The invariant test was vacuous. It excluded paths containing .worktrees/venv by checking
candidate.parts on the absolute path — and it runs from .worktrees/issue-14272/, so every
file was excluded and the scan reported clean having read nothing. Same shape as the bug it
guards. Fixed by filtering on the path relative to the repo root.

Then it was over-broad. Matching pip targets to repo files by basename flagged four false
offenders, because a hardcoded deploy path like /opt/autobot/app/requirements.txt cannot be
traced back to a source file from the YAML. Narrowed to the mapping the YAML does determine: a
file the same role copies and then pip-installs. That is exactly this bug's shape and cannot
guess.

The third mutation exists because the first version of that narrowed rule read only src: — the
ai-stack role uses src: "{{ item }}" with a loop:, so the scan found no copies and the rule
was vacuously true for the very role this issue is about.

Risks

The AI stack now installs requirements-ai-filtered.txt. If the rewrite ever produced an empty
file, pip would install nothing and succeed — worth watching on the first run, though the
constraint line surviving is what the tests pin.

Model Used

Opus 5 (1M context).

Closes #14272

@github-actions

Copy link
Copy Markdown
Contributor

✅ SSOT Configuration Compliance: Passing

🎉 No hardcoded values detected that have SSOT config equivalents!

@mrveiss

mrveiss commented Aug 15, 2026

Copy link
Copy Markdown
Owner Author

Two things I checked on this myself before the review lands, both worth recording.

The widened pattern changes one existing file's output, and it is a fix rather than a regression. autobot-backend/code_analysis/requirements.txt carries -c ../../constraints/shared.txt — two levels. The old single-depth pattern silently left it alone:

- -c ../../constraints/shared.txt
+ -c /opt/autobot/code_source/constraints/shared.txt

So that file had the same latent defect as the AI stack's: had it ever been installed from a directory at a different depth, pip would have failed the same way. No role installs it through this script today (grep finds no invocation), so nothing changes in practice — but it is a behaviour change in a shared script and should not be discovered by someone else later. autobot-backend/requirements.txt is byte-identical before and after.

The empty-output trap fails loud, not silent. A requirements file consisting only of the -e ../autobot_shared line makes grep -Ev match nothing, which exits 1; with set -o pipefail the script exits 1 and the ansible task fails the play. Verified directly:

exit=1  bytes=0

That is the safe direction — pip never sees a 0-byte file and "succeeds" installing nothing. Pre-existing behaviour, not introduced here, but it is the failure mode I flagged as a risk in the PR body and it turns out to be already handled.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant