Scaling Phase 1: multi-tenant onboarding + replica-safe coordination

Decouples "many users" + "many server replicas" from "many machines" so the
platform is tenant-isolated and horizontally safe on the current single node.

- Per-signup workspaces (cm-auth): a new hosted-identity sign-in provisions and
  owns its own workspace instead of joining the first. Config-gated by
  auth.per_signup_workspace (default off); concurrent first-logins serialized by
  a per-subject advisory lock so no duplicate workspaces.
- Terminal tickets in Postgres (migration 0016, hashed, single-use): any replica
  can redeem a ticket minted by another. Drops the in-process ticket map.
- Container registry in Postgres (migration 0017, agent_containers): Terminal
  and Sandbox managers resolve an agent's container through a shared registry,
  so a 2nd replica reuses it instead of spawning a duplicate. node_id recorded
  as 'local' (Phase 2 hook). Boot reconcile removes only true orphans, so
  terminals now survive a redeploy (tmux sessions resume).
- Per-workspace quotas (cm-api/quota.rs): plan-tier caps on agents + live
  containers, enforced at agent create + terminal spin-up (reconnects allowed),
  returned as HTTP 402. New GET /api/quota surfaces usage vs limits.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
Omar Sobh
2026-06-23 18:24:51 -07:00
co-authored by Claude Opus 4.8
parent f8f2b65e1f
commit e9ce368ec1
19 changed files with 669 additions and 205 deletions
+11
View File
@@ -6,6 +6,17 @@ use uuid::Uuid;
use crate::DbError;
/// Count of non-deleted agents in a workspace (for per-workspace quotas).
pub async fn count_active(pool: &PgPool, workspace_id: WorkspaceId) -> Result<i64, DbError> {
let n: i64 = sqlx::query_scalar(
"SELECT count(*) FROM agents WHERE workspace_id = $1 AND deleted_at IS NULL",
)
.bind(workspace_id.as_uuid())
.fetch_one(pool)
.await?;
Ok(n)
}
/// Inserts an agent together with its access policy in one transaction —
/// an agent without a policy must never be observable (§7.7).
pub async fn insert(pool: &PgPool, agent: &Agent, policy: &AccessPolicy) -> Result<(), DbError> {