9 Commits
Author SHA1 Message Date
james.maes 6ea2852af1 feat(devoverlay,logging): live log stream — every swift-log line into the overlay
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.
2026-05-12 14:27:57 -05:00
james.maes 384ec5b3ef feat(05-05): add JarvisLogChannel.mcp for AGENT-11 timeout warning
ConfirmingToolDispatcher needs to emit a WARNING log line on broker timeout
(AGENT-11). The plan specifies the log lands in JarvisLogChannel.mcp, but
that case did not yet exist in the enum.

Adds .mcp (rawValue 'mcp') to the channel enum and updates the two
case-count tests (ChannelTests + LoggingTests) to expect 8 cases.
2026-04-25 14:17:35 -05:00
james.maes 3aabdd616e feat(04-03): TokenDeltaDropOldestChannel per-element drop policy + JarvisLogChannel .replay/.devoverlay (AGENT-10)
- TokenDeltaDropOldestChannel<Tag>: actor-backed AsyncSequence with per-element drop policy. Overflow drops oldest dropTag elements only; non-dropTag elements suspend the producer (backpressure). Saturated-with-non-dropTag fallback path also suspends rather than dropping a protected event.
- 6 tests: T1 below-cap, T2 oldest-drop on overflow, T3 toolCall NEVER dropped under tokenDelta firehose (AGENT-10 critical invariant), T4 load test 10000 tokenDelta + 1000 toolCall @ cap=2048 — exactly 1000 toolCalls delivered, T5 non-dropTag suspend path, T6 finish drains buffer.
- Logging ChannelTests: targeted assertions for the .replay + .devoverlay additions (LoggingTests.test_sevenChannelsAreDefined updated alongside the enum extension in commit 2614639).
2026-04-24 17:53:43 -05:00
james.maes a7fd068f70 feat(04-03): ReplayLog actor with batched writes + OrphanDetector for OBS-07 crash recovery
- ReplayLog actor: opens replay.db with WAL pragmas + DDL + meta seed; beginSession/startTurn/record/endTurn/close. Writes batched in 50ms window OR 64-event chunks. endTurn appends a turn_end event, flushes, UPDATEs ended_at + stop_reason, then PRAGMA wal_checkpoint(TRUNCATE) for the per-turn fsync. Failures logged via JarvisLogChannel.replay; never propagated.
- OrphanDetector actor: opens its own connection, increments meta.crash_count, runs the OBS-07 query (ended_at IS NULL AND turn_id NOT IN (turn_end events)), stamps each orphan with stop_reason='orphan_recovered' + recovery_marker='detected_at_launch:crash_count=N'.
- 12 new tests: L1-L8 (session/turn/buffering/window/chunk/large-blob/nothing-masked) + O1-O4 (orphan vs non-orphan, race window, crash_count increment, end-to-end SIGKILL parity).
- Adds JarvisLogChannel.replay + .devoverlay (additive — Logging test updated to assert 7 cases). The full Task 3 channel-tests file lands next commit.
2026-04-24 17:53:43 -05:00
james.maes cf61b6bac8 feat(02-01): add Bus package with discriminated-union Codable + fixtures
- New `packages/Bus` SPM package (Swift 6 strict concurrency, WebKit linked).
- `BUS_PROTOCOL_VERSION = "2.0.0"` + shared `HudState` / `TurnTerminator` /
  `BusCoder` in `Protocol.swift`.
- `BusOutbound` (8 cases) + `BusInbound` (2 cases) with hand-written
  `Codable` using a `type` discriminator and exhaustive switches — SE-0295
  synthesized `{"case": {...}}` shape is rejected by design.
- `BusReply` plist-serializable reply + `BusError` error surface.
- 14 JSON fixtures + 24 XCTest round-trip tests asserting byte-equal
  re-encoding, shape invariants, UUID-lowercasing, and negative-path decode
  failures. All green.
- `JarvisLogChannel` gains `case bus` (OBS-06 extension per RESEARCH-07);
  `LoggingTests.test_fiveChannelsAreDefined` updated to match.
2026-04-23 17:23:02 -05:00
james.maes 813c690555 fix(01-WR-01): count + report dropped log lines on FileRotatingWriter failures
Phase 1 REVIEW.md WR-01 (OBS-06): `FileRotatingWriter` used `try?` on
both `FileHandle(forWritingTo:)` and `handle.write(contentsOf:)`, so a
disk-full, permission-revoked, or FD-evicted write silently dropped the
line with no signal. OBS-06 reads as "rotation must not lose data".

packages/Logging/Sources/JarvisLogging/FileRotatingWriter.swift
- Add `droppedLinesThisWindow` counter (serial-queue-local, no lock).
- Add `warnedAboutOpenFailureThisWindow` flag to emit a one-time
  os.Logger fault per rotation window (prevents spam if the failure
  persists for hours).
- `append()` now explicitly increments the counter on both the
  nil-handle path and the `handle.write` throw path, then logs a
  fault via `os.Logger` (subsystem `com.koftwentytwo.jarvis`,
  category `logging.file`) so failures are visible in Console.app
  even when the file log itself is the thing that's broken.
- `rotateIfNeeded()` emits an `.error`-level summary when the
  just-closed window lost lines, then resets both flags for the new
  window.
- Add `droppedLinesSnapshot()` test-only accessor that reads the
  counter through the serial queue (no TSan race).

packages/Logging/Tests/JarvisLoggingTests/FileLogHandlerTests.swift
- New `test_dropsLinesWhenHandleUnavailable`: points the writer at a
  path that is a regular file (so directory creation and file-open
  both fail), appends three lines, asserts `droppedLinesSnapshot() == 3`.
2026-04-23 16:14:56 -05:00
james.maes 206b4aa13f refactor: rename bundle ID com.kingsrook.jarvis → com.koftwentytwo.jarvis
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).
2026-04-22 17:56:37 -05:00
james.maesandClaude Opus 4.7 23917e58f2 feat(01-02): build Logging package (OBS-06, D-17, D-18, D-20)
- 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>
2026-04-22 13:27:34 -05:00
james.maes d8617ffe01 feat(01-01): add four SPM packages with Swift 6 strict concurrency
- packages/Keychain — zero SPM deps (Security.framework at link time only)
- packages/Logging — depends on apple/swift-log 1.5.3+; library product is
  named JarvisLogging to avoid collision with swift-log's own Logging module
- packages/Config — depends on Keychain + Logging (product JarvisLogging)
- packages/Shell — depends on Config + Logging; links AppKit,
  ServiceManagement, IOKit, Carbon for hotkey/launch-at-login surfaces

Every target (main + test) opts into .swiftLanguageMode(.v6) per D-04 so
data-race errors are compile-time failures, not warnings.

Placeholder sources (one per package) plus one trivial XCTest per package
per D-03 so each package builds standalone and has a passing test. Real
sources land in Plan 02 (Keychain/Config/Logging) and Plan 04 (Shell).

Bus/LLM/MCP/Voice/Memory packages NOT pre-created per D-01 — they arrive
in their owning phases (P2/P4/P5/P6/P7) to keep rebuild scope tight.
2026-04-22 12:21:07 -05:00