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:
- 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)
- A service named after one concept actually serves the other (fleet-events — observes factory runs, not fleet products)
- 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-eventsrepo →factory-events(Phase C1 —gh repo rename)
gyrum-catalog/manifests/fleet-events.deploy.yaml→factory-events.deploy.yaml+ content (Phase B3 / warp#2298)ghcr.io/gyrum-labs/fleet-eventsimage →ghcr.io/gyrum-labs/factory-events(Phase C2)- Vault keys
FLEET_EVENTS_DB_URL/_BEARER_TOKEN/_GITHUB_WEBHOOK_SECRET→FACTORY_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.aihostname — 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-factoryrepo — 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 writesFACTORY_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-eventsalready cloned needsgit remote set-urlonce 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.aihostname 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:
gh repo view gyrum-labs/factory-eventsreturns success; old URL redirects.docker pull ghcr.io/gyrum-labs/factory-events:latestsucceeds.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.
gyrum-catalog/manifests/factory-events.deploy.yamlexists;fleet-events.deploy.yamldeleted.- Outstanding warp tickets — searching warp for "fleet-events" in title or body returns zero open results.
- 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):
vault listreturns noFLEET_EVENTS_*keys.gh container list(or ghcr API) returns nofleet-eventstags newer than the last cascade build.- 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/runnersURL 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)