Skip to content

Add $schema versioning to fleet.json; carry scope per server entry.#1240

Open
floitsch wants to merge 3 commits into
floitsch/build-artemis-service.s-new.040from
floitsch/build-artemis-service.s-new.050
Open

Add $schema versioning to fleet.json; carry scope per server entry.#1240
floitsch wants to merge 3 commits into
floitsch/build-artemis-service.s-new.040from
floitsch/build-artemis-service.s-new.050

Conversation

@floitsch
Copy link
Copy Markdown
Member

@floitsch floitsch commented May 20, 2026

Adopts the pod-specification $schema pattern for the fleet file, and
introduces the per-service scope concept by attaching it to each
server entry. This is the on-disk half of the org-agnostic data-plane
work; the in-memory model still exposes a single organization-id and
gets a follow-up.

New on-disk shape

{
  "$schema": "https://toit.io/schemas/artemis/fleet/v2.json",
  "id": "<uuid>",
  "broker": "<server-name>",
  "groups": { ... },
  "migrating-from": [...],
  "servers": {
    "<server-name>": {
      "type": "supabase",
      "host": "...",
      "scope": "<blob>"
    }
  },
  "recovery-urls": [...]
}

The legacy top-level "organization" UUID is gone. The broker
reference stays a plain string. Each server entry carries its own
opaque scope alongside its connection info — the scope is unread by
ServerConfig.from-json (the reader pre-strips it).

For the current Toit-hosted setup, scope is the organization-id UUID
stringified. Future per-service backends (pod-store, fleet-store) will
get their own scope under their own server entry without any schema
churn.

Why scope-on-server (rather than nested under broker)

Migrating-from servers automatically carry their own scope without
needing a parallel scope map at the top level. Picking a different
broker is just changing the broker string. Adding new services
(pod-store: "<name>", etc.) doesn't require restructuring the
broker block. The cost is conceptual: connection info and authorization
info now live in the same object — see the discussion in REFACTOR.md.

Compatibility

  • Reader accepts both shapes. Files with $schema use the new
    layout (scope is read from servers[broker-name].scope); files
    without it fall back to the legacy top-level organization.
  • Writer always emits the new shape, copying the fleet's single
    organization-id into every server entry's scope field for now.
    Any edit to an old fleet.json upgrades it in place on next write.
  • In-memory FleetFile.organization-id is unchanged in shape and
    type; renaming it to a Scope-typed field is a follow-up. Scopes on
    non-broker server entries are read but ignored — they become
    load-bearing once the in-memory model tracks per-server scope.

Tests

  • fleet-root-test gains a back-compat case that downgrades the new
    file to the legacy shape (strips $schema and scope fields, moves
    the broker's scope back to a top-level organization) and exercises
    the reader.
  • cmd-fleet-init-test and cmd-fleet-create-reference-test keep
    reading fleet-json[\"broker\"] as a string.
  • make test — 82/82 passed
  • make test-supabase — 32/32 passed (rerun pending after this PR's
    scope-on-server amendment)

The schema URL is a placeholder; it goes live when we publish the
schema JSON to public/schemas/fleet/ alongside the pod-spec schemas.

floitsch added 2 commits May 19, 2026 18:20
Adopts the pod-specification pattern (a $schema URL string identifies
the format) for the fleet file. The new on-disk shape:

  {
    "$schema": "https://toit.io/schemas/artemis/fleet/v2.json",
    "id": ...,
    "broker": { "ref": <broker-name>, "scope": <uuid> },
    ...
  }

Replaces the legacy top-level "organization" UUID and bare-string
"broker" with a single "broker" object that nests its ref alongside
its scope. The scope is opaque to the fleet schema; for the current
Toit-hosted setup it happens to be the organization-id UUID stringified.
Future per-service backends (pod-store, fleet-store) get the same
nested shape with their own scopes.

Reader accepts both shapes:
- Files with "$schema" use the new layout.
- Files without it fall back to the legacy fields.

Writer always emits the new layout — any edit to an old fleet.json
upgrades it in place on next write.

In-memory model is unchanged: FleetFile still exposes
'organization-id' as a Uuid. Renaming that to a Scope-typed field is a
follow-up.

Tests:
- cmd-fleet-init-test and cmd-fleet-create-reference-test now read
  fleet-json["broker"]["ref"] when looking up the broker name.
- fleet-root-test gains a back-compat case that downgrades the new
  format to the legacy shape and exercises the reader.
Restructures the new fleet.json shape: the broker reference is again a
plain string referring to a server name, and each server entry carries
its own scope alongside its connection info:

  {
    "$schema": "...",
    "broker": "<name>",
    "servers": {
      "<name>": { "type": ..., "host": ..., "scope": "<blob>" }
    }
  }

Migration-from servers automatically carry their own scope without
needing a parallel scope map at the top level. Picking a different
broker is just changing the 'broker' string.

The reader pulls the scope field out of each server entry before
handing the rest to ServerConfig.from-json, so ServerConfig stays
scope-free in memory. For now only the broker's scope is actually used
(it populates organization-id); scopes on other entries are read but
ignored. They become load-bearing once we track per-server scope in
memory.

The writer emits the new shape with the fleet's single organization-id
copied into every server entry. The in-memory FleetFile is unchanged.

Tests reverted to reading fleet-json["broker"] as a string and the
back-compat downgrade in fleet-root-test now strips the scope field
from server entries (and moves the broker's scope back to a top-level
'organization').
@floitsch floitsch changed the title Add $schema versioning to fleet.json; nest broker reference. Add $schema versioning to fleet.json; carry scope per server entry. May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant