> ## Documentation Index
> Fetch the complete documentation index at: https://docs.synheart.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing without hardware

> Mock wearable streams, a local Synheart cloud, deterministic recordings, and CI patterns.

You don't need a real watch, a real platform account, or a real network connection to develop and test Synheart integrations. The CLI ships three building blocks that cover almost every test scenario:

* **`synheart mock`** — emits a vendor-shaped biosignal stream to your SDK.
* **`synheart local`** — runs a local mirror of the consent + ingest cloud endpoints.
* **`synheart sync --check`** — pins exact runtime / spec versions across machines and CI.

Pick the smallest combination that unblocks your test. You rarely need all three.

## Mock wearable streams

`synheart mock` produces deterministic vendor-shaped streams that your SDK consumes as if they came from a real device. Useful for unit tests, UI demos, and reproducing user reports.

```bash theme={null}
synheart mock start                                    # default: whoop / baseline scenario
synheart mock start --vendor garmin --scenario workout
synheart mock start --rate 100hz --duration 5m
synheart mock start --seed 42                          # deterministic output for tests
```

Default endpoints — listen with whichever transport your SDK uses:

* WebSocket: `ws://127.0.0.1:8787`
* SSE: `http://127.0.0.1:8788/events`
* UDP: `127.0.0.1:8789`

All three carry the same payload, so your tests don't have to know which is configured.

### Deterministic record + replay

For regression tests, capture a mock stream once and replay it on every run:

```bash theme={null}
synheart mock record --vendor whoop --duration 15m --out fixtures/session.ndjson
synheart mock replay --in fixtures/session.ndjson --speed 2.0 --loop
```

Commit the `.ndjson` file alongside your tests. Replay accepts the same transport flags as `start`, so the SDK code under test doesn't change.

### Choosing a scenario

A scenario is a named time-series profile (`baseline`, `workout`, `recovery_high`, `stress_event`, …). List and inspect them:

```bash theme={null}
synheart mock list-scenarios                # all vendors
synheart mock list-scenarios --vendor whoop
synheart mock describe baseline             # signal envelope + expected event mix
```

Pick the scenario whose envelope matches the path you're testing — `stress_event` for high-arousal HSI states, `recovery_high` for low-strain outputs, etc.

## Local platform server

`synheart local` mirrors the cloud's consent + ingest endpoints on `127.0.0.1`. Use it when you need the full cloud flow — uploads, consent tokens, JWT validation — without burning real platform quota or needing network.

```bash theme={null}
synheart local                                              # plain HTTP on :8083
synheart local --port 9000 --api-key my-key                 # custom credentials
synheart local --https                                      # TLS + /etc/hosts entry
synheart local --https --domain api.synheart.example
synheart local --web --web-port 8090                        # status dashboard
synheart local cleanup --remove-certs                       # reverse the OS changes
```

In your app config, point the SDK at the local server's base URL the same way you'd point it at production. The endpoint shapes and auth contract are identical.

The `--https` mode generates a local CA, trusts it in the OS keychain, and adds a `127.0.0.1 <domain>` entry to `/etc/hosts` — so your SDK hits `https://api.synheart.example` exactly as it would the production host. Run `synheart local cleanup --remove-certs` when you're done to reverse those OS changes.

The `--web` flag runs a small status dashboard on a separate port showing connected SDK clients, queued ingests, and recent consent grants. Useful for debugging "did my upload arrive?" questions.

## Combining the two

The common end-to-end shape:

```bash theme={null}
synheart mock start &        # 1. fake biosignals into your SDK
synheart local --web &       # 2. fake cloud accepting uploads
# 3. run your app or test suite pointed at both
```

Your app sees a vendor-shaped stream coming in and a working cloud accepting HSI uploads, with no real device or network involved.

## CI / CD patterns

For deterministic builds, install the runtime once locally, commit the lockfile, then `sync` in CI:

```yaml theme={null}
# .github/workflows/build.yml
- run: curl -fsSL https://synheart.sh/install | sh
- run: synheart login --token ${{ secrets.SYNHEART_CI_TOKEN }}
- run: synheart sync --check       # fails the build if synheart.lock would change
- run: flutter build apk
```

Use `synheart login --token` (non-interactive) with a CI service-account token. Tokens are scoped per project and per environment; rotate them via the platform dashboard.

`synheart sync --check` is the most important line: it fails the build if your committed `synheart.lock` no longer matches what `sync` would resolve to. That catches silent runtime drift on PRs before it ships.

### Running mock + local in CI

For integration tests that exercise the full SDK path:

```yaml theme={null}
- run: synheart mock start --seed 42 --duration 10m &
- run: synheart local --port 8083 &
- run: ./run-integration-tests.sh
```

Use `--seed` so test runs are reproducible across machines.

## When you do need real hardware

A few things only a real device can validate:

* BLE pairing and reconnection edge cases (mocks don't simulate radio).
* HealthKit / Health Connect permission prompts as the user sees them.
* Watch ↔ phone session handoff timing and battery impact.
* Vendor-specific OAuth flows end-to-end (mock simulates the data, not the OAuth dance).

Everything else — signal processing, HSI envelope shape, consent gating, capability gating, error paths — is testable without hardware.

## Where to go next

<CardGroup cols={2}>
  <Card title="Synheart CLI reference" icon="terminal" href="/synheart-cli">
    Full reference for `mock`, `local`, `sync`, and related commands.
  </Card>

  <Card title="Quickstart" icon="rocket" href="/quickstart">
    The shortest path from zero to a running integration.
  </Card>
</CardGroup>
