{
  "_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-0484",
    "kind": "work",
    "objective": "WT-0484 Composition plane — chains, compose, line grammar, combinatorial automations with parent linkage",
    "detail": "# WT-0484 — Composition plane — chains, compose, line grammar, combinatorial automations with parent linkage\n\n## GOAL\nAny sequence of capabilities (a chain of dispatch calls, /api/surface compose, a misc line with pipes, a webhook that triggers a chain, a sheet column of =DISPATCH cells feeding each other, an agent run that fans out) is itself a capability with a contract; every step runs through the resolver with cause=parent:<receipt>, and the chain receipt links every child so the owner can read WHY → WHAT → ACK → RETURN → RECEIPT for the whole automation.\n\n## WHY THIS EXISTS\nThe owner asked how to formulate combinatorial automations across Mac, iPhone, browser and messages. Compose exists (/api/surface compose, `composed` layer) but its steps have no parent linkage, the line grammar resolves one call, and \"chain\" rows are prose. Composition must be a first-class object with proof.\n\n## CURRENT STATE (measured 2026-09-23)\n- /api/surface compose (composed layer, surface_composed_0.json); /api/chain door exists (functions/api/chain); /api/resolve line grammar (functions/_lib/grammar.js); /api/hooks webhooks; sheet formulas; agent runs fan out.\n- No parent_receipt_id on any child call today.\n\n## SOURCE OF TRUTH\n- functions/api/chain/*, functions/api/surface (compose), functions/api/resolve.js, functions/_lib/grammar.js\n- functions/api/hooks/*\n- the `composed` surface layer\n\n## IN-SCOPE INVENTORY\n- Chain object: `chains` table (main DB): id, name, steps (JSON array of {key, args (may reference `$prev.return.<path>` and `$step[n].return.<path>`), route?, on_error: stop|continue|branch:<step>}), owner_principal, created_at; a CHAIN_<NAME> directory row per saved chain (so every spelling applies).\n- Verbs: CHAIN_RUN {chain_id | steps inline, args, cause} → runs steps through the resolver with cause=parent:<chain receipt>; CHAIN_DEFINE; CHAIN_LIST; COMPOSE (surface compose kept, now delegating to CHAIN_RUN).\n- Grammar: the misc line accepts `KEY args | KEY2 $prev.return.x` and compiles to an inline chain.\n- Triggers: a hook row may name a chain (WT-0485 hook receipts become the cause); a sheet column of =DISPATCH cells referencing the prior row is documented as the cell composition.\n- Proof set: three cross-plane automations — (1) NET_LINE → SHEETS_APPEND → TEXT send to the owner; (2) PHONE_SCREENSHOT → R2 → BROWSER_MARKDOWN of the receipt page; (3) inbound tag → CHAIN_RUN → reply. Each child has parent_receipt_id.\n\n## OUT OF SCOPE\n- Scheduling/recurring runs (automations are off by LAW: no unrequested automations; a chain runs when called). New planes.\n\n## ONTOLOGY (separate axes; never a flat string)\n- TOOL SURFACE: dispatch CHAIN_*; POST /api/chain; misc line with pipes; hook-triggered; cell column\n- CAPABILITY: CHAIN_RUN/DEFINE/LIST, COMPOSE\n- OBJECT: a chain and its steps\n- ROUTE / CONTEXT: per step (inherits or overrides)\n- PROTOCOL: in-Worker orchestration calling the resolver\n- EXECUTOR: Worker (orchestrator) + each step's executor\n- PLATFORM: the build\n\n## DISCOVERY (run these first; they answer, they do not prove)\n- `curl -sS \"https://ops.miscsubjects.com/api/chain\" -H \"x-terminal-key: $TERMINAL_KEY\"`\n- `curl -sS \"https://ops.miscsubjects.com/api/surface/layers/composed?limit=10\" -H \"x-terminal-key: $TERMINAL_KEY\"`\n- `curl -sS -X POST https://ops.miscsubjects.com/api/resolve -H \"x-terminal-key: $TERMINAL_KEY\" -H \"content-type: application/json\" -d '{\"line\":\"NET_LINE\"}'`\n\n## CONTRACT (FIELD LAW)\n- CHAIN_RUN `{chain_id (one-of with steps), steps (array ≥ 1 of {key (required), args (object|string), route?, on_error (enum, default stop)}), args (object, chain inputs), cause, dry (bool)}` → `{ok, chain_receipt_id, steps:[{n, key, receipt_id, confirmation, return (≤ 20,000 in the chain return; whole at the child receipt), status}], stopped_at?}`.\n- References: `$prev.return.<jsonpath>`, `$step[n].return.<jsonpath>`, `$args.<name>`; an unresolvable reference → 400 ref_unresolved naming the step and path.\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\":\"CHAIN_RUN\",\"body\":{\"steps\":[{\"key\":\"NET_LINE\"},{\"key\":\"D1_QUERY\",\"args\":\"SELECT 1 AS one\"}]}}'`\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\":\"CHAIN_RUN\",\"body\":{\"steps\":[{\"key\":\"NET_LINE\"},{\"key\":\"SHEETS_APPEND\",\"args\":{\"sheet\":\"sh_ahznwfyd\",\"values\":[[\"$prev.return.ip\",\"$prev.return.dish.uptime_s\"]]}},{\"key\":\"TEXT_SEND\",\"args\":{\"to\":\"+17079135888\",\"from\":\"+14245134626\",\"text\":\"line $step[1].return.ip\"},\"on_error\":\"stop\"}],\"args\":{},\"dry\":false},\"cause\":\"task:WT-0484\"}'`\n\n## RAW CONFIRMATION SHAPE\nChain: HTTP 200 + chain_receipt_id immediately after the chain row is persisted (before steps run); per step: that step's executor confirmation.\n\n## RAW RETURN SHAPE\nThe steps array with each child receipt; each child return whole at its receipt.\n\n## ERROR SHAPES\n- ref_unresolved\n- step_failed (with on_error=stop → stopped_at)\n- authority_denied on a step (the chain records it and stops)\n- chain_not_found\n\n## RECEIPT / TRACE / PARENT LINKAGE\nchain receipt with children; every child proof_run has parent_receipt_id = chain receipt; the receipt page renders the tree.\n\n## TEST MATRIX\n| case | what runs | kind |\n|---|---|---|\n| inline 2-step | NET_LINE → D1_QUERY | live |\n| saved chain | CHAIN_DEFINE then CHAIN_RUN by id, CHAIN_<NAME> row appears with 13 spellings | live |\n| cross-plane 1 | NET_LINE → sheet → text | live |\n| cross-plane 2 | phone screenshot → R2 → browser markdown | live |\n| cross-plane 3 | inbound tag → chain → reply | live |\n| ref error | a bad $prev path → ref_unresolved | fixture |\n| stop on error | a failing middle step → stopped_at=2, step 3 not run | fixture |\n| line pipes | misc line `NET_LINE | D1_QUERY SELECT 1` → same as inline | 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\": \"http_ok\", \"id\": \"chain\", \"url\": \"https://ops.miscsubjects.com/api/chain\"}`\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- no unrequested automations (no scheduler is added; a test asserts no cron/trigger rows were created)\n- DNS failure in a middle step isolates that step (on_error=continue)\n\n## DEPENDENCIES\n- depends_on: WT-0470, WT-0471, WT-0485\n- OWNS (only this task rewrites): functions/api/chain/*; functions/_lib/chain_run.js (new); migrations/0487_chains.sql (new); CHAIN_* rows; the pipe extension of functions/_lib/grammar.js (coordinate with WT-0472: additive token only)\n- SHARED (additive edits only): functions/_lib/grammar.js (WT-0472 owns; add the `|` token additively); functions/api/surface compose (WT-0474 owns the door; delegate to CHAIN_RUN additively)\n\n## HANDOFF FOR NEXT SESSION\n- Persist the chain row before running steps (the ack law).\n- Cross-plane proofs need WT-0478/0479/0480/0483 executors; if one is not ready, run the chain with the steps that exist and record the missing executor as step_failed with its exact error.\n- Evidence: three chain receipt ids with their trees.\n\n## DONE LAW (this task is done when every line is true and evidenced; not before)\n- Chains are rows with contracts and spellings.\n- Three cross-plane automations proven with parent linkage.\n- Fixtures pass; no scheduler exists.\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-0485"
    ],
    "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": "chain",
        "url": "https://ops.miscsubjects.com/api/chain"
      }
    ],
    "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:04-07:00",
    "updated_at": "2026-09-22T19:52:04-07:00",
    "audit": "/api/work/task/WT-0484/audit",
    "submit_to": "/api/work/task/WT-0484/submit"
  }
}