Slice 3 of dev-overlay-end-to-end. Adds a fourth DevOverlay tab that
tails every log record from every Jarvis subsystem in real time —
agent, voice, vision, memory, MCP, bus, replay, system — without
polling files or relying on Console.app.
How it works:
1. `LogBroadcaster` (new) — process-wide actor with a 500-line ring
buffer + subscriber set. Borrowed shape from
OrchestratorEventBroadcaster so the project's three broadcasters
share a mental model. New subscribers replay the buffer in order,
then go live.
2. `BroadcastLogHandler` (new) — swift-log LogHandler conformance.
Formats each log call into a `LogLine` and schedules an unstructured
`Task { await LogBroadcaster.shared.publish(...) }` so the logging
caller never blocks on actor isolation. Synchronous handler contract
preserved; ordering is best-effort under heavy load.
3. `LoggingBootstrap.make(label:)` now returns
`MultiplexLogHandler([file, os, broadcast])` — the new handler is
purely additive. File rotation + os.Logger streaming unchanged.
4. `DevOverlayLogsView` (new) — fourth tab in the overlay. Subscribes
to `LogBroadcaster.shared` on appear, caps at 1000 lines, renders
monospaced. Per-channel filter (Menu w/ checkboxes), per-level
filter (debug → critical), substring search, Pause/Resume button
(Cmd+P), auto-scroll-to-bottom while not paused. Color-coded by
level (warn=orange, error/critical=red).
Tests:
- 5 new LogBroadcasterTests covering publish/cap/replay/live/handler.
- swift test --package-path packages/Logging → 22/22 pass.
- swift test --package-path packages/DevOverlay → 14/14 pass.
- bash scripts/check-app-builds.sh → PASS.
- 18/18 boundary gates green.
Redaction note: file handler still routes through Redact.apply for
disk writes; the broadcaster sees raw messages because the DevOverlay
is a developer-only in-process surface. If this ever becomes
user-facing, route through Redact before publishing.
Owner change: project will be owned by KofTwentyTwo. Bundle ID updates
propagate to three ${PRODUCT_BUNDLE_IDENTIFIER} targets, the Keychain
service name (SEC-01 / D-10), the OSLog subsystem identifier, and the
FileRotatingWriter DispatchQueue label. pbxproj regenerated via
xcodegen generate.
Forward-looking planning docs (STATE, REQUIREMENTS, PATTERNS, VALIDATION)
updated to match. Historical records (completed PLAN.md / SUMMARY.md /
RESEARCH.md / audits / CONTEXT / DISCUSSION-LOG) deliberately left as-is
to preserve the audit trail of the original naming decision.
Verified: 49 SPM tests pass (4 Keychain + 15 Config + 13 Logging + 17
Shell), xcodebuild Debug build succeeds with full codesign pipeline.
Decision logged in STATE.md Key Decisions (Locked 2026-04-22).
- JarvisLogChannel: four cases (agent, tools, ui, system)
- JarvisLogHandlerFactory.bootstrap wires MultiplexLogHandler that
fans out to FileLogHandler + OSLogHandler (D-17)
- FileLogHandler applies Redact.apply once (S-4 single call site)
- OSLogHandler does NOT redact (os.Logger handles %{private}@ at
system layer; callers redact untrusted input before logging)
- Redact covers exactly 5 patterns: sk-ant-, Authorization:Bearer,
sk- (OpenAI), AKIA, ghp_ (D-20, OBS-06); Anthropic branch ordered
before OpenAI so sk-ant- consumes the full prefix
- FileRotatingWriter: lazy midnight rotation via TestDateProvider-
injectable DateProvider; serial DispatchQueue; retain-7 GC on
rotate (D-18)
- LogPaths.channelDirectory = ~/Library/Logs/Jarvis/
- Swift 6 strict: ISO8601DateFormatter.jarvisShared uses
nonisolated(unsafe) since the formatter is documented thread-safe
after configuration but not Sendable-annotated by Apple
- OSLogHandler uses fully-qualified Logging.Logger to disambiguate
from os.Logger (both imported)
- Tests: 13/13 pass (7 Redact + 2 FileLogHandler rotate/retain +
4 bootstrap/factory/channels)
- Deletes Plan 01 placeholders
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>