Conversation
…n pool On a fresh roll the executive board-deck eval placed its tile correctly but bound data_scope='team:<other-id>' because that team's description advertised the referenced table. The guidance said team:<id> is for a tile that 'must read a different team's data', and the model judged the condition true from a description alone. State the default outright: a data reference that names a table without naming a team resolves inside the destination's own root; team:<id> is only for a home the user explicitly names. Applied to the create_tile/update_tile docstrings and both dashboards spec notes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… is absent Dev checkouts keep a repo-local .venv, but poetry-managed installs (CI) store the virtualenv in poetry's cache, so the hardcoded orchestra/.venv/bin/python path made every worker-cycle helper fail with 'Orchestra venv not found' on CI runners. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-run guard Typed provider-event definitions have no Tasks log mirror, so the store-only lookup in _running_execution raised 'No task found' when _ensure_not_active_task guarded an authored mutation on one. Resolve through _resolve_task_for_mutation, which already falls back to the typed Tasks API exactly like the mutation paths it protects. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…hing The image build authenticated every clone with one personal access token carrying write scope across every private repository its owner could reach. It was passed as a build argument, so it was recorded verbatim in the metadata of every layer that followed, and written into a global git config, so it persisted in the image filesystem too. Only two of the six repositories are private: branding and the iso-animation submodule its canvas kit needs. Each is now read with its own repo-scoped, read-only deploy key, mounted as a secret for the single command that needs it. Both keys are offered on one ssh invocation, so github resolves whichever is authorised for the repository being fetched and no host aliasing is needed. The other four clones — unisdk, unillm, magnitude and the job-watcher's own unisdk — are public and now run unauthenticated, as does resolving their SHAs. Nothing in the build carries a credential that can write anywhere. UNIFY_KEY is untouched here: it is still baked into the image because that is currently the only way the runtime receives it. Moving it to the cluster secret is a separate change that has to be sequenced against the pods.
The cache-diff upload ran under always(), and consolidation is outcome-blind, so a shard with one failing roll pushed that roll's full trajectory into the shared store. Write-misses replays hits, which made the recorded failure deterministic on every subsequent rerun until a prompt change rotated its keys -- observed on the dashboards team-routing re-record, which needed exactly such a rotation to recover. Gate the upload on the shard passing: a discarded diff costs one re-roll, a poisoned entry costs a key rotation. Failure logs still upload either way. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…'s residue The seeded branch of the contact/transcript scenario fixtures recommits the shared scenario contexts whenever the embeddings backfill did work — which is nearly every session, since each rollback re-creates rows under new ids and orphans their vectors. That recommit ran under only the scenario seeding lock, while tests serialize on a different lock and roll back at START, not at end. So a finished test's created rows (e.g. the Acme Corp support contact from test_nameless_service_contact_preserves_ no_name) stay live until the next test's rollback, and any session whose setup recommitted in that window baked them into the rollback target. Every later test then faithfully restored the leaked rows: the mutation scenario held 7 or 8 contacts depending on process interleaving, and every LLM prompt embedding the contact count flipped between variants — unresolvable cache thrash for read-only CI (12 of the residual contact_manager failures in run 31538082830 trace to this and its cascades). Take the scenario's test lock inside the seeding lock (same order everywhere, no inversion) and roll every context back to its stored commit before the embeddings check, so a recommit can only ever capture the committed seed state plus vectors. In a fresh CI database every commit is pristine by induction; long-lived local databases with historically tainted commits reset via --overwrite-scenarios. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
poetry env info --executable exits nonzero inside the CI test session even though the install-step-created cache env exists, and an inherited VIRTUAL_ENV makes poetry silently adopt the unify test venv where Orchestra is not installed. Route the fallback through 'poetry run python' with VIRTUAL_ENV stripped — the same mechanism orchestra's scripts/local.sh uses to boot the server in the same job. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A deploy key authorises exactly one repository, and github binds the ssh session to the first key that authenticates -- so offering several on one connection lets whichever answered first decide what the rest of the clone can reach. Bind each repository to its own host alias and identity instead. The canvas stage also needs an ssh client: the base node image ships git but not openssh, so an ssh transport fails there with 'ssh: not found'.
The system-source clones read two private repositories over ssh, using a read-only deploy key each. The image ships git but not openssh, so the transport failed with 'ssh: not found' before any key was consulted.
Dev machines bootstrap Orchestra with a repo-local .venv, but CI's poetry install hid the virtualenv in poetry's cache, so test helpers that exec Orchestra's interpreter had no stable path and fell back to invoking poetry at test time — which silently resolves an activated foreign virtualenv and fails outright inside CI's tmux test sessions. Install with POETRY_VIRTUALENVS_IN_PROJECT=true in every workflow that sets Orchestra up, cache the created .venv alongside poetry's package cache, and collapse the helper to the single invariant path <orchestra>/.venv/bin/python with a loud error when it is missing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Backend storage order varies between sessions for identically-seeded data (rollback re-inserts rows under fresh log-event ids), so unsorted federated reads returned the same contacts in session-dependent order. That order is embedded verbatim in LLM-visible tool results, which makes read-only cache replay miss on prompts that differ only by row order. Sorting server-side makes the docstring's creation-order contract actually hold. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
In interrupt mode a tool completion (or steering event) arriving while the LLM is thinking cancels the in-flight step and re-issues the turn with the updated context. The cancelled step's request is therefore never recorded, so a cached read-only replay - where the lookup resolves instantly, long before the real backend tools finish - deterministically issues that exact unrecorded request and died on the miss. Treat a typed CacheMissError with tools still in flight the way the live run treated the never-answered call: discard the step and fall back to the tool-wait block, which grants a fresh turn once the superseding event lands. With nothing in flight the miss stays fatal, so read-only CI still fails closed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…inistic - ask/update stop tests: anchor the stop on the first assistant turn via _wait_for_next_assistant_response_event instead of wall-clock sleeps. A stop racing the first LLM call cancels it mid-flight, which records nothing and therefore can never replay from cache (the whole-cache scan showed zero recordings of ask_stop's opening call). - routing tests: replace time_ns-derived team ids with fixed constants in a dedicated 61M band, and clean leftover team rows before each test. The id is embedded verbatim in the accessible-teams prompt block, so a wall-clock id can never replay. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AsyncToolLoopHandle.stop is async; calling it bare created an un-awaited coroutine, so the outer loop was never stopped when the guard tripped — result() returned the cached early response while the loop kept running as a zombie, issuing further LLM calls with nondeterministic progression (unreplayable from cache, and billed for nothing). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RoutingScenario team ids are embedded verbatim in the accessible-teams system-prompt block and echoed in destination tool-call arguments, so random ids could never replay from the LLM cache under read-only mode. Give each scenario a fixed pair in a dedicated 62M band and pre-clean the team roots on setup. The guidance/function eval sentinels sat in the user message with hex runs too short for cache-key scrubbing, so fix those too. Every other flagged time_ns/uuid team-id site was audited and left random with a comment: those tests drive managers programmatically (or, for the transcript ask evals, the id provably never enters LLM input), so randomness isolates concurrent runs at no replay cost. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Orchestra migrated off poetry: uv.lock is its lockfile and uv sync creates the repo-local .venv the test helpers exec directly. Cache the created .venv keyed on orchestra's SHA, drop the poetry install and its in-project shim, and align the helper's guidance with the uv invariant. Shared-rules bump removes the poetry branches from the formatting rule and the committed hook template. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e it for the rest
DashboardManager and its tests are deleted; canvas is the one visualization surface. The manager registry, actor surface, primitives registry/scope, coordinator activity, offline-runner function mode and settings all lose their dashboard wiring, and the actor prompts and examples now teach canvas only. The visualization eval is rehomed to tests/actor/state_managers/simulated/canvas and asserts no plan touches a dashboards primitive. Context-registry and team-homing tests that used Dashboards contexts as fixtures now use Canvas/Views, Canvas/Actions and Workflows/Meta. test_scope's expected alias set also gains canvas and ingestion — it was stale against scope.py on staging and failing there before this branch. Retiring function mode removes UNITY_OFFLINE_TASK_MODE from the runner contract, and the pod entrypoint used that variable's presence as the switch deciding a pod is an offline task-run pod — without a matching change, every offline task pod would boot interactive. The gate now keys on UNITY_OFFLINE_RUN_KEY, which the contract always sets. The dispatcher and contract tests drop their assertions on the deleted variable (offline_runner, offline_runner_contract and local_offline_dispatcher suites all pass); .secrets.baseline moves only by line numbers. Targeted suite: 569 tests. The only failures are 5 environment-only llm_client ones (platform-default model read from the staging assistant; nothing here touches llm_client) and 2 that already fail on staging (ingestion primitives missing Parameters docstrings; the scoped prompt-context test asserting the pre-discovery format). The canvas_manager suite passes 124/124 and the rehomed visualization evals route to canvas on fresh inference.
The render gate's harness page hardcoded actions: [] in its canvas/init message, so every canvas with an ActionButton reviewed with a visible "No action named ..." error and the critique flagged working controls as missing — observed live while verifying the SmartLead reply review canvas on staging, where the populated-state critique reported the approve and reject buttons absent while the same view mounted them fine under console. The harness now receives the same CanvasActionDescriptor shape console hands the frame (name, label, input schema, confirmation, destructive — never the dispatch target): create_view passes the resolved actions, update_view passes the revision's actions or the stored rows when the revision does not touch them, and preview rebuilds descriptors from the stored Canvas/Actions rows. update_view also validates actions before the review now, for the same reason bindings resolve before it — the gate must judge the action set the revision will actually publish. A harness contract test asserts descriptors are offered and that no function_id or task_id ever crosses the boundary.
Picks up the auth rule whose data-endpoint example now names canvas tokens instead of dashboards, and regenerates the aggregate.
Staging edited the dashboards ManagerSpec, the Dashboards scoped tables, the dashboard tests and the dashboards prompt-supersession test in place; all of those files are deleted on this branch, so each resolves to the deletion. test_scope keeps the alias set without dashboards — staging independently added canvas and ingestion to the same expected set, so the two sides agree except for the retired alias. The global-agent-rules submodule resolves to 9d5f956, a reconciling merge of the diverged staging (canvas-tokens rule) and main (uv poetry-drop) branches created locally in the rules repo; AGENTS.md is regenerated against it and carries both sides. The secrets baseline keeps the newer timestamp.
… probe Two latent bugs seen together in logs/pytest/2026-08-12T00-08-04: - tests/conftest.py cached a single 2s Orchestra probe for the process lifetime. Under parallel_run, sessions probing a still-warming (or briefly overloaded) server cached False, pytest_sessionstart skipped unify.init(), and tests crashed later with "EVENT_BUS has not been initialised yet". The first check now retries for up to 30s when UNITY_TEST_SOCKET is set (parallel_run sessions) before concluding False; plain pytest without Orchestra still fails fast, and the final verdict stays cached so init and requires_orchestra skips agree. - unify/events/manager_event_logging.py guarded incoming ManagerMethod publishes but not outgoing ones, so a dead bus turned a successful manager-method result (or the method's own exception) into a RuntimeError from the publish. All lifecycle publishes now go through _publish_lifecycle_event, which degrades to a warning. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The STT/TTS plugins each open a WebSocket to their provider and read the key from the environment. Mounting those keys in the runtime leaves them readable by in-process sandbox code, so hold them only in the sidecar and forward the socket: read the caller's placeholder credential off the handshake, open the upstream with the real one injected, relay every frame verbatim both ways (no buffering). The credential sits in a different place per provider (Authorization header, xi-api-key header, api_key query param).
Point the Deepgram/Cartesia/ElevenLabs plugins at the sidecar's /voice/<provider> passthrough over loopback, with the pod's UNIFY_KEY as the nonce, so the runtime no longer needs the raw voice keys in its environment. No sidecar configured (self-host / local dev) falls back to the plugins' own env-key behaviour.
hmahmood24
had a problem deploying
to
unity-testing
August 12, 2026 13:54 — with
GitHub Actions
Failure
hmahmood24
had a problem deploying
to
unity-testing
August 12, 2026 13:54 — with
GitHub Actions
Failure
The broker authorized Orchestra's metering gate with the provider-shaped body model (bare 'openai/gpt-5.4-mini'), which the gate's @openrouter marker never matches -- so every model outside the curated catalogue was refused 402 on each call, and curated ones passed only by colliding with the catalogue's suffix-stripped entries. In production this collapsed every voice fast-brain turn to the 'One moment.' fallback and killed the ManagersWorker and StorageCheck aux models, while terra/sol kept working. Each route now derives the accounting spelling from its own identity -- chat/completions is OpenRouter traffic, so '<id>@openrouter'; the Messages route is Anthropic, so '<id>@Anthropic' -- and uses it for authorize and settle, while the provider still receives the body's bare id verbatim. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tavily (search) and Recall (bots) are plain REST authenticated with an Authorization header. Their keys are held only in the sidecar, so the pod's clients point here with UNIFY_KEY as the nonce and this swaps in the real key (Bearer for Tavily, Token for Recall) before forwarding. No spend to meter, so it forwards and returns the provider's response unchanged.
Voice, Tavily and Recall all need the same answer -- where is the sidecar, and is there one -- so derive it once from UNILLM_LLM_GATEWAY_URL (and the UNIFY_KEY nonce) here rather than re-deriving it at each call site.
Point the Tavily and Recall clients at the sidecar's /proxy/<provider> with UNIFY_KEY as the nonce, so the runtime no longer needs their keys; recall's configured-check now keys off the relay secret that stays on the pod. Also fold the voice helper onto the shared broker_origin resolver. Self-host falls back to env keys throughout.
YushaArif99
had a problem deploying
to
unity-testing
August 12, 2026 14:41 — with
GitHub Actions
Failure
YushaArif99
had a problem deploying
to
unity-testing
August 12, 2026 14:41 — with
GitHub Actions
Failure
YushaArif99
had a problem deploying
to
unity-testing
August 12, 2026 14:41 — with
GitHub Actions
Failure
YushaArif99
had a problem deploying
to
unity-testing
August 12, 2026 14:41 — with
GitHub Actions
Failure
YushaArif99
had a problem deploying
to
unity-testing
August 12, 2026 14:41 — with
GitHub Actions
Failure
YushaArif99
had a problem deploying
to
unity-testing
August 12, 2026 14:41 — with
GitHub Actions
Failure
YushaArif99
had a problem deploying
to
unity-testing
August 12, 2026 14:41 — with
GitHub Actions
Failure
| const EXEC_ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/; | ||
|
|
||
| app.post('/exec', auth, async (req: Request, res: Response) => { | ||
| app.post('/exec', requireExecEnabled, auth, async (req: Request, res: Response) => { |
| }); | ||
|
|
||
| app.post('/exec/signal', auth, async (req: Request, res: Response) => { | ||
| app.post('/exec/signal', requireExecEnabled, auth, async (req: Request, res: Response) => { |
magic-marty
approved these changes
Aug 12, 2026
magic-marty
left a comment
Collaborator
There was a problem hiding this comment.
Approving staging→main release: pod secret-isolation (voice+Tavily+Recall→sidecar, /exec disabled) plus the standing staging delta. Flow smoke is red for a pre-existing CI clone-auth issue, not this change; merging via admin override per owner direction (urgent).
magic-marty
approved these changes
Aug 12, 2026
magic-marty
left a comment
Collaborator
There was a problem hiding this comment.
Release approval: broker metering fix verified on staging (llm_broker tests 19/19, orchestra gateway pins 13/13); promoting to restore non-curated OpenRouter models in prod.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release PR from staging to main.
Carries the OpenRouter spend-hardening and credential work alongside
in-flight test/CI fixes from other sessions.
Per AGENTS.md section 8 the image leads the manifest: this must merge, the
base image build must run, and the built image must be verified to contain
these changes, before unify-deploy is promoted.
🤖 Generated with Claude Code