KAHN Cloud v0.3 — ingest + tenant isolation shipped
Shipped:v0.3.0-ingest tag on kahn-hq/kahn main; live at
https://kahn.host behind airlock SSO.
What this unlocks
KAHN went from “airlock-gated dashboard with no data” to “producers can POST orchestrator transitions and the owning user sees their run in the history view within seconds”. The product shape moved from demo to usable. Every multi-tenant surface on the KAHN side is now enforced at the database layer via Row-Level Security with a non-superuser app role. A bug that forgets to set tenant context returns zero rows, not someone else’s data.The surface that’s now live
POST https://api.kahn.host/v1/ingest/transitions— NDJSON ingest, bearer-token-authenticated viakahn_live_sk_*keys.scripts/provision-tenant.py— idempotent tenant + key provisioning against the admin DSN.--rotatefor key rollover.scripts/push-run.py— operator-side pusher, 1 MiB chunking, 429 exponential backoff, graph.json auto-embed.kahn_appPostgres role withNOSUPERUSER NOBYPASSRLSso the RLS policies actually execute.lookup_api_key()+lookup_tenant_by_org()SECURITY DEFINERhelpers for pre-tenant-context lookups.
Why it took a full session
Three root-cause bugs surfaced only under a real production probe, not in tests:- Idempotent re-push doubled DB rows. Fixed by content- aligned append with a refuse-to-rewrite guard.
- RLS was inert at runtime. Railway’s default
postgresrole bypasses every policy. Fixed with migration + env rotation. - Every airlock JWT 401’d.
python-josesilently doesn’t support EdDSA. Fixed by swapping toPyJWT[crypto].
Doctrine deltas captured
Four new doctrines, two prompt-ops, one campaign — all cross-linked from this learning. Any future cloud surface (choco, stratt, traceo) that goes behind airlock + RLS can now start from those rather than rediscover the landmines.What’s next
- Taskset 6d — CI bridge onboarding for choco/stratt/traceo.
Reuses 100% of today’s ingest + provisioning code via the
StorageBackendProtocol. - Airlock
org_idclaim — when available, KAHN migrates fromuser:<sub>tenancy toorg:<id>multi-user tenancy with zero schema change (just anUPDATEontenants.airlock_org_id). - Phase 3 billing — dormant; unlocked when three external prospects indicate paying intent. Until then KAHN Cloud runs as a single-plan beta with a 90-day retention, 100 tx/sec rate limit.