# ADR 0134: Diagnostic journal is bounded local evidence

> Source: https://github.com/max-listov/stitchkit/blob/master/docs/decisions/0134-diagnostic-journal-is-bounded-local-evidence.md

---

# ADR 0134 — Diagnostic journal is bounded local evidence

## Context

The application entrypoint already has no-queue admission, ordered/latest bounded channels,
failure-isolated event sinks and managed file operations. None owns the combined contract needed
by a local metadata journal: synchronous schema validation and serialization, retained-byte
admission including the write in flight, one append/rotation order, exclusive path ownership and
finite generations. Reassembling those guarantees in each application makes overload and shutdown
semantics drift.

This evidence is useful after a process problem, but it is not business state. Calling it durable
would be false: an accepted frame is only retained in process memory, an append completion is not
an `fsync`, and abrupt termination may leave a partial tail or stale ownership lock.

## Decision

Expose `createDiagnosticJournal()` from the evolving, server-only `stitchkit/application`
entrypoint. The application supplies a Zod event schema, a normalized absolute local file path and
five positive limits: event bytes, pending items, pending bytes, file bytes and retained files.

`submit()` validates and serializes synchronously before bounded admission. Accepted frames receive
one process UUID epoch and a contiguous sequence, enter one FIFO writer and retain their serialized
bytes until their append attempt settles. Capacity, invalid, oversized, closed and terminal-failure
refusals are explicit and consume no sequence. One manager owns the canonical path through an
exclusive mode-`0600` lock; rotation retains at most the declared number of regular files and never
follows a final-path or generation symlink.

`flush()` waits for accepted append attempts through its call boundary. `close()` stops admission,
drains accepted frames and releases ownership. Their timeout and cancellation options bound only
the caller's wait: physical work and its memory ownership continue until settlement. Writer,
rotation and close failures become terminal status and an isolated optional diagnostic callback;
they never recurse into the journal.

There is no reader or repair API. A non-newline active tail found at startup is preserved by
rotation and counted; the new process starts a fresh epoch and sequence. The path is operator
configuration, never event data.

## Consequences

- Applications get one reusable finite local evidence recipe without changing existing sink or
  observability semantics.
- Exact ordering is process-local. Epoch plus sequence identifies a run boundary but proves neither
  remote receipt nor exactly-once execution.
- `accepted` means accepted to bounded memory; `written` means an append completed; neither means
  storage durability.
- A deployment that requires crash recovery, replay, remote aggregation or stale-lock arbitration
  must provide a real durable store or deployment-owned log collector instead.
- The Node filesystem dependency remains isolated behind `stitchkit/application`; browser-safe
  entrypoints do not import it.
