It read "The API key is intentionally not required. Some OpenAI-compatible APIs
do not require a key", while validate_config.yml fails when the key is empty and
the provider is enabled. Enabling the provider against a keyless endpoint stopped
with "You need to define a required configuration setting".
baibot is the authority here, and it agrees with the validation rather than the
comment: `openai::Config` takes `api_key: String`, whereas the provider whose key
really is optional is a different one, `openai_compat`, with
`api_key: Option<String>`. So the comment described a real baibot feature, just
not this provider's.
The validation stays as it is; the comment now says what the code does, and
points at the provider the keyless case belongs to.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SEH3vxYSQ5SV4N5z61eyGT
They were hard-wrapped at 80 characters, broke mid-parenthesis, and spent lines
restating what the code below them does.
Rewrapped at natural boundaries instead, with the narration dropped and only the
reasons, gotchas and surprises kept. Section dividers stay - they delineate long
plays rather than narrate them.
Comments only; no scenario behaviour changes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SEH3vxYSQ5SV4N5z61eyGT
Scenarios install their Galaxy dependencies with `force: true`, so two roles
running at once re-extract the same collections and roles into ~/.ansible and
pull them out from under each other mid-play. It surfaces as a collection that
was working moments earlier going missing:
the connection plugin 'community.docker.docker' was not found
Found while running five scenarios in parallel, where it cost a run.
ANSIBLE_HOME relocates both `collections/` and `roles/`, so one variable covers
both halves; the scenarios' ANSIBLE_ROLES_PATH workaround now follows it rather
than hardcoding ~/.ansible/roles. Left alone if already set, and unset in CI,
where each role runs in its own job and has nothing to collide with.
Verified by removing var/molecule-ansible-home entirely and running
matrix-alertmanager-receiver from cold: green through idempotence, with the
collections and roles landing under the per-role directory - which also shows
nothing was quietly relying on the shared ~/.ansible being populated.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SEH3vxYSQ5SV4N5z61eyGT
baibot is the first bot rather than a bridge, and the shape
differs from the appservices: it is a plain Matrix client that logs in with a
password, sets up its profile and then syncs. It publishes no port, so nothing
can be probed over HTTP; what it says about itself in the journal is the only
window into whether the role's configuration reached the process.
What the scenario proves:
- The unit is active with no automatic restarts, AND baibot got past startup
into its sync loop. The second half is what carries the scenario. baibot never
exits when startup goes wrong - it retries the failing step forever with a
growing delay - so the unit sits there `active` with `NRestarts` at 0 while
the bot is permanently half-started. Pointing `user.avatar` at a file that is
not there reproduces exactly that: the unit assertion still passes, the sync
assertion does not.
- The display name the bot announces it wants is the role's `user.name`, which
is neither the role's default nor what the stub reports the account already
has.
- The rendered `logging` string took effect per target: baibot's own records
appear at DEBUG (the role ships `info`) while everything underneath stays at
the `warn` catch-all. The second half is the control, and raising the
catch-all turns 2 DEBUG records into 161.
- The rendered config carries the scenario's homeserver, identity, command
prefix, admin patterns and user patterns, and uses password authentication
exclusively, with the access-token keys rendered as nulls.
- The statically-defined agent survived the provider templating - the
per-provider template rendered to YAML, parsed, merged and nested into the
list - key by key.
- The container runs as the uid/gid the playbook supplies (1234, not the 1000
the base image already has), on the image version defaults/main.yml pins, and
could write its session into the data path.
No AI provider is contacted and none is needed. baibot calls a provider only
when a message asks an agent to do something, so a static agent with a
placeholder key and a base URL that resolves nowhere still has to survive the
bot's startup parsing - which is the part worth testing.
The shared stub grew what a syncing Matrix client needs and an appservice did
not: /sync (with a `next_batch`, and holding the call open for the timeout the
client asked for, or the bot spins the stub in a hot loop), the media config
and upload endpoints a bot setting its own avatar insists on, /keys/upload with
its key counts, and filter creation. Without the media config in particular,
baibot never gets past profile setup.
The shared stub task gained a STUB_VERBOSE knob. The stub already advertised
the environment variable but there was no way to set it from a scenario, and
for a component with no port of its own its request log is the only place to
see what the component is actually asking for.
Note: molecule-shared/homeserver-stub.py also carries a loosened /login match
from another scenario being written in this same tree at the same time; it was
already in the working copy and is not mine.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SEH3vxYSQ5SV4N5z61eyGT
6b4b7647e fixed this for synapse-usage-exporter only. A checkout owned by
a different user makes the git task fail from then on, either with a
permission error or with git's dubious-ownership protection, until
someone removes the directory on the host by hand. It gets into that
state when the matrix user's uid changes (a server migration or a restore
onto a differently numbered user), when an earlier clone ran as another
user, or when someone runs git as root inside the checkout.
Every other role cloning a repository onto the server was open to the
same failure, so ensure the checkout's ownership recursively before
updating it at the remaining 54 sites.
The three matrix-synapse ext clones also gain force=yes. They were the
only on-server clones without it, which left a checkout that an
interrupted run had half-written wedged, instead of repaired on the next
run.
matrix-matrixto used to clone as root into a directory that nothing ever
chowned, unlike every other role. It now becomes the matrix user too.
The Element Web and SchildiChat Web theme checkouts live on the Ansible
controller, where correcting ownership is not ours to do, so they merely
mark the checkout as a safe directory for git.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat: support container_network=host across all roles + systemd templates
Mirror the pattern Slavi introduced for matrix-coturn (aafa8f0) across the
fork: every 'Ensure X container network is created' task gets a
'when: <var> not in ["", "host"]' guard so MDAD does not try to
docker_network create a network literally named 'host' (returns 403,
since host is a pre-defined Docker network).
Mirror the same guard in every systemd unit template that does
'ExecStartPre=docker network connect <addnet> <container>' loops over
matrix_<role>_container_additional_networks: skip the connects when the
container is on host networking (where additional --network attaches
are invalid).
Unblocks DiD setups where MDAD-managed containers share their host's
network namespace (matrix-mdad outer compose service joined to central
postgres/openldap networks) to reach external services on the outer
Docker daemon.
* Simplify container network guards (!= 'host') and fix duplicate when
Guarding on the empty string ('') as well was misleading: systemd unit
templates still render an unconditional --network= flag, so an empty
network value produces a broken docker create command. Only 'host' is
actually supported, so only guard on that. This also matches the
existing convention in the Traefik role
(when: traefik_container_network != 'host').
Also fix a duplicate when key in the meshtastic-relay role, where the
network-creation task already had a when condition - the two are now
combined into a list.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Slavi Pantaleev <slavi@devture.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Replaces `community.docker.docker_image` with the modern
`docker_image_pull` and `docker_image_build` split modules. Drops the
`ansible_version` compatibility ladder and the now-redundant
`_container_image_force_pull` variable (the new pull module handles
registry refresh natively via `pull: always`). Also registers
`_container_image_build_result` so that a self-build rebuild correctly
triggers a service restart.
Related to https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/5191.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
For each of the 34 roles (3 clients, 9 bots, 22 bridges), this commit:
- Adds `_restart_necessary: false` default variable
- Adds `register:` directives to config/image/systemd tasks
- Computes `_restart_necessary` via set_fact (OR of all .changed results)
- Wires `(_restart_necessary | bool)` in group_vars/matrix_servers
This allows the systemd service manager to skip unnecessary restarts
when running install-* tags and nothing actually changed.
Service roles and complex multi-service roles will follow separately.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>