clone

an offline map explorer where each world, from a game map to a city's open data, ships as one .atlas file

feat/atlas-next-horizon
atlas / docs / decisions / 0011-one-event-stream.md
0011-one-event-stream.md 2.6K rendered
1# 11. One leveled event stream, and a lane of its own for it23- **Date:** 2026-08-024- **Status:** accepted5- **Where it is written down:** issue #5 §9, §10 decision 14;6 [logging.md](../logging.md)78## Context910A pipeline that crawls, derives, composes, enriches and gates has a great deal11to say, and it has two audiences that want the same thing: a person watching a12run, and an agent diagnosing why it failed. Ad-hoc prints serve neither —13they cannot be filtered, correlated, or turned off, and they contaminate stdout14for anything that wants to parse a report.1516## Decision1718The system narrates itself through **one leveled, structured event stream**:19Go's standard `log/slog`, with no wrapper library. `internal/logging` is only20the level policy, the attribute vocabulary and the CLI wiring, written down in21one place.2223- Levels with intent: `debug` mechanics; `info` one line per meaningful unit of24 work; `warn` something tolerated a human should eventually see; `error` an25 operation failed. Warn is not a softer Error.26- Text on **stderr** by default, so piped stdout stays clean for product27 output; `--log-json` for machines; `--log-level`, then `ATLAS_LOG`, then28 `info`. An unrecognised level is refused, not ignored.29- A small shared attribute vocabulary — `op`, `volume`, `world`, `lens`,30 `stamp`, `source`, `enricher`, `dur`, `path` — exported as a constructor per31 key, so a key is never a bare literal at a call site where it could be32 misspelled into invisibility. **Keys name domain facts, never code33 organization**: which component emitted an event is the logger's concern.34- `Setup` is called once, explicitly, from a command's `main`. There is no35 `init`.3637`internal/logging` is a **lane of its own** in `tools/depcheck`, so who may38import it is answered by the import matrix rather than by where it happens to39sit: everybody may, except `format/`, which depends on the standard library40alone.4142`analysis/` and `render/` mirror it with a thin console-backed `log` module, and43an ESLint rule forbids bare `console.*` outside it. The matching Go analyzer44forbids `fmt.Print*`/`log.Print*` outside a command's product-output path.4546## Consequences4748- The workbench's streamed pipeline output is this same stream rendered as49 rows. Nothing special is emitted for it.50- The headless parity runner captures the browser console, so a failing tour51 step ships its console context for free.52- The vocabulary is semi-standardized in the `semconv` spirit: a package with a53 fact none of the keys names may add its own, and a key that earns its way54 into several packages is promoted into the table.