Repository navigation
Description
The cross-repo ref-update feeds (refUpdates GraphQL #112, GET /api/v1/events/ref-updates REST #114) drop a genuinely-remote row for anonymous callers when a local private repo shares both the repo name and the owner's trailing DID segment.
Root cause is the wire slug. publish_ref_update (crates/gitlawb-node/src/api/repos.rs) broadcasts the slug as {owner_did.split(':').last}/{name}, discarding the DID method/host. did:web:host:alice and did:gitlawb:alice both emit alice/widget. The feed gate (ref_update_row_visible) therefore cannot tell a remote public repo's row from a local private repo's row when their names and trailing segments collide, so it fails closed and drops the row.
This is fail-safe (it never serves a private repo's row) and negligible for full did:key ids, but for did:web / truncated handles it silently hides legitimate remote activity from the anonymous feed.
Reproduction (by execution)
Local private did:web:host:alice/widget; a remote row for the different owner did:gitlawb:alice, same name, is dropped for anon in both slug forms:
ref_update_row_visible(private did:web:host:alice/widget, anon, "did:gitlawb:alice/widget") -> false
ref_update_row_visible(private did:web:host:alice/widget, anon, "alice/widget") -> false
Fix direction
Carry the full owner DID on the ref-update wire slug (and align the mirror-row bare-key storage) so the gate compares methods instead of a lossy trailing segment. The feed gate could then reuse the did:key-aware normalization used elsewhere (did_matches / DEDUP_CTE) without the fail-open the current short-slug scheme would cause. This is a cross-peer format change, so it needs a compatibility path for older peers.
Context: raised during review of #143 (P1). The gate there is intentionally strict to stay fail-closed given today's lossy slug; this issue tracks the format fix that removes the over-drop without reopening the #112 / #114 leak.
Activity
Gravirei commentedon Jul 2, 2026
taking this one....
test(node): add ref-update owner_did round-trip, DB, and API tests (T…
fix(Twigpine#144): fold in P2 review items
fix(Twigpine#144): add owner_did to local cert events in list_repo_ev…
fix(node): carry full owner DID on ref-update wire event (Twigpine#144)
test(node): add ref-update owner_did round-trip, DB, and API tests (T…
fix(node): add owner_did to GraphQL, broadcast, and REST feed surfaces (
fix(node): carry full owner DID on ref-update wire event (Twigpine#144)
test(node): add ref-update owner_did round-trip, DB, and API tests (T…
fix(node): add owner_did to GraphQL, broadcast, and REST feed surfaces (
fix(node): carry full owner DID on ref-update wire event (Twigpine#144)
test(node): add ref-update owner_did round-trip, DB, and API tests (T…
fix(node): add owner_did to GraphQL, broadcast, and REST feed surfaces (
fix(node): carry full owner DID on ref-update wire event (Twigpine#144)
test(node): add ref-update owner_did round-trip, DB, and API tests (T…
fix(node): add owner_did to GraphQL, broadcast, and REST feed surfaces (
fix(node): carry full owner DID on ref-update wire event (Twigpine#144)
test(node): add ref-update owner_did round-trip, DB, and API tests (T…
fix(node): add owner_did to GraphQL, broadcast, and REST feed surfaces (
fix(node): carry full owner DID on ref-update wire event (Twigpine#144)
test(node): add ref-update owner_did round-trip, DB, and API tests (T…
fix(node): add owner_did to GraphQL, broadcast, and REST feed surfaces (
fix(node): carry full owner DID on ref-update wire event (#144) (#145)
feat(node): sign and verify gossip ref-update events
fix(node): authenticate gossip ref-update events before writing them (T…