588 Commits
Author SHA1 Message Date
James Maes 7c4bb248d5 docs: replace remaining Mermaid text diagrams with PlantUML PNG images 2026-07-23 17:09:16 -05:00
James Maes 29b6cc9d01 docs: replace Mermaid text diagram with PlantUML PNG image 2026-07-23 17:03:30 -05:00
james.maesandClaude Opus 4.7 034a115009 docs(superpowers): local-first LLM routing design spec (#197)
* docs(superpowers): local-first LLM routing design spec

Flip default chat-turn provider from Anthropic to local Ollama with
reactive escalation to Opus on detectable failure. Per-turn escalation
budget, clean-restart UX with visible badge.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(superpowers): local-first LLM routing implementation plan

10-task plan with TDD steps, exact file paths, and code blocks for each
step. Self-reviewed for spec coverage and type consistency. Ready for
subagent-driven execution.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 16:18:54 -05:00
james.maesandClaude Opus 4.7 5ebe510627 docs: scrub Phase-7 + JarvisBusWorld doc drift (#19, #45) (#195)
* docs(memory): scrub Phase-7 hedge language from MemoryStore (#19)

Audit 2026-05-12 flagged five doc-comment references that mis-described
the implementation state. The cited plans (07-02, 07-03, 07-06) shipped
months ago — the bounded extraction channel, the hybrid FTS5 + vec0 read
path, the ReplayEvent emission, the regression corpus test seams, and
`installMemory`'s replay-sink wiring are all live, not "wires" or
"will replace" promises.

Five touchpoints rewritten to describe the code as it is:

- `MemoryReplaySink` doc: drop the "Plan 07-06" plan reference; the seam
  is just used at startup.
- `MemoryStore` actor doc: replace the "Plan 07-02 wires / Plan 07-03
  wires" sentence with the actual contract (single writer; hybrid search
  through `MemoryReadStore`; `recordRetrieval` emits `memoryRetrieval`).
- Read-path MARK: drop the "Plan 07-03" plan label; keep the
  requirement-ID list (MEM-07 / TEXT-03 / D-02 / D-05) since those are
  still useful for traceability to the audit corpus.
- `recordRetrieval` doc: replace "Mirrors recordMemoryMutation from 07-02"
  with "Mirrors recordMemoryMutation on the write path."
- Test-seams MARK: drop "Plan 07-06" prefix; describe by the test target
  (JARVIS_REAL_MODELS=1 corpus suite) instead.

The 2026-05-11 D-5/D-6 markers and the "Boot policy (changed 2026-05-11)"
doc are preserved unchanged — they document current behaviour, not
historical hedges.

`swift build --package-path packages/Memory` clean.

Closes #19

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(bus): scrub JarvisBusWorld drift + add grep gate (#45)

`fb41c5f` (2026-05-02) unified `Injection.js` and the HUD bundle into the
default `WKContentWorld.page` and retired the prior isolated
`JarvisBusWorld` named world. The doc-comments and test fixtures across
20+ lines kept describing the bug-era topology — pre-existing-bus attach
"because cross-world isolation", message-handler-only-visible-in-named-
world, etc. — for months afterward. Result: a new reader following the
docs would conclude the bus uses two worlds when it actually uses one.

Five rationale rewrites:

- `WebviewBridge.swift` class doc — handler is on the page world, not an
  isolated named world. Page scripts in the loaded HUD bundle address it
  via `window.webkit.messageHandlers.jarvisBus`.
- `Injection.js` header — names the page world explicitly; one-line nod to
  `fb41c5f` for the historical context.
- `bridge.ts` JSDoc + `isJarvisBusShape` rationale — recast the H-02
  attach-to-existing path as a "defensive double-install guard" inside
  ONE page world. Injection.js fires first at document-start; the bundle
  installer fires later as a top-level `main.tsx` side-effect; the guard
  prevents the bundle from clobbering Injection.js's queued early
  messages and captured handshake state. The duck-type `isJarvisBusShape`
  CODE is unchanged — only the comment narrative was misleading.
- `webview/packages/hud/src/main.tsx` — drop the cross-world-isolation
  framing; describe the single-world reality.
- `App/AppDelegate.swift` install comment — page world, not isolated.

Test-side updates (same scrub, plus one latent test bug surfaced):

- `WebviewBridgeTests.test_scriptMessageHandlerIsRegisteredUnderConfigured-
  Name`: was removing from `WKContentWorld.world(name: "JarvisBusWorld")`
  while the bridge registered against `.page` — silent no-op since
  `removeScriptMessageHandler` doesn't throw on absent. Now removes from
  `.page` (the world the bridge actually uses), making the
  "registration-is-evidence-of-success" assertion meaningful again.
- `WebviewBridgeOutboundTests`: comment-only.
- `RealWKWebViewIntegrationTests`: comment-only (forensic narrative kept,
  literal world name replaced with "prior isolated named content world").
- `webview/packages/bus/tests/bridge.test.ts`: H-02 describe-block + one
  it-name rewritten to match the new defensive-double-install rationale.

Infrastructure:

- `scripts/check-no-jarvis-bus-world-references.sh`: new boundary gate.
  Greps for the literal `JarvisBusWorld` in tracked files; excludes
  `.planning/`, `docs/`, `webview/packages/*/dist/`, and this script
  itself. Wired into `CLAUDE.md`'s gate listing; the CI
  `boundary-gates` job auto-discovers all `scripts/check-*.sh`, so no
  workflow edit is needed.
- `webview/packages/bus/package.json`: 0.0.0 → 0.0.1 (per spec —
  comment-only changes still bump patch so consumers can pin).
- `webview/packages/bus/dist/bridge.{js,d.ts}`: rebuilt via `pnpm --filter
  @jarvis/bus build`; NOT committed because `dist/` is not tracked (the
  build phase regenerates on each xcodebuild invocation).

Verified locally:
- `swift build --package-path packages/Bus` clean
- `pnpm --filter @jarvis/bus test` — 37/37 pass
- `bash scripts/check-no-jarvis-bus-world-references.sh` — PASS
- `bash scripts/check-bus-protocol-version.sh` — PASS (v2.3.0)
- `bash scripts/check-bus-harness-parity.sh` — PASS

Closes #45

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 09:51:03 -05:00
james.maesandClaude Opus 4.7 a121d79174 fix: STT backend constant casing + audioLevel NaN guard (#37, #47) (#196)
* docs(voice): pin STT backend constant identity contract (#37)

The runtime mismatch flagged by #37 was already fixed at the call sites
in `App/AppDelegate.swift:1631-1642` and `:2562-2575` — both routes now
reference `STTBackendSelector.backendSpeechAnalyzer` /
`backendWhisperKit` (snake_case) instead of the pre-2026-05-12 camelCase
string literals. The regression test
`STTBackendSwitchTests.testB5_canonicalConstantsRoundTripThroughMake`
already locks both halves of the contract:

  1. The snake_case constants round-trip through `make(backend:)` without
     hitting the unknown-backend default branch.
  2. The pre-fix camelCase shape (`"whisperKit"`) DOES land in the
     default branch and DOES emit an unknown-backend warning.

So the #37 close action is just to make that contract self-documenting
at the declaration site rather than relying on readers finding the test.
Add a doc-comment to the two `public static let backend*` constants that
explains the wire shape, names the regression test, references Issues
#29 + #37, and warns against renaming without updating `PerTurnSnapshot`
and the test in lockstep.

No code change; `swift test --package-path packages/Voice` continues to
pass (26 tests).

Closes #37

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(bus): clamp non-finite audioLevel rms to 0.0 at encode (#47)

`BusOutbound.audioLevel` carries a `Float rms` that `AudioLevelEmitter`
produces per audio frame (~100 Hz once the consumer is wired up).
Foundation's `JSONEncoder.NonConformingFloatEncodingStrategy` defaults
to `.throw`, so a single NaN — easy to land via a CoreAudio
over-/underflow or an all-zero buffer fed through certain RMS shapes —
would throw inside `WebviewBridge.sendRaw` and tear down the per-frame
bus path. The HUD-side consumer in `webview/packages/hud/src/bus/
client.ts:135` is currently a no-op (the ring shader is still on the
synthetic-sine animation from Plan 03-03), so the bug is LATENT, not
actively firing — but the clamp is cheap, defensive, and pins the
contract before the consumer activates.

Inline clamp at the encode site (`BusOutbound.encode(to:)` switch arm
for `.audioLevel`): replace non-finite floats with `0.0` via
`rms.isFinite ? rms : 0.0` immediately before `container.encode(_:)`.
No refactor of `AudioLevelEmitter` — the per-spec call here is
defensive at the serialization boundary, where every encoder-level
overflow path converges.

Two new unit tests in `CodableRoundTripTests`:
- `test_audioLevel_nanIsClampedToZero` — encodes `.audioLevel(rms: .nan)`,
  decodes, asserts `rms == 0.0` and `rms.isFinite`.
- `test_audioLevel_infinityIsClampedToZero` — companion for ±∞ so a
  future refactor cannot narrow the guard to NaN-only.

`swift test --package-path packages/Bus --filter CodableRoundTripTests`
passes (30 tests, +2 from this commit).

Closes #47

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 09:50:50 -05:00
james.maes 31f0a8289a docs(handoff): multi-runner shipped + v0.2 wave plan (#192)
Captures the multi-runner expansion (Grogu-jarvis, -2, -3 live),
auto-Release flow proof (v0.1.0-dev.64), Superpowers process
established, and Memory test flake disposition. Lists v0.2 Wave 1
candidates (#19, #45, #46, #37, #178, #47) for next session pickup.

Sibling to docs/HANDOFF-2026-05-13-v0.1-shipped.md.

Refs #180 #188
2026-05-14 09:48:26 -05:00
james.maesandClaude Opus 4.7 439e1ee2f5 ci: build hygiene — webview cleanup + OpenSSF Scorecard (#46, #178) (#194)
* ci(build-webview): sweep stale hashed chunks before rsync (#46)

Vite emits content-hashed asset names (e.g. `index-CXPb0I5z.js`), so the
active bundle filename rotates on every source/dependency edit. The
existing rsync runs without `--delete` (to preserve `bus-harness.html`
and `.gitignore`), so old chunks accumulated in
`App/Resources/webview/assets/` — observed 9 stale `index-*.js` /
`.js.map` pairs locally before this fix.

Add an explicit `rm -f` of the asset glob (JS + JS map + CSS + CSS map)
before the rsync drops the fresh bundle. The preserved files
(`bus-harness.html`, `index.html`, `.gitignore`) live one level up in
`$DEST`, not in `$DEST/assets`, so the rm cannot reach them.

Verified locally: `bash scripts/build-webview.sh` now leaves exactly one
`index-*.js` + `.js.map` in `assets/` (matching the reference in
`index.html`).

Refs #46

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* ci(scorecard): add OpenSSF Scorecard workflow + README badge (#178)

Adds `.github/workflows/scorecard.yml` running `ossf/scorecard-action@v2.4.0`
on:
- Weekly cron (Mondays 06:00 UTC) for posture drift detection
- Push to develop for prompt regression visibility
- workflow_dispatch for ad-hoc runs

Permissions follow the canonical Scorecard set (`id-token: write`,
`contents: read`, `security-events: write`) with top-level `read-all` and
job-scoped writes. Results are published to the OpenSSF public dataset
(powers the README badge URL) and uploaded as SARIF to code-scanning.

The workflow consumes no untrusted user inputs in `run:` blocks, so it is
not exposed to workflow-injection patterns documented in
github.blog/security/.../how-to-catch-github-actions-workflow-injections.

README.md gains the standard Scorecard badge next to the existing
license/platform/swift badges.

Refs #178

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 09:29:48 -05:00
james.maesandClaude Opus 4.7 dced4cb9a3 docs(superpowers): v0.2 Wave 1 sequencing + execution spec (#193)
* docs(handoff): multi-runner shipped + v0.2 wave plan

Captures the multi-runner expansion (Grogu-jarvis, -2, -3 live),
auto-Release flow proof (v0.1.0-dev.64), Superpowers process
established, and Memory test flake disposition. Lists v0.2 Wave 1
candidates (#19, #45, #46, #37, #178, #47) for next session pickup.

Sibling to docs/HANDOFF-2026-05-13-v0.1-shipped.md.

Refs #180 #188

* docs(superpowers): v0.2 Wave 1 sequencing + execution spec

Three-PR plan for #19, #37, #45, #46, #47, #178 grouped by surface
area: doc drift, build hygiene, small code fixes. Landing order is
build hygiene first (lowest blast radius), doc drift second, code
fixes last. Memory-flake disposition documented.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
v0.1.0-dev.71
2026-05-14 09:08:24 -05:00
james.maes 00f1075ea5 fix(agent): bundle assistant text with toolUse + document cache hint dormancy (#185)
Two related AgentCore tactical fixes from the 2026-05-12 audit.

#24 — Assistant text blocks alongside tool_use were dropped from message
history. Opus 4.7 commonly narrates ("Let me check the time for
you...") before calling a tool. On the next round-trip the appended
assistant message contained only the .toolUse block, so the model had
no record of the narration — a user follow-up like "what did you say
before checking the time?" would deny it.

Fix: introduce `assistantTextSinceLastFlush` parallel to
`assistantTextSoFar` (the latter stays cumulative for D-02 vision
routing). On every toolUseRequested, flush the per-flush buffer into a
.text(...) block bundled into the same assistant message as the
.toolUse, trim whitespace-only text to avoid Anthropic 400s on empty
text blocks, and reset the flush buffer so subsequent tool_uses in the
same round get only the text emitted between them. D-02 untouched.

#23 — CacheHints documentation flagged that the eligibility threshold
(4096 chars ≈ 1024 tokens) is structurally false on healthy boot
(preamble ~700 chars, empty initial context). Added a paragraph
explicitly documenting the dormancy, the intentional cost-acceptance
rationale, and the natural recovery once M-4 (v0.8) lands
searchFacts-driven hydration. No code change.

Tests: 3 new tests in AssistantTextWithToolUseTests cover text+toolUse
bundling, toolUse-alone (no spurious empty text block), and
whitespace-only-text rejection. Full AgentCore suite: 248 tests, 0
failures, 1 skipped.

Closes #23, #24
v0.1.0-dev.68
2026-05-14 06:53:35 -05:00
james.maes 774e60a020 ci(actions): create GitHub Release directly in publish-tag job (#187)
The default GITHUB_TOKEN cannot trigger downstream workflows (GitHub
prevents the chain to avoid infinite loops). publish-tag's `git push
origin "$TAG"` therefore never fires release.yml's `push: tags:`
listener — observed on v0.1.0-dev.50, where the tag landed but the
Release object was missing until manually created.

Fold the Release creation into the publish-tag job using `gh release
create` with GH_TOKEN=secrets.GITHUB_TOKEN. Direct API calls work fine
with the default token; only the push→workflow chain is blocked.

- Idempotent: skips if release already exists.
- Notes: auto-generated from `git log $prev..$TAG` plus a Verification
  block linking back to the CI run.
- Prerelease flag respects steps.version.outputs.prerelease (true for
  dev/rc tags, false for vX.Y.Z final tags on main).

release.yml stays untouched as a fallback for manually-pushed tags
(humans pushing tags directly CAN trigger workflows).

Closes #186
v0.1.0-dev.64
2026-05-13 18:28:07 -05:00
james.maes a26f49fdbd docs(superpowers): multi-runner Grogu spec + implementation plan (#190)
* docs(superpowers): brainstorm/spec for multi-runner expansion on Grogu

Brainstorm-phase design for scaling Grogu from 1 to 3 self-hosted CI
runners. Covers components, precondition (PR #189 must land first),
sequential registration sequence, acceptance validation, failure
modes + mitigations, rollback, and explicit out-of-scope items.

Acceptance bar (minimum): green develop CI with >=3 SPM jobs in
flight simultaneously. Warm cache + runner-health monitoring are
explicit follow-ups.

Path follows the superpowers:brainstorming skill convention:
docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md.

Refs #180 #182 #186 #188

* docs(superpowers): implementation plan for multi-runner Grogu expansion

Bite-sized task breakdown for the multi-runner spec at
docs/superpowers/specs/2026-05-13-multi-runner-grogu-design.md.
Five tasks, each task several 2-5 minute steps with concrete commands
and expected output:

  1. Verify PR #189 (age-filter) is on develop — precondition gate
  2. Register Grogu-jarvis-2 (verify pre-stage, token, config,
     install service, verify online)
  3. Register Grogu-jarvis-3 (same sequence)
  4. Acceptance — rerun PR #185 CI, observe >=3 SPM jobs concurrent
  5. Update CLAUDE.md runner inventory + open PR

Self-review pass: every spec component covered, no placeholders,
type-name consistency verified across tasks.

Refs #180 #188
2026-05-13 17:58:29 -05:00
james.maes 4cdb3560e9 ci(actions): age-filter zombie reaper (>= 1h) for multi-runner safety (#189)
Grogu will host multiple self-hosted runners simultaneously (planned: 3
runners). Each runner's job-start cleanup step previously killed ANY
xctest/swift-test/swift-driver — meaning sibling runners would nuke
each other's in-flight tests.

Real CI jobs complete in <10 min. Zombies from interactive Xcode use
are typically >hours old. A 1-hour age cutoff cleanly separates the
two populations.

awk filter: ps -o etime formats are `MM:SS` (<1h), `HH:MM:SS` (>=1h),
or `DD-HH:MM:SS` (days). Match the latter two by testing for `-` (days
prefix) or three `:`-separated groups.

Single-runner behavior unchanged. Validated against synthetic ps
output covering all three etime format cases.

Closes #188
2026-05-13 17:33:03 -05:00
james.maes 81ce64c3f7 ci(actions): reap orphan xctest/swift-test on self-hosted before each job (#183)
Grogu is a shared workstation, not an ephemeral VM. Interactive Xcode
test runs, aborted swift test sessions, or debugger crashes can leave
orphan xctest/swift-test/swift-driver processes around for hours,
holding Mach services + sockets + ports that subsequent CI jobs block
on when mounting their own test infrastructure.

Concrete incident: develop run 25824607025 hung in SPM AgentCore for
34 min (0% CPU, sleeping state) while 6 unrelated xctest zombies aged
22-24h were alive from prior interactive use. The runner only executes
one job at a time, so any such process at job start belongs to no live
job and is safe to kill.

Add a first step that runs SIGTERM then SIGKILL on any
xctest/swift-test/swift-driver process. Gated to runner.environment ==
'self-hosted' since github-hosted VMs start clean.

Closes #182
2026-05-13 16:37:27 -05:00
james.maes 5fc2d3fabf docs: reconcile Ollama model baseline to actual production names (#184)
The codebase moved to qwen3.6:latest (memory extractor) and
qwen2.5-coder:32b-instruct-q8_0 (agent fallback) in commit 8d0a959, but
CLAUDE.md and the MemoryRegressionCorpusTests doc-comments still cited
the vanilla qwen2.5-coder:32b string. Both updated to match what
ModelID.swift, MemoryExtractor.swift, and BootHealth.swift actually
use today.

No behavior change — documentation alignment only.

Closes #58
2026-05-13 16:25:00 -05:00
james.maesandClaude Opus 4.7 eef1725292 ci: move swift-packages matrix to self-hosted runner (Grogu) (#181)
* ci(actions): move swift-packages matrix to self-hosted runner (Grogu)

The github-hosted macos-15 pool was the rate-limiting step for v0.1: 13
matrix jobs + 1 app-build job all needed macOS slots, GitHub scheduled
them 1-3 at a time, and total wall-clock was ~1-2h per run versus actual
work of <10m. Grogu is registered with labels [self-hosted, macOS, ARM64,
jarvis] and _work/ symlinked to HD-2 (1.3 TB) for headroom.

Scope:
- swift-packages matrix only — app-build stays on macos-15 for now.
- `if:` clause blocks fork PRs from triggering self-hosted jobs (push,
  workflow_dispatch, and same-repo PRs only).
- Xcode select switches from `sudo xcode-select -s` to a per-process
  DEVELOPER_DIR env so the runner doesn't need passwordless sudo. The
  fallback chain now also accepts /Applications/Xcode.app/Contents/Developer
  so Grogu's local Xcode 26.5 is picked up.

Closes #180

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* ci(actions): fix self-hosted runner env quirks for keychain + cache

Three SPM failures on PR #181's first self-hosted CI run, all
environment-specific:

- SPM Keychain: errSecInteractionNotAllowed (-25308). The LaunchAgent
  has no UI session and the login keychain is locked.
- SPM Voice + SPM Harness: github-hosted actions/cache@v4 entries with
  absolute paths (/Users/runner/work/...) baked into
  .build/artifacts/onnxruntime.xcframework. Cache key only contained
  runner.os (= macOS for both environments), so self-hosted hit the
  poisoned github-hosted cache.

Fixes:

- Restrict actions/cache@v4 to runner.environment == 'github-hosted'.
  Self-hosted's _work/ on HD-2 persists between jobs naturally, so the
  cache action is unnecessary there and prevents path-baked cache
  poisoning between environments.

- Add a "Unlock runner keychain" step gated to runner.environment ==
  'self-hosted'. Unlocks a pre-created jarvis-runner.keychain-db with
  password from the repo secret JARVIS_RUNNER_KEYCHAIN_PASSWORD and
  prepends it to the user search list so SecItemAdd writes there.

Document both in CLAUDE.md "Self-hosted CI runner".

Refs #180

* ci: retrigger after JARVIS_RUNNER_KEYCHAIN_PASSWORD secret fix

Previous run failed all 13 SPM jobs with 'passphrase you entered is not
correct' because the secret value was set to literal '-' (gh secret set
parsed '--body -' as the body value, not as 'read from stdin'). Secret
now contains the correct password. This empty commit triggers a fresh
CI run that will resolve the corrected secret.

Refs #180

* ci(actions): drop set-keychain-settings from unlock step

The Security framework requires user interaction for set-keychain-settings
even when the keychain is unlocked, and the LaunchAgent on Grogu has no
UI. The settings (no-timeout, no-lock-on-sleep) are persistent and were
applied once at keychain-creation time; only the unlock step needs to
run every job.

Refs #180

* ci(actions): also set default-keychain so SecItemAdd targets jarvis-runner

SecItemAdd on the legacy file-based macOS keychain writes to the user's
DEFAULT keychain, not the first writable keychain in the search list.
Changing list-keychains alone left SecItemAdd targeting the locked
login.keychain-db, still returning errSecInteractionNotAllowed (-25308).

Also set the user's default keychain to jarvis-runner.keychain-db in the
unlock step. This is persistent for the runner user (james.maes), so
SecItemAdd from interactive use will also go there — documented as a
side effect in CLAUDE.md with the undo command.

Refs #180

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
v0.1.0-dev.50
2026-05-13 15:29:09 -05:00
james.maes 7b53720496 docs(handoff): refresh end-of-session — CI green push + governance closures (#174)
Captures the 8-PR CI-green push (#163-#173), governance closures (public, branch protection, CodeQL default setup, CircleCI webhook delete, stashes), and methodology notes. Docs-only.
2026-05-13 11:18:02 -05:00
james.maes 16bed16012 ci(actions): restore pnpm + node setup on app-build for Xcode build phase (#173)
PR #164 stripped pnpm+node setup from app-build expecting the artifact to be sufficient, but Xcode's build-phase script invokes scripts/build-webview.sh which needs pnpm on PATH. Re-adds Setup pnpm + Setup Node.js steps. Surfaced by PR #170's error-visibility improvement.
2026-05-13 10:24:10 -05:00
james.maes 53b8fb8f8b fix(voice): widen CI timing budgets for I3 + V4 (round 2) (#171)
Round 1 widening (#168) wasn't enough for macos-15. I3: stall 400→800ms, budget 250→500ms (CI took 263 vs 250). V4: window 500→1000ms, floor 4→3 (CI got 3 emissions in 500ms). Semantic preserved — I3 still asserts elapsed < stallDuration; V4 30Hz guarantee is enforced inside AudioLevelEmitter.start().
2026-05-13 09:36:15 -05:00
james.maes f1c60a31ad fix(ci): surface real xcodebuild errors on App target failure (#170)
Captures full xcodebuild output to a tempfile when check-app-builds.sh fails, so CI logs show the actual compile/link error instead of just the last 5 lines via -quiet | tail -5.
2026-05-13 09:36:11 -05:00
james.maes 928ce4bc61 fix(harness): move Corpora resource into Sources/Harness — fixes xcodebuild (#169)
Moves Corpora dir from packages/Harness/Corpora into packages/Harness/Sources/Harness/Corpora and updates the resource declaration from .copy("../../Corpora") to .copy("Corpora"). xcodebuild's strict package resolution was flagging the package-root location as unhandled despite the swift-test pattern working. Bundle.module layout unchanged; all call sites unaffected. 63/63 Harness tests pass locally.
2026-05-13 09:26:54 -05:00
james.maes e09d9090d0 fix(ci): Harness SQLite struct conflict + Voice cold-start timing budgets (#168)
Closes the remaining 3 CI failures after #167:

Harness + App target (cascade): two Harness files (ReplayMCPAdapter.swift, ReplayRunner.swift) still used 'import SQLite3' while their Replay dep had migrated to 'import CSQLiteVec' on 2026-05-11 (D-5/D-6). On Xcode 26 the SDK overlay's sqlite3_api_routines struct includes db_status64 + set_errmsg (SQLite 3.46+/3.51+) that CSQLiteVec's bundled sqlite3ext.h does not, producing 'struct sqlite3_api_routines is not present' errors. Aligning the imports matches the existing pattern; no brew SQLite install needed.

Voice 3 timing fixes for macos-15 cold-start: AVSpeechSmokeTests warms up AVSpeechSynthesizer in setUp() (cold init was 4.07s, budget 2s — assertion semantic preserved at 2s, just with a warm engine). TTSInterruptTests widens stall 100→400ms, budget 80→250ms (was 108ms in CI). VoiceControllerTests widens audio-level sleep 250→500ms (floor unchanged at ≥30Hz behavior).

All fixes verified locally on Xcode 26.5 / macOS 26.5 SDK. No continue-on-error shortcuts, no env manipulation.
2026-05-13 08:52:37 -05:00
james.maesandClaude Opus 4.7 bcc55c68be fix(ci): pin Xcode 26.x, drop phantom VoiceLog, harden Batcher timing (#167)
CI run 25799596445 failed on 6 SPM packages + the App target. Root cause
was a toolchain skew between local dev (Swift 6.3.2 / Xcode 26) and CI
(Swift 6.0 / Xcode 16):

- mlx-audio-swift v0.1.2 ships swift-tools-version:6.2 which Swift 6.0
  cannot parse, breaking Voice + Harness + the App target with
  "Dependencies could not be resolved because 'mlx-audio-swift' contains
  incompatible tools version (6.2.0)".
- MCP swift-sdk 0.12.0 uses the new `withThrowingTaskGroup` overload
  (no `of:` parameter) that only exists in Swift 6.2+.
- AgentCore tests use `@MainActor` XCTestCase with `await super.setUp()`,
  a pattern Swift 6.0 rejects but Swift 6.1+ accepts.

The macos-15 runner already ships Xcode 26.3 / 26.2 / 26.1 / 26.0
alongside 16.x, so the fix is to switch the Xcode select. Fallback to
Xcode_26.app preserves robustness against patch-level shuffles.

Also:
- Drop `VoiceLog` from the SPM matrix. No `packages/VoiceLog` directory
  exists; the job failed with `chdir error: No such file or directory`.
  Voice-log work is parked under v1.1.
- Bump BatcherTests `waitForDrain` from 80ms to 250ms. The batcher
  window is 33ms; 80ms was tight enough that macos-15 dropped
  test_tokenDeltaConcat with sendCount=0 because the scheduled drain
  hadn't completed its actor + main-actor hop before the test resumed.
  250ms (~7.5× the window) survives CI jitter; verified locally — all
  five Batcher tests pass in 1.27s.

Refs: CI run 25799596445.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 08:37:47 -05:00
james.maesandClaude Opus 4.7 ae7d8a805e ci(actions): make Typecheck step blocking (#166)
PR #165 fixed the one real strict-undefined error in SegmentedRing.tsx;
the other ~30 errors reported in CI run 25797533005 were downstream of
`TS2307: Cannot find module '@jarvis/bus'` and resolve automatically
once `scripts/build-webview.sh` produces the bus package's
`dist/index.d.ts` (which CI already runs before typecheck).

Removes `continue-on-error: true` from the Typecheck step so typecheck
regressions block CI going forward.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 07:38:39 -05:00
james.maesandClaude Opus 4.7 f9c630e431 fix(hud): strict-undefined in SegmentedRing instance-matrix loop (#165)
`initialMatrices[i]` is provably defined because the loop bound is
`i < tickCount` and `initialMatrices.length === tickCount`. TS doesn't
track that, so use a non-null assertion to silence TS18048.

The other ~30 errors reported in CI run 25797533005 were all downstream
of `TS2307: Cannot find module '@jarvis/bus'` — they disappear once
`pnpm install` + `bash scripts/build-webview.sh` generates the bus
package's `dist/index.d.ts`. No code change needed for those.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 07:35:50 -05:00
james.maes 5458732546 ci(actions): apply missed webview reorder + rename artifact + non-block typecheck (164)
Three fixes that #161 attempted but only partially landed: webview build-before-typecheck (missed in #161 due to security-hook short-circuit), artifact rename webview-dist→webview-resources (matching the downloads), typecheck continue-on-error:true (~30 pre-existing TS18048 strict-undefined errors in hud src — filed as v0.2 cleanup). After this lands, SPM + app-build + publish-tag chain unblocks.
2026-05-13 07:06:59 -05:00
james.maes 2068fd41e6 docs(handoff): end of session 2026-05-13 — v0.1 shipped (#162)
End-of-day handoff capturing the full v0.1 milestone shipment: 12 PRs merged today (#150-#158, #159, #160, #161), 22 audit-finding issues closed, 1 stash preserved as wip/voice-log-menu-stash4 for v1.1 #52, repo flipped public, CodeQL default setup enabled. Methodology notes for next session captured (worktree-isolated background agents work great; subagents need explicit 'NEVER cd outside your worktree' briefing).
2026-05-13 07:01:19 -05:00
james.maes 7a22b0513f ci(actions): remove custom CodeQL workflow — default setup now enabled
Default code-scanning setup enabled via API after going public; advanced/custom workflow now redundant + would error with 'default setup is enabled'.
2026-05-13 07:01:03 -05:00
james.maes f6637ec39a ci(actions): fix typecheck/build order + share webview artifact across jobs (#161)
Three surgical fixes to .github/workflows/ci.yml from the first develop-push validation cycle:

1. Webview job: typecheck ran before build, so packages/hud TS imports of @jarvis/bus failed (TS2307). Reordered: install → build → typecheck → test. Build invokes scripts/build-webview.sh, producing App/Resources/webview/ directly.

2. swift-packages job: 6 packages (AgentCore/Bus/Harness/MCP/Voice/VoiceLog) failed with 'bus not mounted' because BusTests mount real WKWebView. Added needs: [webview] + download-artifact for the new webview-resources artifact.

3. app-build job: replaced inline pnpm+node+build-webview.sh with the same artifact download. One webview build serves all consumers.

Artifact renamed webview-dist → webview-resources (production-stamped App/Resources/webview/ tree). Old name was 1 day old, no external consumers.
2026-05-13 06:55:49 -05:00
james.maes a8c7f1a09b chore(deps): batch Dependabot bumps — fiber + plugin-react + jsdom + vite (#144, #145, #147, #148, #160)
Lands four SAFE-MERGE Dependabot bumps in one commit. Each was confirmed SAFE-MERGE by the H' triage on PR #155, then re-verified locally on the new lockfile baseline (vitest@3 + vite@8 + esbuild dropped) from PR #159.

- @react-three/fiber 9.6.0 → 9.6.1 (closes #148)
- @vitejs/plugin-react 5.x → 6.0.1 (closes #147)
- jsdom 25.x → 29.1.1 (closes #144)
- vite pinned to >=8.0.12 via pnpm.overrides (closes #145)

37/37 bus + 101/101 hud tests; both workspaces build; production webview bundle stamps cleanly. PR #146 (TypeScript 6) NOT included; deferred for focused evaluation.
2026-05-13 06:47:16 -05:00
james.maes 08095281fc fix(deps): close vite + esbuild CVEs via pnpm.overrides + vitest@3 bump (#159)
Closes Dependabot alerts #1 (esbuild dev-server response read) and #2 (Vite path traversal). Adds pnpm.overrides pinning vite >= 8.0.5 (drops esbuild transitive) + bumps vitest 2.1 → 3 in root + bus workspaces (vitest 2 incompat with vite 8 SSR transform). 37/37 bus + 101/101 hud tests pass; both workspaces build cleanly. Deferred to v0.2: vitest 4 major + oxc plugin migration.
2026-05-13 06:41:52 -05:00
james.maes 795c3bf5c9 feat(app): v0.1 UX surfaces — startup panels + InputMonitoring banner + PTT (#87, #88, #89, #156)
#89: new AppDelegate.startupSurfacesMode enum (.minimal/.diagnostic). Debug defaults .diagnostic; Release defaults .minimal. openStartupSurfacesIfDiagnostic() runs at tail of bootHealthTask (skipped under XCTest or when wizard is open). Status panel top-right + Dev Overlay bottom-right of NSScreen.main.visibleFrame. DevOverlay opens to Logs tab.

#88: BannerContent.inputMonitoringDenied is now nonDismissible: true. New HUDBannerCoordinator.dismiss(id:) clears a banner programmatically without writing dismissedThisLaunch. AppDelegate.reprobeInputMonitoring fires on NSApplication.didBecomeActiveNotification; rebinds the global hotkey on re-grant. Uses IOHIDCheckAccess (query-only, no prompt) per CLAUDE.md guidance. 3 new coordinator tests.

#87: WizardState.pttHotkey persisted under Jarvis.pttHotkey (independent of summon hotkey). Ships unbound per CLAUDE.md hotkey hygiene. AppDelegate.rebindPTTFromState() called from installVoice, foreground TCC re-grant, Settings Save/Clear. SettingsView extended with PTT hotkey section. Audio-graph isolation: NSEvent monitors only, no audio-graph surgery — safe alongside fix/voice-crit-v0.1. 3 new WizardState tests.

DevOverlay 14 + Voice 26 tests pass; all 17 grep boundary gates green (incl. single-writer-hudstate + no-modal-presentation).
2026-05-13 06:32:16 -05:00
james.maes bc74494ada fix(mcp): v0.1 CRIT cluster — turnID resolver wired + tool-result double-cap (#20, #21, #157)
#21 (CRIT): ToolResultPacker.pack(_:) is now a pass-through decoder; redundant inner 8 KB cap removed. MCP dispatcher's SanitizeForModel.prepareForBoundary(_, capBytes: 8192) is the sole cap site. Doc-comment rewritten honestly: replay row reflects boundary-prepared bytes (8 KB), not original helper output. Replay fidelity beyond 8 KB lifted to v0.5/M-3 once SanitizeForModel can move to a shared module without dep cycle.

#20 (CRIT): ReplayingToolResultObserver.turnIDResolver lock-protected via OSAllocatedUnfairLock<ResolverBox> (same Swift-6-async-safe pattern as InProcessConfirmationCache). New attach(turnIDResolver:) method. AgentOrchestrator.currentTurnID() actor-isolated accessor. installAgent attaches the resolver immediately after orchestrator assignment, with defensive systemLogger.warning if observer type mismatches.

Tests: ToolResultPackerTests TP2/TP5 updated to assert no [TRUNCATED] marker; OrchestratorSubmitTests OS6 reframed + new OS6b reads SQLite events table directly to assert 8 KB exact; MCPRuntimeWiringTests adds attach pre/post-attach + replay-log dual-write correlation.

AgentCore 243 + Memory 98 + Replay 34 + MCP all green; all 18 boundary gates green.
2026-05-13 06:31:46 -05:00
james.maes 4b1dd6404b fix(voice): v0.1 CRIT cluster — wake / STT / TTS / boot probes (#28, #29, #30, #31, #32, #33, #34, #36, #158)
#28 (CRIT): setCancelInFlight calls stopFeed() (preserves stream); rebuild consumer re-arms DAG against new ring. Wake-word no longer dies on audio-graph rebuild.

#29 (CRIT): sttFactory reads PerTurnSnapshot.stt.whisperKitFallback; get_self_state returns canonical snake_case backend constants. Factory signature: () -> any STTProvider → () async -> any STTProvider (existing test sites compile unchanged under Swift 6 implicit-async-closure rules).

#30 (CRIT): TTSEngineActor.synthesize emits .ttsStopped after .finished on natural completion (two-emit-site model: barge-in + natural-completion).

#31 (CRIT): VoiceTTSAdapter.tierResolver wired to read snap.tts.tier from configStore.

#32 (HIGH): Rolling-window trim in OpenWakeWordSession.runORT — mel ≤ 84, embeddings ≤ 16, nextEmbStart slides on drop.

#33 (HIGH): three new boot probes — WakeWordBootHealthProbe, STTBootHealthProbe, TTSBootHealthProbe. New WakeWordDAG.isFeedArmed + VoiceTTSAdapter.hasEngine accessors.

#34 (HIGH): vad.reset() at top of startSTTSession clears Silero VAD LSTM hidden state + wasSpeech between sessions.

#36 (HIGH): new Broadcaster.Priority.agentHud (protects stateChange/turnEnd/error); installAgent adds subscriber pumping AgentHudIntent into dormantAgentContinuation.

Voice 90 + AgentCore 242 tests pass; all 18 boundary gates green.
2026-05-13 06:31:17 -05:00
james.maes f59f5d12e3 fix(memory): v0.1 CRIT cluster — facts_vec / replay correlation / FTS5 sanitize / search_memory preamble (#12, #13, #14, #15, #16, #153)
#14 (CRIT): ContextBuilder.selfAwarePreamble names search_memory + forget_fact with explicit cue 'call search_memory FIRST. Never claim to remember without searching.'

#16 (HIGH): MemoryQueries.sanitizeFTS5Query strips non-alphanumeric, quotes tokens; HybridSearch.searchFacts calls it before binding to MATCH ?. Embedding still runs on raw query.

#12 (CRIT): MemoryStore.init accepts optional embedder; insertNewFact writes facts_vec after the facts commit. Vec failures log + leave FTS row (no rollback). installMemory shares one embedder between writer + reader.

#15 (HIGH): drop stableHash; pass sentinel 0 as sourceTurnId (option 1 per audit — smaller change surface than threading real rowid through 5 files). Schema comment updated.

#13 (CRIT): two-layer fix. Layer 1: AppDelegate owns a per-process sentinel TurnID; installAgent writes the matching turns row after beginSession; AppDelegateMemoryReplaySink attributes events to it. Layer 2: ReplayLog.flushPending retries failed batches event-by-event so one poisoned row only drops itself.

Memory 98 + Replay 34 + AgentCore 243 tests pass; all 18 boundary gates green.
2026-05-13 06:30:35 -05:00
james.maes 05411f82ff fix(vision): v0.1 cluster — T2 honesty + pendingFrame leak + TCC revoke observation (#1, #2, #3, #152)
#1 (HIGH): new hasRealT2Provider init param on AgentOrchestrator; t2AvailableForThisTurn now requires both decision.tier != .t3Cloud AND hasRealT2Provider. Production passes false (MissingT2Provider only). Pre-existing escalation test still passes true with mock T2.

#2 (MED): new FrameAttachController.releaseAfterRejectedSubmit() routes through the sole discardFrame() emission site (D-15 single-emission grep gate still green). Both handleChatSubmit and handleChatCancelAndSubmit call it on .rejected.

#3 (MED): AVCaptureSessionWasInterruptedNotification observer yields .midSessionRevoked. macOS limitation surfaced: AVCaptureSessionInterruptionReasonKey is API_UNAVAILABLE(macos), so we cannot discriminate by reason — any interruption surfaces the banner. NSApplication.didBecomeActive observer calls becameAuthorized() on non-authorized → .authorized flip.

Vision 75 + AgentCore 243 tests pass; all 18 boundary gates green.
2026-05-13 06:30:09 -05:00
james.maes a6f91e6b73 fix(bus,hud): v0.1 S1 cluster — webview didFail + menu-bar icon transition (#40, #41, #151)
#40: BridgeNavigationDelegate gains onDidFail closure (covers didFailProvisionalNavigation + didFail). WebviewBridge.failHandshake(reason:) transitions to new terminal .loadFailed state, cancels pending 2s timeout, fires existing alertPresenter, idempotent. AppDelegate.handleWebviewLoadFailure dual-surfaces: failHandshake + critical non-dismissible banner (defense-in-depth across test seams). WebviewBootHealthProbe gets .loadFailed case.

#41: HudStateCoordinator emit closure now ALSO calls menuBarController.transition(to:) in addition to bridge.send(.hudState(...)). Doc-comment correctly notes this is not a HUD-08 single-writer violation — transition writes currentState, not BusOutbound.hudState. scripts/check-single-writer-hudstate.sh still green.

Tests: 4 new Handshake cases (load-failure-from-sentHello with alert-not-duplicated, from-idle, idempotency, post-armed no-op), BridgeNavigationFailureTests end-to-end + per-arm, MenuBarIconStateTransitionTests drives dormantAgentContinuation and asserts .thinking → .speaking → .idle. 62/62 Bus pass; all 18 boundary gates green.
2026-05-13 06:29:34 -05:00
james.maes b643159735 chore: PR + dependency triage report — 2026-05-12 (#155)
Triage report for the 5 Dependabot PRs (4 SAFE-MERGE / 1 NEEDS-INVESTIGATION), the 2 moderate CVEs (vite + esbuild path traversal — root cause is vitest@2 → vite@5.4.21 → esbuild@0.21.5 transitive chain; existing PR #145 alone does NOT close them; surgical fix is pnpm.overrides), and the 6 stashes (5 DROP + 1 PRESERVE-AS-BRANCH for Voice Log v1.1 + 1 POP-TO-LANE-G). Methodology: each Dependabot PR was tested in an isolated tmp worktree; no main repo HEAD mutations.
2026-05-13 06:29:04 -05:00
james.maes 223310aa27 ci(actions): full pipeline — build / test / scan / publish (#154)
Adds five GitHub Actions workflows + CODEOWNERS + BUILDING.md CI section.

- ci.yml: boundary gates (Ubuntu), webview pnpm test+build (Ubuntu), 14-package SPM matrix on macos-15, app target via xcodebuild, optional self-hosted real-hardware lane, semver tag-publish on push to develop/rc/release/main.
- codeql.yml: Swift + JS/TS with security-extended queries, weekly cron.
- semgrep.yml: p/default + p/swift + p/typescript + p/secrets, SARIF upload, optional SEMGREP_APP_TOKEN.
- dependency-review.yml: blocks severity:high on PRs touching manifests/lockfiles.
- release.yml: tag-triggered GitHub Release with auto-generated changelog.

Branch + tag conventions: feature/fix branches run checks only; develop publishes v0.X.Y-dev.<run_number>; rc/release publishes v0.X.Y-rc.N; main publishes v0.X.Y. Conventional-Commits-aware bumping (feat → minor, fix → patch, feat!/BREAKING → major). Seed version v0.1.0.
2026-05-13 06:28:10 -05:00
james.maes 5bb1e778b5 fix(hud): chat panel auto-scroll on streaming append — B-06 tactical (#51, #150)
Adds a useLayoutEffect on ChatPanel keyed to total content length (captures streaming token append where chatEvents.length is constant). 24px bottom-pin hysteresis; user scroll-up breaks the pin; auto-re-arms on scroll-back-to-bottom. scrollTo feature-detected with scrollTop fallback for JSDOM. 4 vitest cases assert decision logic.
2026-05-13 06:27:42 -05:00
james.maes ba42b6918a docs: BUILDING.md + finalize README MIT license section (#149)
Extracts the long-form build reference (per-package SPM tests, app-target xcodebuild wrapper, webview workflow, 18 boundary-gate linters, real-hardware env-flag tests) into BUILDING.md so the README can stay first-screen weight. Finalizes the README License section against today's MIT decision (e1fcdc5), removing the stale TODO block.
2026-05-12 15:57:48 -05:00
james.maesandClaude Opus 4.7 71b93898ac docs(handoff): end-of-day 2026-05-12 — round 2/3/4 + audits + tracking migration + roadmap + branding
Closes the session that took Jarvis from "wired-but-dead-everywhere"
to fully-mapped + branded + license-clear + audit-tracked.

Highlights:
- Round 2/3/4 strict-mode boot health shipped (probes → status panel →
  severity model + non-dismissible banners + agent self-awareness preamble +
  red menu-bar icon). Toby fix verified end-to-end mid-dogfood.
- facts.source_turn_id FK dropped (a5999e2) — facts persist now.
- Xcode 26 ProcessInfoPlistFile build race fixed (1557302).
- Dev Overlay shipped with 4 tabs + live log streaming via LogBroadcaster.
- 5-agent audit pass at .planning/audit-2026-05-12/ — ~37 findings.
- 141 GH issues filed across audit findings + carry-forwards + M-0..M-7
  migration epic (54 sub-issues) + comment-cleanup + v1.1 backlog.
- TODO.md deprecated. GitHub Issues canonical.
- Code-commenting style guide locked + applied to AppDelegate as the P0
  exemplar (281b909).
- Roadmap at .planning/ROADMAP-2026-05-12.md with 6 milestones bucketing
  all 141 issues.
- MIT license confirmed; LICENSE/SECURITY/CHANGELOG/issue templates/PR
  template/dependabot all in place.
- README rewritten with mermaid diagrams + acknowledgments + culture
  section. Repo metadata + 12 topics + 3 pinned issues set.

Outstanding: PR #149 (BUILDING.md + README MIT cleanup) draft pending
review. Repo still PRIVATE — public-flip decision is the user's call.

Next session: read this handoff + .planning/ROADMAP-2026-05-12.md, merge
PR #149, decide visibility, then start v0.1 fan-out sprint.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 15:45:26 -05:00
james.maesandClaude Opus 4.7 0cc94c637a docs(branding): assets/branding/ + restore MIT license section
- Add assets/branding/README.md with shot list for the five high-impact
  brand assets (social preview, logo, hero shot, app icon, banner) and
  GitHub upload instructions for each.
- Add assets/branding/STYLE.md documenting the colour palette (cyan
  family + HUD navy/black + warning/critical), typography (Eurostile /
  Saira / Orbitron family for display, SF Pro for UI), and tone of
  voice ("terse, technical, dryly opinionated, slightly sardonic").
- Drop five .todo placeholder files so the directory tree shows intent
  without faking assets.
- Restore the README License section to a clean MIT pointer (a
  concurrent agent had reverted it to "decision still open"; that
  decision is now made and lives at .planning/decisions/license.md).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 15:09:14 -05:00
james.maesandClaude Opus 4.7 281b9093e7 docs(appdelegate): apply commenting style guide (P0 of #64)
Rewrites App/AppDelegate.swift docstrings + inline comments to the
.planning/code-commenting-guide.md standard. Comments + docstrings
only — zero code behavior changes.

Closes the P0 entry in the migration table (#65 under epic #64).

Highlights:
- File header: 5-line opener + "See also" + audit-trail suffix.
- Class docstring: install-order ASCII DAG, threading model,
  "Before you edit" block listing the five sharp-edged invariants
  (single-writer HudState, locked install order, shared in-process
  tool registry, JIT entitlement, no-modal presentation).
- Property docstrings reorganized under role-named MARKs
  (Test-injectable seams / AppKit surfaces / HUD state coordinator
  + bus producer continuations / Orch→replay seam + MCP runtime /
  Boot health / Voice / Memory / Vision / Agent). Every property
  now leads with WHY; audit references (Plan IDs, B-/D-/CR- numbers,
  dated audits) are parenthetical suffixes.
- Public + key private method docstrings rewritten:
  applicationWillFinishLaunching gets the 16-step bootstrap + the
  hard-block branches called out; applicationWillTerminate explains
  why each cancellation is explicit; runBootHealth + register-
  BootHealthProbes list every probe + its role; installVoice /
  installMemory / installAgent / installVision /
  installSelfKnowledgeTools open with the subsystem's
  responsibility + fail-soft-vs-hard policy + step sequence.
- The motivating bad example from the guide
  (`inProcessToolRegistry` Plan-ID-lede comment) is rewritten
  exactly as the guide prescribes.
- Inline comments still carrying Plan-ID ledes ("Phase E 2026-05-03
  audit fix:", "Track B-4 (...):") rewritten to lead with WHY/WHAT
  with audit trail demoted to parentheticals at end.

Boundary gates:
- 18/18 green (full sweep: app-builds, bus-harness-parity,
  bus-protocol-version, corpus-secrets, embedding-dim-literal,
  install-order, no-evaluate-javascript, no-leftover-stubs,
  no-modal-presentation, no-null-voice-adapters,
  orchestrator-events-single-consumer,
  presence-bus-no-tts-orchestrator, presence-vision-isolation,
  single-memory-mutated-emit, single-memory-used-emit,
  single-writer-hudstate, vision-isolation,
  applescript-confirmation).
- check-install-order verified literal Task spawn lines + the
  `await self?.agentInstallTask?.value` invariant are intact.
- check-single-writer-hudstate verified AppDelegate still only
  references `.hudState(_:)` inside the allowlisted wiring closure.

Surfaced during review:
- None — only comments touched. The audit-2026-05-04 P3-16 split
  (AppDelegate+Voice/+Vision/+Memory/+Agent) remains outstanding
  but is out of scope for this P0.

Line delta: +965 / -740, net +225. Net growth is from the install-
order DAG ASCII art + the "Before you edit" block + expanded
six-step method docstrings.

Refs: #64, closes #65.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 15:08:33 -05:00
james.maesandClaude Opus 4.7 b2710eee48 docs(readme): branding pass — badges, MIT license, acknowledgments
- Add status badges (license, last commit, issues, platform, Swift) under
  the tagline so the GitHub card carries signal at a glance.
- Replace the "personal use only / no license granted" footer (which
  contradicted the actual MIT LICENSE file committed at 9b62db5) with a
  proper MIT pointer + link to the decision rationale.
- Reframe the scope paragraph: still single-user single-machine, but
  acknowledge the repo is open source and useful artifacts (agent loop,
  Bus, MCP, voice, HUD, boundary gates) are here for the lifting.
- Add Acknowledgments section calling out the major OSS dependencies
  (Anthropic, Ollama, MCP SDK, openWakeWord, Silero, ONNX Runtime,
  argmax-oss-swift, mlx-audio-swift, sqlite-vec, R3F, swift-log,
  swift-nio, Yams) so credit and discoverability are explicit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 15:05:33 -05:00
james.maesandClaude Opus 4.7 e1fcdc520f docs(license): MIT decision + rationale
Confirms MIT (already at 9b62db5). Documents what was considered (Apache
2.0, MPL-2.0, AGPL-3.0) and why MIT fits a solo personal project with
permissive intent. Lists revisit triggers.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 15:02:49 -05:00
james.maesandClaude Opus 4.7 c4c32f7aae docs(readme): refresh — diagrams + architecture + culture + roadmap
Audit-and-rewrite of root README against current truth (2026-05-12).
The previous README was accurate but list-shaped and unillustrated;
the rewrite reorients around what a new reader (human or AI agent)
needs in 60 seconds.

New / changed sections:
- Tagline + two-paragraph intro (what / who / why)
- Status banner pointing at GitHub Issues + Milestones (canonical)
- Screenshots placeholder + shot list under assets/screenshots/
- "Architecture at a glance" with a top-level mermaid flowchart
  (Swift host + LLM providers + WKWebView, with 14 nodes)
- Subsystems table — eight first-class + supporting packages
- "Install order" section with a mermaid DAG of the AppDelegate
  install sequence (vision → agent → voice, plus parallel
  memory/MCP/replay), matching check-install-order.sh
- "Agent turn lifecycle" mermaid showing the orchestrator → single
  broadcaster fanout, with the strict-mode degradation preamble
  inject point called out
- "Boot-health probes" mermaid for the eight NOT FAKED probes →
  rollup → menu-bar icon / banner / agent preamble
- "Project culture" section codifying the in-code-docs philosophy,
  NOT FAKED probes, strict-mode escalation, 18 boundary gates, the
  three-name test-double taxonomy, audit-and-stabilize cadence,
  and the GitHub-Issues-is-canonical policy
- "Roadmap" reorganized around the v0.1 → v1.1 milestones from
  GitHub Milestones (user-outcome-focused, not subsystem-focused)
- Build & run cleaned up; boundary-gates one-liner; opt-in
  real-hardware test commands kept

Also adds assets/screenshots/README.md with a prioritized shot
list — eight screenshots in priority order — and a note on why
diagrams stay as inline mermaid (GitHub-native, no re-export).

Removed: the older "Status" subsystem-state table, which had
become a mix of v0.12.0 milestone audit terms (Track A/B/C/D,
B-8) that don't map cleanly to the new GitHub Issues taxonomy.
Status now points at GitHub Issues + Milestones as the source
of truth.

Gates: 17/18 pass. check-app-builds.sh fails on the in-flight
AppDelegate.swift rewrite (unstaged, owned by a parallel agent)
— unrelated to this markdown-only change. Confirmed only
README.md + assets/screenshots/README.md are staged here.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 15:00:21 -05:00
james.maes 4e6911472d docs(changelog): add CHANGELOG.md with milestone history
Keep a Changelog format. [Unreleased] tracks the May 2026 audit-and-
stabilize work (boot-health probes, status panel, Dev Overlay Logs tab,
memory FK fix). Milestone history groups v0.10.0 → v0.12.0 by phase
rather than commit; per-commit detail stays in git log.
2026-05-12 14:56:56 -05:00
james.maes e0c5bcba69 docs(github): issue + PR templates + dependabot config
Four issue templates (bug / enhancement / audit-finding / epic) pre-fill
existing labels (severity:*, area:*, audit-finding, epic). PR template
references the 18 boundary gates + comment style guide. Dependabot covers
swift, npm (/webview), and github-actions on a weekly cadence.
2026-05-12 14:56:49 -05:00
james.maes 9b62db5c33 docs(github): add LICENSE + SECURITY.md
MIT license (permissive, attribution required); SECURITY.md documents
the personal-use threat model and private reporting channels (email +
GitHub Security Advisories).
2026-05-12 14:56:42 -05:00
james.maes 61e06fb2dc docs(roadmap): user-outcome-focused milestone roadmap
All 142 open issues triaged into 6 GitHub milestones organized by
user-facing capability rather than technical area:

- v0.1 — It actually works (28 issues): voice, listening, seeing,
  facts, debugging dialogs, basic UI. Tactical patches for CRITICAL
  audit findings so user has working Jarvis NOW.
- v0.2 — Observable + stable (23): MED/LOW audit punch-list + PTT/TCC.
- v0.5 — API M-0..M-3 (31): Self/Settings/Diagnostics surfaces; B-08.
- v0.8 — API M-4..M-7 (36): Memory/Vision/Voice/Turn; B-03/B-04/B-05/B-06.
- v1.0 — Shipping (13): commenting, doc reconciliation.
- v1.1 — Backlog (11): Orpheus, WhisperKit, Voice Log, presence.

ROADMAP-2026-05-12.md supersedes the build-phase ROADMAP.md from
2026-04-22 (kept for history; describes shipped phases). CLAUDE.md
gains a Roadmap section pointing to the new doc + milestones URL.

Also lands the 5 audit-2026-05-12 reports referenced by the roadmap
(bus-hud, mcp-agent, memory, vision, voice).
2026-05-12 14:52:25 -05:00