Decisions

ADR-179 — Factory and fleet are disjoint concerns; fleet-events is renamed to factory-events

Through 2026 H1 the fleet's vocabulary has used **fleet** and **factory** somewhat interchangeably:

#179

ADR-179 — Factory and fleet are disjoint concerns; fleet-events is renamed to factory-events

  • Status: Accepted
  • Date: 2026-05-10
  • Supersedes: nothing (introduces a framing that prior ADRs assumed implicitly)
  • Cross-links: ADR-127 (docs-as-typed-playbooks; original fleet-events architectural context); warp#2294 (rename cascade meta-EPIC); warp#2117 (the fleet-events deploy ticket, body to be updated to factory-events as part of cascade)

Context

Through 2026 H1 the fleet's vocabulary has used fleet and factory somewhat interchangeably:

  • "fleet-events" — the webhook ingest + jobs query service (warp#1122 v0, deploy queued via warp#2117)
  • "fleet-config/" — the registry directory (DNS / cost-tiers / auth-models / postgres-cluster)
  • "fleet hosts" — Hetzner machines provisioning services
  • "fleet-wide" — across all gyrum-labs repos
  • "dark-factory" — cross-cutting orchestration repo holding ADRs, playbooks, runbooks
  • "factory pipeline" — the spec-to-deploy compilation flow (warp#2192 family)
  • "factory" — sometimes the playbook runtime; sometimes the broader build apparatus

The collision becomes a real problem when:

  1. A surface owned by one concept lives in the other's housing (warp.gyrum.ai/runners — runners is a factory concern, but the page lives in the board app)
  2. A service named after one concept actually serves the other (fleet-events — observes factory runs, not fleet products)
  3. Operators have to repeatedly disambiguate during architectural conversation ("when you said fleet-events earlier, did you mean…")

The need for explicit disjoint framing surfaced during the 2026-05-10 evening incident where warp.gyrum.ai/runners broke with a PAT-scope error, and the conversation about where the data plane should live immediately collided with the vocabulary problem.

Decision

We adopt framing-B: factory and fleet are disjoint concerns.

Factory Fleet
What The runtime + mechanism that builds services The collection of SaaS products that run
Shape Verb / kitchen / compiler Noun / plates / output
Examples Playbook execution engine, gyrum-create-service CLI, deploy pipelines, CI runners, factory-events (event ingest) Customer-facing products the factory ships
Repo examples gyrum-labs/dark-factory, gyrum-labs/devtools, gyrum-labs/playbook-runtime, gyrum-labs/factory-events, gyrum-labs/warp (internal apparatus today; may evolve), gyrum-labs/ai-frontend (operate-mode is factory ops; other modes may host fleet surfaces) (no examples yet — pre-launch)
Owns dark-factory/, gyrum-create-service (sub-E warp#2198), gyrum-provision (sub-F warp#2199), playbooks tree, hosts.yaml + fleet-config/ (substrate config used by both, name preserved for backwards compat), gyrum-catalog/manifests/ per-product manifests + canonical URLs once products exist

Factory makes fleet. Spec → factory mechanism → service-in-fleet.

Today the fleet (in this strict sense) is empty — there are no customer-facing SaaS products yet. Every running service is factory infrastructure (the apparatus that will produce fleet members in the future). The factory pipeline tickets (warp#2192-2199) are explicitly the lift that turns this apparatus into one that can produce fleet members at scale.

Cascade: fleet-events → factory-events

Under framing-B, the fleet-events service is structurally factory-shaped — it observes factory runs (CI workflows, deploys, agent transitions), not fleet products. The name lies. Rename to factory-events.

Why now:

  • The service isn't deployed yet (warp#2117 outstanding). No production data plane to coordinate around.
  • Operator habits aren't established. No bookmarked URLs to invalidate.
  • Outstanding tickets are mutable (warp#2117, warp#2187, warp#2257, plus the cutover family 2117-2121).
  • Every day we defer compounds the lexical confusion in PRs / ADRs / tickets / session diaries.

Renames (cascade scope, surveyed via grep across the fleet on 2026-05-10):

  • gyrum-labs/fleet-events repo → factory-events (Phase C1 — gh repo rename)
  • gyrum-catalog/manifests/fleet-events.deploy.yamlfactory-events.deploy.yaml + content (Phase B3 / warp#2298)
  • ghcr.io/gyrum-labs/fleet-events image → ghcr.io/gyrum-labs/factory-events (Phase C2)
  • Vault keys FLEET_EVENTS_DB_URL / _BEARER_TOKEN / _GITHUB_WEBHOOK_SECRETFACTORY_EVENTS_* (Phase C3, write alongside; old kept for 30-day soak)
  • ~20 file references across dark-factory docs (warp#2296), fleet-events internal (warp#2297), gyrum-catalog (warp#2298), ai-frontend src (warp#2299), devtools + ticket bodies (warp#2300)

Stays (deliberate):

  • events.gyrum.ai hostname — already neutral, no prefix to fix.
  • fleet-config/ directory — config used BY the running substrate, applies to both factory + fleet hosts. Name correctly describes its role.
  • gyrum-labs/dark-factory repo — already correctly named (factory orchestration).
  • hosts.yaml — inventory of running substrate hosts, both kinds.
  • Historical session diaries (before 2026-05-10) — historical accuracy preserved.
  • ADR-127 (docs-as-typed-playbooks) — not edited; this ADR (178) cross-links forward.

Phased rollout

Tracked under meta-EPIC warp#2294:

  • Phase A (in-band): ADR-179 (this file, warp#2295) lands.
  • Phase B (parallel consumer PRs): warp#2296 (dark-factory docs) · warp#2297 (fleet-events repo internal docs) · warp#2298 (gyrum-catalog manifest) · warp#2299 (ai-frontend code) · warp#2300 (devtools + bulk ticket-body update).
  • Phase C (operator-confirm, audit-logged, after all of Phase B lands): C1 = gh repo rename; C2 = ghcr image rebuild + push under new name; C3 = vault writes FACTORY_EVENTS_* alongside existing keys.
  • Phase D (30-day cleanup window): remove old ghcr tags, decommission old vault keys, drop redirect once activity zeroes.

Consequences

Positive:

  • Vocabulary in PRs / tickets / ADRs / session diaries unambiguous going forward.
  • New contributors onboard with a clean factory/fleet mental model.
  • The factory-bus inversion (future ticket — making factory-events the source of truth, gh a downstream sink) becomes namesake-coherent.
  • The runners-page migration (out of warp board into ai-frontend operate) has clear vocabulary to defend.

Negative / cost:

  • Cascade work — ~7 PRs across 5 repos + ~6 ticket-body updates. Bounded but non-trivial.
  • 30-day GitHub redirect window operationally easy but requires monitoring (anyone bookmarking old URLs gets a head's-up via GitHub's auto-redirect notice).
  • Anyone with gyrum-labs/fleet-events already cloned needs git remote set-url once Phase C1 lands.
  • Old vault keys stay readable through the 30-day window — small attack surface increase. Mitigated by Phase D's cleanup.

Neutral:

  • events.gyrum.ai hostname unchanged → operator URLs in monitoring + documentation stay stable.
  • ADR-127 not edited → backward-link readers still find historical context.

Verification

End-to-end after Phase C lands:

  1. gh repo view gyrum-labs/factory-events returns success; old URL redirects.
  2. docker pull ghcr.io/gyrum-labs/factory-events:latest succeeds.
  3. grep -rn "fleet-events" ~/work/gyrum-labs/{dark-factory,ai-frontend,gyrum-catalog,devtools,warp,fleet-events,factory-events} returns zero matches outside cross-link banners.
  1. gyrum-catalog/manifests/factory-events.deploy.yaml exists; fleet-events.deploy.yaml deleted.
  2. Outstanding warp tickets — searching warp for "fleet-events" in title or body returns zero open results.
  3. Vault: FACTORY_EVENTS_* keys present and consumers use them; old keys remain readable through Phase D's 30-day window.

After Phase D (30 days later):

  1. vault list returns no FLEET_EVENTS_* keys.
  2. gh container list (or ghcr API) returns no fleet-events tags newer than the last cascade build.
  3. GitHub redirect from old URL still works (GitHub maintains it indefinitely until the URL is reused by a different repo).

Out of scope for ADR-179

  • Actually deploying factory-events (warp#2117 — separate ticket, awaits deploy script from warp#2187).
  • The deeper factory-bus inversion (the long-term vision where factory-events becomes the source of truth and gh is a downstream sink). Filed as a sister ADR + ticket post-cascade.
  • Renaming gyrum-labs/dark-factory — already correctly named.
  • Renaming fleet-config/ — correctly named.
  • Migrating any production observability data (none exists yet — service isn't deployed).
  • Renaming surfaces that aren't fleet-events specific (e.g. /operate/runners URL stays — it's the factory-ops UI living in ai-frontend's operate mode).

References

  • warp#2294 — rename cascade meta-EPIC
  • warp#2295 — this ADR's filing ticket
  • warp#2296 / 2297 / 2298 / 2299 / 2300 — Phase B sub-tickets
  • warp#2117 — fleet-events deploy (body updated to factory-events as part of warp#2300)
  • warp#2187 — fleet-events deploy script (body updated to factory-events as part of warp#2300)
  • ADR-127 — docs-as-typed-playbooks (closest prior fleet-events architectural context; preserved as historical, cross-link forward to ADR-179)