Skip to content

Spectre sink: Logging & output architecture — Serilog event core + Spectre.Console frame + NDJSON machine path #391

Description

@ChrisonSimtian

Summary

Replace the inherited NUKE console output with a two-layer model:

  • Serilog owns the structured event stream (one set of log calls, fanned
    out to a human sink and a machine sink).
  • Spectre.Console owns the rich frame (run header, end-of-run summary
    table), driven directly by the build executor — NOT routed through a sink.

Adds first-class NDJSON output so agents/tools can shell out to Fallout and
parse a clean machine stream.

Motivation

Supports the AI-native CLI goals: NDJSON streaming, describe --json,
structured errors, semantic exit codes. The structured-event model maps a
single set of log calls onto both a pretty console and a machine stream, so
human and agent consumers stay in sync from one source of truth.

Design notes

Two layers, kept strictly separate. The trap is driving a Spectre
Progress/Live region from inside an ILogEventSink — those are stateful
console-region takeovers and can't be fed by decoupled events. Logging layer
= the event stream; presentation layer = the frame.

Tasks

  • SpectreConsoleSink : ILogEventSink — level→colour mapping,
    Markup.Escape on rendered text (paths/arrays/GUIDs contain [ ]),
    AnsiConsole.WriteException for exceptions
  • NDJSON sink via Serilog.Formatting.Compact.CompactJsonFormatter (CLEF)
    → stdout
  • OutputMode flag + logger build that branches: human → Spectre sink,
    json → CLEF sink (branch, don't run both — avoids ANSI corrupting the
    NDJSON stream by construction)
  • stdout/stderr discipline in json mode: NDJSON on stdout, all
    diagnostics/human chatter on stderr
  • Promote end-of-run summary to a Spectre Table (executor-driven,
    human mode only)
  • JSON-mode structured summary record (single event with results as
    properties) as the equivalent of the table
  • Wire into the host output/logger configuration (swap inherited console
    sink)

Acceptance criteria

  • fallout build renders rich human output incl. summary table; no markup
    parse errors on real-world messages (paths, arrays)
  • fallout build --output json emits valid NDJSON on stdout, one object per
    line, parseable by jq, zero ANSI contamination; diagnostics on stderr
  • Exceptions render via Spectre in human mode and are captured (@x) in json mode

Out of scope (follow-ups)

  • Progress/Live spinners — human-only polish, separate item; this is where
    the two layers can fight over the console
  • Custom semantic NDJSON schema — start on CLEF, diverge only if
    describe --json consumers need a bespoke contract (cost: re-handling all
    property-value unwrapping)

Refs

  • Keep sink package surface minimal — assembly-version conflicts in the
    build-loaded context are a known NUKE pain point

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request
    No fields configured for Feature.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions