The repo's async convention is fire and forget: ASYNC_POLL is 0 whenever
ASYNC_ENABLED is true, and the swarm test lane forces it true through
extra vars. A task dispatched that way returns a stub, so a changed_when
or failed_when reading its own register evaluates against nothing and can
never report changed and never fail. Several tasks carried a
"not ASYNC_ENABLED and" prefix in front of those conditions, added to
avoid touching undefined rc and stdout, which turned the guard off
entirely rather than adapting it.
That is how the nextcloud plugin configuration stayed broken unseen: the
batch reported ok after 0.8s while its delegated commands kept running,
the next task read the half written configuration, and no failure in any
of them could surface.
Every async in the repo was decided individually rather than swept. Where
nothing consumes the result, the async stays and a one line rationale now
records what does not read it. Where a later task, a handler or a browser
does consume it, either the async goes or the result is collected.
Collecting is what the new reaper does. It waits for a whole batch, then
reports every broken job at once instead of aborting on the first, so one
run shows whether a single item or the whole set is broken. Deciding what
counts as broken lives in a filter plugin, because the distinction is
subtle enough to deserve tests: a module reports failure in msg, a command
in rc and stdout, an idempotent API answers "already exists" and means
success, and a job that cannot be read at all comes back marked finished
with no outcome, which would otherwise read as green.
Timing cost is roughly one to two minutes on a deploy measured in hours.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
taiga-back applies migrations from its own entrypoint on every boot. The
manager sidecar then ran 'manage.py migrate' too, and in compose there
is no converge wait, so the two applied the same migrations at once and
aborted with a duplicate-object error ("column ... already exists").
Swarm passed because its converge wait means taiga-back is already
migrated before the manager runs. Make the manager only wait for the
migrations to be applied ('migrate --check', read-only, retried) instead
of applying them, so taiga-back stays the sole migrator. No-op in swarm
where the check passes immediately.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The taiga-manager entrypoint 'python manage.py' exited immediately (no subcommand), crash-looping so migration exec hit 'No such container'. Give it a durable entrypoint and invoke django via 'python manage.py <cmd>'. Also render the frontend conf.json unconditionally since compose mounts it always.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
container exec/inspect ran on the swarm manager while the task may run on
a worker, yielding No such container or an empty container id. Use the
existing resolve_host_cid helper (HOST_NODE + LOCAL_CID + delegate_to)
for the ollama model pre-pull, the taiga admin migrations and the
peertube post-backfill health inspect, matching the fider/matomo/decidim
pattern. The helper resolves to the local host + compose cid in compose
mode, so that path is unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add tests/lint/repository/test_name_emoji_and_length.py: every Ansible task
name and GitHub Actions workflow/job/step name must start with an emoji (first
char not 0-9/A-Za-z) and be <= 80 chars.
- emit emoji names at the source: cli/build/include generator now writes
"🔧 setup <app>" / "🚿 flush handlers after <app>" so generated
tasks/groups/*-roles.yml satisfy the convention too
- convert existing task/step/job/workflow names to emoji-prefixed, choosing a
task-fitting icon per action (📦 install, ✅ ensure, 🔍 probe, 🥾 bootstrap,
🚀 deploy, 🧩 service-module load, ⬇️ checkout, 📂 include-routines, ...)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace compose-mode-specific `{{ BIN_COMPOSE }} exec ... {{ SERVICE }}`
+ `args.chdir: lookup('container', ..., 'directories.instance')`
invocations with `container exec -i {{ ..._CONTAINER_ADDRESS | quote }}`
(plus `--workdir` flag where chdir was load-bearing). The container
exec wrapper resolves the actual runtime container name on both
compose (compose-suffixed name) and swarm (stack-task-id-suffixed
name) via the `container_address` lookup, so the task no longer
assumes the compose-mode service-name address.
Pure-syntax adaptation only — no behavioural change, same register /
when / failed_when / no_log semantics preserved on every task.
Roles touched (12 task files):
- web-app-espocrm (1)
- web-app-friendica (2)
- web-app-listmonk (1)
- web-app-openproject (2)
- web-app-snipe-it (3)
- web-app-taiga (1)
- web-app-wordpress (2)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- tasks/01_administrator.yml: pass DJANGO_SUPERUSER_PASSWORD to
createsuperuser; without it Django sets an unusable password and
every API/native login attempt 401s.
- files/playwright/_shared.js: logoutFromTaigaNative asserts at /login
directly; Taiga redirects logged-out users to /discover where the
form is gated behind a Login link.
- files/playwright/test-themed-routes.js + templates/playwright.env.j2:
gate gradient assertions on CSS_SERVICE_ENABLED so the LDAP-only
variant (stock Taiga UI, no web-svc-css) falls back to a readiness
check instead of failing on missing injected theming.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds tests/lint/ansible/test_no_redundant_default_on_module_io.py which
flags `<reg>.{stdout,stderr,rc} | default(...)` inside `changed_when:`,
`failed_when:`, or `until:` lines. Those conditionals only fire after
the module has actually executed, so the fallback can never apply --
keeping it just hides bugs and noise.
Cleans up the 21 existing offenders across 14 role files. The taiga
upsert-admin task additionally gains a `not ASYNC_ENABLED and ...`
short-circuit so its async-poll-0 path no longer leans on a silent
empty fallback for stdout/stderr; with the short-circuit, the
`default('')` is genuinely dead code.
Cross-task references (a later task reading a registered result of an
earlier task that may have been skipped via `when:`) stay out of scope
and remain a legitimate use of `| default(...)`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* scripts/lint/autoformat.sh:
- rename run_sort_claude_settings worker to run_claude (matches the
renamed scripts/lint/claude.sh).
- drop the EXIT trap that wiped status_dir; cleanup happens explicitly
after `wait` returns, so a parallel worker that interrupts the
parent never races a vanished status dir.
- each worker now captures its tool's exit code and writes one of
OK / SKIP / FAIL. Tolerated `expected violations remain`-style exits
(markdownlint-cli2 rc≤1, ansible-lint rc≤2) still count as OK; only
real failures count as FAIL.
- all workers run to completion regardless of individual tool failures
(so the user always sees the full picture); after the summary, the
script exits 1 if any worker reported FAIL.
* scripts/lint/sort_claude_settings.sh -> scripts/lint/claude.sh
(history preserved via git mv); update test_claude_settings_sorted.py
fix-hint accordingly.
Plus working-tree drift across roles/, group_vars/, inventories/,
requirements/, and .pre-commit-config.yaml accumulated from the
make-test setup phase regenerating generated artefacts during recent
test runs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Rename lookup plugin from `docker` to `container`
- Switch all lookups from `lookup('docker', ...)` to `lookup('container', ...)`
- Normalize compose file keys:
- docker_compose → compose
- docker_compose_override → compose_override
- docker_compose_ca_override → compose_ca_override
- Centralize compose path resolution via docker_paths_utils
- Update compose_file_args to always derive paths from DIR_COMPOSITIONS
- Align all roles, templates, and vars with container/compose naming
- Update and rename unit tests accordingly
This prepares the codebase for engine-agnostic container backends
(e.g. Docker ↔ Podman) and removes legacy docker-specific assumptions.
https://chatgpt.com/share/6987a7cc-d374-800f-99ad-bb4c8f92c59e
- Switch all docker compose invocations to the compose wrapper
- Update comments, task names, and log messages accordingly
- Simplify handlers and tasks to rely on wrapper-managed flags and env files
- Align tests and documentation with compose-based workflow
https://chatgpt.com/share/69866ede-be2c-800f-94b0-bffcf8fed260
- Replace lookup('docker', ..., want='...') with lookup('docker', ..., 'path')
- Allow both top-level keys (directories/files) and dotted paths
- Simplify docker lookup API and reduce lazy dict propagation
- Update unit tests to reflect new lookup semantics
https://chatgpt.com/share/6984ccea-8290-800f-a6d7-ec0e94df95a0
Remove implicit docker_compose variable usage and resolve all docker paths
(files, directories, env) via lookup('docker', application_id).
This prevents scope leakage, centralizes path resolution, and makes docker
context deterministic across roles and handlers.
https://chatgpt.com/share/6984ccea-8290-800f-a6d7-ec0e94df95a0
Add CPU/memory/pids limits for taiga, async, front, gateway, events, async-rabbitmq, events-rabbitmq, manager, and protected. Align manager service usage (was taiga-manage) in admin tasks and inits compose. Switch to variable-driven service names (TAIGA_* vars), add container_name patterns, normalize volume mappings via TAIGA_VOLUME_STATIC/MEDIA, fix depends_on to use TAIGA_* vars, and set RabbitMQ hostnames from vars. Remove obsolete Development.md.
Conversation reference: https://chatgpt.com/share/68da83b7-0cb4-800f-9702-d8a2d4ebea71 (replace with this chat’s share link)
Add roles/web-app-taiga/tasks/01_administrator.yml to handle admin creation via 'createsuperuser' and, on failure, an upsert fallback using 'manage.py shell'. Ensures email, is_staff, is_superuser, is_active are set and password is updated when needed; emits CHANGED marker for idempotence.
Update roles/web-app-taiga/tasks/main.yml to include the new 01_administrator.yml task file, removing the inline admin logic for better separation of concerns.
Uses taiga-manage helper service and composes docker-compose.yml with docker-compose-inits.yml to inherit env/networks/volumes consistently.
Chat reference: https://chatgpt.com/share/68af7637-225c-800f-b670-2b948f5dea54