block / block/buzz

Merge coordinator: reference implementation + design questions (policy-gated protected-ref merges)

Open
#4,822 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

## Context

`VISION_PROJECTS.md` lists the **merge coordinator** among the designed-but-unbuilt forge roles: the agent that "runs the merge train, requests human sign-off." We've been self-hosting a relay as the system of record for our org's repos and needed that role now, so we built a reference implementation and would like to converge it with wherever the project wants this to go: [`buzz-merge-coordinator` on our fork](https://github.com/happyvertical/buzz/tree/feat/merge-coordinator/crates/buzz-merge-coordinator).

## Shape

One small binary (no daemon state, no unsafe, ~600 lines + 15 predicate tests) that gates a protected-ref fast-forward on three fail-closed predicates, all bound to the **exact head OID**:

1. **Approvals** — kind:46030 grants / 46031 denies with tags `["t","git-merge"] ["r",] ["x",]`; N distinct signers qualifying by bound-channel role (default: admin) or allowlist; any qualifying veto refuses.
2. **CI evidence** — kind:1630 events (`["t",] ["l","success"|"failure"]` + the same `r`/`x` binding); latest attestation per required context from listed attestor pubkeys must be success.
3. **External disposition** (optional) — `POST {repo_id, head_oid, dst_ref}` to a configured URL must return `{"allow":true}`; the seam for an external tracker to hold merge-authority state without the coordinator knowing anything about it.

Then it pushes `oid:ref` over smart HTTP with its own identity (a bound-channel admin), posts kind:1631 + a human-readable decision to the bound channel, and refusals name the failed predicate. The relay's transport protections (`push:` role floor, `no-force-push`) stay as the independent layer underneath — we've been running that combination live.

## Design questions for maintainers

- **Kind/tag conventions**: we reused `KIND_APPROVAL_GRANT/DENY` (46030/46031) with a `t=git-merge` scope, and 1630 for CI results per the VISION merge-flow sketch, with single-letter tags (`r`/`x`/`t`/`l`) so evidence is server-side filterable with standard filters. Is that the vocabulary you'd want, or is a dedicated kind range planned for review approvals / CI attestations?
- **Placement**: workspace crate (as in the branch) vs folding the logic into the relay behind `require-approval` transport enforcement? We see value in both existing — transport counting as defense-in-depth, the coordinator for the richer predicates (CI, disposition, vetoes).
- **Client reuse**: the crate carries a self-contained ~150-line NIP-98 client because `buzz-cli`'s `BuzzClient` is private; if a shared client were extracted into `buzz-sdk`, that module disappears.

Happy to adapt the branch to your conventions and open a PR — or treat this as field input if you'd rather build it differently.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.