Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
e556884
Initial spec, decisions, and setup log for TacNet
yifu001 Apr 18, 2026
16ef5e4
Add mission infrastructure: worker skill, services, library, init script
yifu001 Apr 18, 2026
5d9068d
Set up TacNet iOS project with Cactus SDK integration
yifu001 Apr 18, 2026
de6b60f
Implement core TacNet foundation data models
yifu001 Apr 18, 2026
1e76ec9
Implement tree helpers and bounded message deduplicator
yifu001 Apr 18, 2026
25e8668
Fix services.yaml: use iPhone 17 simulator, remove tail pipes
yifu001 Apr 18, 2026
079f124
Implement BluetoothMeshService flooding and TTL logic
yifu001 Apr 18, 2026
99806da
Implement model download service with resumable progress and app gating
yifu001 Apr 18, 2026
15da392
Implement tree builder workflow and onboarding views
yifu001 Apr 18, 2026
99485de
Implement BLE network discovery and join tree sync
yifu001 Apr 18, 2026
54adce9
Implement role claiming protocol and selection UI
yifu001 Apr 18, 2026
08a76ae
Implement live tree updates and organiser promotion flow
yifu001 Apr 18, 2026
9a590ff
Implement PTT audio capture and transcript serialization
yifu001 Apr 18, 2026
248f180
Implement message routing filters and envelope construction
yifu001 Apr 18, 2026
86b625e
Implement compaction engine triggers and SITREP synthesis
yifu001 Apr 18, 2026
211d0e6
Implement main live-feed screen with routed transcript and compaction…
yifu001 Apr 18, 2026
10d44c3
Implement tab shell navigation and tree view status UI
yifu001 Apr 18, 2026
316812d
Implement data flow screen with realtime telemetry and tests
yifu001 Apr 18, 2026
d736896
Implement settings organiser controls and role actions
yifu001 Apr 18, 2026
e5bf416
Implement SwiftData transcript persistence and after-action review se…
yifu001 Apr 18, 2026
bd81495
Implement drag-and-drop tree editing with reorder persistence
yifu001 Apr 18, 2026
2d20096
Implement AES session-key exchange and encrypted message persistence
yifu001 Apr 18, 2026
037bfc4
Implement TreeSyncService auto-reparenting and routing update tests
yifu001 Apr 18, 2026
3b5686d
Implement priority escalation false-positive guards
yifu001 Apr 18, 2026
57a980c
Implement model download gate UI progress and enforcement tests
yifu001 Apr 18, 2026
6ef8ac5
Implement cross-area lifecycle wiring and end-to-end integration tests
yifu001 Apr 18, 2026
fc933ab
Add step-by-step manual testing guide for 53 device assertions
yifu001 Apr 18, 2026
84482d1
Add Linear project structure for team tracking
yifu001 Apr 18, 2026
0040ae0
Fix model download pipeline — resolves T01 Phase 1 (#23)
Apr 18, 2026
ab5a243
Mission setup: test-and-fix infrastructure for TacNet
Apr 18, 2026
4db4d47
Fix ModelDownloadService: handle non-zip payloads and surface interru…
Apr 18, 2026
736661a
Gate MainViewModel.startPushToTalk when mesh has no connected peers
Apr 18, 2026
265295d
Add TacNetUITests XCUITest target and Simulator smoke walkthrough
Apr 18, 2026
6aa16b8
Document TacNetUITests target and add test-ui / test-unit service com…
Apr 18, 2026
77707e2
Update ios-worker skill with xcodeproj gem + SwiftUI a11y pitfall gui…
Apr 18, 2026
104746e
Drive TacNet-source warnings to zero (warnings-cleanup-and-final-regr…
Apr 18, 2026
3f56c8a
Synthesize scrutiny validation for test-and-fix milestone
Apr 18, 2026
4a12e30
Reject non-zip download payloads in production mode (fix-model-downlo…
Apr 18, 2026
614df6d
Extend UI smoke suite with real bootstrap gate and settings role cove…
Apr 18, 2026
1711468
Synthesize scrutiny rerun for test-and-fix milestone
Apr 18, 2026
0a22d9c
Run user-testing validation for test-and-fix milestone
Apr 18, 2026
90d504f
added base bluetooth mesh, will probably need to update paths to make…
AryaaSk Apr 18, 2026
0419ab4
Enhance BluetoothMeshService and ContentView with detailed logging an…
Nalin-Atmakur Apr 18, 2026
3ffaca4
Add 3-stage communication pipeline: Parakeet STT, Gemma LLM, AVSpeech…
Nalin-Atmakur Apr 18, 2026
e026cd4
Add Gemma weight integrity check and STT diagnostic logging
Nalin-Atmakur Apr 19, 2026
45d8146
Add Parakeet bundle diagnostics and Gemma fallback for STT
Nalin-Atmakur Apr 19, 2026
f664515
Add post-extraction integrity checks to catch corrupt Gemma weights
Nalin-Atmakur Apr 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .factory/init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/bin/bash
set -e

# Resolve repo root dynamically (this script is invoked from the repo root by the mission runner)
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"

# Verify Xcode is available
if ! command -v xcodebuild &> /dev/null; then
echo "ERROR: xcodebuild not found. Ensure Xcode is installed."
exit 1
fi

# Verify Xcode developer tools are pointing to Xcode.app (not CommandLineTools)
XCODE_PATH=$(xcode-select -p)
if [[ "$XCODE_PATH" != *"Xcode.app"* ]]; then
echo "WARNING: xcode-select points to $XCODE_PATH, not Xcode.app"
echo "Run: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer"
fi

# Verify Cactus XCFramework is present inside the repo
CACTUS_XCFRAMEWORK="$REPO_ROOT/Frameworks/cactus-ios.xcframework"
if [ ! -d "$CACTUS_XCFRAMEWORK" ]; then
echo "WARNING: Cactus XCFramework not found at $CACTUS_XCFRAMEWORK"
echo "This project requires the XCFramework to be vendored under Frameworks/."
fi

# Verify iPhone 17 simulator runtime is available
if ! xcrun simctl list devices available 2>/dev/null | grep -q 'iPhone 17'; then
echo "WARNING: iPhone 17 simulator not found in available devices."
echo "List available devices with: xcrun simctl list devices available"
fi

echo "Init complete. Repo root: $REPO_ROOT"
54 changes: 54 additions & 0 deletions .factory/library/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# TacNet Architecture

## Overview

TacNet is a native iOS app (Swift/SwiftUI) that creates decentralized tactical communication networks over BLE mesh. Phones are organized in a command tree. Leaf nodes push-to-talk, parent nodes run on-device AI (Gemma 4 E4B via Cactus) to compress child messages into summaries that propagate upward.

## Component Relationships

```
Views (SwiftUI) ViewModels (ObservableObject) Services (Actors/Classes)
───────────── ────────────────────────── ───────────────────────
MainView ←──→ MainViewModel ←──→ AudioService
TreeView ←──→ TreeViewModel ←──→ BluetoothMeshService
DataFlowView ←──→ DataFlowViewModel ←──→ CompactionEngine
SettingsView ←──→ OnboardingViewModel ←──→ MessageRouter
TreeBuilderView ←──→ TreeBuilderViewModel ←──→ RoleClaimService
RoleSelectionView ←──→ RoleSelectionViewModel ←──→ TreeSyncService
NetworkScanView ←──→ NetworkDiscoveryService
PinEntryView ←──→ ModelDownloadService
```

## Data Flow

1. **PTT → Transcript**: AudioService records PCM → CompactionEngine calls cactusTranscribe → transcript text
2. **Transcript → Broadcast**: MessageRouter wraps transcript in Message envelope → BluetoothMeshService floods to mesh
3. **Receive → Route**: BluetoothMeshService receives message → MessageDeduplicator checks UUID → MessageRouter decides: display? queue for compaction? ignore?
4. **Compaction**: CompactionEngine collects child transcripts → triggers on count/time/priority → calls cactusComplete → emits COMPACTION message upward
5. **Persistence**: All received messages → SwiftData store for after-action review

## Key Invariants

- Audio is NEVER transmitted over BLE. Only text (transcripts and summaries) crosses the mesh.
- Every phone runs both CBCentralManager and CBPeripheralManager simultaneously.
- All messages flood the entire mesh. App-layer filtering (MessageRouter) decides what to show based on tree position.
- BROADCAST: visible to sender's siblings + sender's parent only.
- COMPACTION: visible to sender's parent only.
- Tree version is monotonically increasing. Higher version replaces local state.
- Organiser-wins on claim conflicts.
- 60s BLE disconnect timeout triggers auto-release and auto-reparent.

## Model Architecture

- Single model: Gemma 4 E4B (4.5B params, INT4, ~2.8GB VRAM) on all devices
- Two-step pipeline: (1) cactusTranscribe for STT, (2) cactusComplete for compaction
- Model weights: 6.7GB, downloaded on first launch via ModelDownloadService
- Cactus SDK: XCFramework + Cactus.swift (free functions wrapping C FFI)

## Concurrency Model

- Swift Concurrency: async/await and actors
- AudioService: manages AVAudioEngine on a dedicated actor
- CompactionEngine: actor that queues messages and runs inference
- BluetoothMeshService: manages CBCentralManager/CBPeripheralManager (must be on main actor for CoreBluetooth)
- UI: @MainActor via SwiftUI
104 changes: 104 additions & 0 deletions .factory/library/cactus-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Cactus SDK Swift API Reference

## Integration

- XCFramework at: `/Users/yifuzuo/Desktop/yifu/startup/projects/hackathon/cactus/apple/cactus-ios.xcframework`
- Swift API file: `/Users/yifuzuo/Desktop/yifu/startup/projects/hackathon/cactus/apple/Cactus.swift`
- Module map: `import cactus` (via module.modulemap in the XCFramework)

## Types

```swift
public typealias CactusModelT = UnsafeMutableRawPointer
public typealias CactusStreamTranscribeT = UnsafeMutableRawPointer
```

## Lifecycle

```swift
// Init model - modelPath points to weight directory
let model = try cactusInit("/path/to/weights", nil, false)
// Parameters: modelPath: String, corpusDir: String?, cacheIndex: Bool

// Destroy model
cactusDestroy(model)

// Reset context
cactusReset(model)

// Stop current inference
cactusStop(model)
```

## Text Completion (for compaction/summarization)

```swift
let messages = #"[{"role":"system","content":"You are a tactical summarizer..."},{"role":"user","content":"Summarize: ..."}]"#
let options = #"{"max_tokens":100,"temperature":0.0}"#

// Non-streaming
let resultJson = try cactusComplete(model, messages, options, nil, nil)

// Streaming
let resultJson = try cactusComplete(model, messages, options, nil) { token, tokenId in
print(token, terminator: "")
}

// With audio input (PCM data)
let pcmData: Data = ... // 16kHz mono 16-bit PCM
let resultJson = try cactusComplete(model, messages, options, nil, nil, pcmData)
```

Response JSON: `{"success":true, "response":"...", "time_to_first_token_ms":..., "decode_tps":...}`

## Transcription (STT)

```swift
// From file
let resultJson = try cactusTranscribe(model, "/path/to/audio.wav", nil, nil, nil, nil)

// From PCM buffer (16kHz mono 16-bit)
let pcmData: Data = ...
let resultJson = try cactusTranscribe(model, nil, nil, nil, nil, pcmData)

// With token callback
let resultJson = try cactusTranscribe(model, nil, nil, nil, { token, tokenId in
print(token, terminator: "")
}, pcmData)
```

## Streaming Transcription (real-time)

```swift
let stream = try cactusStreamTranscribeStart(model, nil)
let partialJson = try cactusStreamTranscribeProcess(stream, audioChunkData)
let finalJson = try cactusStreamTranscribeStop(stream)
```

## Key Options

```json
{
"max_tokens": 100,
"temperature": 0.0,
"top_p": 0.95,
"min_p": 0.15,
"repetition_penalty": 1.1,
"stop_sequences": ["\n"],
"custom_vocabulary": ["tactical", "medevac", "extraction"]
}
```

## Audio Format

All audio input must be: **16-bit signed integer PCM, 16000 Hz sample rate, mono (single channel)**.

## Error Handling

All functions throw `NSError(domain: "cactus", code: -1)` on failure. Use `cactusGetLastError()` for detailed error description.

## Model Weights

- Path: `/opt/homebrew/opt/cactus/libexec/weights/gemma-4-e4b-it/`
- Size: 6.7 GB (INT4 quantized)
- For app: download from Cactus-Compute HuggingFace on first launch
39 changes: 39 additions & 0 deletions .factory/library/environment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Environment

## Development Machine

- macOS (darwin 25.4.0), Apple Silicon
- Xcode 26.4 at `/Applications/Xcode.app`
- Swift 5.9+
- `xcode-select -p` should point to Xcode.app (not CommandLineTools)

## Repo Root

This project's canonical path is the current git repo root (resolved dynamically by `.factory/init.sh`). Do NOT hardcode absolute user paths in any script or config — use relative paths or resolve from `$(git rev-parse --show-toplevel)`.

## Cactus SDK

- XCFramework (vendored): `Frameworks/cactus-ios.xcframework` — binary artifact. Do NOT modify.
- Swift API reference: `.factory/library/cactus-api.md`
- Real model weights (dev-only, not required for Simulator mission): installed via Homebrew at `/opt/homebrew/opt/cactus/libexec/weights/gemma-4-e4b-it/` (6.7GB INT4). Tests use mocks; the Simulator does not need real weights.

## Test Devices

- **For this mission:** iPhone 17 Simulator on iOS 26.4 (or latest available). Single device only.
- **Future (out of scope):** 4+ physical iPhones with iOS 16+ for BLE mesh, real Cactus inference, real mic, and multi-phone flows. See `MANUAL_TESTING.md`.

## Simulator Lifecycle Commands

```bash
xcrun simctl boot 'iPhone 17'
xcrun simctl install 'iPhone 17' <path-to-TacNet.app>
xcrun simctl launch 'iPhone 17' com.tacnet.app
xcrun simctl io booted screenshot /tmp/step.png
xcrun simctl terminate 'iPhone 17' com.tacnet.app
xcrun simctl shutdown 'iPhone 17'
```

## Git

- Remote: https://github.com/Nalin-Atmakur/YC-hack (main branch)
- **Do NOT push** unless the orchestrator explicitly instructs. Commit locally only.
67 changes: 67 additions & 0 deletions .factory/library/ui-tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# TacNetUITests target

The TacNetUITests target hosts XCUITest-driven smoke walkthrough of every
reachable non-BLE screen. It is wired into the shared `TacNet` scheme's
TestAction so `xcodebuild test -only-testing:TacNetUITests` runs it directly.

## Launch arguments consumed by the app

`TacNet/Views/ContentView.swift` defines a small `UITestMode` helper that reads
process launch arguments:

- `--ui-test-skip-download` — short-circuits `AppBootstrapViewModel` so the
model-download gate unlocks immediately and the app navigates to the Welcome
screen without attempting the 6.7 GB model download. Required for almost
every UI test.
- `--ui-test-route=pin-entry` — replaces the root view with the dedicated
`UITestPinEntryHost`, presenting the real `PinEntryView` against a seeded
`DiscoveredNetwork`. Used by the PIN entry test because PIN entry is
otherwise unreachable in Simulator (no BLE → no discovered networks).
- `--ui-test-route=settings` — replaces the root view with `UITestSettingsHost`
so UI tests can assert role-gated Settings affordances without running full
onboarding/network flows.
- `--ui-test-download-fixture=<name>` — deterministic bootstrap fixtures:
- `stuck`: keeps the download gate visible at 0% with no error.
- `failfast`: unlocks immediately (similar effect to skip-download).
- `--ui-test-role=organiser|participant` — seeds role state for
`--ui-test-route=settings` so tests can verify organiser-only vs participant
controls.

Both flags are inert when not supplied, so production launches are unaffected.

## Key conventions

- Container views that have child accessibility identifiers (buttons,
text fields) must use `.accessibilityElement(children: .contain)` **before**
`.accessibilityIdentifier(...)`. Without `.contain`, SwiftUI propagates the
container's identifier to every child and overrides their individual
identifiers. The old `tacnet.*.root` identifiers on TabShell, TreeView,
DataFlowView, SettingsView, etc. have all been migrated to this pattern.
- Tab-root identifiers (`tacnet.tree.root`, `tacnet.dataflow.root`,
`tacnet.settings.root`, `tacnet.main.root`) can show up as any XCUIElement
type depending on SwiftUI layout. Tests resolve them via
`app.descendants(matching: .any).matching(identifier: ...).firstMatch` (see
the `anyElement(_:identifier:)` helper in `TacNetUITests.swift`).
- The PTT control uses `.accessibilityElement(children: .combine)` to surface
as a single static-text element named `tacnet.main.pttControl`.
- Reference screenshots live in `TacNetTests/Screenshots/` at the repo root
(organiser walkthrough, welcome screen, PIN entry host). They are reference
artifacts captured via `xcrun simctl io booted screenshot`, not asserted
against in tests.

## Running

```bash
# Full test suite (unit + UI)
xcodebuild test -project TacNet.xcodeproj -scheme TacNet \
-destination 'platform=iOS Simulator,name=iPhone 17,OS=latest'

# UI tests only
xcodebuild test -project TacNet.xcodeproj -scheme TacNet \
-destination 'platform=iOS Simulator,name=iPhone 17,OS=latest' \
-only-testing:TacNetUITests
```

The UI tests expect the `iPhone 17` Simulator to be available (UDID visible
in `xcrun simctl list devices available`). Pin appearance to light for stable
screenshots with `xcrun simctl ui 'iPhone 17' appearance light`.
54 changes: 54 additions & 0 deletions .factory/library/user-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# User Testing

## Validation Surface

**Primary surface for this mission:** iOS Simulator (iPhone 17, iOS 26.4 / latest).

The TacNet product is ultimately a native iOS app designed for multi-phone BLE operation, but this mission validates **only the single-device automation surface** — Simulator-runnable behavior. Multi-phone, BLE, real Cactus inference, and real mic flows are out of scope and documented in `MANUAL_TESTING.md` for future manual verification with 4 physical iPhones.

## Testing Tools

- **`xcodebuild test`** — XCTest unit/integration tests (existing suite in `TacNetTests/TacNetTests.swift`, 119 tests). Covers all pure logic: models, routing, compaction triggers, tree helpers, dedup, version convergence, role claim protocol, download state machine (mocked client), PTT state transitions (mocked mesh).
- For this project, default scheme test execution may prioritize UI test-plan entries; to reliably validate unit assertions use explicit selectors: `-only-testing:TacNetTests` (and combine with `-only-testing:TacNetUITests` for full-sweep evidence).
- **`xcodebuild test` + XCUITest** — New `TacNetUITests` target (added by Feature 3 of the current mission) drives the simulator UI walkthrough. Used for VAL-UI-* assertions.
- **`xcrun simctl`** — Simulator lifecycle (boot, install, launch, screenshot, terminate, shutdown) and console streaming (`launch --console-pty`).
- **Screenshots** — Capture via `xcrun simctl io booted screenshot <path>.png` for evidence. Stored under `TacNetTests/Screenshots/` when committed as part of regression evidence.

## Validation Concurrency

Single `xcodebuild` invocation at a time. No parallelization of validators for this mission.

**Max concurrent validators: 1.** Rationale: one Simulator instance; `xcodebuild test` already parallelizes internally across test classes; resource headroom does not benefit from running multiple xcodebuild processes simultaneously.

## Console Red-Flag Grep Strings

During any smoke walkthrough, the console stream (captured via `xcrun simctl launch --console-pty 'iPhone 17' com.tacnet.app`) MUST NOT contain:

- `Fatal error:`
- `Thread 1: EXC_`
- `SIGABRT`
- `Modifying state during view update`
- `AttributeGraph: cycle detected`
- `Unhandled error`

Occurrences of any of these strings fail VAL-UI-013.

## Known Limitations (Documented, Not Bugs)

- **Simulator has no Bluetooth.** All BLE-dependent flows rely on mocked `BluetoothMeshTransporting` in unit tests. Simulator smoke walkthrough cannot exercise real BLE.
- **Cactus inference requires real weights (6.7 GB).** Tests mock `CactusClient`. Simulator smoke does NOT require real inference.
- **`AVAudioEngine` may be unreliable in Simulator.** Tests mock `AudioService`. Smoke tests do not exercise real mic capture.
- **GPS in Simulator is simulated** — can be controlled via `xcrun simctl location` if needed, but this mission does not exercise GPS end-to-end.

## Physical-Device-Only Assertions (Out of Scope This Mission)

Listed in `MANUAL_TESTING.md` — 53 manual assertions covering BLE mesh, real Cactus, real mic, multi-phone flows. They remain the definition of "fully working on hardware" and must be run on 4 physical iPhones before any production release. They are NOT part of this mission's `validation-contract.md`.

## Flow Validator Guidance: iOS Simulator

- Use only `iPhone 17` Simulator (`platform=iOS Simulator,name=iPhone 17,OS=latest`).
- Stay inside repo root `/Users/lucaspfingstenplanells/Desktop/YC-hack`; do not write outside `.factory/validation/<milestone>/user-testing/` and mission evidence directories.
- Respect single-run isolation: no parallel `xcodebuild` processes and no shared mutable simulator state across simultaneous validators.
- If your flow depends on simulator state, boot/clean/reset only within your own sequence and leave the simulator shut down when done.
- Keep evidence paths scoped to your assigned group id under `{missionDir}/evidence/<milestone>/<group-id>/`.
- Do not modify product logic for validation convenience; if environment/setup blocks testing, report blocker with concrete command output.
10 changes: 10 additions & 0 deletions .factory/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
commands:
build: xcodebuild build -project TacNet.xcodeproj -scheme TacNet -destination 'platform=iOS Simulator,name=iPhone 17,OS=latest'
clean-build: xcodebuild clean build -project TacNet.xcodeproj -scheme TacNet -destination 'platform=iOS Simulator,name=iPhone 17,OS=latest'
test: xcodebuild test -project TacNet.xcodeproj -scheme TacNet -destination 'platform=iOS Simulator,name=iPhone 17,OS=latest'
test-ui: xcodebuild test -project TacNet.xcodeproj -scheme TacNet -destination 'platform=iOS Simulator,name=iPhone 17,OS=latest' -only-testing:TacNetUITests
test-unit: xcodebuild test -project TacNet.xcodeproj -scheme TacNet -destination 'platform=iOS Simulator,name=iPhone 17,OS=latest' -only-testing:TacNetTests
clean: xcodebuild clean -project TacNet.xcodeproj -scheme TacNet
warnings-only: xcodebuild clean build -project TacNet.xcodeproj -scheme TacNet -destination 'platform=iOS Simulator,name=iPhone 17,OS=latest' 2>&1 | grep ': warning:' | grep -v 'cactus.framework'

services: {}
Loading