Decision Log
canonical· pm · updated 2026-09-07 · source
| Date | Decision | Rationale | Outcome |
|---|---|---|---|
| 2026-09-07 | Render project split into staging and production; render.yaml becomes a clean mirror (effort #1604, sub #1721) | The spike-era comments recorded findings from setup (Docker dockerfilePath/dockerContext not CLI-settable, Blueprint apply is Dashboard-only) that now live in apps/api/docs/render-validation-spike.md — render.yaml had drifted into a history log instead of reading as current state, and it no longer matched the Render project's two-environment reality after today's split. | render.yaml rewritten as a clean mirror: tedos-api-staging (free, Staging) + tedos-api-production (Starter, Production standby, no traffic), envVarGroups (api-staging populated, api-production declared for #1655), no databases: block (Auto Sync stays off, verify in the Dashboard). Docs (render-conventions.md, knowledge/environments.md, render-pg-boss-reliability-test.md, + the sub #1655/#1623 planning docs) updated to today's renames: tedos-api-blueprint-poc→tedos-api-production, tedos-product-db→tedos-production-db, tedos-pgboss-reliability-test→tedos-staging-db (kept, repurposed as staging's DB — not deleted), tedos-console-poc→tedos-console-staging, tedos-api-poc deleted. |
| 2026-09-07 | Quality gates become executable contracts; defects get a severity axis (ADR-019, effort #1703) | Review and merge criteria lived only as prose, so nothing verified them: PR #1689 merged with four untriaged CodeRabbit findings (two real bugs) while every declared gate read green; three rules stated a different "the gates"; the existing .githooks/pre-push blocked on lint errors ONLY, narrower than the rules' own claim, while the kit's prePush seam shipped empty and unused; the captain classifies a PR CLEAN from mergeable state and the status rollup alone, where local checks leave no trace and CodeRabbit triage state is invisible; and labels carry priority but no severity, so impact and urgency are one axis. A standards review supplied the definitions (ISO/IEC 20246, ISO/IEC/IEEE 1044, 24765, 29119, 15288, ISO 19011:2018, ISO 9000:2015, ISO/IEC 17021-1). | Accepted. One vocabulary in .claude/rules/quality-vocabulary.md (engineering vs audit families never mixed; "observation" removed — an unbreached requirement is an OFI); every gate names entry criteria, exit criteria, a decider and a waiver; entry enforced by a blocking git pre-push hook (gates humans and delegated agents alike, which a Claude Code hook cannot), exit by evidence the merge step can read; sev:blocker, sev:major, sev:minor, sev:trivial separate from priority:p0–p3, closed disposition set. Lands in tedos first, upstream to cckit once proven. Cost zero. Deferred: corrective-action records with effectiveness verification, review-type formality map. |
| 2026-06-26 | Wiki ingest: develop @ e8d0254 (kit worktree/session-ownership #896/#897) → wiki/kit-worktree-session-model.md (effort #884) | Dogfood of the self-writing engine: pulled develop into the effort and synthesized its change into the new wiki/ layer instead of letting it live only in commit messages + the kit rule. | First ingested wiki/ page; bookkeeping (INDEX row, this log line, orientation back-link) applied; lint green. Synthesis was Claude-driven (engine backend wiring deferred, #890). |
| 2026-06-26 | Hosting is Vercel (admin/web) + Fly (tedos-api) — the DigitalOcean/desktop stratum is retired (effort #884) | The 2026-05-21 docs (tedos-product-decisions.md, tedos-devops-plan.md, tedos-implementation-plan.md) still asserted DigitalOcean + Tauri desktop + per-seat-USD as current, while the live system is the web admin on Vercel + the Fly API (Fly Managed Postgres) and B2B MXN pricing — an unrecorded host decision plus stale canonical docs outranking their successors. | Host decision recorded here (was never logged); the three desktop/DO docs demoted to historical with superseding banners (kept for context, git is the archive). Part of the LLM-Wiki adoption (llm-wiki-pattern.md). |
| 2026-06-17 | Tasks live in the Plan Engine graph; GitHub issues stay synced (elimination deferred) (ADR-005, ACCEPTED 2026-06-20 — amends the "GitHub issues+Projects = SoT" hard rule in CLAUDE.md; depends on ADR-004) | Colliding triple-write (GitHub issues+Projects, tickets.ts JSON, graph); Projects v2 is flat; Actions billing-blocked → task automation already broken; terminal/desktop/Cowork parity demands a networked SoT. Direction: graph = task SoT; ingest open issues→plan_nodes, closed→snapshot (history migrated); keep GitHub issues SYNCED with the graph (bidirectional mirror), do NOT eliminate yet; elimination deferred — open question: graph↔git-history coordination + a correct visualization (inventory at decision: ~57 open / ~166 closed). | Accepted; built by effort #560 (5-table model adds sync_event for the idempotent, loop-free GitHub↔graph mirror). SEQUENCING: GitHub issues stay operative + synced until the graph is the daily driver and ingest is verified — no elimination without an explicit future decision. Rules aligned: kit-engine-boundary.md #3/#4, CLAUDE.md task rule. Done: ingest+sync job, re-key branch-naming/worktree//kit-gc, tickets.ts retired (#570). |
| 2026-06-16 | Plan Engine: plans move from files to an editable/actionable DB-backed graph (ADR-004, ACCEPTED 2026-06-20 — supersedes #221) | The operator rejected git-as-CMS (no editing via IDE) and asked to edit + act on plans from admin/desktop or Claude. Plans only (knowledge stays file-based). One Postgres graph (plan_node/plan_dependency/plan_version/plan_link + sync_event = 5 tables), 3 views (Roadmap=timeline projection, Plan, Subplan), roadmap aligned by construction, same backend for admin and Claude (MCP). Body = markdown+blocks (no JSX runtime). | Accepted; built by effort #560 (the plan IS the parent issue, ADR-006 — no MDX plan file). One-shot ingest of existing GitHub issues→graph; reconciled plan-output-format.md/workflow-vs-product.md/kit-engine-boundary.md/CLAUDE.md. |
| 2026-06-12 | Knowledge governance baked into claude-kit v0.7.0-beta.4 (#349) | José: "update the kit, so kit builds knowledge this way". Rule template knowledge-base.md in profiles software/content/research/automation; /kit-init scaffolds knowledge/INDEX.md + a generic knowledge-lint.sh (config-driven); per-project extension in knowledge-lint.local.sh (survives /kit-update); task-close template flips status: instead of archiving (same stale as #347). | PRs #350/#352 merged; installed plugin updated to beta.4; tedos migrated to the generic+local model and plans.dir in the config corrected to the canonical one. |
| 2026-06-11 | Knowledge governance: wipe policy + frontmatter + INDEX + CI lint (#340–#342) | Audit (3 agents) found healthy content with no governance: 0 frontmatter, CLAUDE.md/workflow-vs-product pointing to the losing decision of #221, 6/8 plans with status↔issue drift. José decided: superseded is DELETED (git = archive; if it exists in knowledge/, it's current), the most recent decision wins, status/owner/updated frontmatter mandatory, INDEX.md manifest, CI knowledge-lint. Declined: scheduled weekly sweep and extending kit-task-* skills with automatic flips. | PRs #343/#344/#345/#348 merged + deployed (admin prod = develop). 4 superseded docs deleted; 22 docs with frontmatter; plans synced against gh; Mission Control → Complete. |
| 2026-06-11 | No RAG for the knowledge base | 26 docs / ~3.8k lines don't need semantic retrieval; the problem was governance, not search — a RAG would index the contradictions as-is. MemPalace (the existing semantic layer) had its search down that day (44k drawers wing tedos, "Error finding id") — fixing it > adding another DB. | Re-evaluate only if knowledge/ exceeds ~100 docs. MemPalace search repair pending (lives outside the repo). |
| 2026-05-19 | AI Shell backend: DigitalOcean (no Supabase) | José's call. DevOps agent to produce DO implementation plan (auth, DB, edge/functions equivalent, storage, CDN for updater + micro app bundles). | Pending DevOps research output |
| 2026-05-19 | Office View tab: Path A (iframe + Python sidecar) | Research found claude-office is iframe-ready (Next.js output: "export" + FastAPI SERVE_STATIC=1). 2-3 days vs 20-30 for native rebuild. | Implementation queued as Task #18 |
| 2026-05-19 | Python runtime: detect/install uv on first launch (not PyInstaller bundle) | Smaller AI Shell installer, ~30s setup wizard on first run. | Setup wizard UX to be designed |
| 2026-05-19 | claude-office hooks scope: per-project (not global) | Avoid polluting ~/.claude/settings.json across all Claude Code sessions. Each AI Shell workspace installs hooks scoped to itself. | Tauri Eng to write per-project hook installer |
| 2026-05-20 | Product renamed: AI Shell → Tu Empresa Digital OS | Full brand name. "Sistema Operativo de tu empresa con IA". Avoids Microsoft Office TM risk. Brand sits inside the tuempresa.digital family. Wordmark: Tu Empresa Digital OS. Short forms TBD (TED OS? OS? @tuempresadigital/os?). Domain candidates: os.tuempresa.digital or tuempresadigital.com/os. | Sweep rename across plan.html, contexts/, package.json. Designer to lock short-form wordmark + lockup. |
| 2026-05-20 | Brand scoping: marketing site uses Neuform "Premium Agency Portal" template; OS app keeps existing Linear/Raycast/Things-3 design system | Source brand file (Newsreader serif + orange/brown + bold marketing aesthetic) is for landing/marketing only. Forcing it onto a desktop productivity tool used 50×/day would be fatiguing. Marketing site ≠ product design. Common pattern. | ⚠️ SUPERSEDED 2026-06-05 (Aurea multi-surface theming) — cool / Linear-Raycast product palette retired; brand-tuempresadigital.md is now a dead stub. |
| 2026-05-20 | MVP scope locked: macOS-only, single-tier (Starter quota), Home = Dashboard merged, integration = A standalone Tauri | José said "hazlo como me recomiendes". PM recommended macOS-only + single-tier (saves ~1 week + ~3 days). Designer recommended Home/Dashboard merge. Integration A = simplest path: standalone Tauri with Tu Empresa Digital brand. SSO and embed come post-MVP. | All future work assumes these constraints. |
| 2026-05-20 | ADRs 001-003 written for scaffold (#6) | Locked: backend = Fastify + Drizzle + Postgres (ADR-001); repo = pnpm workspace monorepo (ADR-002); frontend state = Zustand + TanStack Query (ADR-003). | Unblocks Tauri Eng (#7), AI Eng (#8), PM sweep rename (#5). |
| 2026-06-08 | Admin matiz: Lino + Tinta + Cian (issue #159) | The Admin is an internal "notebook" (Plans/Roadmap/Decisions) — its own matiz of the Aurea core, distinct from brand and user apps. Light Lino ground (not Pergamino), Tinta (#0F0E0C) carries the contrast, Cian #0891B2 is the single accent (NOT azafrán, reserved to brand). Geist + Geist Mono (notebook voice). Chosen over teal ("muy conocido") and muted blues ("triste") — José wanted more contrast, "más cerca del tint". | Design system + main layout designed in Paper (page 3-0, 5 artboards following 5-0 structure). Docs: knowledge/admin-design-system.md, knowledge/admin-tone.md. Open: tokens → apps/admin @theme. |
| 2026-06-05 | Aurea-derived multi-surface theming (supersedes 2026-05-20 "OS keeps Linear/Raycast" + the brand.md §5 warm-vs-cool split) | José: "Todo debe hacerle honor al brand Aurea, pero con sus matices." ONE warm Aurea core ("Botánica Restrained"); each surface (docs, admin, app) gets its own matiz; the app is user-focused (ease & usability first). The cool zinc/indigo product palette is retired. | Design files updated 2026-06-08 (brand.md, tedos-design-system.md, designer AGENT.md, brand-tokens.css). Open: per-surface matiz token architecture (Designer) → unblocks globals.css rewrite + PR #127 re-theme. |
| 2026-05-21 | Free-tier modules as growth attractor | Current modules (AssistantChat, GitHub Contributions, etc.) will be free features — a curiosity hook to attract potential clients before they convert to paid. Freemium funnel strategy. | Designer must treat free modules as showcase-quality — they're the first impression. Gate premium modules clearly but don't make free ones feel crippled. Informs UI revamp: free modules get full polish, not placeholder treatment. |
| 2026-05-21 | MemPalace per-project wing architecture | One wing per project prevents cross-project contamination. tedos = ai-assistant, nts = NTS Clinic. Each project's Stop + PreCompact hooks mine only their own Claude session folder into their own wing. Existing NTS content migrated from tedos → nts via ChromaDB metadata update (4,421 drawers). | All new projects get their own wing + scoped hooks. Pattern: mempalace mine ~/.claude/projects/-Users-...-<project>/ --mode convos --wing <name>. |
| 2026-05-21 | Agent structure expanded: designer, devops, backend agents added | PM and Tech Lead existed. Added Designer (design system, brand, screens, motion), DevOps (DO infra, CI/CD, Tauri distribution), Backend (Fastify, Drizzle, Postgres, pg-boss, auth). Each agent owns a MemPalace diary wing (agent-<role>) and saves project content to wing=tedos in its domain room. | All 5 agents documented in .claude/agents/. Orchestrator routes by role per CLAUDE.md. |
| 2026-05-21 | Knowledge base mined into MemPalace with room routing | Added knowledge/mempalace.yaml mapping files to rooms: ADRs/decisions → room=decisions, design/brand/screens → room=architecture, impl/devops plans → room=planning. Hooks updated to also mine knowledge/ on every session stop. | Agents can now mempalace_search for ADRs, design tokens, or deployment plans without reading static files directly. |
| 2026-05-21 | ADR cross-references fixed: contexts/ → knowledge/ | ADR-001, ADR-002, ADR-003 all referenced stale contexts/tedos-*.md paths (folder was removed). Fixed to knowledge/tedos-*.md. ADR-001 also referenced tedos-devops-plan.html → corrected to .md. | ADRs are now self-consistent and linkable. |
| 2026-05-20 | Sweep rename complete: AI Shell → Tu Empresa Digital OS (issue #5) | PM agent replaced all "AI Shell" text occurrences in contexts/, plan.html, .claude/ rules/skills/agents, ADR cross-references, and brand file. Historical log entries (2026-05-19) preserved as rename-history record. | grep -ri "AI Shell" . returns 0 results (excluding pre-rename log rows). New file-naming pattern: tedos-<role>-<topic>.html. Short form for code/infra: TeDOS. |
-
2026-06-26 -- Effort #908 (PR #914): added
kit knowledge query— search-first wiki retrieval with QUERY→page promotion reusing the ingest cascade; documented the kit knowledge CLI surface. -
2026-06-27 -- ADR-010 (effort #934): build our own Refine-inspired app framework
@tedos/core(NOT @refinedev) so it stays RSC-first per ADR-008. One<TedosApp>shell + typed provider contracts (auth/access-control/router/data/i18n) over@tedos/api-client/@tedos/auth+ aResourceregistry + runtimeTenantConfig(#922). Scaffold sub #935; provider impls in subs #936–941. -
2026-06-27 -- Effort #922 (PR #949): Client Configuration Framework — runtime multi-tenant config (org_config/feature flags/encrypted secrets/Host-resolved tenant + branding), one app serves every domain, config edits never rebuild.
-
2026-06-27 -- Add wiki/tenant-brain-economics.md — per-tenant LoRA model economics: train≈$0, shared multi-LoRA GPU is the only real cost (~$5–12/client/mo @100 clients); illustrative tiers, pricing not decided (ADR-010 Phase 0 to calibrate)
-
2026-06-28 -- ADR-012 (#1061): app import boundaries — non-admin apps (console, client apps) import generic UI primitives from the neutral
@tedos/ui, never@tedos/ui/admin*(admin skin). Promoted Input/Select/Segmented (+ reconciled PageHeader/SectionLabel) to neutral; admin re-exports them (one source). ESLint@typescript-eslint/no-restricted-importsguard forbids the promoted names from@tedos/ui/adminin apps/** except apps/admin/**. Screens/shell reuse left in place, flagged for José. Rule:.claude/rules/app-import-boundaries.md. -
2026-06-28 -- ADR-014 (effort #1087, #1088): extract claude-kit to a standalone public repo
jeiemgi/cckit— reverses the no-separate-repo / kit-lives-in-tedos / kit-global-only direction. Done = the bash kit migrated (dispatcher + lib bundle + orchestrate/autopilot, driven fromcckit.config.json); cutting tedos/NTS over to consume cckit is a separate deferred effort. Auto-release on merge to main (conv-commits), Astro Starlight docs, agent-agnostic contract (AGENTS.md+cckit <verb> --llm), pure-bash fallback. Branding cckit's own (no tedos). -
2026-07-02 -- Effort #1110 (PR #1134): tedos readied to switch its kit to standalone cckit — baseBranch config, zsh-safe libs, retired the in-repo plugin fork + autobump, statusline repointed to cckit.
-
2026-07-02 -- cckit adoption switch landed (effort #1122, PR #1140): lifecycle skills resolve from cckit@skills-dir plugin, kitVersion 0.3.0, named overrides kept, cckit update is the channel.
-
2026-07-03 -- ADR-015 (effort #1115, #1121): future module implementations ship as
@tedos/modules-<name>packages — an ADR-012 extension (apps import them, they never import apps); the@tedos/coreregistry stays the vocabulary + gate. The API module-key alias mirror (#1119) recorded as accepted duplication with the registry as source of truth. CS-WhatsApp forward-compat direction: one WhatsApp connector, a generic webhook entry, a phone-identity seam. -
2026-07-03 -- Effort #1115 (PR #1152): one canonical module registry in @tedos/core — 11 English keys, legacy-Spanish aliases derived, console/comprender/api wired, idempotent stored-key migration, ADR-015 module packages
-
2026-07-03 -- ADR-015 AMENDED (José, #1154): ONE
@tedos/modulespackage (packages/modules, subpath per module) — not one package per module. Every module ships a typedmodule.config.tsmanifest (key bound to the canonical ModuleKey) declaringrequiredConnectors. New connector entity:CONNECTOR_REGISTRYvocabulary in @tedos/core mirroring the module-registry pattern; implementations stay tenant-aware in packages/engine/src/connectors and are injected by the host (whatsapp, hubspot, stripe share one connector each). -
2026-07-03 -- PR #1163 (#1129): student commerce backend — Stripe Checkout session + per-project webhook, OXXO added to payment methods
-
2026-07-03 -- ADR-016 (spike #1156, effort #1131): student auth = better-auth + Drizzle adapter embedded in the Fastify API — tenantId-scoped via a thin tenant-aware adapter wrapper (the one non-upstream piece, needs a security review before production); phone OTP via the
phone-numberplugin withsendOTPinjected over the WhatsApp connector (ADR-015 pattern, auth never imports the engine); auth tables provisioned viapackages/domain/src/provisioning.tstemplateDdl; Clerk stays operator-only (two auth systems by design). Student portal = ONE multi-tenant Next.js appapps/portalresolving tenant by hostname over @tedos/ui + @tedos/core + @tedos/api-client (supersedes putting the student surface in comprender; thin-app ADR-008 makes it near-free, one deploy). Rejected: per-tenant Supabase Auth, Clerk-for-students (SMS-only, no WhatsApp), Ory Kratos, Keycloak/Zitadel, bespoke. -
2026-07-03 -- Ingest PR #1166 (#1131): student auth (better-auth) + portal /student/me identity seam → new wiki/student-auth-and-portal.md
-
2026-07-10 -- ADR-017 (effort #1257, sub #1258): three-surface architecture — console = superadmin tenant-config surface (module enablement per tenant, connections, limits + the platform level absorbed from admin, #1261); ONE multi-tenant white-label tenant app on the client's domain serves operators AND students with role-split layouts and fully separate auth stacks (Clerk operator / better-auth phone-OTP student, never shared sessions); apps/portal is the BASE of the tenant app (standards audit: ADR-016 multi-tenancy, React.cache 15/15 data-fns vs comprender 0/10, RSC client-only-on-leaves, type-* 145 vs 62 raw) — comprender's assets (dual-rail shell, module gating, 10 operator screens) migrate in, then comprender retires (#1262); apps/admin DEPRECATED — frozen immediately (nothing new lands), deleted once console absorbs the platform level. Supersedes effort #1253.
-
2026-08-31 -- ADR-017 AMENDED (José, #1428): ONE domain per tenant (
<tenant>.tuempresa.digital) — the separate operator host is retired (admin.<tenant-domain>has no TLS under the one-label Vercel wildcard, the #1428 bug; Clerk satellite pricing rejected). Operator access is role-gated IN the app (Clerk +(operator)route group), students/public on better-auth, same domain;console.tuempresa.digitalunchanged. Migration:<tenant>.operador.tuempresa.digitalkeeps working until the role-gated operator surface ships on the tenant domain (#1435), then the operador.* host redirects and the host-detection code (isOperatorHost,apexHostFromOperatorHost, the #1412 layout exemption, the proxy apex→operator bounce) is removed. #1414's host-resolution premise disappears. -
2026-08-31 -- ADR-017 amendment SHIPPED (effort #1438, subs #1439–#1443): the operator workspace is role-gated by PATH on the tenant domain —
apps/portal/src/proxy.tssends/operator/*(+ Clerk internals) to the Clerk gate on<tenant>.tuempresa.digital; WHAT is checked is unchanged (Clerk session in the proxy/layout, org→projectId→role at the API). The retired hostsadmin.<tenant-domain>and<tenant>.operador.tuempresa.digitalanswer a permanent 308 to the same path on the tenant domain; host-detection (isOperatorHost,apexHostFromOperatorHost,PORTAL_OPERATOR_HOST, the #1412 layout exemption, the apex→operator bounce) is removed. Auth coexistence verified: per-tenantstu_*.session_tokenbetter-auth cookies vs Clerk__session/__client_uat— no name collision, zero cross-stack reads; the shared CSP already carried the Clerk allowlist. The neutral operator chrome keys off a proxy-set surface marker (lib/surface.ts). -
2026-08-31 -- ADR-017 AMENDED again (effort #1444): client-owned custom domains are back IN scope — a tenant's store/student surface may live on the client's own domain (e.g. tienda.comprender.mx), administrable from the console. Shipped: the Configurar → Dominios screen (
/org/<slug>/configurar/dominios, sub #1445 — the nav item was a dead 404) + console BFF over the existing #922/#930 provisioning API (Vercel add + DNS challenge + verify; 503 fail-closed surfaced as "provisioning not configured"); sharedDnsStatusvocabulary in@tedos/shared; UNIQUE constraint onproject.domain(sub #1446 — Host resolution must be unambiguous; NULLs free); the threeVERCEL_*env vars documented inapps/api/.env.example+ 15 domain-route tests over the injectableVercelDomainClientseam (sub #1447). Token minting stays the operator's manual Vercel-dashboard step. Doc refresh:cd-and-domain-provisioning.mdretargeted comprender →apps/portal(sub #1448). -
2026-09-02 -- Effort #1467 (portal editorial look, live-review iterations 2.1–2.31): the tenant portal's client surface commits to the BRAND CYAN/NAVY editorial palette on the
.client.editorialtoken scope — MD3-style tonal values layered onto the existing token names (canvas #F7FBFD · surface #FFFFFF · elevated #EAF6FC · sunken #D9EEF7; fg = navy #1A2456 family; accent/primary = brand cyan #29B8E8 with navy foreground, ≈6.37:1; ink panel = deep navy #131A3F; coral--contrasttertiary used sparingly). No preset/theme system — ONE scope, per-tenant brandingTokens override at runtime; the operator surface is never tenant-branded. Shipped with it: stepped accordion checkout on /carrito (localStorage persistence, session-derived state wins), Mi cuenta holder with real URL segments + sidebar, Stripe-first account/payment surfaces (backend subs #1472–#1475 filed), infinite 3D ring carousel on the home offerings section, store bar composition pass (one 44px control height, ONE active-state language = navy ink fill for TagPill + Segmented scope-wide, one 4-option sort Segmented), header icon-button pair normalized to variants-only. Composition-check-per-batch + the quick-lane rule (assistant applies small tweaks directly) adopted as process. -
2026-09-06 -- ADR-018 (effort #1527, sub #1532; José 2026-09-06): Clerk is retired entirely — better-auth becomes the ONE auth library. Two instance KINDS stay by design: the per-tenant student instances (ADR-016, unchanged) + a NEW platform instance on the API control schema (
platform_*) for tedos staff now and tenant operators in Phase 3, with theorganizationplugin as the tenant record (replaces Clerk Organizations /project.clerk_org_id),admin(user lookup + session revoke → console screens, replaces the hosted dashboard) andbearer. Staff sign-in = email OTP via the platform Resend account, invite-only (no Google SSO in Phase 1). Transition = dual-accept API guard (Clerk OR platform session) until Phase 3. Three efforts: #1527 (admin/console/chat off Clerk, 09-04→09-08) → #1533 (tenant identity + org migration script +clerkStore.tsvault →accounttable, 09-09→09-14) → #1538 (portal/operator/*off Clerk, cross-subdomain cookie design after the #1604 Render/Cloudflare checkpoint, delete every@clerk/*dep, one maintenance-window cutover, 09-15→09-18). Cost is NOT the driver (Clerk was $0) — one stack + ownership of the tenant record are. Supersedes in part ADR-016 § "Clerk stays operator-only" and ADR-017 § 2 / Auth design "operators authenticate with Clerk". Status Proposed until José ratifies on the #1527 PR.