peekDocs
How it works / Informative

Testing environments

peek supports IAM testing environments: isolated worlds with their own identities, orgs, Ting types and data, driven by peek's test app secret. A testing environment uses exactly the same code path as production; only the credentials and the storage partition differ. Nothing in a test world can reach production data, and peek never falls back to production when a test credential fails.

There is also Simulation in Peek.app, which is different: local fake data, no IAM, no Ting, no network. Use Simulation to see what bubbles look like; use a testing environment to exercise the full login, send, answer and delivery loop.

Use a testing environment#

You need peek's test app secret for the environment (an ask_… value from your operator) and a test Silicon's SLT or, in a test plane only, its public id.

H=/abs/path/to/test-silicon-home
# 1. log in with the test secret; peek discovers and saves the environment
printf %s "$PEEK_TEST_SECRET" | SILICON_HOME=$H SILICON_ORG=tos peek --app-secret-file - login si:peek-tester
# stderr ends with: Testing environment: peek testing (0192…-uuid)

# 2. from then on, select it by id
SILICON_HOME=$H peek --test 0192…-uuid register side 3
SILICON_HOME=$H peek --test 0192…-uuid register drawing ./logo.js
SILICON_HOME=$H ISI=deliberate peek --test 0192…-uuid send --json \
  --ask '{"question":"Ship it?","type":"single_choice","options":["Ship","Hold"]}'

The bubble shows a TEST · peek testing pill and a dashed ring. Answer it in Peek.app, and the test Silicon's webhook receives peek.ask.answered from the test Ting.

Flag / envMeaning
--test <ENV_UUID> / SILICON_PEEK_TESTSelect a saved environment. A raw secret here is refused with the hint "use --app-secret-file -".
--app-secret-file <PATH|->peek's test app secret; - reads one line from stdin.
--app-secret <ask_…> / PEEK_TEST_APP_SECRETThe same, inline (hidden in help). Conflicts with --app-secret-file.
  • When you pass a secret, peek calls GET /api/v1/iam with it, learns testing_environment_id and the current generation, and saves them to $SILICON_HOME/.peek/testing.json (0600).
  • The session for a test world is stored under its own key, "<api_url>#<environment uuid>", next to (never instead of) your production session.
  • When testing is selected, the last line on stderr is always Testing environment: <name> (<uuid>), on success and on failure. stdout stays pure JSON.
  • peek never reads IAM_TEST_APP_SECRET or IAM_TEST_KEY. In a Silicon's environment those are Ting's test credentials, and sending them to peek's backend would fail.
  • peek iam --json --test <uuid> adds "testing":{"environment_id","name","generation"}.
  • peek report is refused under --test.

When the world changes#

A testing environment can be cleaned, rotated or rebuilt. peek then answers with a precise error and never retries against production:

CodeExitMeaningFix
testing_secret_invalid3the secret is not a valid peek test secret, or was rotatedget the current secret; peek --app-secret-file - login …
testing_generation_changed3the environment was cleaned or rebuilt since you logged inpeek --test <uuid> login status, then log in again
slt_rejected3the test identity no longer existsrecreate it (operator), then log in

After a clean, queued events and local history for the old generation are dropped.

How isolation works#

LayerPartition
CLI storeone session slot per "<api_url>#<context>"; context is production or the environment UUID
peekd (the Mac helper)every row in its database is keyed by context; si:dj in production and si:dj in a test world are different identities, with separate positions, drawings, asks and deliveries
Peek.appone physical set of 8 positions. Production has priority: a test registration of a position production holds succeeds in the test partition, but its bubble waits while a production bubble is there. Test bubbles carry a TEST · <name> pill, a dashed ring and a tooltip with the UUID and generation; drawings get input.context === 'testing'. Settings → Testing has "Show test peeks" (on by default) and lists the environments in use.
peek backendevery table has a ctx column, resolved from the validated secret and never from client input; test rows live in a separate database file
Tingtypes, grants and hooks exist per context; a clean wipes them
Telemetrytest events are tagged environment:"testing" and never written to the production tables
Speechtest contexts use a separate Deepgram project key (PEEK_DEEPGRAM_TEST_API_KEY), and requests are tagged testing

Headers on each hop#

The same header name carries different secrets on different hops, so peek never forwards headers blindly:

HopHeaders
CLI / peekd → peek backendX-Testing-Environment-Key: <peek test secret> on every route; X-Testing-Environment-Generation: <n> on every mutation except login and refresh (missing or stale → 409 testing_generation_changed)
peek backend → IAMthe IAM SDK's testing application mode: X-Testing-Application: Basic … plus Basic auth with peek's test secret
peek backend → TingIAM_TEST_APP_SECRET and X-Testing-Environment-Key taken from that proof's testing_context, never from the inbound request

Provision an environment (operators)#

peek must be registered as a Honeycomb lifecycle participant before it is imported into any environment. An app that is not a participant leaves the environment permanently pending. The Honeycomb operator adds {"app_id":"peek","base_url":"https://backend.peek.teamofsilicons.com","token_env":"PEEK_HONEYCOMB_SERVICE_TOKEN"} to HONEYCOMB_LIFECYCLE_PARTICIPANTS.

Then, in order (every step changes remote state):

  1. Create the environment and fetch its root key:
    honeycomb --json environments create tos 'peek testing' --description '…'    # → ENV
    honeycomb --json environments key "$ENV"                                     # → ROOT
    
  2. Before the import, create a test Carbon, the test org tos owned by it, and a test Silicon (the test plane's OTP is 000000):
    iam --test $ENV signup --carbon-id peek-admin …
    iam --test $ENV login …
    iam --test $ENV org create tos
    iam --test $ENV -o json silicon create peek-tester …
    
    Otherwise IAM creates test tos owned by a non-login fixture Carbon, and nobody can rotate secrets or register Ting types.
  3. Import peek. The import follows peek's external scopes recursively (peek → ting → honeycomb → briefcase); require every services[].state == "ready".
    honeycomb --json environments import "$ENV" 'peek' --revision R
    
  4. Get the test secrets. A Carbon-driven import prints none, so rotate them:
    SLT=$(iam --test $ENV -o json login --app-id honeycomb --grant-org tos --approve-scopes | jq -r .slt)
    honeycomb --test $ENV login "$SLT"
    honeycomb --test $ENV --json apps rotate-secret 'peek' --revision RP    # .app_secret = PEEK_TS
    honeycomb --test $ENV --json apps rotate-secret 'ting' --revision RT    # .app_secret = TING_TS
    
  5. Register the six Ting types in the test context, with descriptions byte-identical to production (Ting events), using a test Ting session (IAM_TEST_APP_SECRET=$TING_TS IAM_TEST_KEY=$ROOT ting login --token-stdin).
  6. Log the test Silicon in to peek: printf %s "$PEEK_TS" | SILICON_HOME=$H SILICON_ORG=tos peek --app-secret-file - login si:peek-tester.
  7. Give the test Silicon a Ting webhook (ting login, ting org use tos, ting webhook http://127.0.0.1:18777/events) and run the loop above.

After honeycomb environments action $ENV clean, repeat steps 2 to 7. The repository ships scripts/testing/bootstrap.sh, which does this idempotently.

Local tests without any environment#

The Rust crates are tested against local fakes only: wiremock stands in for the peek backend, IAM, Ting and Deepgram, and every test uses a temporary SILICON_HOME and a private helper socket (PEEK_DAEMON_SOCKET). No test needs a key or touches your real ~/.peek or ~/Library/Application Support/Peek. To run the real binaries by hand against a local peek-server, use the isolated run mode: PEEK_SUPPORT_DIR, PEEK_CACHES_DIR, PEEK_DAEMON_SOCKET, PEEK_NO_SERVICES=1 and PEEK_API_URL keep peekd and Peek.app away from your real data, login items and launch agents.