# Worldtree b188 + b189 bridge cutover, and the selene metadata that lied `[2026-08-25]` Three arcs in one day, all infra-ops side, all landed. ## b188 — matrix.yaml pre-sync (#406/#409/#410 closed) From b188 the bridge reads per-agent `rendering` + `ambient_buffer_size` from `config/matrix.yaml` ONLY; agent `config.yaml` matrix blocks are gone from the image. Staged as `6417115` in `worldtree-instance-configs`, deployed to both instances with operator approval. - mimir gets thinking-to-thread + tool-call reactions + 7 reaction labels; forseti and lofn stay quiet. - **Rider #409 pruned six dead agents** (bragi, leif, troi, soong, cara, glados) from BOTH rosters — originally scoped personal-only, which I flagged as a possible oversight and it was. **The settling fact worth keeping: the engine roster comes from the image's baked `agents/` directory (only `config/` is bind-mounted), and both instances run the same image**, so instance-level evidence about which agents the engine lists generalises by construction. - Both rosters now exactly `[mimir, forseti, lofn]` — the three engine agents actually bridged. mask/vili/echo exist in the engine, deliberately unbridged (operator ruling). ⚠ **Edited text-surgically, not via a yaml round-trip** — PyYAML would reflow 1,249 lines and drop every comment, and the comments are the documentation. ⚠ **`deploy-wt-config` uses `docker restart`, NOT `compose up`.** A `compose up` on corviduo-dev re-resolves the image tag and can silently swap the running build — which would turn an "inert pre-sync" into an unintended image roll on two live instances. That property is easy to lose in a future refactor of the script. ## b189 — #407 bridge extracted to its own repo (#404 umbrella closed) Bridge now `gitea.phasefinal.com/pfi/wt-matrix-bridge`, its own repo, own CI. ⚠ **It publishes to the `pfi` ORG, not `vh`, and the reason is structural:** `vh` is a **USER**, not an org. Gitea scopes user-namespace packages to the owning user — there are no package collaborators on a user namespace. **No service account can ever publish to `gitea.phasefinal.com/vh/*`.** claude-bot is an Owner of `pfi`, so that is where it goes. Token `wt-matrix-bridge-ci` (id 28, scopes `write:package,read:repository`), vaulted at `nh3-dev/.config/claude-bot/gitea-token-wt-matrix-bridge-ci`. **Minted a dedicated token rather than reuse `claude-bot-sdk-ops` or `arbo-ci`, both of which already carry `write:package`** — a shared credential cannot be revoked without collateral. ⚠ A first mint attempt succeeded then failed to save; Gitea returns a token value exactly once, so it was unrecoverable. Deleted the orphan (id 27) rather than leave a live package-write credential on the account. **Both instances PINNED** to `f3f8ec902267` (`e90f436`), closing the #410 shape: `WORLDTREE_IMAGE` was pinned and the bridge was the one drifting service. ⚠ The pin moved from `b178285b1cb5` because a cross-frontier bug-hunt found the M_EXCLUSIVE **fallback could itself litter unboundedly** in exactly the state it was written for. **The safety net had the same failure mode as the thing it was catching** — and my staged window leaned on that fallback. ## #411 — the debug-room failure, diagnosed twice and wrong both times first My theory: the alias was held by orphaned rooms. **Refuted by a directory probe returning 404.** The real cause: Synapse's **M_EXCLUSIVE** — an appservice may only create aliases inside a namespace it has RESERVED, and `aipa_appservice.yaml` had `namespaces.aliases: []`. ⚠ **I inferred a cause from a symptom that was the RESPONSE to the cause** — the log's "re-resolving alias" line is the recovery path firing, not evidence the alias exists. One directory probe settled it and I reasoned instead. Fixed with operator clearance: added `regex: '#aipa-debug-[a-z0-9_-]*:matrix\.phasefinal\.com'` (exclusive) at `/opt/docker/conf/synapse/aipa_appservice.yaml` on **ana-docker** (NOT `/opt/docker/data/`, which worldtree-dev's issue cited). **My regex was tighter than the proposed `#aipa-debug-.*`**, which fullmatches only because `.` also matches the `:` separator and would equally claim other homeservers. Pre-apply sweep (an `exclusive: true` claim can make Synapse refuse to START): aliases matching '%aipa-debug%' 0 total room_aliases on the homeserver 1 <- why it went unnoticed this long rooms created by @aipa-debug 17 <- the litter, confirmed unaliased Synapse healthy in 40s, both bridges rode through. **The aliased create then worked FIRST TRY on the next personal recreate** — designed path, fallback never fired, both reuse mechanisms live (canonical-alias rediscovery AND the room-id cache). ⚠ The #411 writer census **inverted its own premise**: the api (uid 1000) cannot write `/app/sessions`, the bridge (root) can — the reverse of the issue text. But worldtree-dev's reconciliation is better than "backwards": pre-#407 the bridge ran from the ENGINE image as uid 1000, and the cutover changed the answer underneath the issue. Both readings were true at their timestamps. **No live writer exists for that path anyway** (`sessions.path` is a legacy default, #330 moved the tools off it), so the chown is optional future-proofing. ## selene-1-mini-8b — a config that lied about what answers forseti's fleet sweep found the only genuine residual in `worldtree-instance-configs`, and it was **live on both boxes, not just drifted in git.** Fixed in `a77639d`. Routing was never broken (`model: "chat-judge"` stays), but `display_name` said "Selene 1 Mini 8B" and the description said "Atla Selene 1 Mini 8B — reward model derived from Llama 3.1 8B" while chat-judge has been backed by **qwen3.8-27b-uncensored** since 2026-08-23. ⚠ **It misstated the KIND of model, not just the identity.** A reward model and a generative judge are different instruments; a consumer reading "pairwise/likert/binary/scalar reward model" would expect scalar-reward semantics qwen3.8-27b does not provide. Verified: `selene-1-mini-8b` -> HTTP 400 (by design), `chat-judge` -> HTTP 200. **NOT changed:** the catalog key and the `selene-judgment` role — `model_roles.yaml` binds to that key, so renaming is worldtree-dev's schema call. Flagged that a role named after a retired model defeats the purpose of role aliases. ⚠ forseti's sharpest finding is for the operator: **`~/.claude/CLAUDE.md` line 502 lists the retired name in the global tools roster.** A broadcast reaches sessions that already exist; the roster line keeps minting new ones. His file, awaiting his word. Also: **there is no fan-out primitive on the bus** — a fleet relay is 73 individual posts, recorded as a real gap rather than papered over.