The role README Production section now runs provision and deploy in a
single docker call: APP and HOST are shell variables passed via -e,
INVENTORY is the in-container SPOT for the duplicated paths, and the
redundant --vars-file (optional, default None) and --id (the inventory
is already narrowed by --include) flags are gone. All 153 role READMEs
regenerated from the template; test-run.yml executes exactly this block.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cli.meta.ci.slots statically and conservatively counts every job the
CI run spawns outside the deploy matrices (reusable workflows opened
recursively, static matrices multiplied out, dynamic ones estimated,
worst entry-*.yml overhead included) and splits the remaining
256-job run budget between compose/swarm/host by the _SHARES weights,
with a per-mode floor and _SLOT_OVERRIDES pins. INFINITO_MAX_JOBS
defaults to 'auto', resolved per mode in apps.sh; the host workflow
drops its hardcoded cap. --matrix renders the budget as a table.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Priority deploy callers and their discover jobs now carry a star
(marker input threaded through single-node into the leaf workflows);
regular callers are labelled distinctly. New test-run.yml extracts the
Production command from a role README and executes it against the
runner (localhost => local connection, Docker socket instead of TTY),
runs parallel to test-environment and gates the final done job.
Lint Mermaid gets the broom emoji like every other lint.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
parse_role_statuses collapsed a role's variant shards per mode with
last-write-wins, so one green shard could mask a failed sibling and
--failed retriggers silently skipped the role (gitlab, run 29599179461).
Aggregate worst-first (failure > cancelled > running > success) and let
parse_role_urls link the worst shard.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mermaid flowchart of the flavors' swarm chain: handler flush before the registration wait, synapse reaching the issuer through the runner-bridge node gateway, and the node-local verifier skip.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The OIDC spec only checked the return URL and a visible body, both of which the installer wizard of a never-installed app satisfies (oauth2-proxy authenticates in front of it), so the crashed one-shot install still went green. After the Keycloak round-trip the URL must now avoid /install/ and land on /login or a /{company_id} dashboard, the two states an installed 3.1.21 serves per its route sources.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The applications menu and the platform/company header interpolated operator and role free text as plain YAML scalars, so any description containing a colon-space broke the rendered config at the from_yaml parse in the branding-asset task; moodle variant 0 hit it as the only deploy combining an active dashboard with web-app-lam, whose description carries 'directories: managing'. All name, description, icon, url and title fields now render through to_json, which yields quoted scalars for arbitrary text, matching what to_nice_yaml already did for the cards block.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The inventory gating removed the manager's unconditional volume and secrets backup groups, which had been the only include paths that ever executed the cleanup roles; svc-bkp-nfs-2-local declares both cleanups itself but their IS_STACK_HOST gate silently skipped them on the nfs host, so the required_by validator failed the deploy. The gate becomes the group_vars constant IS_BACKUP_HOST (any svc-bkp-* group membership), which covers every include site since only the five backup roles include the cleanups, and both roles now ensure the backups root exists before installing their timer: cleanback refuses a missing root by design and the size-cleanup script walks it with os.listdir.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The install and realm-import waits accepted Shutdown as success, so a crashed job passed silently: akaunting went green without ever installing, and a keycloak import crash left synapse against a realm-less provider, surfacing as matrix Playwright OIDC timeouts. The state probe moves to a shared sys-svc-compose script where only Complete passes, Shutdown fails loudly with the task error, and Failed/Rejected count as pending because the jobs now restart on-failure with three bounded attempts, turning the observed import race from a coin flip into self-healing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three layers of one chain. The CI verifier polled the service matrix_matrix, which no variant creates (the ansible flavor deploys a node-local MDAD runner, the compose flavor names its services matrix_synapse and friends); workload: node-local routes it to the established skip like bigbluebutton. Under swarm the stack deploy is a notified handler, so the registration wait started before any bridge existed and killed the play with the handler still pending; a flush before the wait deploys the stack first, and is a no-op in compose mode. Synapse resolves the OIDC issuer through two docker layers where both 127.0.0.1 and host-gateway point at the wrong loopback; the issuer now maps to the runner bridge's node gateway (local subnet .1), emitted only when OIDC is enabled so a no-auth setup keeps its previous arguments, proven by the full Playwright suite against the live cluster.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The six iteration skill wrappers move from infinito-iteration-* to i8-iteration-* (frontmatter, consistency lint prefix, alias and cheatsheet references follow). The new i8-cheatsheet skill routes to the operator cheatsheet and prints its prompt blocks verbatim, or just the block matching a named situation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The sidecar script contains no shell dollars anymore, so the swarm-only replace escape is dead; tests pin the exec-as-PID1 shape and the dollar-free invariant.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The compose and swarm render paths launder dollars differently; the launched argv arrived with $pid collapsed to an empty string and $! doubled, and the sidecar crash-looped on a sh syntax error, so opentalk's wait for the embedded object store exhausted its retries. The bucket bootstrap now polls /status from a backgrounded subshell and exec makes the server PID 1, which needs no pid bookkeeping and receives docker stop's TERM directly; the poll loop dies with the container and readiness stays gated by the consumer's bounded wait.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Picks up the postgres --empty pre-clean covering text search dictionaries and configurations, which unblocks taiga's restore drill. CI needs the 3.1.2 release on PyPI before this pin can deploy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Release metadata stays a manual operator step, mirroring the same ask-gate in backup-docker-to-local.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A force_bridge app (matrix's MDAD flavor) deploys as a node-local compose stack and publishes its local port on its host, while openresty runs as an overlay task whose 127.0.0.1 is its own loopback; the readiness probe died on 502. The proxy_pass lookup now resolves networks.local.force_bridge (trust-tagged for the 2.19 templar, hard-failing on an unrendered template instead of silently falling back to loopback) and keys the decision on the real DEPLOYMENT_MODE, since such apps rewrite the effective mode to compose via compose_mode_force. The upstream becomes host.docker.internal:<local_port> rendered as a literal directive, because the request-time resolver cannot see /etc/hosts entries, and the swarm openresty service maps host.docker.internal to the host gateway like prometheus already does. Non-force_bridge renders stay byte-identical.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The setup passed --no-start as the container command, which the ca-trust wrapper exec'd as a binary (exit 127); the flag does not exist in the image's entrypoint at all. Invoking /usr/local/bin/akaunting.sh with no arguments is the real one-shot contract: with AKAUNTING_SETUP=true it runs artisan install and exits without starting Apache. The swarm wait gate also accepted Shutdown as success and let the crashed job pass without ever installing; the state probe now lives in install_job_state.sh and only Complete passes, while terminal states fail loudly with the task error.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rewrite all 254 role descriptions to a uniform noun-phrase schema
(function-first, no leading verb, no trailing period, <=120 chars) and
enforce it via the extended description lint. Rename 12 role README H1
titles for clarity (e.g. Backup Container to Local -> Backup Docker
Volumes, CSS Service -> Corporate Design, NGINX Legal -> Imprint) and
regenerate their Cosmos and Quick Setup sections. Overview table
regenerated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
extend_inventory appended the volume, secrets and nfs backup groups to the test inventory unconditionally, so the DR-drill ran on hosts whose roles declare no backup. For roles whose only volume is backup-disabled (registries, unbound, redis, openresty) the volume drill produced a payload-less generation and failed its non-empty assertion. Each leg now follows the closure of the role that induces it: volume and (transitively, via volume-2-local's secrets_backup consumer) secrets on the app closure, nfs on svc-storage-nfs-server's closure via its nfs_backup consumer. Enumeration confirms no consumer-active role loses its leg; a README documents the group derivation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
WAIT_FOR_TIMEOUT is an iteration count, not seconds, and CNG wait-for-deps leaks one postgres connection per iteration (establish_connection, never disconnected). At 1800 iterations of the 1s default the dedicated instance's non-superuser slots filled with idle gitlab connections before migrations could claim one, deadlocking the deploy. 60 iterations of 30s keeps the 30-minute budget at a thirtieth of the leak rate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The overview table now shows Name, Status, Description, More, Integrated
with. The Homepage, Video and Install links collapse into one 'More'
column of emoji links (🌐 homepage, 🎬 video, 🛠️ install).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The two named volumes carry no mounts and stay empty; every piece of proxy state (configs, certs, webroot) arrives through deploy-rendered read-only binds, so the volume-backup drill produced a payload-less generation and failed. Same pattern as the registry, unbound and redis roles: backup.disabled on the service, the container_backup consumer statically off, and the volumes.yml opt-out documenting the exemption.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A registry serving the swarm its locally built images cannot be exercised as a swarm stack of its own (chicken-and-egg with the pulls it backs), so both roles disable the swarm mode and the svc.registry category default follows. This only removes the standalone swarm variants from test-deploy discovery; the constructor bootstrap still deploys both registries manager-pinned inside every swarm job via application_allowed, which does not read modes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Name the four deploy caller jobs so the Actions UI separates the two
lines: '⭐ Priority · single-node/swarm' and '🔁 Regular · single-node/swarm'.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Upstream matrix-docker-ansible-deploy (pinned ref: master) renamed all
bridge variables to the matrix_bridge_<name>_ prefix; its config sanity
check now hard-fails on the old matrix_<name>_ names, killing the
mdad-bootstrap service so Synapse never starts and the loopback probe
exhausts its retries.
Rename all 10 emitted bridge _enabled vars to matrix_bridge_* (verified
1:1 against the upstream CHANGELOG rename map), drop the redundant
default(false) (services.matrix.plugins always defines every key), and
drop the dead matrix_mautrix_gitter_enabled (no such role upstream).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Strict-Transport-Security strip in the shared per-location partial
was gated on 'lookup(tls, app, enabled)', so on plaintext transports
(onion, and pure-http clearnet) it never rendered and the upstream
app's own HSTS header (kix: max-age=31536000; openproject/Rails
force_ssl: same) leaked to the http client. That violates RFC 6797 and
the onion e2e TLS/HSTS specs caught it.
Make the strip unconditional. No behaviour change on TLS nodes: the
proxy still adds its own HSTS in the tls-gated ssl block of
nginx_ssl_header.j2. On http-only/onion vhosts nothing re-adds it (the
add is in the same tls-gated block), so the leaked upstream header is
simply removed — which is correct, since HSTS over plaintext is invalid.
Verified live: kix onion emits no HSTS header and its tls-hsts spec
passes; openproject rides the same shared partial.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The roles overview now lists only tested-envelope roles (lifecycle
alpha/beta/rc/stable/maintenance) and renders below the renamed
'Use it online' section with an introductory sentence. Rename the
former 'Get Started' heading and drop the redundant subsection.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The snapshot directory lives under the dump base (both derive from INFINITO_RESCUE_DIAGNOSTICS_DIR), so copytree copied its growing destination into itself until ENAMETOOLONG; the suppressed error left a local-dumps/<stamp>/local-dumps chain that failed the artifact upload of otherwise green jobs (swapfile, wireguard-plain). The copy now ignores the snapshot's own subtree and every ancestor holding it, which also excludes stale sibling snapshots of the same app; a regression test drives real copytree over the production topology.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add cli.build.readme.overview (make readme-index / make docs) rendering a
roles overview in the root README: Name, Lifecycle, Homepage, Video,
Description, Integrated with, Install. New info-media lint requires
homepage + video in every invokable role's meta/info.yml (opt out via
'# nocheck: info-media' in meta/main.yml); backfilled 147 roles with
researched, adversarially-verified homepages and official videos.
Retire the 'unsupported' lifecycle value: fold it into 'eol' as a valid
live end-of-life status (shipped but untested/unmaintained) across the
stage lists, symbol glossary, allow-list lint and docs. Retag confluence,
jira, minio, phpldapadmin to eol and magento to pre-alpha.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both roles already mark their only volume backup.disabled (resolver state and redis cache are rebuildable), so the volume-backup drill produced a generation without payload and failed its non-empty assertion. The container_backup consumer is now statically off with the volumes.yml opt-out documenting the exemption, matching the registry roles; derive_includes proves the backup legs leave both closures.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The gitlab dedicated-postgres failure exhausted all 167 non-superuser slots, but the rescue artifact could not show which clients held them. The collector now dumps pg_stat_activity (per-backend rows, query truncated to 120 chars) and a usename/datname/state connection histogram for every container with postgres in its name, via psql over the container's peer-authenticated socket. Runs only in the failure path and capture() never raises, so a non-postgres name match just records the exec error.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>