Summary
Publishing a Coworld is fully self-serve, but turning it into a league is not. POST /v2/coworld-league-seeds is TEAM_AUTH, so a Coworld owner cannot create a league for their own game — the last step of shipping a game requires a Softmax employee.
Current behaviour
$ coworld league create zero-sum
RuntimeError: Access denied (403) for /api/observatory/v2/coworld-league-seeds.
$ coworld --elevated league list
RuntimeError: Access denied (403) for /api/observatory/v2/coworld-league-seeds.
--elevated is a no-op without is_softmax_team_member, which is an employee flag gating much more than leagues (per its own help text: "private leagues, cross-user artifacts, SQL access"). So there is no scoped permission to request — the only route is asking a staff member to run it.
The public OpenAPI at /api/observatory/docs reflects this: /v2/leagues and /v2/games expose get only, and no league-seed path is published at all.
Why it matters
Everything up to this point works without a human in the loop: coworld build, certify, upload-coworld, hosted smoke certification, upload-policy, xp-request. A game can be published, certified 10/10, and made canonical entirely self-serve — and then stops, because it has no league, so no ladder, no standings, and no reason for anyone else to play it.
It also blocks iteration rather than just launch: any change needing a new league or a settings change means another staff round-trip.
Suggested shape
A scoped capability rather than the employee flag — for example, allow seeding a league only for a Coworld the caller owns, with the platform commissioner, and leave everything else (allied_teams, custom commissioners, cross-user artifacts) staff-only. Rate limiting or a cap of one league per Coworld would bound the blast radius.
If it is intentionally gated — for cost, curation, or ladder quality — that is a perfectly good answer, and saying so in the docs would help. Right now the gate is only discoverable by hitting a 403 whose message suggests an expired token ("You may lack permissions, or your token may be expired. Run: uv run softmax login"), which sends people down the wrong path.
Context
zero-sum:0.1.8 (cow_36202b83-04d1-4307-84d4-06832f069adb), certified 10/10 with hosted smoke 5/5, canonical, with a static replay viewer bundle. Ready to be a league; waiting on a staff seed.
Summary
Publishing a Coworld is fully self-serve, but turning it into a league is not.
POST /v2/coworld-league-seedsisTEAM_AUTH, so a Coworld owner cannot create a league for their own game — the last step of shipping a game requires a Softmax employee.Current behaviour
--elevatedis a no-op withoutis_softmax_team_member, which is an employee flag gating much more than leagues (per its own help text: "private leagues, cross-user artifacts, SQL access"). So there is no scoped permission to request — the only route is asking a staff member to run it.The public OpenAPI at
/api/observatory/docsreflects this:/v2/leaguesand/v2/gamesexposegetonly, and no league-seed path is published at all.Why it matters
Everything up to this point works without a human in the loop:
coworld build,certify,upload-coworld, hosted smoke certification,upload-policy,xp-request. A game can be published, certified 10/10, and made canonical entirely self-serve — and then stops, because it has no league, so no ladder, no standings, and no reason for anyone else to play it.It also blocks iteration rather than just launch: any change needing a new league or a settings change means another staff round-trip.
Suggested shape
A scoped capability rather than the employee flag — for example, allow seeding a league only for a Coworld the caller owns, with the platform commissioner, and leave everything else (
allied_teams, custom commissioners, cross-user artifacts) staff-only. Rate limiting or a cap of one league per Coworld would bound the blast radius.If it is intentionally gated — for cost, curation, or ladder quality — that is a perfectly good answer, and saying so in the docs would help. Right now the gate is only discoverable by hitting a 403 whose message suggests an expired token ("You may lack permissions, or your token may be expired. Run: uv run softmax login"), which sends people down the wrong path.
Context
zero-sum:0.1.8(cow_36202b83-04d1-4307-84d4-06832f069adb), certified 10/10 with hosted smoke 5/5, canonical, with a static replay viewer bundle. Ready to be a league; waiting on a staff seed.