Skip to content

Firehose #commit omits prevData, breaking inductive verification on strict relays #169

@simnaut

Description

@simnaut

Summary

Cirrus's firehose #commit events (com.atproto.sync.subscribeRepos#commit) omit the prevData field. Per the lexicon, prevData is the MST root CID of the previous commit (corresponding to the since rev) and is "effectively required for the 'inductive' version of firehose." Without it, relays running strict commit validation cannot verify cirrus commits and reject every commit after the first, freezing the repo.

Evidence

A cirrus #commit frame currently contains only:
[blobs, blocks, commit, ops, rebase, repo, rev, seq, since, time, tooBig] — no prevData.

The reference relay (indigo) cmd/relay/relay/verify.go:

// first commit from an unknown account (prevData nil) is accepted unverified
if prevRepo == nil && evt.PrevData == nil { return nil }
if evt.PrevData == nil { return fmt.Errorf("missing prevData field") }

Behavior is gated by Config.LenientSyncValidation: strict relays drop the event (repo freezes); lenient relays index it unverified (warning only).

Observed on two independent cirrus repos — did:web:simnaut.io and did:plc:uwbl4k3tza7eyjv3morkrld2. On the latter, two relays read the firehose to the same cursor (seq 6205), yet a strict relay (relay.feeds.blue) is frozen 106 days at 3me7toj67qs2c while a lenient relay (bsky.network) is at head 3mmk5tdw2mc27. Same input, divergent state — purely strict-vs-lenient. The relay.feeds.blue operator confirmed they run standard indigo with LenientSyncValidation off (deliberate strict mode, not an outdated build), and their logs show "commit message failed verification ... err: missing prevData field". As more relays tighten validation, this breaks cirrus federation more widely.

Fix

The previous commit's MST root is already in scope at every write call site in account-do.ts (the repo object captured before applyWrites, alongside the existing prevRev). Populate prevData = repo.commit.data:

  • packages/pds/src/sequencer.ts: add prevData: CID to CommitData and CommitEvent; set prevData: data.prevData in sequenceCommit's eventPayload (it then flows through the existing CBOR encoder automatically).
  • packages/pds/src/account-do.ts: in rpcCreateRecord, rpcDeleteRecord, rpcPutRecord, rpcApplyWrites, add prevData: repo.commit.data to the CommitData (next to since: prevRev).
  • Update test/firehose.test.ts to assert prevData equals the prior repo.commit.data, and scripts/verify-firehose.ts's CommitEvent interface.

Related: #167 (getLatestCommit) is a separate conformance gap, not the indexing blocker. Fixed by #170.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions