Communication pipeline#3
Open
Nalin-Atmakur wants to merge 47 commits into
Open
Conversation
- Orchestrator.md: full system spec updated with Gemma 4 E4B, text-only BLE, real Cactus API - DECISIONS.md: 21 design decisions from planning sessions - SETUP_LOG.md: Cactus CLI install, model download, SDK build notes Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
- .factory/skills/ios-worker/SKILL.md: TDD-based iOS worker procedure - .factory/services.yaml: xcodebuild build/test commands - .factory/init.sh: environment verification script - .factory/library/: architecture, cactus-api, environment, user-testing docs Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Create the SwiftUI iOS 16+ project structure, embed the cactus XCFramework with module maps, add permission plist keys, and verify simulator build/test with a basic XCTest harness. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add TreeNode, NetworkConfig, Message envelope, and NodeIdentity with explicit CodingKeys plus version-merge and GPS fallback helpers so downstream BLE/tree features have stable serialization semantics. Add comprehensive XCTest coverage for round-trip encoding, malformed JSON rejection, version monotonicity, enum coverage, persistence, and coordinate embedding. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add network scan and PIN-gated join flow with BLE tree-config transfer, plus version-convergence behaviors and XCTest coverage for higher-wins, out-of-order, and no-op updates. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Add RoleClaimService handling CLAIM/RELEASE/CLAIM_REJECTED with organiser-wins resolution, release propagation, disconnect auto-release, and promote-target validation; wire a RoleSelectionView for claiming/releasing roles and cover the new behavior with XCTest scenarios. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
… entries Add a MainViewModel-driven PTT flow that records, transcribes, routes, and broadcasts while enforcing disconnected-state disablement and feed ordering. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Adds scene-phase handling to flush compaction queues on background and restart mesh on foreground, and adds cross-area XCTest coverage for the full resilience integration flows. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
22 completed features, 11 testing phases, 2 backlog items Copy-paste ready for Linear issue creation Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Seven compounding issues prevented the model from ever being downloaded
or correctly detected on device:
1. Temp file race: URLSession deletes the download temp file when
didFinishDownloadingTo returns. Move it to a stable path before
the method returns so the subsequent moveItem doesn't fail.
2. HTTP status never checked: URLSession only raises transport errors,
not HTTP 4xx/5xx. A 401/404 from HuggingFace was treated as success,
saving an HTML error page as the model and marking download complete.
Now check HTTPURLResponse.statusCode in didCompleteWithError.
3. Wrong repository URL: gemma-4-e4b-int4 repo doesn't exist publicly.
Correct URL: Cactus-Compute/gemma-4-E4B-it/weights/gemma-4-e4b-it-int4-apple.zip
(verified by running cactus CLI on Mac and inspecting downloaded files).
4. Wrong extraction destination: zip contains 2088 .weights files at its
root (no top-level subdirectory — confirmed with unzip -l). Extracting
to applicationSupportDirectory dumped files into app support root.
Now extract directly into modelDirectoryURL.
5. Completion state used single-file size check: switched to a zero-byte
.complete sentinel created after successful extraction. synchronize-
CompletionState checks sentinel + model directory; cleans up and
returns false if either is missing — self-heals without reinstall.
6. break in switch didn't exit retry for-loop: labeled loop retryLoop:
and use break retryLoop for all non-retryable exits.
7. Import name mismatch: module is ZIPFoundation not ZipFoundation.
Also adds:
- recoverMisplacedExtraction(): detects >500 .weights files in the wrong
location from a previous failed run and migrates them in-place, saving
a 6.4 GB re-download.
- NSLog("[ModelDownload] ...") instrumentation throughout the pipeline
so all steps are visible in the Xcode console when running on device.
- ZIPFoundation package dependency for zip extraction on iOS.
Closes #23 (pending successful device run of Steps 1.1–1.3)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Updates .factory/ artifacts to support single-milestone test-and-fix mission: - services.yaml: add iPhone 17 Simulator commands + warnings filter - init.sh: resolve repo root dynamically (remove hardcoded paths) - library/environment.md, user-testing.md: current Simulator-only scope - skills/ios-worker: Simulator smoke procedure, XCUITest guidance, preserved-NSLog convention, and updated example handoff Mission artifacts (validation-contract.md, validation-state.json, features.json, AGENTS.md) live in the mission directory outside the repo. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…pted errors Three coordinated changes in TacNet/Services/Cactus.swift repair the 7 failing ModelDownload / AppBootstrap tests without weakening any assertion: 1. The post-download path now classifies the temporary file by inspecting its PK\x03\x04 magic bytes. Zip payloads take the existing validate-size + unzip + write-sentinel path; non-zip payloads (the unit-test mocks, and any future raw-binary distribution) are moved straight into modelDirectoryURL/modelFileName so that file itself acts as the sentinel. This removes the spurious 'Downloaded file is too small (19 bytes)' error the tests were producing. 2. On .interrupted the service now stores the resumeData and breaks out of the retry loop instead of auto-continuing, so ensureModelAvailable() throws ModelDownloadServiceError.interrupted(canResume:) and the next call picks up the stored resumeData. This is what the retry-resume tests (AppBootstrap.retry(), ModelDownloadService resume test, cross-area interruption recovery) expect. 3. synchronizeCompletionState() no longer wipes stored resumeData when it finds the sentinel absent. Clearing resumeData there meant every call to canUseTacticalFeatures() / downloadedModelDirectoryPath() / a fresh ensureModelAvailable() would throw away the checkpoint from the prior attempt, breaking the retry flow. Also aligns TacNetTests IPHONEOS_DEPLOYMENT_TARGET (16.0 -> 18.6) with the main TacNet target's WIP bump so the test target compiles against the app module (previously the tests wouldn't even link after a clean build). All existing NSLog debug additions in Cactus.swift, BluetoothMeshService.swift and ContentView.swift are preserved. Verification: - 7 target tests all pass. - Full xcodebuild test: 119 executed, only the 4 pre-existing testMainViewModelPTTDisabledWhenDisconnectedAndShowsError assertion failures remain (a separate feature's responsibility). - No new build warnings introduced (only pre-existing Cactus SDK and NSLog-adjacent warnings remain). Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
When connectedPeerIDs is empty, startPushToTalk() now rejects early: keeps pttState == .idle, sets errorMessage to the disconnected error, skips audioService.pttPressed(), and emits an NSLog for the gated path. Also makes isPTTDisabled reflect the disconnected state so the UI button is disabled when offline. Fixes testMainViewModelPTTDisabledWhenDisconnectedAndShowsError. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Introduces a repeatable regression harness for the iPhone 17 Simulator that launches the app (bypassing the 6.7 GB model-download gate via a new --ui-test-skip-download launch argument), then walks every reachable non-BLE screen: Welcome, Create Network, Tree Builder (add/rename/remove cycle), Join Network, Network Scan (empty state), PIN entry (via --ui-test-route=pin-entry host), Role Selection (seeded tree), and all four tabs (Main w/ PTT press, Tree, Data Flow w/ INCOMING/PROCESSING/ OUTGOING sections, Settings) with tab cycling. Adds accessibility identifiers on every key control and wraps container roots with accessibilityElement(children: .contain) so child identifiers propagate. Reference screenshots captured under TacNetTests/Screenshots/. All 119 unit tests plus 8 UI tests pass with 0 failures. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…mands Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…dance Based on feedback from simulator-ui-smoke-walkthrough-and-fix feature: - Recommend Ruby xcodeproj gem for adding new Xcode targets - Document SwiftUI accessibility-identifier container-vs-child propagation footgun requiring .accessibilityElement(children: .contain) before .accessibilityIdentifier Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…ession)
- BluetoothMeshService: wrap cactusComplete default + use { Date() } to
avoid non-Sendable function conversion warnings; switch AVAudioSession
option from deprecated .allowBluetooth to .allowBluetoothHFP.
- Cactus.swift: make metaPtrs / optStrCopy 'let' (never mutated); drop
unnecessary unsafeBitCasts in cactusIndexGet (base-address types
already match the C signature).
- ContentView.swift: migrate the two onChange(of:perform:) call sites
to the iOS 17+ two-parameter closure form.
Preserves all NSLog debug additions and touches no behavior. Full test
suite runs 119 unit + 8 UI tests with 0 failures; clean build produces
zero TacNet-source warnings (only allowlisted upstream cactus.framework
umbrella-header warnings remain).
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…ad-non-zip-integrity) Introduce ModelDownloadConfiguration.requiresZipArchive (default: true, matching production) plus ModelDownloadServiceError.invalidArchive. In production mode, a download that does not begin with PK\x03\x04 magic bytes is now rejected BEFORE being promoted to the sentinel path, so an HTTP error body (e.g. 19 bytes of "Access denied") can no longer falsely unlock canUseTacticalFeatures(). Tests override the flag via makeModelDownloadService(requiresZipArchive: false) so the existing mock fixture tests continue to work. Added two new XCTests: - testEnsureModelAvailableRejectsNonZipPayloadInProductionMode - testEnsureModelAvailableAcceptsNonZipPayloadInTestMode Results: 121 unit tests pass (119 + 2 new); 8 UI tests pass; 0 TacNet-source warnings. Existing NSLog debug lines preserved; new rejection path logs with the same [ModelDownload] prefix convention. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…rage Adds two new XCUITest cases: testBootstrapDownloadGateRendersAndGatingUIIsAccurate launches without --ui-test-skip-download using a new --ui-test-download-fixture=stuck fixture to hold the real downloadGate visible and asserts the gate container, title, progress bar, locked-features copy, hidden retry button, and no-crash for 10s. testSettingsTabShowsRoleAppropriateAffordances launches --ui-test-route=settings with --ui-test-role=organiser|participant against a new UITestSettingsHost that seeds a deterministic NetworkConfig and renders the real SettingsView, covering VAL-UI-011 for both role states (organiser sees editTree+promote+releaseRole; participant sees only releaseRole). Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
… xcode project work
…d error handling Includes PTT gesture fix, UI test hardening, README, and validation suite updates.
… TTS - Add ModelHandleProviding protocol and BundledModelInitializationService for loading models from the app bundle (Parakeet CTC 0.6B) - Switch CactusTranscriber from Gemma (.shared) to bundled Parakeet, decoupling STT from the 6.4 GB download gate - Create TextToSpeechService with AVSpeechSynthesizer backend, utterance queue, sender role prefix, and enable/disable support - Wire TTS into MainViewModel.handleIncomingMessage() to speak incoming broadcasts and compactions aloud - Stop TTS on PTT press to prevent mic feedback - Download and bundle Parakeet CTC 0.6B INT4 Apple weights (727 MB) - Add ParakeetCTC to Xcode bundle resources and TextToSpeechService to compile sources Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add weight file count verification in synchronizeCompletionState() to detect corrupt/truncated Gemma extractions and force re-download - Add diagnostic NSLog in CactusTranscriber.transcribePCM16kMono() to show which ModelHandleProvider is being used (BundledModel vs Download) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Log Parakeet bundle resource availability at CactusTranscriber init - Add fallback to Gemma if Parakeet model fails to load - Better diagnostic output to trace which model provider is active Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Verify no zero-byte weight files after zip extraction (catches truncated extraction from ZIP64 edge cases or iOS memory pressure) - Verify minimum weight file count (500+) after extraction - Block sentinel file creation if integrity check fails - Add same checks to synchronizeCompletionState for subsequent launches - If corruption detected, clean up and force re-download Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.