**Direction C recorded, with its provenance, plus the source-grounded design it implies. No implementation, no REQ activation, no acceptance granted, no milestone membership change by this comment (todlando, 2026-09-12 09:5xZ).**

## Provenance of the direction, stated because it is relayed and not first-hand

Reavo confirmed **direction C** for #300. The confirmation reached me through a relay chain — operator → lia → doyle → me (doyle's dispatch, 2026-09-12 09:42Z) — and it **supersedes the earlier A/B fork** doyle filed on this issue. I did not receive it from the operator, I am not its author, and nothing below should be read as the operator's words. Scope record this attaches to: #304 intake, comment 5630275229, which retains #300 in the operator bag in full.

C as ruled: the now-signal can report the controller-attached state, so the USER_INPUT event should detect the attached controller's node ID; and **if** the remote node needs a certified means of communicating the event back, something like a **handshake code the USER_INPUT event can know and use**.

## C's premise is true in source. Its FIRST clause alone is not sound.

The attached-controller datum exists and is reported: `Attachment { controlled, controller_node, viewers, viewer_nodes }` at `crates/spt-daemon/src/attachment.rs:118-125`, populated from the controller seat's `by` at `crates/spt-daemon/src/broker.rs:3621` (`controller_by()`, `:1603`), surfaced as `controlled` / `controller-node` and asserted in `crates/spt/tests/attach_link_push_e2e.rs:392-421`.

Three source facts say that datum cannot be the identity of a particular USER_INPUT:

1. **It is absent for a real controller in one shipped case.** `attachment.rs:113-117`: "a local controller presents no node identity, so 'somebody is driving' is knowable when 'which node is driving' is not."
2. **It lags the decision it describes.** `broker.rs:1614-1620`: the perch info stamp "lags the seat decision (KH 7.15 / info.rs terminal_normalize)", and `SessionInfo.controller_by == None` is "ambiguous between empty and local". A value that lags cannot date an event.
3. **Sampling it at event time is the handoff counterexample already on this issue** (my input-contract packet §2; doyle's standing "current-controller inference stays rejected"). A submits, the harness queues it, B takes the seat, the hook fires, the sample says B. Reading the now-signal rather than `driven_by` does not change that.

**So C is deliverable through its SECOND clause.** The handshake code is not an extra for an awkward case — it is the mechanism.

## The trusted identity path already exists; the missing thing is the association

`crates/spt-daemon/src/attach.rs:419` — `origin_node` **must** be the handshake-proven remote id from the broker's handshake (`:348`, `:454` take it as a parameter; `access_check` at `:32` sees it). A proven controller node id therefore exists **at attach time, before any input flows**. What is missing is not proof of origin but a **carried association** between that proof and one semantic submission.

The authorization arm that would consume it is already shipped and needs no change: `crates/spt-daemon/src/wan.rs:1289-1345` `request_quoted_paths` — envelope required, non-`user-msg` refused, quoted absolute paths extracted (`quoted_path_candidates`, capped), then the **proven origin node** is asked to serve each path with `audience = msg.target`, `HELPER_ENTRY_TTL_MS`, and the message id as the entry's `origin`; every refusal emits one `HELPER_SERVE_FOR ... outcome=declined` line. Its authorization inputs are exactly: proven origin, committed user text, audience.

## What the event side does not carry, and one constraint that must not be broken

- `crates/spt/src/api/delivery.rs:115-134` `state_io_kind` is deliberately **pure**, and its own comment forbids precisely the shortcut C's first clause suggests: "it still cannot consult the edge, the sentinel or the stamp." Provenance must ride as **data on the event**, never as a condition on its classification.
- `delivery.rs:141-152`: `IoEvent::new(id, kind, payload).with_mid(mid)` carries no origin, no receipt, no submission id — and the funnel is explicitly best-effort and "structurally unable to affect the caller", so a grant decision may not live inside it.
- `crates/spt/src/rc.rs:210-216`: the controller reserved-row identity marker is **shipped off** (`STATUS_ROW_ENABLED = false`, bug #14). No design may assume an in-band identity surface inside the session.

## Missing contract: a seat-bound input-provenance code

- **Mint** at an admitted Control attach, bound to (session id, endpoint incarnation, controller **seat generation**, proven origin node). A handoff retires the old code; a viewer gets none.
- **Read** by the session's own adapter through an existing authenticated read verb — no new transport.
- **Report** with the `api state busy` payload, captured **at the moment the adapter accepted the submission**.
- **Verify and authorize**: a code that verifies, is unretired, and names one continuous seat occupancy since mint runs the existing `request_quoted_paths` arm (origin = the code's proven node, audience = receiving endpoint, 24h TTL, once per input/path). Missing, retired or unverifiable **refuses by name**. Refusal is the default arm.

This is **smaller than the (A) capability** I specified earlier: (A) needed a receipt-bearing input transport; this needs none, because the code is read out of band and reported with a payload the adapter already sends.

**Residual hole, named rather than buried — and it needs a ruling before implementation.** Capture-at-acceptance is the adapter's act and core cannot verify when it happened. In the queue case the event carries B's code; the path then resolves on B's machine, so usually a 404/decline — but if B happens to hold that path, B's file is exposed to the audience under B's code without B typing it. Core alone cannot close this. It closes only if the adapter contract **requires** capture at acceptance and core may refuse on a seat-generation change between mint and report, which only the adapter can witness.

## Proposed acceptance (not granted)

1. Real remote `spt rc` input from node A to an endpoint on node B with a quoted absolute path — the existing WAN-envelope test is **not** coverage.
2. USER_INPUT carries a verifying code whose bound origin equals A's handshake-proven node id.
3. One scoped registration on A: the path, audience = receiving endpoint, 24h TTL, `origin` naming the input, and FILE_ACCESS_HELPER emitted **once per input/path** — not per keystroke, not per repeat.
4. Cross-node fetch 200 with byte equality; an edit on A visible through the reference; a delete yields 404. The manual-serving 200/16898 in the issue body is explicitly not this.
5. Refusal arms, **each with its own positive control**: no code; retired post-handoff code; viewer attach; code from another session/incarnation. A refusal suite with no passing arm proves nothing.
6. A path typed but never reaching USER_INPUT grants nothing — core never parses terminal keys into grants.
7. Replay re-registers nothing and does not move the TTL.

Packet: `.spt/preserved/todlando-300-directionC-20260912/design.md`, sha256 `7bf65bb1ddd019316aa7babb124f26dfa827f78d188af7f82a05633bf8ab44eb`, 8994 bytes. Subject read: `origin/main` @ `24a7ba0a`, read-only. Separate from the frozen #304 stub-gate driver (`a9510e1e`), which this does not touch. No build, live probe, product execution or elevation.

*-todlando@HFENDULEAM*
