TypeScript is canonical for the solution plane
Status: Accepted · Date: 2026-07-05 · Area: Deployment
Context
Per-solution provisioning existed as two deliberately maintained twins: the
bash infrastructure/azure/provision-solution.sh (declared source of truth)
and the in-product deployOrbitStack() TypeScript path the Aurora agent chat
used. Only the naming helper was byte-verified between them; everything else
had to be kept in sync by hand, and the drift was no longer hypothetical:
- the share-quota constant diverged (TS 5 GiB vs bash 100 GiB) and failed a
live deploy with an opaque ARM
InvalidHeaderValueerror; - the TS path was Cloudflare-blind — every agent-chat deploy produced a
stack without a front door, requiring a manual
deploy.sh provision <id>chaser; - the registry write-back guessed the public URLs by string interpolation from the zone name, recording links no one had verified existed.
Meanwhile the intended operating model is the Aurora agent as the primary
operator — which needs partial operations (fix just the front door, re-check
just storage, roll just the apps), structured results the model cannot
misparaphrase, and a toolset far wider than one monolithic “deploy” verb. The
bash monolith could not be reached from the aurora container (no az, no
scripts, no config file), and its complexity existed largely to work around an
az-CLI defect (create --yaml silently drops identity/registries/secrets/
scale) that the ARM SDK simply does not have.
Decision
- One engine, in TypeScript:
implementation/shared/orbit-deploy(@maxq/orbit-deploy, export./azure) owns the solution plane. It is a catalog of idempotent steps, each runnable in three modes (plan= read-only diff,apply= reconcile,verify= read-only assertions), composed into scenarios:deploy,redeploy-apps,frontdoor,storage,verify,teardown. Every step returns a structuredStepResult(status, detail, evidence, remediation) and every run emits aRunLogpersisted on the registry solution record (deployment.lastRun). - Three drivers share it: the Aurora agent tools (ten of them, from
solution_statusto double-confirmedteardown_solution), the ops CLI (deploy.sh solution <id> [scenario]→ the package’scli), and thecreateSolutionauto-deploy hook. - Bash keeps the platform plane — the human-run singletons:
bootstrap,postgres,services,aurora, andbuild-images.sh. Image building stays human (commit → tag →build-images.sh); the engine’spreflight.imagesstep only validates that the pinned tags exist in ACR and stops the deploy when they don’t. - The engine ports the live-proven front-door recipe (asuid TXT → grey-cloud →
hostname add → managed cert → SniEnabled bind → re-proxy) and the edge
lockdown transform rule to TypeScript, closing the Cloudflare gap; the seed
job becomes conditional (skipped when both shares already carry a
.gitclone, forceable viareseed).
Consequences
provision-solution.shis legacy — kept only until the engine’s front door is live-proven on a real solution, then deleted. The naming scheme’s bash/TS parity is enforced by a script gate (orbit-deploy/scripts/parity-names.sh) rather than by discipline.- Agent-chat deploys now produce the same stack as the ops path — front door, edge lockdown, verified URLs in the registry — and the agent can run partial scenarios instead of full redeploys.
- The
auroraapp’s env contract grew (Cloudflare token/zone, edge flag, per-solution agent secrets, the previously-missing Mission Control image tag), rendered byprovision-aurora.sh; the aurora image build context moved toimplementation/for the shared-packagefile:dependency. - The solution-service schema gained
deployment.lastRun— live registries need the rebuiltsolution-serviceimage before run logs persist in production. - Destructive teardown is exposed to the chat agent, but double-gated:
confirm: trueand aconfirmIdthat must equal the solution id (enforced in the tool body and incanUseTool), with WorkOS user auth as the immediate follow-on.
Evidence
implementation/shared/orbit-deploy/— the engine (steps, scenarios, runner, Cloudflare client, status, diagnostics, CLI, parity gate)implementation/aurora-webapp/codebase/src/lib/solutions/deploy-azure.ts— now a thin adapter;src/lib/agent/deploy-tools.ts— the tool surfaceinfrastructure/azure/deploy.sh(solutionsubcommand) andprovision-aurora.sh/app-aurora.yaml.tmpl(the env contract)memory/orbit-deploy-engine.md— the decision record