Files
ngit-grasp/tests
DanConwayDev 96cb60501a feat(nip34): require reciprocal announcements before maintainer state is authorized
Follow the reciprocal membership rule from the refined NIP-34 maintainers
model (nips 781590b): a pubkey listed as a maintainer is only *invited*
until its own announcement for the same identifier lists back an existing
confirmed maintainer. State events from invited maintainers are no longer
authorized; previously any pubkey reachable through recursive `maintainers`
expansion was authorized without ever acknowledging the role.

compute_membership replaces get_maintainers_recursive as the single
membership computation: a fixpoint over announcements that confirms a
listed pubkey once their own announcement lists back a confirmed
maintainer. The owner is always a confirmed maintainer of their own
repository, since announcing a repository in their namespace is what
creates it on this service. collect_authorized_maintainers keeps its
signature so all state-authorization call sites pick up the new semantics
unchanged.

Invited maintainers' announcements are deliberately still fetched,
accepted (maintainer exception) and walked by the sync dependency
machinery - the reciprocal announcement is exactly how the relay notices
an invitation was accepted. To complete that flow, an acceptance stored
via the maintainer exception is now pre-saved and stored state events are
re-applied (new reapply_stored flag on process_state_event) so the newly
confirmed maintainer's latest state re-points the owner's repository
without another push; without this the stored state short-circuited as a
duplicate and the invitation flow stalled.

Remove the dead pre-membership helpers (AuthorizationContext,
find_latest_state_for_announcement, find_latest_authorized_state,
is_latest_state) that encoded the superseded semantics and had no other
callers. Tests updated: invited state is rejected until acceptance
(tests/state_authorization.rs), the invitation sync test now asserts the
owner's refs are withheld until the invitee accepts, and grasp-audit
maintainer fixtures publish reciprocal announcements.

Scope deliberately excluded: the indexed `M`/`m` role tags and the
moderator role from nips 986edd1 land in follow-up commits; this commit
changes membership semantics for the deprecated `maintainers` tag only.

Validation: git::authorization unit tests, state_authorization suite,
sync invitation tests and grasp-audit lib tests all pass.
2026-08-19 11:29:30 +00:00
..