dependabot/github_actions/github/codeql-action-4
17
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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. |
||
|
|
f9cd25d66e |
chore(test-naming): converge on Mock/Fake/Stub convention; document in CLAUDE.md; rename worst-mismatch stragglers
Per audit-2026-05-04 P2-15: 26 Mock*, 21 Fake*, 12 Stub* across the test corpus, often used interchangeably for the same role. New CLAUDE.md section "Test naming conventions" (line 127) sets the rule: - Mock*: records calls AND returns scripted responses (assertion driver). - Stub*: returns canned data without recording (deterministic input). - Fake*: alternative implementation with realistic behavior (in-memory state-holder). Renamed 15 worst-mismatch stragglers in the older corpus (per audit constraint, did NOT touch types added in today's P1+P2 fix commits): Stub* → Mock* (records + scripts): - HybridSearchTests: StubEmbedder → MockEmbedder - HybridSearchTests: StubStore → MockStore - SessionHistoryTests: StubStore → MockStore - InProcessMemoryToolsTests: StubHybrid → MockHybrid - InProcessMemoryToolsTests: StubHistory → MockHistory - InProcessMemoryToolsTests: StubForget → MockForget Mock* → Stub* (canned data, no recording): - STTBackendSwitchTests: MockSpeechAnalyzerBridge → StubSpeechAnalyzerBridge - STTBackendSwitchTests: MockWhisperKitBridge → StubWhisperKitBridge - VoiceWiringTests: MockVADEngineForW4 → StubVADEngineForW4 - VoiceWiringTests: MockSTTProviderForW4 → StubSTTProviderForW4 - VoiceWiringTests: MockTTSForW4 → StubTTSForW4 - VoiceWiringTests: MockOrchestratorForW4 → StubOrchestratorForW4 - VoiceWiringTests: MockBannerForW4 → StubBannerForW4 - VoiceWiringTests: MockBusForW4 → StubBusForW4 Fake* → Mock* (records + scripts): - WebviewBridgeOutboundTests: FakeJSEvaluator → MockJSEvaluator - HudStateCoordinatorBusWiringTests: FakeJSEvaluator → MockJSEvaluator (the comment on the type already said "Records each call for assertion") Skipped per audit constraint: - StubCapture/StubSink (Vision FrameAttachConfirmSendWiringTests, P1+P2) - MockVADEngine + MockOrchestratorForController siblings (Voice VoiceControllerTests/VADGatedSessionTests, today's track-B churn) Tests pass: Voice 87+23, MCP 85, Memory 88, Bus 58, AgentCore 19+72, Vision 19, Shell 7+5. App target builds clean. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
6f6617e67b |
fix(test): update F-A2-01 stale JarvisBusWorld assertion to .page
The Bus production switched from `WKContentWorld.world(name: "JarvisBusWorld")` to `WKContentWorld.page` in |
||
|
|
1f8e03edeb |
fix(track-a): demo-blocker class + audit reports + chat-turn e2e tests
User feedback: 50+ hours of agent work, nothing demonstrably working.
Fanned out 6 deep auditors (voice, HUD, vision, memory, LLM, tests);
all reports landed at .planning/audit-2026-05-03/ with brutal-honesty
mandates. Synthesis (SYNTHESIS.md) confirmed: every modality has at
least one fatal break between code-that-passes-tests and
code-that-runs. Track A is the smallest credible path to one working
modality (text turn + animated rings).
Closed under TDD discipline:
**Item 4 — HUD idle ring static rendering (F-A1-01).**
- webview/packages/hud/src/hud/stateUniforms.ts:30 — was
`pulse: 0.0, rotate: 0.0` for idle, the all-static configuration
that rendered STANDBY as dots instead of animated rings. Now
pulse: 0.4, rotate: 0.05 — gentle ambient distinct from booting +
thinking.
- webview/packages/hud/tests/stateUniforms.test.ts — table updated;
new regression-guard `STATE_PARAMS[*] is not all-static` (7 cases,
one per HudState) prevents anyone from re-zeroing a state.
**Item 1 — CacheHints eligibility gate (likely streamTruncated cause).**
- packages/AgentCore/Sources/AgentCore/CacheHints.swift —
+ static func eligibleForSystemPrompt(_:ttl:). Anthropic's prompt
cache requires ≥1024 tokens at the breakpoint; below that, the
server returns 200 OK + immediate-EOF for `extended-cache-ttl`
hints. The orchestrator's default system prompt is ~10 tokens.
Helper returns nil for sub-threshold prompts so no cache_control
marker is emitted.
- packages/AgentCore/Sources/AgentOrchestrator/AgentOrchestrator.swift
— call sites now pass `CacheHints.eligibleForSystemPrompt(finalSystem)`
through runTurnLoop instead of unconditional `.extended1h`.
- Tests: CacheHintsEligibilityTests (6 cases), RequestBodyTests R5a/R5b
(2 cases verifying small-prompt → no cache_control in encoded JSON,
large-prompt → cache_control present).
**Item 2 — StreamOutcome diagnostic.**
- packages/AgentCore/Sources/AnthropicProvider/StreamOutcome.swift —
new pure classifier that distinguishes:
- non-2xx HTTP status
- 200 OK + 0 bytes (cache_control / auth-header rejection class)
- 200 OK + bytes + 0 frames (malformed body)
- 200 OK + frames + EOF before message_stop (mid-stream drop)
- 200 OK complete (healthy)
AnthropicProvider's read loop counts frames + bytes and logs the
summary once per stream. Production logs now distinguish failure
modes that previously all surfaced as `streamTruncatedFinal`.
- Tests: StreamOutcomeTests (7 cases, all branches).
**Item 3 — KeychainError surfacing.**
- packages/AgentCore/Sources/AnthropicProvider/AnthropicAPIKeyProvider.swift
— new builder `make(keychain:item:)` returns the
`@Sendable () async throws -> String` closure with errors
propagating verbatim. Closes the audit's hidden-401 finding:
`(try? keychainStoreLocal.get(.anthropic)) ?? ""` swallowed the
real KeychainError into an empty x-api-key, producing
`401 x-api-key header is required` indistinguishable from a
stale-key 401. Now the actual error reaches the chat panel via
AnthropicProvider → orchestrator.error → BusForwarder →
submitRejected.
- App/AppDelegate.swift — both Anthropic provider construction sites
(installAgent, installVision T3 wiring) now use the propagating
builder.
- Tests: AnthropicAPIKeyProviderTests (6 cases — itemNotFound,
unexpectedStatus, duplicateItem propagation; happy path; explicit
item; default item).
**Item 5 — F1 #2 chat-turn round-trip e2e tests.**
- packages/Bus/Tests/BusTests/RealWKWebViewIntegrationTests.swift —
+ 2 new tests using a real WKWebView:
- test_chatTurnRoundTrip_busOutboundReachesPageHandler — Swift
`bridge.send(.turnStarted/tokenDelta/turnEnded)` reaches the
page's onOutbound handler. This is the test the v0.12.0 audit
called out as catching BLOCKER-INT-1, INT-2, INT-3,
F-E-RACE-1, F-E-FK-1, F-E-WIRE-1 in one shot.
- test_chatTurnRoundTrip_busInboundFromJSReachesSwiftHandler —
JS-side `window.jarvisBus.send({type:'chatSubmit',...})` —
exactly what ChatInput.tsx does — reaches the bridge's
onInbound handler with the right body.
**Verification:**
- AgentCore: 215/215 (was 178; +37 across BusForwarder, CacheHints,
StreamOutcome, AnthropicAPIKeyProvider, RequestBody R5).
- Replay: 33/33.
- Bus: 57/58 (1 pre-existing failure: F-A2-01 stale `JarvisBusWorld`
assertion documented in AUDIT-FINDINGS, separate scope).
- webview/packages/hud: 94/94 (was 87; +7 stateUniforms regression-
guards + idle table updates).
- All 15 boundary grep gates: PASS.
- scripts/check-app-builds.sh: PASS.
**Audit reports retained at .planning/audit-2026-05-03/:**
- SYNTHESIS.md (consolidated, with triage plan)
- hud-audit.md, llm-audit.md, memory-audit.md, tests-audit.md,
vision-audit.md, voice-audit.md, voice.md (per-modality detail)
**Carry-forward (NOT closed this commit):**
- F-A2-01 stale WebviewBridgeOutboundTests assertion (pre-existing).
- Voice (F): models never bundled, audio graph never instantiated,
STT bridge body is `_ = chunk`, TTS engine nil. ~1 day.
- Vision (F): AVCapturePhotoOutput allocated but capturePhoto never
called; HUD camera button doesn't exist. ~1 day.
- Memory (F): Apple's stripped libsqlite3 prevents sqlite-vec from
loading; "future ops plan" has zero commits. ~3 days.
- LLM (D+): NoopBusGateway still drops tool-call events
(BLOCKER-INT-1).
- Tests (C-): 5 XCTAssertTrue(true) tautologies + multiple
rubber-stamp tests defending stubs.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
326a27d530 |
test(bus,f1): real-WKWebView handshake integration test — would have caught the WKContentWorld bug class
Phase F1 first deliverable, AUDIT-AND-FIX-PLAN.md. Pragmatic scope
adjustment: lands as `packages/Bus/Tests/BusTests/RealWKWebViewIntegrationTests.swift`
(SPM test target, runnable via `swift test`) instead of a brand-new top-
level `IntegrationTests` Xcode target. Reasoning:
• Xcode-target scaffolding requires substantial pbxproj surgery (new
PBXNativeTarget + dependency proxy + build-config list + 2 build
configs + sources/frameworks phases + N package-product-dependencies)
that risks breaking the project file.
• The Bus package's existing SPM test target already imports WebKit and
uses real WKWebView in its other tests; adding to it is a pure file-
addition with no project-graph changes.
• SPM `swift test` runtime is immune to upstream Xcode 26 RunningBoard
error 5 that had blocked Phase 3's xcodebuild test runtime.
• Phase D-Phase-2 of AUDIT-AND-FIX-PLAN.md specifies this exact path
(`packages/Bus/Tests/BusTests/RealWKWebViewIntegrationTests.swift`),
so F1's "first starter test" + D-Phase-2's required test collapse
into one shipping file.
Two tests, both pass in ~1.0–1.4s on the fixed branch:
test_endToEndHandshake_reachesArmed
Constructs a real WKWebView, loads a tiny HTML page so Injection.js
runs at document-start, calls bridge.startHandshake(), polls for
handshakeState == .armed within 2.5s. Asserts armed AND alert-path
NOT fired (alert is the FAILURE handler).
On the fb41c5f-fixed branch: passes (~1.0s — load + Injection.js +
handshake round-trip in unified .page world; auto-ack-hello at the
stub layer means no bundle handler needed).
On the bug branch (WKContentWorld(name: "JarvisBusWorld") for
Injection.js + page world for the message handler): would hang on
.sentHello, hit the 2s production timeout, transition to .timedOut,
invoke alertPresenter. Both assertions fail. THIS is the test that
would have caught the WKContentWorld isolation bug before shipping.
test_endToEndHandshake_passesThroughSentHello
Same setup but samples handshakeState rapidly post-startHandshake()
to confirm .sentHello was observed before .armed. Defends against a
future regression where Swift short-circuits .armed without the JS
round-trip (which would make the first test pass spuriously).
Test verdict on production code: green. Bus suite count delta: 54 → 56
tests. One failure (F-A2-01) remains unchanged — pre-existing stale
JarvisBusWorld assertion in WebviewBridgeOutboundTests.test_sendWhenArmedCallsEvaluator.
Honest scope: 3 of the 4 planned F1 starter tests still TODO:
- Wizard happy path
- Toggle HUD via hotkey
- Ask-the-agent-something flow (would catch BLOCKER-INT-2 directly)
The third is the highest-priority remaining F1 work — once it lands,
BLOCKER-INT-2 becomes a failing test we can then TDD-fix in Phase E.
Refs: .planning/AUDIT-AND-FIX-PLAN.md Phase F1 + Phase D-Phase-2.
|
||
|
|
96a8e2da72 |
feat(09-04): add chatSubmit / chatCancelAndSubmit / submitRejected bus messages + AppDelegate text-input handlers (D-10, D-12, BLOCKER-1, WARNING-4)
Wire layer: - BusInbound gains chatSubmit(text:) + chatCancelAndSubmit(text:) cases. - BusOutbound gains submitRejected(reason:) case. - BUS_PROTOCOL_VERSION 2.2.0 -> 2.3.0 (Swift + TS); fixtures byte-identical. AppDelegate (chat-panel handlers): - handleChatSubmit + handleChatCancelAndSubmit dispatch into AgentOrchestrator.submit(.text(...)) / cancelAndSubmit(.text(...)) (D-12). - BOTH handlers call tryPhraseAttachIfMatch BEFORE submit so phrase-matched text input arms the FrameAttachController (WARNING-4 closure — previous plan only wired chatSubmit). - BLOCKER-1 user-side: appendUserTextIfRunning appends user text to TurnTranscriptStore on .ran/.superseded so MemoryExtractionCoordinator finds non-nil pair text. - handleTextOutcome routes SubmitOutcome.rejected to a Bus toast via RejectReasonCopy.body — byte-identical wording to the voice-path HUD banner (D-10 single source of truth). VISION-03 gate adjustment: - check-presence-vision-isolation.sh Layer 3 no longer flags `cancelAndSubmit` in App/ files holding PresenceSignalBus references. Plan 4 legitimately introduces orchestrator.cancelAndSubmit at the chat-panel handler call site; the SEC-06 invariant (presence enrichment lives outside the wrapper) is enforced by AgentOrchestrator.runTurn and proven by AgentOrchestratorPresenceEnrichmentTests. TTSEngine* and runTurn (private) remain forbidden tripwires. Tests: - CodableRoundTripTests adds round-trips for chatSubmit / chatCancelAndSubmit / submitRejected; webview round-trip.test.ts mirrors. - 54/54 Bus tests pass; 37/37 TS bus tests pass; check-bus-protocol-version reports parity at v2.3.0. |
||
|
|
87aec282a0 |
feat(09-02): wire FrameAttachController + Bus frameAttachRequested + broadcaster release subscriber (D-15, D-16, INT-07-04)
- App/Vision/AppDelegateFrameAttachAdapters.swift (NEW): FrameAttachCaptureSourceAdapter wraps CameraCapture, FrameAttachReplaySinkAdapter wraps Replay.ReplayLog (placeholders log via JarvisLogChannel.replay — see file docstring for FK rationale), FrameAttachControllerReplaySinkBridge bridges Vision's FrameAttachReplaySink actor to FrameAttachController.ReplaySink protocol - AppDelegate: new frameAttachController + frameAttachReleaseTask properties; installVision now constructs FrameAttachController (D-15); installAgent waits for visionInstallTask before constructing the orchestrator and passes visionRouter:; new step 5d frame-attach release subscriber subscribes broadcaster's .frameAttach priority and fires onAssistantTurnComplete() on .turnEnd for image-bearing turns (D-16) - AppDelegate: tryPhraseAttachIfMatch(_:) helper exposed for Plan 4's chatSubmit + chatCancelAndSubmit handlers (WARNING-4: must call from BOTH paths) - AppDelegate.installBus: bridge.onInbound now switches on BusInbound; .frameAttachRequested → frameAttachController.requestAttach(reason: .hudButton) - BusInbound: additive .frameAttachRequested case + Discriminator + Codable arms (NO default — exhaustive-switch drift preventer); BUS_PROTOCOL_VERSION 2.1.0 → 2.2.0 in Swift + TS mirror - TS protocol: matching frameAttachRequested case + decoder arm; round-trip.test.ts asserts version 2.2.0 + decodes new fixture - New fixtures (parity): packages/Bus/Tests/BusTests/Fixtures/frameAttachRequested.json + webview/packages/bus/fixtures/frameAttachRequested.json (byte-identical, no trailing newline per check-bus-protocol-version.sh) - Memory package bumped from .v13 to .v14 (cascade: Memory depends on AgentCore which now requires v14 due to JarvisVision dependency added in Task 1) - xcodegen regen for the new App/Vision/AppDelegateFrameAttachAdapters.swift source file - 2 new FrameAttachReleaseSubscriberTests prove broadcaster→onAssistantTurnComplete glue (image-bearing turns release once; text-only turns NEVER release); subscription uses devOverlay priority for the sync wait to avoid competing with broadcaster's drain on orch.events - 1 new CodableRoundTripTests entry (test_roundTrip_frameAttachRequested) - Phase 7 SOLE-emission-site invariant intact: FrameAttachDiscardSiteGrepTests passes; check-presence-vision-isolation.sh exits 0; orchestrator-events single-consumer grep gate exits 0; 65 AgentOrchestratorTests + 51 BusTests + 34 webview tests all green - App target compiles cleanly (check-app-builds.sh exits 0) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
a5107218e8 |
test(07-03): add failing in-process MCP tools + Bus session-history tests
- InProcessMemoryToolsTests: dispatch coverage for search_memory,
search_conversation, forget_fact through InProcessToolRegistry; stub
dispatchers; requiresConfirmation gate (D-02 forget_fact only);
unknown-tool error
- SessionHistoryOutboundTests: BusOutbound.sessionHistory round-trip +
shape ("type":"sessionHistory") + version constant present
RED: tests reference InProcessTool, InProcessToolRegistry,
SearchMemoryTool, SearchConversationTool, ForgetFactTool, plus
BusOutbound.sessionHistory + Bus.TurnRow — none exist yet.
|
||
|
|
61ba047068 |
chore: merge executor worktree (worktree-agent-af785327 / plan 02-04)
# Conflicts: # project.yml |
||
|
|
a63d521d38 |
feat(02-04): add bus parity + HUD-04 lint + harness-parity pre-build scripts
Three build-breaking check scripts + two smoke test harnesses + two fixture dirs: - scripts/check-bus-protocol-version.sh: greps Swift vs TS BUS_PROTOCOL_VERSION constants, diffs the two fixture directories (packages/Bus/Tests/BusTests/ Fixtures/ vs webview/packages/bus/fixtures/). Fails build on any drift. - scripts/check-no-evaluate-javascript.sh: scans App/ + packages/ for `.evaluateJavaScript(` outside test dirs; HUD-04 architectural lint. - scripts/check-bus-harness-parity.sh: byte-identical check between canonical webview/bus-harness.html and bundle copy (Plan 02-03 provides the bundle copy; this script enforces no-drift going forward). - scripts/test-check-bus-protocol-version.sh + bus-mismatch/ fixture: drives the protocol-version checker against a v2.0.0/v1.9.0 mismatch, asserts exit 1 + both versions in error text. - scripts/test-check-no-evaluate-javascript.sh + bus-evaluate-js/ fixture: drives HUD-04 lint against bad.swift (evaluateJavaScript) + good.swift (callAsyncJavaScript). Asserts bad.swift flagged, good.swift not flagged. Fixture is copied to a temp dir to bypass the production */test-fixtures/* path-skip rule. [Rule 3 - Blocking] Normalized Swift-side fixtures to drop trailing newlines. The 14 JSON files under packages/Bus/Tests/BusTests/Fixtures/ had stray trailing \n while the TS mirror at webview/packages/bus/fixtures/ did not. Plan 02-02's SUMMARY documented the no-trailing-newline convention (matches Swift JSONEncoder default) but Plan 02-01's fixtures were authored via a text editor that added them. Stripping \n lets check-bus-protocol-version.sh pass without relaxing the byte-equality invariant. Swift CodableRoundTripTests remain green (24/24) because JSONSerialization ignores trailing whitespace. |
||
|
|
de59a2d211 |
feat(02-03): add OutboundBatcher + fill in WebviewBridge outbound path
- OutboundBatcher: actor-based 33ms coalescer (latest-wins audio, concat tokens, flush-then-send for state transitions). Task.sleep-based window per RESEARCH §HUD-06. Order preserved on flushAndSend. - WebviewBridge.sendRaw(_:): real callAsyncJavaScript call with primitive string payload argument (HUD-04 / T-02-13 — never concat-into-body). - WebviewBridge.send(_:): gates on handshakeState == .armed, else throws BusError.bridgeNotReady; delegates to sendRaw. - WebviewBridge.startHandshake(): now actually sends the hello frame via sendRaw (bypasses the armed gate — hello is what STARTS the handshake). - WKUserScript at .atDocumentStart in JarvisBusWorld installs window.jarvisBus stub before any page script runs (pitfall 3). - JSEvaluator protocol seam: WebviewBridge holds an evaluator, production uses WKWebViewJSEvaluator (WKWebView wrapper); tests use a recording fake so the outbound suite doesn't need a real WebKit process. - WebviewBridge: OutboundBatcher.Sink conformance — sendRaw already matches the Sink signature. Tests: 11 new (5 Batcher + 6 Outbound), 47 total all green. Invariants: 0 .evaluateJavaScript( call sites in packages/Bus/Sources/; 1 webView.callAsyncJavaScript call site (in WKWebViewJSEvaluator). |
||
|
|
f7f87d8dba |
test(02-03): add failing OutboundBatcher + outbound WebviewBridge tests
RED phase — these tests reference APIs that do not yet exist:
- OutboundBatcher actor (postAudio, postToken, flushAndSend)
- WebviewBridge.JSEvaluator protocol + internal test-only init
- WebviewBridge WKUserScript injection resource
Adds packages/Bus/Sources/Bus/Resources/Injection.js + declares
resources: [.process("Resources")] on the Bus target so the bundle
contains the document-start stub that GREEN will load.
|
||
|
|
a555093865 |
feat(02-01): add WebviewBridge + Handshake state machine
- `Handshake.swift` — `HandshakeState` enum (`.idle` → `.sentHello` → `.armed` / `.mismatched` / `.timedOut`) + `HandshakeTiming.timeout = .seconds(2)`. - `WebviewBridge.swift` — `@MainActor final class` conforming to `WKScriptMessageHandlerWithReply` with `MainActor.assumeIsolated` to read `WKScriptMessage.body` under Swift 6 strict concurrency (Apple DevForums 751086). Installs its handler in `WKContentWorld.world(name: "JarvisBusWorld")` so page scripts cannot observe or post to the bus. - Inline handshake handling: `helloAck` matching `BUS_PROTOCOL_VERSION` arms the bridge; mismatch or 2s timeout flips to terminal state and invokes an injectable `alertPresenter` (NSAlert-free under test). `onInbound` is never called for `helloAck`. - Internal `handleInboundString(_:replyHandler:)` seam lets tests exercise the decode path without synthesizing `WKScriptMessage` (not constructible from user code). - `send(_:)` is a stub that serializes via `BusCoder` but raises `BusError.bridgeNotReady` until armed. Plan 03 swaps the stub body for a real `callAsyncJavaScript` wiring. - 5 HandshakeTests + 7 WebviewBridgeTests cover: match/mismatch/timeout/ cancel-on-arm transitions, decode-success dispatch, decode-failure reply, non-string body reply, onInbound-throws reply, nil-return implicit success, handler registration. All green (36 total Bus tests pass). |
||
|
|
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.
|