Ready Lwt-Unix filesystem writer

Observe_fs_lwt_unix.create accepts an application directory and returns an Observe.Drain.t directly. Missing directories are created recursively. Each accepted log is appended as compact NDJSON to YYYY-MM-DD.jsonl, where the date comes from the log's semantic UTC timestamp.

The drain joins Observe_lwt_unix.flush and Observe_lwt_unix.shutdown. Applications configure the returned drain once and continue logging through Observe.Logs.

let* filesystem =
  Observe_fs_lwt_unix.create_exn ~dir:".observe/logs" ()
in
let config =
  Observe.Config.create_exn ~service:"orders" ~drains:[filesystem] ()
in
Observe_lwt_unix.init_exn config;
run_application ()

Acceptance means bounded ownership transfer, not a completed write, fsync, or crash durability. Full and closed writers reject before NDJSON projection. The ready lifecycle owns the registered worker and waits for cleanup when registration loses a shutdown race. Its advanced lifecycle report gives each ready writer a distinct bounded filesystem-N identity and exposes cumulative rejection or accepted-work loss without leaking the directory path. Call the ready shutdown path before process exit.

Regular-file writes run directly on the Lwt event-loop thread instead of its preemptive worker pool. This removes a cross-thread round trip for every write, but a slow or stalled local, FUSE, or network filesystem can therefore delay other fibers on that loop. The writer is intended for ordinary local files.