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.
The cross-repo ref-update feeds (
refUpdatesGraphQL #112,GET /api/v1/events/ref-updatesREST #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:aliceanddid:gitlawb:aliceboth emitalice/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:keyids, but fordid: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 ownerdid:gitlawb:alice, same name, is dropped for anon in both slug forms: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.