Decisions
Every ADR governing the fleet's choices.
What we picked, what we ruled out, and the reasoning that survives across sessions. Sourced from dark-factory/docs/decisions/; sorted newest first.
Through 2026 H1 the fleet's vocabulary has used fleet and factory somewhat interchangeably:
Gyrum's operational logic today is scattered. Provisioning a runner involves:
Two concrete divergences surfaced on 2026-05-09 made the lack of a named principle expensive:
Every gyrum-fixup fire emits structured evidence at fire time — not just "did the gate stop complaining?" — so fixer correctness is queryable, auditable, and…
Every SaaS app the fleet runs has exactly one trust boundary — the BFF — and internal services trust the network behind it. New services default to no public…
ai-frontend has 95 noun-routes (/operate, /infra, /projects, /platform, /me, /ops, /team, /incidents, /release-status, …) shaped around organisational silos…
Same gating shape as ADRs 171 + 172. Reclassify to Accepted when warp#1762 Phase 1.1 (type:deploy_request schema) ships, demonstrating the typed-ticket-on-Warp…
The companion JSON Schema lives at [docs/specs/pipeline-contract-v0.md](../specs/pipeline-contract-v0.md).
This ADR locks the design now while the substrate paper is fresh, but the architecture it commits to is gated on prior phases shipping evidence:
The fleet's unattended work runs as Claude Code sessions on the operator's laptop. The substrate paper (docs/proposals/unattended-pipeline-execution-substrate.m…
Per [warp#1783](https://warp.gyrum.ai/items/1783) the self-healing EPIC has no dispatcher: the auto-filed warp ticket rides the existing agent-executor queue,…
The auto-diagnosis library is a directory of versioned YAML rules under gyrum-knowledge-base/auto-diagnosis/<shape>.yaml. Each rule has six required fields…
Every gyrum-* tool, ansible wrapper, and CI hook that can fail emits a structured JSON event when it fails. The event has six required fields (tool, context,…
ai-research today is one binary holding every fleet secret (SSH, Hetzner, GitHub PATs). The operator wants to put it on the internet but the secret surface is…
Operator audit 2026-05-07 surfaced 4,455 PRIVATE container versions across the three highest-volume repos on GHCR (GitHub Container Registry, the OCI image…
The current warp ticket model has type (bug | feature | chore | docs | refactor | security | renewal | audit | epic | principle | campaign) which answers WHAT…
Phase 0 of EPIC [warp#1721](https://warp.gyrum.ai/items/1721). Operator (jon, 2026-05-07 ~01:30Z) named the structural shape: "we're using our own runners.…
Phase 0 of EPIC [warp#1686](https://warp.gyrum.ai/items/1686) ("Stacked PRs — branch of a branch"). Today every gyrum-* tool assumes PRs target main. This…
The problem this ADR closes is upstream of the receiver, not in it. Push lands on main before release.yml has run; :latest does not yet point at the new SHA.…
Phase 0 of EPIC [warp#1189](https://warp.gyrum.ai/items/1189) ("direct ssh/sudo access forbidden; all access via scripts"). The EPIC is correct in structural…
Sub-ticket H0.1 of EPIC [warp#1582](https://warp.gyrum.ai/items/1582) (fleet host-state-as-source-of-truth). Sister to [ADR-153](./153-host-state-declarative-sc…
Phase 0 of EPIC warp#1646 (fleet SaaS chrome). The EPIC's structural lift only works if the shell-vs-page boundary is locked BEFORE Phase 1 extraction; without…
Sub-ticket S0.3 of EPIC warp#1551 (fleet sitemap-as-source-of-truth) — the third and last of the Phase 0 ADRs. ADR-155 (S0.1, shipped 2026-05-06 PR#664) names…
Sub-ticket S0.2 of EPIC warp#1551 (fleet sitemap-as-source-of-truth). Phase 0 ships three sister ADRs that lock contracts before Phase 1 substrate ships: S0.1…
Sub-ticket S0.1 of EPIC warp#1551 (fleet sitemap-as-source-of-truth). Phase 0 ships three sister ADRs that lock contracts before Phase 1 substrate ships: S0.1…
Sub-ticket of EPIC warp#1592 Phase 0. Phase 0 ships three sister ADRs that lock the SaaS template library's contracts before any Phase 1 template ships: T0.1…
Operator (jon, 2026-05-06) named the architectural shape behind warp#1581: four hosts (gyrum-ci-runner, warp-01, dark-factory-db, agent-worker-01) appeared on…
Phase 0 of EPIC [warp#1568](https://warp.gyrum.ai/items/1568) (EFF-8: sub-agent rate-limit graceful degradation). Tonight's session (2026-05-06) surfaced a…
gyrum-review-pr runs the 3-persona AI review panel (Priya / Marcus / Lin) against an open PR. Each persona is implemented as an LLM that produces a review BODY…
Today (post-r1+r3, 2026-04-26), every fleet host that terminates TLS via acme.sh --dns dns_cf carries a Cloudflare API token on disk with Zone:DNS:Edit…
[ADR-005](./005-cardinality-labels-vs-fields.md) sets the library rule: an attribute becomes a Prometheus label only if its value set is bounded by…
Server bootstrap scripts historically came in two shapes:
infrastructure/deploy.sh has been emitting === STAGE: <Name> === lines since the Platform UI's Deploy tab shipped — the pipeline stepper in…
Warp today is a tools-only kanban: the home page (/) renders the board, /login renders a 350-line three-path login form, and every other route (/items/:id,…
On 2026-05-05 the fleet merged 18 PRs against this and sister repos. Every PR cited its driving Warp ticket in the body (Closes warp#NNN), and…
The fleet currently has one production bearer-token implementation — warp's internal/auth package (see refs section). It mints wrp_<32-hex-chars> tokens,…
The fleet today gates HTTP endpoints with a coarse four-value scope string — admin / user / agent / readonly — checked at route-mount time via…
gyrum-go/pkg/auth was authored as the fleet's intended shared auth library (Argon2id + JWT + httpOnly cookies + RBAC port shapes), but no repo currently uses…
[warp#1442](https://warp.gyrum.ai/items/1442) (EPIC: warp public identity — mobile-first home page + login + account) opens warp to phone access, which the…
The fleet's standards docs are static. ADR-117 declared the module-guidelines tier (dark-factory/guidelines/<module-type>@v<n>.md) as the canonical home for…
The fleet ships a visual canon (warp#865 is mid-rollout) but no structural canon. Folder and component layout — where source files live, where tests live,…
Phase 0 of EPIC [warp#1318](https://warp.gyrum.ai/items/1318) (activity-gated heartbeat). Today's session surfaced two failure modes that the current heartbeat…
As of 2026-05-05 the gyrum fleet runs 22 production projects against one Postgres at 10.0.0.3:5432, all using the role darkfactory, which has GRANTs on every…
Phase B of the self-hosted runner migration ([warp#1363](https://warp.gyrum.ai/items/1363), PR#228) flipped warp's CI to self-hosted ARM64 runners. The…
A "product" in the gyrum fleet is the user-facing thing — warp, ai-research, distill, devtools, dark-factory itself. A user thinks "I use warp"; they do not…
The current self-hosted runner pool (gyrum-ci-runner-1, gyrum-ci-runner-2 — both Hetzner CAX Ampere ARM64 hosts) leans on the host as the unit of isolation.…
Sub-ticket of EPIC [warp#1358](https://warp.gyrum.ai/items/1358) — per-project changelog + /changes pages + PR title-format ticket-ID contract. Today the fleet…
The fleet is about to begin a non-trivial cross-language migration: warp#1263 EPIC ports the devtools bash CLIs to Go binaries. Naive line-by-line porting of…
Every fresh gyrum-start-work rebuilds the same context the just-shipped sub-agent already had. Reading the ADR cluster, sibling tickets, recent merges, area…
Durable engineering content lives in git ([ADR-126](./126-durable-engineering-content-in-git.md)). The substrate is settled. The shape of the content within…
Multiple times this session (and many sessions before) operators and agents have written durable engineering content — design rationales, conventions,…
The factory has accumulated rich SIGNAL — the agent-reports journal (warp#246), structural-check verdicts, persona-review outcomes, the curator's blocking…
The fleet has shipped two compatible-but-distinct shapes for "what a pipeline step looks like". The library shape — gyrum-pipelines — is block-composition:…
Five gy-queue MVP build attempts — cloud_brave_amber, light_grain_stone, haven_willow_wind, heath_noble_ridge, pond_leaf_falcon, cliff_quartz_north — burned…
Today's warp-01 → warp-02 cutover failed twice: cert acquisition raced with DNS propagation (Caddy http-01 challenge couldn't validate because Let's Encrypt's…
Today the gate stack catches code-level defects (build, test, coverage, complexity, gosec, staticcheck) but does NOT catch the "module ran clean, reality is…
Today the agent brief is the only contract for module-typed work (DB changes, playbook authoring, API endpoints, UI components, ansible roles, agent briefs…
Today every sub-agent brief has to embed the relevant ADRs, principles, memory rules, and CLAUDE.md sections verbatim, because the agent has no canonical place…
The 2026-04-26 PR cycle produced two --admin overrides on the same wrong-premise pattern: Marcus blocked devtools#126 citing the "docs/shared/ propagation…
migrate-service-to-fresh-host.yaml and provision-host.yaml hardcode cx22 as the destination Hetzner server type. The 2026-04-26 dry-run on GAF surfaced "Server…
The board today carries a three-tier taxonomy ([warp #299](https://warp.gyrum.ai/items/299)): initiative > epic > ticket. What is missing is a layer above…
The factory today runs on localhost:9400: local-only, no auth, fine for development. As the runtime moves from rendering dashboards to executing privileged…
The recent fan-out of type: claude steps ([warp #334](https://warp.gyrum.ai/items/334)), structural checks for those steps ([warp #335](https://warp.gyrum.ai/it…
ADR-109 introduced two shapes for runtime-driven Claude calls: type: claude (Claude is the step) and observer: (Claude watches a step). Both are real, but they…
ADR-107 named the principle ("gates as playbook primitives") and migrated four open gate tickets ([#313](https://warp.gyrum.ai/items/313) dry-run,…
Today the factory runs two parallel execution worlds and only one of them is visible.
> Numbering note. Slots 105 and 106 are claimed by in-flight ADR > tickets ([warp #317](https://warp.gyrum.ai/items/317) e2e gate; > [warp…
The warp-01 → warp-02 cutover that triggered this work is the third host migration the fleet has run (after db-shared-01 → db-buzzy-01 via…
> Numbering note. The originating brief and warp epic > (warp #313) named this "ADR-100". Slot 100 was already filled by > 100-factory-growth-boundaries.md…
ADR-097 (accepted earlier today) committed to absorbing the operator-facing PM kanban into the factory at gyrum.ai/pm/* and shrinking warp.gyrum.ai to API +…
The fleet has had warp as its system-of-record AI-worker inbox since ADR-077 and has had structured PM, epics, and a claim-returns-context-bundle protocol…
The fleet today has one production host (warp-01, the Hetzner CX22 carrying warp + distill + hello-world) and a queue of host work (Buzzy box, dark-factory-db,…
The factory at gyrum-labs/ai-frontend is the operator's everything-pane: today, 2026-04-25, it has 77 routes, 1,772 tests, and is growing roughly five routes…
2026-04-25 produced three consecutive sub-agent brief failures inside one session. SWARM-AR was briefed to "implement ADR-095 backups" with a playbook + UI…
SWARM-AA landed this evening and gave warp items three structural fields they were missing — parent_id (the link from a child item up to the work it belongs…
> Superseded note (2026-04-25, same day, ~6 hours later). ADR-103 > reverses the operator-UI cut below: the operator-facing PM kanban > stays at warp.gyrum.ai…
Tonight there are roughly forty-seven open issues across gyrum-labs/* repos that the operator works in directly through the GitHub UI, and roughly forty-seven…
ADR-092 §"Data persistence" landed three persistence shapes for project databases (ephemeral, durable, off-host) and then explicitly punted on backups:…
Today's first end-to-end exercise of the new ADR-092 deploy pipeline hit "needs source on disk" pain twice in one evening. The deploy-project ansible role's…
While bringing up warp.gyrum.ai end-to-end through the new ADR-092 pipeline, the operator hit a recurring shape problem: every gyrum project that exposes an…
Tonight's first end-to-end deploy of warp to warp.gyrum.ai failed for hours and required a manual quick-path because the existing pipeline conflated two things…
ADR-071 picked "Weft" as the product name for Gyrum's SaaS factory two days ago. The semantic intent — that the Gyrum factory has its own user-facing name…
The Gyrum platform is built on a two-phase contract. Phase 1 (today): AI agents help author, debug, and extend playbooks — the human talks to Claude, Claude…
Every gyrum-managed host runs a security telemetry stack — auditd for filesystem and syscall events, Falco for eBPF container events, AIDE for binary…
Every gyrum-managed host registers with the observability stack as a final step of its provision pipeline and de-registers as the first step of its destroy…
Every cloud VM provisioned by a gyrum pipeline carries a cloud-init user-data payload that handles package install, ops-user creation, firewall rules, and…
Any recurring operational rule in the Gyrum platform passes through three layers on its way to being load-bearing — prose in a prompt or doc, a structural…
Every playbook step declares its inputs and its outputs as named, typed ports. Wiring between steps is explicit — a downstream input names an upstream output…
Every side-effecting call to an external system — gh, git, ssh, curl, ansible, docker, psql, gcloud — flows through a shared toolkit script in devtools/ before…
> Numbering note. The user brief named this "ADR-082". Slot 082 was > filled earlier today by 082-experiment-experiments-url-split.md > (landed via PR #345…
ADR-081 §10 left one open question on the Top-10 trickle's critical path: the /experiment (singular, Experiment mode-home) vs /experiments (plural, fleet…
The Platform UI (ai-frontend) has reached ~70 shipped routes across the five modes (Home / Ship / Operate / Infra / Experiment), the persona homes (/me, /ops,…
ADR-078 ships trigger-driven orchestration in four phases; the Phase 2b MVP (cron-only, direct in-process invocation) is single-replica and best-effort-on-miss…
> Supersession note. This ADR supersedes ADR-077 §3 — the > ~/.gyrum/proposals/, ~/.gyrum/approvals/, ~/.gyrum/actions/ > journals and the paired gyrum-propose…
We extend the ADR-068 playbook runtime with a trigger layer — an additive triggers: section in the playbook YAML that declares how a playbook gets fired…
Every project's YAML grows a deployments: block that binds each of its repos to a concrete origin: a host alias resolved through gyrum-catalog, a TCP port, a…
We promote distill-gyrum-ai/e2e-integration/ from "distill's own end-to-end suite" to Fleet-E2E — the fleet's cross-product branch-testing service, a single…
We separate the Gyrum compute surface into three planes — Dev, CI, Ops — and forbid any shared filesystem, shared credentials, or shared runtime between them.…
Every feature branch opened as a pull request on any repo inside a project (ADR-059) spins up its own ephemeral, full-stack preview environment at a private,…
Every infrastructure mutation Gyrum performs — DNS records, Cloudflare Tunnel routes, Cloudflare Access applications and policies, Caddy site configuration,…
> Superseded in part by [ADR-091](./091-rename-weft-to-crank.md). §1 (product name = Weft) is replaced — the product is now Crank. Every other section of this…
We ship a single Svelte component — <PlaybookRunner> — as the canonical frontend binding to the ADR-068 playbook runtime. The component accepts a playbook id…
We gate the playbook runtime (ADR-068) with a six-part security model: (1) per-playbook authorisation via allowed_personas: + allowed_users: front-matter,…
We build an embedded, Postgres-backed playbook runtime inside ai-research that executes playbooks (ADR-067) as first-class server-side work. The runtime…
A Playbook is a unified primitive — one schema, one front-matter, one catalogue — with a kind: discriminator that selects kind-specific extension fields; every…
The Platform UI is converging on two recurring visualisation shapes that are neither full charts nor single scalars. They appear in KPI tiles, alert rows,…
ADR-054/058 gave the Platform UI a five-mode lens (Home / Ship / Operate / Infra / Experiment). ADR-059 added a second orthogonal axis — project. Both answer…
ADR-060 introduced capture-layer experiments (exp-315 Hetzner audit, exp-316 GitHub repo audit, planned exp-317 Prometheus drift, exp-318 Caddy routes, exp-319…
The gyrum platform is operated as a single-tenant system today: one operator, one set of projects, one set of infrastructure, one set of secrets, one fleet…
The Platform UI (ai-frontend, SvelteKit + Svelte 5 runes) has grown a set of recurring visual primitives — KPI tiles, status pills, mode switchers, side rails,…
Two pieces of generic infrastructure currently live inside application repositories:
Two engines already live in gyrum-labs/ai-research:
ADR-054 and ADR-058 landed the five-mode shell — Home / Ship / Operate / Infra / Experiment — as the Platform UI's primary navigation. Modes are verbs: "what…
ADR-054 (shipped earlier on 2026-04-22) split the Platform UI's single-page mode dispatcher into three dedicated routes — /ship, /operate, /experiment — and…
On 2026-04-22 the fleet observability rollout added 17 per-product scrape jobs to Prometheus one at a time, as each service was wired through…
On 2026-04-22 the Platform UI's Operate-mode screen flagged research.gyrum.ai and guardian.gyrum.ai as reporting identical 11.36 % error rate and 21.7 ms p95 —…
On 2026-04-22 a security-follow-up probe of the observability stack on dark-factory-ops (178.104.63.31) found the live and the bootstrap compose files in three…
ai-frontend ADR-003 (2026-04 draft in ai-frontend/docs/decisions/003-three-modes-platform-ui.md) ruled that the Platform UI's three modes — Ship / Operate /…
[ADR-051](051-observability-by-default-in-build-pipeline.md) wired observability into every backend emitted by the build-full pipeline: pkg/observ import,…
The Platform UI's Operate mode ([ai-frontend §5](https://github.com/gyrum-labs/ai-frontend/blob/main/docs/platform-ux-redesign-proposal.md#5-operate-mode))…
build-full (the 73-step pipeline at ai-research-dev/cmd/server/pipeline/) generates brand-new SaaS products from briefs. Every product shipped through this…
Note on ADR number: drafted as ADR-049 in parallel with the alertmanager bearer-auth work. A parallel agent merged an unrelated ADR-049: Alertmanager…
Issue #268 was filed describing alertmanager.gyrum.ai and ntfy.gyrum.ai as "publicly exposed with no auth", severity HIGH.
The ops VPS (dark-factory-ops) runs Caddy as the public ingress for the four observability surfaces: grafana.gyrum.ai, alertmanager.gyrum.ai, ntfy.gyrum.ai,…
The 2026-04-22 manual end-to-end wire-up of distill into the observability stack (dark-factory issues #266–#273) surfaced three related failure modes in the…
The Tier-0 pack ([ADR-013](013-templates-in-dark-factory.md), [ADR-014](014-stable-uid-as-idempotency-key.md)) answers five versions of one question: is this…
The original [observability playbook](../observability-playbook.md) was a Phase-1-shaped checklist: nine numbered steps an operator copy-pasted into a service…
pkg/email ships a LogSender for dev/CI so operators can see that a send "happened" without wiring a real provider. The same instinct — "dump everything so we…
ADR-042 commits us to a Sender abstraction with multiple concrete implementations. The question this ADR answers is which concrete sender ships first — and by…
Transactional email (password resets, receipts, verification codes, invites) is a Tier-1 gap on the [platform gap audit](../platform-gap-audit.md). Every…
deploy.sh gained a Verify observability stage ([ADR-040](./040-grafana-provisioning-at-deploy-time-not-ci-time.md)) that probes Loki for recent log lines and…
Phase 3 of the observability rollout ([ADR-013](013-templates-in-dark-factory.md), [ADR-014](014-stable-uid-as-idempotency-key.md)) produces per-service…
pkg/audit/sink (ADR-038) needs a tamper-evidence property: after the stream leaves the process, an auditor should be able to detect insertion, deletion, or…
pkg/audit already exists: a structured, asynchronous audit logger backed by a Store interface, designed for services that need a high-throughput record of who…
Distill's YouTube handler takes a user-supplied URL and dereferences it server-side. So do (or will) summarisers, feed fetchers, OEmbed integrations, and any…
Every gyrum service with cookie-based authentication needs CSRF protection on state-changing endpoints. The two mainstream patterns are:
The security tranche (threat model, standards, playbook, runbook, tripwires, alerting) identified three library-level controls every service needs to integrate:
pkg/observ standardised gyrum Go services on log/slog, JSON output, the service/version/commit/release_track ambient tags, and the layered redactor. A handful…
Phase 2c of the observability rollout adds a database/sql wrapper to [gyrum-go/pkg/observ](https://github.com/gyrum-labs/gyrum-go/tree/main/pkg/observ). The…
Prometheus metrics answer "how is the service behaving", but several operational questions are about the service itself: is it reachable right now, what…
[ADR-001](001-self-hosted-observability-stack.md) committed us to self-hosting Loki + Prometheus + Alloy + Grafana (+ Tempo in Phase 6). It did not answer…
Phase 1 of the observability rollout shipped pkg/observ as the foundation for every gyrum Go service: build identity, JSON slog logger, probe primitive,…
[security-standards.md](../security-standards.md) lists ~15 rules every service must follow. Some can be enforced mechanically (dependency pins, SHA-pinned…
Credentials — HMAC session secrets, API keys, DB passwords, SSH keys, OAuth client secrets — do not stop being valuable to an attacker on any schedule. The…
Honeytokens are fake credentials and fake resources planted in a system where legitimate users would never touch them. Any touch is, by construction, an…
The threats enumerated in [security-threat-model.md](../security-threat-model.md) span a wide surface: auth, authz, input validation, output encoding,…
User-visible contracts (latency, availability, success rate) are the concerns we most want to alert on correctly. The two failure modes of alerting on them:
An alert without a runbook is a notification that wakes someone up with a problem they don't know how to solve. Real incidents — and years of other teams'…
Grafana lets alert rules be created and edited from the UI. That path is attractive: click-to-save, immediate effect, no YAML syntax. But a rule edited in the…
[ADR-001](001-self-hosted-observability-stack.md) put Grafana + Loki + Prometheus on a self-hosted VPS. Phase 5 needs alerting: a rule evaluator, a router, and…
This slot is intentionally empty. ADR-020 and ADR-022 both exist; no ADR-021 was ever written.
The factory runs one Postgres instance (dark-factory-postgres) that every product-needing-SQL shares. [platform-gap-audit §5.5](../platform-gap-audit.md#55-sing…
Multi-repo products (frontend + backend + worker, typically also migrations) introduce a coordination problem single-repo products do not have: in what order…
The factory has ~30+ repos under gyrum-labs/ (see [platform-gap-audit §1.2](../platform-gap-audit.md#12-current-shape)). Today, "what is a product?" is…
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…
ADR-002 chose log/slog and ADR-003 chose JSON-line output; the Phase 1 library in [pkg/observ](https://github.com/gyrum-labs/gyrum-go/tree/main/pkg/observ)…
On-call triage and platform health are different questions asked by different people at different times.
Grafana identifies a dashboard by its uid — a short stable slug that, together with the organisation, uniquely names the dashboard. A POST to Grafana's…
The Phase 1 observability library lives in github.com/gyrum-labs/gyrum-go/pkg/observ ([ADR-008](008-single-observ-library-vs-per-service-convention.md)). A…
[ADR-011](011-one-question-per-dashboard.md) establishes that every dashboard answers one question. That rule is about purpose. Purpose alone does not prevent…
Dashboards grow. A dashboard that started as "is this service healthy?" acquires a panel for the one time someone debugged a memory leak, then a panel for the…
Phase 3 of the observability rollout ([observability-architecture.md](../observability-architecture.md#whats-not-here-yet)) wires deploy-stage dashboard…
The log pipeline has six serial stages (see [observability-architecture.md#data-flow--logs](../observability-architecture.md#data-flow--logs)): app → stderr →…
Every Go service in the factory needs the same things: JSON log lines on stderr, build-identity fields on every line, redaction, a probe primitive, a…
Every log line leaves the process with the possibility of embedding a secret. The failure mode is catastrophic and one-way: once a credential has reached Loki,…
When a service logs an error, the Phase 5 alerting story needs to group errors into a small, named set of categories so that SLO burn-rate alerts can target…
Loki indexes by labels. Every distinct combination of label values creates a new stream; chunks are allocated per stream. High-cardinality labels (user IDs,…
Canary deployments are a Phase 3+ feature: split traffic between two replicas of the same service, compare error rate and latency between them, promote the new…
Once we committed to slog (ADR-002) and a Loki-backed stack (ADR-001), the on-wire line format still had a choice. slog ships both JSONHandler and TextHandler;…
The observability library needs a structured logging core. Every Go service in the factory will import it, so the choice propagates everywhere and is expensive…
Phase 1 of the observability rollout ships a structured-logging library (github.com/gyrum-labs/gyrum-go/pkg/observ — see [gyrum-go…