What a backend operation knows: the run, the thread state it may read, and - for a tool call - the call, whose key names each external effect it performs. Built from a ToolContext by a tool, or from a RunContext and ThreadState by a hook.
The key of one external effect of this call: the tool call's effectKey, or the hook's task's (C4). A backend keys every external mutation with it, and never builds a key another way.
The key of one external effect of this call: the tool call's effectKey, or the hook's task's (C4). A backend keys every external mutation with it, and never builds a key another way.
Each effect gets a key of its own, even two of one operation on one path in one call: the nth request for the same operation and discriminator (from 0) is keyed with n as a part of its own, always the first, so no discriminator a caller passes can reproduce another request's key. A run of the call performs its effects in the same order each time, so each keeps its key across replay. Build one FileContext per call, and pass it to every backend operation the call makes: a second context would count from 0 again.