Expand description
XF.4 — authorising a guest-returned effect’s file paths.
Design: cross-file-writes.md §6.
§Why the check lives at the boundary
Effect::WriteToFile writes into a file the editor may not have open. That
needs fs:write authority over the path, and the check has exactly one
place it can run.
Not at the applier: by the time an effect reaches Editor::handle_effect
the host has no idea which plugin produced it, because effects from a
plugin and from a native mode are the same type — deliberately, since that
is what lets a mode drive an edit without the host growing a per-feature
Action. Threading a plugin id through the effect would mean putting
provenance inside guest-returned data, which is exactly what
provenance_ids_are_host_issued_unique_and_stamp_the_plugin_layer forbids.
At the boundary the provenance is still known: the trampoline holds the
plugin’s Store<PluginState>, and PluginState::grant is its effective
CapabilityGrant. So the conversion authorises, and an effect that
reaches the editor has already been checked.
§What a denial does
Replaces the effect with an Echo, so the user is told rather than left
wondering why a key did nothing — the same reasoning as
ProviderViewOutcome::Declined.
And drops what came after it in the batch (CD.3c). This used to keep
the rest of a Many, on the reasoning that “one denied write must not
silently cancel the other things an action did”. That holds for independent
effects and is wrong for a commit, where what follows a write presumes it
happened: org’s capture returned [write, close the buffer], so a denied
target closed the capture and the user’s text went with it. The host’s
applier stops a batch after a write that fails for any other reason
(apply_effect_host); a denial is the same failure, found earlier, and is
handled the same way. Effects before the write are kept.
Structs§
- Effect
Authorizer - Authorises the file paths in a plugin’s returned effects against its grant.