# Recipient policies and selective reencryption

`RecipientPolicyManager` implements `pass init` inside `crates/storage`. It
accepts the storage-owned `InitRequest`, so root initialization and `--path` /
`-p` initialization share the same validated relative-path rules as every
other repository operation. One empty identity removes the policy at that
exact directory; any other identity list is written one item per line with a
final newline, matching upstream `pass`.

## Hierarchy

An entry inherits the nearest `.gpg-id` in its directory or an ancestor.
Nested files override their parent for the complete nested subtree. Exact
fingerprints, key IDs, and user IDs are resolved by `KeyStore`; comments,
whitespace, duplicates, missing identities, and ambiguous identities use the
same rules as encryption elsewhere in storage.

Changing a policy considers only entries below that directory which are not
shielded by a deeper override. Removing an override makes those entries inherit
the nearest policy above it. Removal is rejected before mutation if an affected
entry would have no policy. Existing public-key session packets are compared to
the resolved certificate set, so entries already encrypted for exactly the
requested recipients are not needlessly rewritten.

As upstream does, removing `.gpg-id` does not remove a pre-existing detached
`.gpg-id.sig`; without a configured signing-key policy the orphan is ignored.
Reinitializing with signing enabled replaces it.

## Authentication

When `PASSWORD_STORE_SIGNING_KEY` behavior is configured, `SigningPolicy`
contains the key used to create a detached signature and the explicit set of
trusted primary fingerprints. A new `.gpg-id` is signed and immediately
verified against that set before filesystem mutation. Inherited policies must
have a signature which verifies against the same trust set. Missing, malformed,
untrusted, and cryptographically invalid signatures are distinct pre-mutation
failures.

## Transaction and Git boundary

Resolution, signature work, decryption, and replacement encryption all finish
in memory before the first repository write. Every affected entry retains its
original encrypted bytes. Repository writes use private, synced temporary files
and atomic per-file replacement. If any write or the storage commit hook fails,
the policy, signature, and every entry are restored in reverse order; new empty
policy directories are removed. A rollback failure is surfaced separately from
the original operation error.

`PolicyCommitter` is the integration boundary for the embedded Git engine. It
receives the exact changed paths and compatible commit intent after repository
bytes have been installed. It is called once for a real change, never for a
no-op, and must restore any staging state before returning an error. The policy
manager then restores repository bytes. `NoGitCommitter` represents a path not
contained in a Git work tree; it is not used for a discovered repository.

The embedded Git implementation owns concrete staging and commits, while this
module owns the all-or-nothing storage mutation contract it invokes.
