{
  "_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-0471",
    "kind": "work",
    "objective": "WT-0471 Resolver / Dispatcher — semantic capability to fully resolved physical invocation",
    "detail": "# WT-0471 — Resolver / Dispatcher — semantic capability to fully resolved physical invocation\n\n## GOAL\nEvery call through the one door resolves a semantic Directory call (key + arguments) into a fully resolved physical invocation (executor, URL/command/target, method, headers/auth, body/argv/env/stdin, session/profile/device), persists that raw invocation BEFORE executing, runs it, and returns confirmation + return + receipt as separate fields. The resolver is one function, used by every surface (WT-0472) and every plane.\n\n## WHY THIS EXISTS\nThe dispatcher today resolves and executes in one motion (functions/api/dispatch.js runHttp/runFn/tenant delegation) and records the result after the fact. A crash or timeout leaves no raw invocation, the return and the confirmation are merged into `last_response`, and no field says which executor actually ran. The owner's law: semantic capability → resolver → physical invocation → executor → confirmation → return → receipt, each a separate field.\n\n## CURRENT STATE (measured 2026-09-23)\n- functions/api/dispatch.js: rows by key; `?invoke=KEY&share=<token>` link form; `?mint_share=1&scope=rows&keys=…&ttl=`; tenant Bearer forwarded to tenant doors; runHttp (curl-like upstream), runFn (in-Worker function), local bridge via functions/_lib/mac_bridge.js bridgeRequest(env,…,{key,device}).\n- functions/api/resolve.js: the line grammar (functions/_lib/grammar.js) resolves a typed line to a key + args; it does not produce a physical invocation.\n- functions/_lib/invocation_record.js writes invocation, last_status, last_response, test_state onto the directory row after execution.\n- Tenant routing: functions/_lib/tenant_devices.js (device-bound token + intent secret, quick-tunnel endpoint) overrides the bridge target per tenant.\n\n## SOURCE OF TRUTH\n- functions/api/dispatch.js\n- functions/_lib/mac_bridge.js\n- functions/_lib/tenant_devices.js\n- functions/_lib/invocation_record.js\n- functions/api/resolve.js + functions/_lib/grammar.js\n- the `directory` table (1,519 rows on 2026-09-23; columns include key, kind, method, url, headers, body, fn, ontology, provider, tier, planner_rank, invocation, last_status, last_response, test_state)\n\n## IN-SCOPE INVENTORY\n- New module functions/_lib/resolver.js: `resolve(env, {key, args, actor, cause, route})` → `{physical:{executor, protocol, target, method, headers, body|argv|env|stdin, session|profile|device}, contract_ref, trace_id}`; pure, no side effects; executors: worker_fetch, worker_fn, mac_bridge_exec, tenant_device, wfp_tenant, sql, r2, kv, queue.\n- Persist-before-execute: `proof_runs` row written with cause + raw_invocation before the executor runs (shape from WT-0470; writer from WT-0485 — until WT-0485 lands, write through logEvent with request=raw_invocation and status=started).\n- Executor adapters, each returning `{confirmation, return, receipt}` separately: HTTP (status + headers + timing), fn (spawn/complete metadata), bridge (`/exec` spawn + exit code + duration), tenant (gate response), SQL (changes/last_row_id/rows).\n- Cause field on every dispatch: header `x-cause` or body `cause`; default `user_request` for owner key, `model:<run>` when called through /api/mcp, `webhook:<hook>` from /api/hooks, `task:<id>` from CONTRACTS_RUN, `parent:<receipt>` from composition.\n- The `?invoke=KEY&share=` link form and `=DISPATCH()` cell go through the same resolver (they already reach dispatch.js; they must not resolve separately).\n\n## OUT OF SCOPE\n- New spellings (WT-0472). Plane executors' internals (WT-0474–0483). Ledger storage (WT-0485). Authority decisions (WT-0487) — the resolver asks admin_session for allow/deny and records the answer.\n\n## ONTOLOGY (separate axes; never a flat string)\n- TOOL SURFACE: POST /api/dispatch (all spellings compile to it)\n- CAPABILITY: DISPATCH, RESOLVE; every Directory key\n- OBJECT: a directory row + arguments\n- ROUTE / CONTEXT: owner key / share token / tenant Bearer / device token → which executor and which device\n- PROTOCOL: HTTP JSON in; HTTP, local process, SQL, gRPC out\n- EXECUTOR: Pages Functions Worker; Mac bridge /exec; tenant Worker; tenant device tunnel\n- PLATFORM: Cloudflare Pages/Workers; the Mac; Workers for Platforms\n\n## DISCOVERY (run these first; they answer, they do not prove)\n- `curl -sS \"https://ops.miscsubjects.com/api/directory/D1_QUERY\" -H \"x-terminal-key: $TERMINAL_KEY\"` — one row with how_to_call.\n- `sed -n 1,120p functions/api/dispatch.js` — the entry and the branch into runHttp/runFn/bridge/tenant.\n- `grep -n \"bridgeRequest\" -r functions/_lib functions/api | head`.\n\n## CONTRACT (FIELD LAW)\n- Request: `{key (required, string, existing directory key), args|body (optional; type per row: string for line rows, object for JSON rows; omitted = row example), cause (optional, enum above, default user_request), route (optional: {device, profile, tenant, egress}), dry (optional bool; true = resolve only, returns physical without running)}` plus header x-terminal-key | Authorization: Bearer <tenant> | ?share=<token>. Conflicts: dry with a send-effect row still returns the physical invocation; args and body are one-of.\n- Response: `{ok, key, trace_id, receipt_id, physical:{…}, confirmation:{…}, return:<any>, error?:{class, layer, detail}}`. `return` is verbatim (JSON or text ≤ 200,000 chars, then truncated with `truncated_at`).\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\":\"NET_LINE\"}'`\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\" -H \"x-cause: task:WT-0471\" -H \"x-trace-id: t-2026-09-23-0001\" -d '{\"key\":\"LOCAL_EXEC\",\"body\":{\"cmd\":\"uname -a\"},\"route\":{\"device\":\"owner-mac\"},\"dry\":false}'`\n\n## RAW CONFIRMATION SHAPE\nHTTP 200 + `confirmation:{status:200, headers:{…}, ms:<n>}` for HTTP executors; `confirmation:{spawned:true, pid, exit:0, ms}` for bridge; `confirmation:{changes, last_row_id}` for SQL. A refused resolution is HTTP 4xx with `error.class` (unknown_key | capability_required | tenant_unknown | route_unavailable).\n\n## RAW RETURN SHAPE\n`return` holds the executor's payload verbatim; `physical` holds the resolved invocation; `receipt_id` resolves at https://miscsubjects.com/receipt/<id>.\n\n## ERROR SHAPES\n- unknown_key 404\n- capability_required 401 (Bearer where x-terminal-key is needed)\n- tenant_unknown 403 (tenant without a `tenants` policy row)\n- route_unavailable 503 (device offline; bridge 522/timeout) with the raw upstream text\n- executor_error 502 with the raw return preserved\n\n## RECEIPT / TRACE / PARENT LINKAGE\ntrace_id in; receipt_id out; proof_run row with parent_receipt_id when cause=parent:<id>; events row (source=dispatch). The receipt page shows the five fields.\n\n## TEST MATRIX\n| case | what runs | kind |\n|---|---|---|\n| HTTP executor | D1_QUERY via dispatch → physical.executor=worker_fn, confirmation.changes | live |\n| bridge executor | LOCAL_EXEC uname → confirmation.exit=0, return has Darwin | live |\n| tenant executor | ONBOARD_DEMO_KEY (vault) calling NET_LINE → executor=wfp_tenant | live |\n| dry resolve | dry:true returns physical and no receipt of execution (a resolve receipt only) | live |\n| persist before execute | kill the executor mid-run (LOCAL_EXEC sleep 120 with a 5 s timeout) → proof_run exists with raw_invocation and confirmation=NONE (timeout) | fixture |\n| cause propagation | /api/mcp tools/call → cause=model:<run> | live |\n| link form | GET ?invoke=NET_LINE&share=<CONTRACTS_LINK_TOKEN> → same physical shape | live |\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\": \"contains\", \"id\": \"dry\", \"url\": \"https://ops.miscsubjects.com/api/dispatch?invoke=NET_LINE&dry=1\", \"needle\": \"physical\"}`\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- stale hosts: rows whose url points at a retired workers.dev host (contracts run 2026-09-23 found several; the resolver must refuse with route_unavailable and the raw DNS error, never a bare 5xx)\n- DNS failure stopping a batch: one unresolvable host must fail one row, not the run\n- Bearer treated as anonymous on /api/tools/mcp.json (2026-09-22)\n- transport 2xx ≠ operation success: a 200 wrapping `{\"ok\":false}` must set error.class=executor_error\n\n## DEPENDENCIES\n- depends_on: WT-0470\n- OWNS (only this task rewrites): functions/_lib/resolver.js (new); functions/api/dispatch.js (the door; the only rewrite allowed in this set); functions/_lib/invocation_record.js\n- SHARED (additive edits only): functions/_lib/mac_bridge.js (additive: pass trace/cause headers through); functions/_lib/event_log.js (call it; do not change its shape — WT-0485 does)\n\n## HANDOFF FOR NEXT SESSION\n- Start by writing resolver.js with `dry` support and switching dispatch.js to call it; ship; then add persist-before-execute; ship once per turn (LAW).\n- The `?invoke=` link and `=DISPATCH()` already enter dispatch.js — verify with the CONTRACTS_LINK_TOKEN link in the vault.\n- Evidence must include one receipt per executor family (HTTP, fn, bridge, tenant, SQL) showing separate confirmation and return.\n\n## DONE LAW (this task is done when every line is true and evidenced; not before)\n- dry:true returns `physical` for every directory row (mechanical, sampled 50 rows with the resolver test in functions/api/dispatch.attenuation.test.mjs extended).\n- Every executed dispatch has a proof_run/events row with raw_invocation written before execution (evidence: the timeout fixture).\n- Confirmation, return and receipt are separate fields in the response and in the ledger.\n- The link form and the sheet cell go through the same resolver (evidence: two receipts with identical `physical`).\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": 1,
    "revision": 1,
    "depends_on": [
      "WT-0470"
    ],
    "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": "contains",
        "id": "dry",
        "url": "https://ops.miscsubjects.com/api/dispatch?invoke=NET_LINE&dry=1",
        "needle": "physical"
      }
    ],
    "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:51:45-07:00",
    "updated_at": "2026-09-22T19:51:45-07:00",
    "audit": "/api/work/task/WT-0471/audit",
    "submit_to": "/api/work/task/WT-0471/submit"
  }
}