Skip to content

Open deviations

Per 00-REFERENCE-ARCHITECTURE.md §3a: an unacknowledged gap from the constitution is drift; an acknowledged one is a decision. This table is that acknowledgment. When a row is fixed, it is deleted, not marked done. A row whose trigger has fired says so — a fired trigger nobody acted on is the same drift this register exists to prevent, just with better paperwork.

Principle Deviation Since Reasoning / trigger to close
P1 (AppHost is the composition root) No .NET Aspire AppHost. SwarmApi.Api is a single ASP.NET Core project; the development composition root is docker/docker-compose.yml, which now orders startup with a healthcheck (api waits for rosbridge). M3 See ADR-0002. Trigger: a second .NET service of this repo's own (the M5 mission layer was the planned one). The compose file already carries four services, so revisit if startup ordering needs more than one healthcheck edge.
P2 (shared kernel) — partly SwarmApi.ServiceDefaults is guarded by an architecture test and a CI size ceiling (2026-09-22), but JWT wiring lives in SwarmApi.Infrastructure rather than the kernel, and there is no OpenAPI document. M3 One service validates tokens, so the kernel has nobody to share them with yet; an OpenAPI generator would be a second third-party runtime package (see the README's dependency budget). Trigger: a second service validating the same tokens, or the first consumer outside this repository needing a machine-readable contract.
P5 (JWT / asymmetric signing), narrowed SwarmApi.Api validates JWT bearer tokens (RS256, JWKS) from an external authservice instance and, when Enforced, denies by default: every endpoint needs a token unless API-SURFACE.md lists it as open — the dashboard's static files, /health, /alive and the GET reads — so every write is attributable, and the identity that proposed a mission plan cannot approve it (ADR-0009). The dashboard has no login UI, so in Enforced mode every one of its buttons gets a 401: start, approve, reject, dispatch — and abort and land-all, so an operator with only the dashboard cannot stop the swarm; approval and stopping then go through the API with a token. In Open mode nobody is identified, so separation of duties does not apply. Tokens carry no tenant claim yet. M3; narrowed 2026-09-21; deny-by-default 2026-09-22; approval gate 2026-09-22 See ADR-0005 and ADR-0009. Trigger: a login flow for the dashboard (it closes the stop-button gap too), a requirement to distinguish readers, or per-tenant token claims (needed by ADR-0006's orchestrator).
P7 (Fly.io) — swarmsim-api Written, not deployed: flyio/swarmsim-api.fly.toml and .github/workflows/flyio.yml exist (ADR-0011), but no Fly app has been created, because the repository has no FLY_API_TOKEN and no authservice to name as SWARM_AUTH_AUTHORITY. The app refuses to run Open (Auth:Required), so it cannot be deployed without one. M3; written 2026-09-22 The one-time setup in flyio/SECRETS.md. Close (delete this row) on the first green deploy, whose last step checks /health for Enforced and File.
P7 (Fly.io) — swarmsim-sim No deployment path for the Gazebo/PX4/ROS 2 stack. The unit ADR-0007 planned — Fly GPU Machines — no longer exists: Fly ended GPUs on 2026-08-01. The headless stack runs on CPU (the SITL smoke flies it on a 4-vCPU runner), so the unit is now per-tenant CPU Machines, created and destroyed per run by the orchestrator ADR-0012 designs. M3; GPUs gone 2026-08-01 Per ADR-0007's amendment and ADR-0012. Trigger: docs/PROMOTION.md's test passing — a named design partner above all — which also stands in for P7's original "first pilot with a real operator".
P12 (tag-driven CI/CD, change detection, ordered deploy) flyio.yml is the tag-driven deploy: tests, then change detection against the previous tag (a missing app is always selected), then one image built and pushed to registry.fly.io, then the deploy and a post-deploy check. It has never run against a real Fly organisation, and with one app there is no ordering to exercise. M3; written 2026-09-22 Same as P7 swarmsim-api. Ordering becomes real with a second unit (ADR-0012's runs, or a deployed authservice).
P3 / P4 (service owns its database, MigrateAsync) Swarm state, missions, mission plans and idempotency keys live in memory, so a restart forgets a pending approval and its code, and a replayed key after a restart runs its write again. Scenario runs persist, as one JSON file per run in ScenarioRuns:Directory (a Fly volume). That is a document store with no entity model, so it is outside P4's rule rather than an exception to it, and it is bounded to one machine (ADR-0011). M3; plans and keys 2026-09-22; run store 2026-09-22 Constitution P4 note. Triggers: a requirement to recall a mission or a plan after a restart; more than one API machine (keys, plans and runs would then need a shared store); or per-tenant storage (ADR-0012). The last two mean Postgres.

Everything not listed here is met as stated in docs/architecture/README.md's compliance checklist.