Stacked on #130 — review the top commit.
Nine headers describing a gate that has existed for months
Nine module headers tell the reader their capability gate "has no Zig mirror", that the flag "appears nowhere in packages/zig/src", and that their actions are therefore "served unconditionally".
Every sentence was true when written. None has been true since ios_config.zig read craft.config.json and ios_dispatch.offerToModules started refusing gated actions before any module runs. gateFor maps every action these nine headers name.
The claim is worse than ordinary staleness because of what it claims. bridge_mobile_securestore.zig tells anyone reading it that the Keychain actions are served with no capability check — a false statement about a security boundary, in the file someone would open to check.
Stated once, not nine times
Repeating the paragraph in nine places is what let it rot in nine places at once, so it is not repeated. Each module now says the gate is read and where, and keeps the divergence it actually needs to describe: Swift's arms have no else, so a disabled capability hangs an untimed promise there and settles as a rejection here.
securestore's gets the longest treatment because it argued the opposite case at length — down to which of two earlier modules' gate patterns to copy if the gate were ever wanted back. That is worth a record: the same paragraph was written in eight other files, by people who checked, and nothing re-checked any of them.
The exception
bridge_mobile_watch.zig keeps its claim, because it is still true. Swift gates WatchConnectivity at setup — if config.enableWatchApp around setupWatchConnectivity — not per action, so no case arm carries an if config. and gateFor correctly maps none of sendToWatch, updateWatchContext or isWatchReachable. Only its cross-reference to securestore and notifcancel needed fixing.
What this deliberately does not change
contactpicker, calendar and motion additionally read an Info.plist key as a stand-in for the flag they could not read. Those checks are still live and now sit behind the real gate, where they can only differ in one direction — refusing an action the config allows. Each header now says so and points at #131, which covers five such proxies.
The plist checks that are crash guards are a different thing and are untouched: audiorec, bluetooth, contacts, location, imagepicker's camera key and speech's microphone key all run before an API that terminates the process when the key is absent. bridge_mobile_contacts.zig already draws that distinction against the picker explicitly and needed no edit.
Documentation only — zig build test:ios 5 + 1067 + 19, all green.