Skip to main content

Module log

Module log 

Source
Expand description

§1/§4/§6 the unified per-clone op log — one JSON-lines sink per clone.

balls owns ONE log file per clone bundle (crate::layout::CloneDir::op_log — clones/<enc>/log), not a per-plugin or per-op-phase tree. Every record is one JSON object on its own line {ts, lvl, src, op, phase, msg}, with src either core (balls’ own lifecycle records — begin/invoke/seal/abort) or a plugin name (balls envelopes each line of that plugin’s stderr, §6). The source is a stamped FIELD, so a reader greps one source or reads the whole interleaved sequence; metrics (§6) are a query over it, never core state.

The log is LOCAL runtime state — gitignored, never committed (like binding.toml), no rotation/retention (stale-but-harmless like an orphan worktree; the Level threshold limits volume instead). One object per line keeps concurrent appends from parallel agents atomic: every line is held at or below [LINE_MAX] (PIPE_BUF) bytes so a single O_APPEND write never interleaves with another agent’s. The only unbounded field is the enveloped plugin-stderr msg (a stack trace, a long git error, a diff line); it is truncated with a [TRUNC_MARKER] so the whole record fits (§1, bl-e6a0).

A single threshold (Log::record) gates BOTH file persistence and the terminal echo: a record below it is emitted nowhere. The two sinks differ in SHAPE, not in gating — the file gets the JSON line (the machine record), the terminal renders every record as its own bare msg text (the human line), core and plugin alike — the raw JSON envelope never reaches the terminal (bl-b6ef). The threshold is the §4 log_level (CLI --log-level ▸ XDG ▸ landing ▸ serde-default info). Logging is best-effort — it never aborts an op, so I/O errors are swallowed.

Structs§

Log
The op-scoped log sink: the per-clone file path, the §4 threshold, the op every record is stamped with, and an injected clock (so tests are deterministic and the library does no hidden time read — wall is the production clock).

Enums§

Level
The §4 severity ladder. Ordered Debug < Info < Error so a record is emitted iff its level is >= the configured threshold. Severity classifies the VOICE, not the op kind (bl-cf39): core narration (begin/seal/done/invoke, reads and mutates alike) is Debug — the default Info keeps routine ops quiet — a plugin speaking (enveloped stderr) is Info; a plugin’s non-zero exit and a core abort are Error (outranking every threshold, so the failure locus always lands — §6).

Functions§

wall
The production clock: unix seconds, the §3 time convention. Injected into a Log so the sink itself stays time-free and unit-testable. A pre-epoch clock — never, in practice — reads 0.