Doctor Check 15b: Sandbox Violation Log

macOS keeps a system-wide sandbox violation log in the unified log: every reporting Seatbelt denial lands as a kernel message with sender Sandbox. Nothing in OrchestKit read it before this check. Click an outcome to see the exact behavior, all four were exercised live on Darwin 25.5.0 on 2026-08-21.

The verified query

/usr/bin/log show --last 15m --style compact --predicate 'sender == "Sandbox"'

Bounded (window is validated as N[smhd]), read-only, no sudo. A real row it returned:

kernel[0:2611b0f] (Sandbox) Sandbox: ecosystemd(2048) deny(1) file-read-data /Library/Preferences/com.apple.security.plist

The four outcomes

OK Observed, zero reported deny events in the window.
Sandbox violations: OK: 0 reported deny events in the last 10m (process filter: bash|node|python|git)
    Caveat: sandbox profiles can deny WITHOUT reporting (measured: a denied
    write from inside CC's Bash sandbox left no unified-log row), so zero
    reported events is not proof of zero denials.

Even the clean path states the honest limit: zero reported is not zero denied.

WARN Observed, deny events found. Top offenders are grouped, never the raw firehose.
Sandbox violations: 14 reported deny event(s) in the last 10m
    Top (count / process / operation):
         6 ecosystemd file-read-data
         4 ecosystemd mach-lookup
         4 ecosystemanalyticsd mach-lookup
    -> Inspect: /usr/bin/log show --last 10m --style compact --predicate 'sender == "Sandbox"'
    -> System daemons (ecosystemd, analyticsd, ...) are normal background noise;
       investigate rows naming your session's tools (bash, node, python, git).
UNOBSERVABLE The log CLI refuses sandboxed callers. Measured: exit 64, log: Cannot run while sandboxed. The check FAILS CLOSED.
Sandbox violations: UNOBSERVABLE: the log query itself was denied (exit 64)
    stderr: log: Cannot run while sandboxed
    This is the expected result when doctor runs inside CC's Bash sandbox:
    the log CLI refuses sandboxed callers. Re-run from an unsandboxed shell:
    /usr/bin/log show --last 15m --style compact --predicate 'sender == "Sandbox"'
    Do NOT read this as zero violations.
Why this branch is the whole point. A monitoring check whose instrument can be silently denied must distinguish "looked and found nothing" from "could not look". Converting a denied query into a zero would be the exact failure class this repo keeps re-finding: a broken gate reporting safety. Exit 2, status unobservable, count null, never 0.
SKIP Non-macOS platforms get an explicit skip with a reason, never a silent pass.
Sandbox violations: SKIP: unified log is macOS-only (uname: Linux)
    On Linux, sandbox denials surface via auditd/journald, not this check.

Contract

ExitJSON statuscountMeaning
0ok0Observed the log, no matching deny events
1violationsN > 0Observed, deny events in window (warn)
2unobservablenullLog query denied or failed (fail closed)
3skippednullNot macOS, explicit reason printed
4n/an/aUsage error (unbounded or malformed window, unknown flag)
Honest limits stated in every output. (1) Reporting denials only: CC's own Bash sandbox denied a probe write with EPERM and left no unified-log row, so absence of rows is not proof of absence of denials. (2) System-wide log, session attribution is best-effort via --process. (3) macOS only.

Where it lives

src/skills/doctor/scripts/check-sandbox-violations.sh   # the check (shellcheck-clean)
src/skills/doctor/references/sandbox-posture.md         # Check 15 lane, sub-check 15b section
tests/skills/test-sandbox-violations-check.sh           # contract test, passes sandboxed AND unsandboxed