Decisions

ADR-017: Platform scope and sequencing

gyrum is a SaaS factory (see [platform-gap-audit.md §1](../platform-gap-audit.md)). It ships product experiments at a cadence of several live products and many more scaffolds, on one VPS, on one shared Postgres, with…

#017

ADR-017: Platform scope and sequencing

Status: Proposed Date: 2026-04-21

Context

gyrum is a SaaS factory (see platform-gap-audit.md §1). It ships product experiments at a cadence of several live products and many more scaffolds, on one VPS, on one shared Postgres, with one shared Go library. The factory thesis is that fast experiment loop plus shared primitives beats per-product perfection.

Given that shape, platform work is not a single backlog of equally-weighted items. It is a ranked list where doing the wrong thing first is as costly as doing nothing. We have spent significant effort on observability (sixteen ADRs through ADR-016) because it was the most immediate need; the platform-gap-audit makes explicit that observability is perhaps 5% of what a real SaaS platform requires. The remainder — auth integration, CSRF, rate limiting, secrets handling, backups, staging, alerting, background jobs, billing, email, feature flags, legal templates, admin surfaces, cost monitoring — is not ambient progress. It requires ranking.

Three forces make this a now-decision:

  1. Live risk. platform-gap-audit §5 lists twelve concrete present-day risks — live XSS in distill, no CSRF, per-IP rate limit only, .env-on-disk secrets, single-shared-Postgres blast radius, untested backups, no staging, no alerting, no cost monitoring. Any of these is a credible path to data loss, credential-stuffing, or runaway spend. An unordered backlog leaves them uncoordinated.
  2. Library-ahead-of-products drift. Several gyrum-go packages (pkg/auth, pkg/billing, pkg/jobs) are production-ready but have zero or near-zero product integration. The cost of not ordering adoption is that every new product reinvents the primitive it could have inherited — erasing the factory benefit.
  3. Thesis fragility. "Fast experiment loop with shared primitives" only holds as a thesis if the primitives are adopted. If work drifts into one-off per-product solutions (which is the default when priorities are unstated), the factory becomes a collection of small projects with a shared VCS host.

Stakeholders are the platform-ish engineers maintaining the shared library and the product owners depending on factory defaults. Both need a visible priority order to argue against.

Decision

We adopt the tiered sequencing documented in platform-gap-audit.md §4 and the 6-month tranches in §6 as the platform plan of record, subject to quarterly review.

Concretely:

  • Tier 1 (existential — present-day risk of data, money, trust, or shipping-cadence loss) blocks Tier 2. No Tier-2 work is scheduled while any Tier-1 item is open.
  • Tier 2 (quality / trust — work that gets us to a product we would sell to a paying customer without flinching) follows Tier 1 and precedes Tier 3.
  • Tier 3 (scale / maturity — work justified by operational load, external scrutiny, or enterprise posture) does not start until Tier 1 and Tier 2 are substantially closed.
  • Tier 4 (cultural / organisational — review cadence, ownership, incident ritual, new-SaaS checklist) runs alongside Tier 1 and Tier 2; it is cheap in engineer-hours and expensive in its absence.

Each tranche in §6 carries an explicit exit criterion. A tranche ends when its exit criterion is observably met — not on its nominal date. The strategic review runs quarterly; at review the tier list may be re-shuffled, the out-of-scope list may be amended (in either direction), and the thesis itself may be re-tested.

The out-of-scope list in platform-gap-audit.md §7 is part of this decision. Anything on that list requires a triggering event — a specific customer, metric, incident, or regulatory change — to move in-scope.

Consequences

What becomes easier. A new platform initiative can now argue its case against an explicit order. "Where does this fit?" has an answer. A product owner blocked by absence of a factory default (auth, billing, staging, flags) can see when unblocking arrives, and can escalate if the tranche slips. Quarterly review creates a known seam for thesis disagreement instead of ambient drift.

What becomes harder. Work that does not fit the current tier is visibly deprioritised. A proposal to build search, SEO tooling, or native-mobile support before Tier-1 and Tier-2 are closed has to argue explicitly against this decision. That is the intended friction; it is still friction.

What we sign up to operate. The quarterly review is load-bearing — if it does not happen, the tier list goes stale. The review is mandated in §4.4 T4-A. The gap-audit itself becomes a living document: each review updates the 🟢/🟡/🔴 matrix in §2 and the tier rankings in §4 against what has actually shipped.

What we accept as risk. The priorities may be wrong. Specifically: "Tier 1 existential" reflects the authors' current judgement of risk likelihood and cost. A security incident, a loud customer, or a regulatory surprise could demand re-ranking outside the quarterly cadence. The decision allows for mid-cycle re-ranking via amending ADR; the cost is process overhead.

Non-consequence: this ADR does not lock specific libraries, subsystems, or product decisions. It locks the shape of the decision-making — tiers, tranches, out-of-scope list, quarterly review. A later ADR can reshape the tiers themselves without superseding this one, provided it re-evidences the thesis.

Alternatives considered

  • Build everything at once. Rejected. Headcount does not support it. Attempting it guarantees that Tier-1 items are under-resourced while Tier-3 items consume effort with no present-day pay-off. This is the default failure mode of an unordered backlog.
  • Per-product opt-in to shared primitives. Rejected. Each product chooses whether to adopt pkg/auth, pkg/jobs, observability, etc. Outcome: the primitives drift, the products diverge, and the factory benefit erodes to zero. The whole point of the factory is that new products inherit defaults; opt-in makes defaults opt-in, which erases the "default" property.
  • Observability-only focus. Rejected. Observability is a means. Without auth, rate limiting, secrets handling, and staging, we are observing insecure systems serving no paying customers. The current state is the artefact of this alternative (implicit rather than chosen), and this ADR is the correction.
  • Security-first ordering (every security gap before any quality gap). Considered and partially accepted — Tier 1 is security-and-data-loss-heavy by design. Full rejection would stall every quality/feature item behind an open-ended security backlog; full acceptance is the current ordering, scoped to "existential" rather than "every imaginable security concern."
  • Customer-driven ordering only. Rejected. Many Tier-1 items (secrets handling, backups, CSRF) are pre-customer and will never surface in a support ticket until they cause an incident. Customer demand is evidence; it is not the only evidence.
  • External consultant roadmap (SOC2 readiness, pen-test findings) drives the order. Rejected for now; revisited in Tier 3 (T3-D, T3-E). External scrutiny is useful but expensive, and it reports on the substrate rather than shaping it — we need the substrate in place first so the findings tell us something new.

Supersedes: none Superseded by: