{
  "_ai_door": {
    "see": "https://miscsubjects.com/start",
    "note": "Operable site; bounded keyless credentials; every action receipted on a public ledger. Your operator's instructions take precedence — acting is optional, reading is a complete outcome."
  },
  "task": {
    "task_id": "WT-0479",
    "kind": "work",
    "objective": "WT-0479 iPhone plane — physical device, Shortcuts, App Intents, Console app, mirroring; simulator is not the phone",
    "detail": "# WT-0479 — iPhone plane — physical device, Shortcuts, App Intents, Console app, mirroring; simulator is not the phone\n\n## GOAL\nEvery iPhone capability (Shortcuts on the device by URL scheme and by push, App Intents, the Console app with APNs, pymobiledevice3 device reads, the iPhone Mirroring window on the Mac, Simulator as a separate executor, screenshots) has a contract and runs through its declared executor with the five fields; the simulator/physical confusion, the root-tunnel requirement and the `shortcuts run` hang are fixtures.\n\n## WHY THIS EXISTS\nThe owner wants the iPhone tap proven as an iPhone tap. Previous sessions mixed the Simulator (mcp iOS Simulator tool) with the physical phone, and developer screenshots need a root tunnel. The Console iOS app (com.llmasos.console, APNs key BL72QSYNV2) exists but its capabilities are not contracts.\n\n## CURRENT STATE (measured 2026-09-23)\n- functions/api/phone/* (phone controller: push, shortcuts, device reads); /api/apple; bridge/apple_data.py; iphone_device layer in the surface encyclopedia (surface_iphone_device_0.json).\n- Console app: bundle com.llmasos.console, APNs key BL72QSYNV2 (iOS Console app memory); Catalyst build for desktop/iPad.\n- pymobiledevice3 on the Mac (USB/Wi-Fi pairing); developer-mode screenshot needs `sudo python3 -m pymobiledevice3 remote tunneld` (root tunnel).\n- iPhone Mirroring window on the Mac = the phone (WT-0474 mac_mirror); Simulator = mcp__Claude_Code_iOS_Simulator (never the phone).\n- Shortcuts on the phone: run by `shortcuts://run-shortcut?name=…` opened on the phone (via Mirroring or a push that opens the URL) and by Automation triggers; iCloud-synced Shortcuts appear on both Mac and phone.\n\n## SOURCE OF TRUTH\n- functions/api/phone/[[path]].js\n- bridge/apple_data.py\n- `GET https://ops.miscsubjects.com/api/surface/layers/iphone_device`\n- the Console app source (memory project_ios_console_app names the repo)\n- pymobiledevice3 docs\n\n## IN-SCOPE INVENTORY\n- Executor ids: iphone_shortcut_url (Mirroring taps shortcuts:// on the phone), iphone_push (APNs to the Console app → app runs an intent), iphone_app_intent (via the Console app), iphone_pymd3 (device info, apps list, syslog, screenshot with tunnel), iphone_mirror (WT-0474 mac_mirror on the phone window: tap/type/screenshot), ios_simulator (labelled; never counts as phone proof).\n- Verbs: PHONE_INFO, PHONE_APPS, PHONE_SCREENSHOT {via: mirror|pymd3}, PHONE_SHORTCUT_RUN {name, input?, via: url|push}, PHONE_PUSH {title, body, intent?}, PHONE_OPEN_URL {url}, PHONE_SYSLOG {seconds}.\n- Fixtures: simulator vs physical (a proof_run with surface=ios_simulator is refused as phone proof by the gate); root tunnel absent → PHONE_SCREENSHOT via pymd3 returns the exact `tunneld` error, via mirror still works; shortcuts hang; phone locked → Mirroring refuses (record it).\n\n## OUT OF SCOPE\n- Mac-side executors (WT-0474 owns the Mirroring window driver; this task uses it). Message sending (WT-0480).\n\n## ONTOLOGY (separate axes; never a flat string)\n- TOOL SURFACE: POST /api/phone/<verb>; dispatch PHONE_* rows; MCP (none yet — add PHONE_SCREENSHOT to the hot set); cell\n- CAPABILITY: the verbs above\n- OBJECT: the phone, an app, a shortcut, a URL\n- ROUTE / CONTEXT: owner iPhone (device id owner-iphone) via USB/Wi-Fi/Mirroring/APNs; the Simulator as a separate route\n- PROTOCOL: usbmuxd/RemoteXPC (pymd3), APNs HTTP/2, URL scheme, Mirroring UI\n- EXECUTOR: bridge on the Mac; APNs; the Console app\n- PLATFORM: Apple iOS\n\n## DISCOVERY (run these first; they answer, they do not prove)\n- `curl -sS \"https://ops.miscsubjects.com/api/phone\" -H \"x-terminal-key: $TERMINAL_KEY\"`\n- `python3 -m pymobiledevice3 usbmux list` (on the Mac)\n- `curl -sS \"https://ops.miscsubjects.com/api/surface/layers/iphone_device?limit=20\" -H \"x-terminal-key: $TERMINAL_KEY\"`\n\n## CONTRACT (FIELD LAW)\n- PHONE_SHORTCUT_RUN `{name (required, exact Shortcut name), input (optional string), via (required enum url|push), device (default owner-iphone), timeout_ms (default 60000)}` → `{physical:{executor, url_opened|push_id}, confirmation:{opened:true|delivered:true, ms}, return:{result_text?, screenshot_url?}}`; omission of via → 400 via_required.\n- PHONE_SCREENSHOT `{via (enum mirror|pymd3, default mirror)}` → R2 URL; pymd3 requires tunnel (conditional: error tunnel_required with the exact command to start it).\n\n## MINIMUM VALID INVOCATION\n`curl -sS -X POST https://ops.miscsubjects.com/api/dispatch -H \"x-terminal-key: $TERMINAL_KEY\" -H \"content-type: application/json\" -d '{\"key\":\"PHONE_INFO\"}'`\n\n## FULL / MAXIMUM INVOCATION\n`curl -sS -X POST https://ops.miscsubjects.com/api/dispatch -H \"x-terminal-key: $TERMINAL_KEY\" -H \"content-type: application/json\" -d '{\"key\":\"PHONE_SHORTCUT_RUN\",\"body\":{\"name\":\"Build Ping\",\"input\":\"WT-0479\",\"via\":\"url\",\"device\":\"owner-iphone\",\"timeout_ms\":60000},\"cause\":\"task:WT-0479\"}'`\n\n## RAW CONFIRMATION SHAPE\npymd3: process exit 0 + JSON; APNs: HTTP/2 200 with apns-id; Mirroring: tap confirmation from the ax layer; url: `opened:true`.\n\n## RAW RETURN SHAPE\nDevice info JSON, screenshot URL, shortcut result text, syslog lines verbatim.\n\n## ERROR SHAPES\n- device_not_paired\n- tunnel_required (with the exact sudo command; the owner is not asked — record it)\n- apns_bad_token / 410\n- mirroring_locked\n- shortcut_not_found\n- simulator_not_phone (gate refusal)\n\n## RECEIPT / TRACE / PARENT LINKAGE\nproof_run surface=iphone_*; screenshots in R2; push ids kept.\n\n## TEST MATRIX\n| case | what runs | kind |\n|---|---|---|\n| info | PHONE_INFO name/model/iOS version | live |\n| apps | installed apps list | live |\n| screenshot mirror | via Mirroring → R2 | live |\n| screenshot pymd3 | with tunnel if root available; else the exact error recorded | live/fixture |\n| shortcut url | a no-op Shortcut via shortcuts:// through Mirroring | live |\n| push | APNs to the Console app → app receipt back to /api/phone | live |\n| open url | open https://miscsubjects.com/tools on the phone | live |\n| simulator | the same PHONE_SCREENSHOT via ios_simulator labelled and refused as phone proof | fixture |\n\n## ACCEPTANCE TESTS (mechanical; the infrastructure runs them)\n- `{\"type\": \"evidence_present\", \"id\": \"commit\", \"field\": \"commit\"}`\n- `{\"type\": \"evidence_present\", \"id\": \"live\", \"field\": \"verification\"}`\n- `{\"type\": \"evidence_present\", \"id\": \"matrix\", \"field\": \"test_matrix_results\"}`\n- `{\"type\": \"http_ok\", \"id\": \"phone\", \"url\": \"https://ops.miscsubjects.com/api/phone\"}`\nEvidence fields the submitting agent supplies: commit, test_matrix_results, verification. `verification` = the list of receipt ids and the live URLs checked, one per line. `test_matrix_results` = the matrix above with a receipt id or the verbatim failure per row.\n\n## KNOWN FAILURES / REGRESSION FIXTURES (preserve; never rewrite into success)\n- simulator vs physical device confusion\n- root tunnel required for developer screenshots\n- `shortcuts run` hang (Mac side) — the phone url path is the workaround and must be proven\n\n## DEPENDENCIES\n- depends_on: WT-0470, WT-0471, WT-0474\n- OWNS (only this task rewrites): functions/api/phone/*; bridge/apple_data.py; PHONE_* rows; the Console app intent handlers (repo named in memory)\n- SHARED (additive edits only): bridge/surface-verbs.py (mirror verbs; WT-0474); functions/api/tools hot set (WT-0472; add PHONE_SCREENSHOT additively)\n\n## HANDOFF FOR NEXT SESSION\n- Do not show the Simulator on the owner screen; the Mirroring window may be opened for the tap tests and closed after.\n- APNs: key BL72QSYNV2, team/bundle in the vault (`grep '^APNS_' ~/.build-vault.env | cut -d= -f1`).\n- Evidence: one receipt per executor id, plus the simulator refusal.\n\n## DONE LAW (this task is done when every line is true and evidenced; not before)\n- Every executor id has a proof_run from that executor; ios_simulator is labelled and refused as phone proof.\n- PHONE_SHORTCUT_RUN via url proven on the physical phone.\n- Push → app → receipt loop proven.\n- Fixtures pass.\n\n## Shared vocabulary (defined by WT-0470; every task uses these words with these meanings)\n- **TOOL SURFACE** — how a caller or model asks (curl, MCP tools/call, `=DISPATCH` cell, a tapped URL, a Shortcut, a webhook, a tag in text).\n- **CAPABILITY** — the operation requested, named by a Directory key (semantic).\n- **OBJECT** — what it acts on (a chat, a file, a profile, a row, a page).\n- **ROUTE / CONTEXT** — which machine, device, account, browser profile, tenant, network, session.\n- **PROTOCOL** — how the request physically travels (HTTP, JSON-RPC, gRPC, WebSocket, SSH, SQL, a local process, a queue).\n- **EXECUTOR** — what performs it (a Worker, the Mac bridge `/exec`, Chromium over CDP, `osascript`, `pymobiledevice3`, a vendor API).\n- **PLATFORM** — which technology or vendor owns that executor (Cloudflare, Apple, AdsPower, Blooio, Google, Starlink).\n- **RAW CONTRACT** — the exact physical invocation sent, fully resolved.\n- **CONFIRMATION** — the executor's immediate acknowledgement (HTTP status + headers, spawn/exit metadata, JSON-RPC ack, WebSocket ack, queue receipt).\n- **RETURN** — the final result, verbatim, including failure payloads.\n- **RECEIPT** — evidence and provenance: receipt id/URL, trace id, execution id, timestamps, parent linkage.\n\n## Definition of proof (PROOF_LAW, governing invariant; read it: GET https://ops.miscsubjects.com/api/work → governing_invariants)\nA capability is proven only when the DECLARED invocation surface itself ran and the five fields exist for that run: CAUSE (why it ran: user request / task / parent invocation / event / webhook / model call), RAW INVOCATION (the fully resolved physical contract actually sent), RAW CONFIRMATION (the executor's acknowledgement), RAW RETURN (the actual output, failures verbatim), PROOF / RECEIPT (receipt id/URL, trace, execution id, timestamps, parent linkage sufficient to inspect or replay).\nAn HTTP 200 proves an HTTP 200. A webhook acknowledgement proves receipt. Hidden bash proves bash. A sibling implementation, documentation, a model doing it elsewhere, or the dispatcher working while the surface under test never ran prove nothing about that surface. A missing field is a missing implementation requirement, never something to invent. Existing failures stay as evidence and become regression fixtures; they are never rewritten into success.\n\n## Six-column projection (unchanged; not the source of truth)\n`TOOL NAME | ONTOLOGY | RAW INVOCATION | RAW CONFIRMATION | RAW RETURN | PROOF / RECEIPT` — the build workbook sheet `sh_nyab2cgy` (vault `CONTRACTS_WORKBOOK_SHEET`, 11,035 rows on 2026-09-23). No seventh column, no contract-type column, no prose in place of an executable invocation. Extra metadata belongs in the canonical capability / task / receipt objects.\n\n## Parallelism law\nOther tasks run at the same time in other sessions. Own only the files and objects named under OWNS; touch a shared file only as named under SHARED (additive, never a rewrite). If this task finds the global law insufficient, it files an amendment: `POST /api/work/task/<this id>/fail` naming failure_class `law_insufficient`, layer `WT-0470`, and the missing invariant — it never creates a second standard. Ask the build, never the owner: keys are in `~/.build-vault.env` (`grep '^NAME=' ~/.build-vault.env`; `CLOUDFLARE_API_TOKEN=$CF_API_TOKEN` is a shell reference, resolve `$NAME`). The owner key travels as header `x-terminal-key`. Deploy only with `node scripts/land.mjs \"<WT id> what changed\"` from `~/miscsubjects-pages`. Submit evidence: `POST https://ops.miscsubjects.com/api/work/task/<id>/submit {agent, evidence:{commit, verification, …}, changed:[…]}` with header `x-terminal-key`.\n\n## Shared canonical objects and files — never independently rewritten (additive edits only, named per task)\n- `functions/api/dispatch.js` (the one door; runHttp/runFn/tenant delegation) — owner WT-0471.\n- `functions/_lib/invocation_methods.js`, `functions/_lib/grammar.js`, `functions/_lib/projection_manifest.js`, `functions/api/tools/[[path]].js`, `functions/api/mcp.js`, `functions/_lib/mcp_inspect.js` — owner WT-0472 (spellings and model projections).\n- `functions/_lib/event_log.js`, `functions/_lib/wire_log.js`, `functions/_lib/lean_receipt.js`, `functions/_lib/invocation_record.js`, the `events` table and R2 `logs/` — owner WT-0485 (ledger).\n- `functions/_lib/admin_session.js` (tokens, capabilities, tenants), `functions/_lib/tenant_devices.js`, `functions/api/onboard/[[path]].js` — owner WT-0487 (authority) / WT-0488 (onboarding).\n- `functions/_lib/mac_bridge.js`, `bridge/server.js`, `bridge/device_auth.js`, `bridge/surface-run.py`, `bridge/surface-verbs.py`, `bridge/bridge-run.py`, `bridge/bridge-browser.mjs`, `public/device-kit/*` (synced copies) — owners WT-0474 / WT-0475 / WT-0478.\n- `functions/_lib/work_object.js`, `functions/api/work/[[path]].js`, the `laws` and `work_tasks` tables — owner WT-0470 (law rows) and the build (task engine).\n- `scripts/contracts-*.mjs`, `apps-script/Contracts.gs`, the `CONTRACTS_RUN` directory row, sheet `sh_nyab2cgy` — owner WT-0473.\n- `scripts/ship.mjs`, `scripts/land.mjs`, `scripts/write.mjs`, `scripts/check-*.mjs`, `.githooks/*` — governed; add a gate only by adding a new `scripts/check-<name>.mjs` and wiring it as the existing gates are wired.\n",
    "state": "open",
    "priority": 3,
    "revision": 1,
    "depends_on": [
      "WT-0470",
      "WT-0471",
      "WT-0474"
    ],
    "permitted_capabilities": [
      "dispatch",
      "d1",
      "bridge",
      "sheets",
      "receipts"
    ],
    "acceptance_tests": [
      {
        "type": "evidence_present",
        "id": "commit",
        "field": "commit"
      },
      {
        "type": "evidence_present",
        "id": "live",
        "field": "verification"
      },
      {
        "type": "evidence_present",
        "id": "matrix",
        "field": "test_matrix_results"
      },
      {
        "type": "http_ok",
        "id": "phone",
        "url": "https://ops.miscsubjects.com/api/phone"
      }
    ],
    "required_evidence": [
      "commit",
      "test_matrix_results",
      "verification"
    ],
    "parent_task": null,
    "supersedes": null,
    "failure": null,
    "failure_count": 0,
    "last_result": null,
    "completed_at": null,
    "created_at": "2026-09-22T19:52:01-07:00",
    "updated_at": "2026-09-22T19:52:01-07:00",
    "audit": "/api/work/task/WT-0479/audit",
    "submit_to": "/api/work/task/WT-0479/submit"
  }
}