MEDIUM 1: session_runtime::start() now returns an explicit
fresh-launch vs replay disposition (session_start_result), and
handle_start_session sets outcome.applied only for a fresh committed
launch. An authenticated idempotent start replay therefore never gains
connection-scoped teardown authority: a broken pipe during a replay can
no longer stop an already-running guest. The control audit event for a
replayed delivery carries the replay disposition
(start_session:replay:<session>).
MEDIUM 2: jsonl_sink truncation now accounts for record delimiters
exactly, so current_bytes_ always tracks the physical file; only
newline-terminated complete records are retained (no blank or partial
lines, bounded read window); the cap is a hard cap (an oversized event
is dropped with a structured operator note; a pre-existing oversized
journal is bounded with a bounded read at construction).
MEDIUM 3: the broken-pipe degrade test now synchronizes through a
mutex-protected condition-variable gate handshake that proves the
dispatch is parked inside the blocked gate before the client resets,
records the start only after the dispatch completes, and the
mark_stopping test destroys every registry lock holder (runtime,
protocol, registry) before the independent registry reopen so the
nonblocking exclusive flock can actually be acquired.
Closes the sol-audit blockers in dd7d3f3:
HIGH - degradation could not stop the guest. create() moved
config.runtime into the protocol and then stored the moved-from config,
so the degrade path always saw an empty runtime pointer and a guest
launched by start_session outlived its vanished controller connection.
The server now shares the live runtime with the protocol (copy on
compose, one owner of teardown authority), and a Linux-gated server test
drives the real create() -> handle_frame -> broken-pipe path and proves
the guest is torn down (fails on the pre-fix ownership bug).
MEDIUM - degradation was not bound to authentication/application. The
degrade path re-decoded the raw frame to extract start_session and its
session id, granting teardown authority with no auth/schema/deadline or
application evidence; a same-UID peer could reset the socket after
submitting a valid-shaped but unauthorized frame to trigger stop() on a
named session. handle_frame now emits structured
receipt_control_outcome metadata (authenticated / applied /
response_success / method / session_id) from the real dispatch, and
degrade_failed_delivery acts only on genuinely authenticated+applied
start_session outcomes; every other outcome records only the
connection-scoped audit event. The raw frame is never re-decoded.
MEDIUM - control-audit.jsonl guarantees. jsonl_sink::record() is now
bounded by an optional max_file_bytes policy with oldest-record
truncation (newest event always attempted); gloved configures the cap
(host::control_audit_max_file_bytes, 4 MiB) with a bound test.
record_control_delivery_audit() surfaces sink write failures as
structured stderr logs instead of discarding them (receipt-chain audit
guarantees stay fatal). The derived control-audit.jsonl path is
registered in all_configured_paths() so it cannot alias the receipt
journal, audit key, session store, or any other configured path, with a
config-distinctness test.
MEDIUM - tests missed the production failure mode. The degrade test now
constructs the real server through create() and drives a real
authenticated+applied start_session over the socket; the broken-pipe
test synchronizes on an observable (runtime recorded the applied start)
before the client resets, removing the reset-vs-write race; a protocol-
level test proves wrong-secret / expired-deadline / rejected / non-start
outcomes never stop the guest; the Linux executor test asserts the
durable mark_stopping ordering survives an independent registry reopen.
LOW - unified the duplicate wire::rpc_error / response envelope in
remote_protocol.cpp with receipt_wire.hpp (ODR hazard).
Validated: clang build + CTest 80/80 local; Ghost g++14.2 build and
CTest in a follow-up artifact. No push.
Two mechanical fixes from the Workflow #218 Ghost E2E evidence:
- gloved exited fatally when a control response could not be written back
to a vanished client (broken pipe after a supervisor timeout), turning a
client disconnect into a daemon crash. Transport-level write failures on
an already-authenticated connection are now connection-scoped: serve_one
reports receipt_audit_serve_outcome::connection_failed, the affected
session is degraded (structured `control` audit event in a new owner-only
control-audit.jsonl journal, idempotent guest teardown for start_session
via the normal stop path with its pending-before-release audit
guarantees), and gloved keeps serving subsequent connections. Listener,
peer-authentication, frame-integrity, and audit-chain failures still fail
closed and remain fatal.
- renamed class-name-shadowing members and TU-local wire types so GCC 14.2
accepts the tree under -Wchanges-meaning (hard error, clang-clean):
receipt_audit_unix_server_config::session_runtime -> runtime,
receipt_audit_protocol::implementation::session_runtime -> runtime,
wire::error -> rpc_error, control_wire::params -> rpc_params,
control_wire::exposure -> exposure_record,
setup_wire::apple_container_runtime -> apple_container_runtime_record.
Member (JSON wire key) names are unchanged.
Regression tests: verify_broken_pipe_delivery_is_connection_scoped (peer
closes with SO_LINGER 0; server must report connection_failed, record the
control audit event, and keep serving) and verify_degrade_failed_delivery
(start_session guests are torn down, failures stay non-fatal and audited).
Introduce the framed guest_channel_transport with shared deadlines and
std::jthread ownership, metadata-only retired-schema quarantine with
fail-closed integrity, stateless frozen-catalog validators with
capability pinned to zero, and the generic local-service proxy with
descriptor-pinned endpoints, alias-only guest sockets, audit-gated
delivery, and a Linux managed runtime capability derived only from a
registry-bound operational factory. Sage vocabulary is confined to
src/adapters/sage.
Model and PTY cannot self-report pass or failure. Glove now runs
each refinement-eval-v1 session through a declarative evaluator that
checks bounded fixture assertions (termination cause, exit code, max
latency, required and forbidden transcript literals) against audited
resource events, then binds the evaluated outcome inside the
authenticated receipt digest. Capability advances to version 1 with
the evaluator landed.