Skip to content

accelerate-v0.6.322

@kanat kanat tagged this 10 Nov 06:43
## Why

With `agent_teams` on, every client call from the customer that owns the
deployment's own Stream app (the app `ROUTER_STREAM_APP_ID` names)
answered 503 "could not read the user's teams from Stream". That
included a `red` user opening a `red` config. This came up in the
AI-3059 live check on staging. `callerTeams` read teams only for an
identity with `Registered` set, and only `streamapp/forwarded.go:164`
sets it. The owner acts with the deployment's key (`stored.go:136`
`ownsDeploymentApp` → `inDeploymentApp`), so its identity has
`Registered=false`, the same as a borrower of the shared app. #1885 R1.1
must keep refusing that borrower.

## How it works

```
callerTeams (teams.go:95)
├─ no token                                  -> no teams
├─ no Stream app for the customer            -> 503
├─ Registered (forwarded token)              -> read teams there
├─ ownApp(customer, StreamApp)               -> read teams there   (new)
│    the deployment app, and the customer is that app's own
└─ otherwise (borrower of the shared app)    -> 503, as before
```

`ownApp` (`session_create.go:229`) is the existing rule for "this app is
the customer's own". `guests.go:157` and `calls.go:402` already use it.

## Why not change `Registered` itself

Its other readers depend on it meaning "a forwarded token":

| Reader | What it does | Changes in this PR? |
| --- | --- | --- |
| `api/teams.go:105` | teams read | yes, this fix |
| `session/manager.go:2168` `handedOut` | matches a hand-out from a
deployment-signed hook (`pinned.deployment == Registered`) | no. Setting
`Registered` for the owner would break its hand-outs |
| `session/manager.go:2225` `keepable` | checks agent channel type
readiness only in a registered app | no |
| `session/manager.go:2265` `callable` | checks agent call type
readiness only in a registered app | no |
| `session/moderation_tools.go:18` | moderation tools only in a
registered app | no (see Question in the ticket) |

## Validation

| Test (AgentTeamsSuite) | Catches |
| --- | --- |
| `TestTheDeploymentAppsOwnCustomerReadsItsUsersTeamsThere` | owner
refused (503 on base). `red` opens `red` (201). `blue` gets the same 404
as an unknown config. A no-team user opens only no-team configs |
| `TestTheDeploymentAppsOwnCustomersForkIsCheckedAgainstItsUsersTeams` |
the fork path for the owner: fork to `blue` gets 404, fork of its `red`
session gets 201 |
| `TestACustomerInTheDeploymentsSharedAppOpensNothingToAUser` (now 2
rows) | a borrower pinned to the deployment app (app mode) is let in
when any pinned app counts as own |
| `TestWithTheSettingOffTheDeploymentAppsOwnCustomerIsNotChecked` |
control: flag off, the owner opens `blue` with no teams read. Passes on
base `teams.go` |

- AgentTeamsSuite: 52/52 pass on a75975b73. UsageIdentitySuite passes
(it holds `TestATokensTeamIsNotMovedByTheAgentsTeamTag`). `go build
./...` and `go vet` (with the integration tag) are clean.
- Mutations of the changed condition, all killed: base condition,
`Registered` dropped, `StreamApp == 0` instead of `ownApp`, pin forced
to 0, `&&` turned into `||`.
- Live re-check on staging (AC-1, AC-2, AC-4) runs after deploy:
unverified here.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Assets 2
Loading