Skip to content

I3609 — A claim replayed after a re-attach keeps the time it was made, and an announce answers with the claim it made

When the MCP bridge replays a client's claims onto the board after a re-attach, carry each claim's original time rather than stamping it now, and make an announce answer with the announcement it just made, not with whichever claim of the peer sorts last.

READY wave 0 · p1 · implementation profile · parallel safe

Part of surfaces-never-disagree — Every surface projects the same state, says when it was observed, and keeps no list of its own.

Ready. Every dependency is done, so majordomus plan start I3609 will be accepted.

Objective

When the MCP bridge replays a client's claims onto the board after a re-attach, carry each claim's original time rather than stamping it now, and make an announce answer with the announcement it just made, not with whichever claim of the peer sorts last.

Why

On 2026-10-20 at 20:35Z the board connection of session d3 re-attached, and the bridge replayed its ten claims. Every one came back stamped 20:35:43Z: 'site-probe-split', written at 09:37Z and long superseded, read as the newest work on the board. The same call's announce answer named 'ui-trains' as its announcement although the claim announced was 'mesh-session-findings', because Peer::announcement is the claim with the latest time, every time was equal, and the tie went to the last name. A board that re-dates stale work says nothing true about when anything happened.

Current state

mcp/bridge.rs replays each remembered claim through announce after Bridge::reinitialize. PeerBoard::announce_claim stamps `at` with SystemTime::now(). PeerBoard::latest takes max_by `at`, and among equal times it returns the last in key order.

Desired state

The bridge stamps a claim with made_at when the server first accepts it, a replay or a takeover carries it, and the board keeps a made_at in the past as the claim's `at` (a newer or unparsable one is replaced by now), so a replayed claim is as old as it was. A server older than made_at, which refuses the unknown field, gets the claim again without it rather than not at all. announce answers with the announcement it made, and Peer::announcement breaks ties by the most recent announce call, never by name.

Scope

  • apps/majordomus-cli/src/peers.rs
  • apps/majordomus-cli/src/mcp/bridge.rs
  • apps/majordomus-cli/src/capability/builtin/peers.rs
  • apps/majordomus-cli/src/commands/mcp.rs

Out of scope

  • The mesh journal's own claim times, which are lamport-ordered events

Dependencies

None. This issue is a root of the graph.

Acceptance criteria

  • A claim replayed after a re-attach keeps the `at` it was announced with
  • announce answers with the announcement it made, whatever the peer's other claims are called
  • Among claims with equal times, Peer::announcement is the one announced last
  • A made_at in the future or one that does not parse is replaced by now, and a replay that a server refuses for made_at is sent again without it

Validation

  • bin/majordomus plan validate
  • cargo test --lib peers
  • cargo test --lib mcp::bridge

Evidence required

  • a_replayed_claim_keeps_its_time_test

Evidence

None recorded. Every token above needs a command or an artifact behind it before this issue can be completed; narrative is refused.

Timeline

started
—
verified
—
completed
—

Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.

Canonical record: .ai/repo/project/issues/I3609.yaml. Read it back with majordomus plan show I3609.

Searches the titles and descriptions of every page this site publishes.