Follow-on from #629, as its own ladder asked: step 1 passes, step 2 fails. The node keys now reach the canonical; no attestation row does — including a consent:replication:v1 grant that the agent did write, federation-scoped, before the round that should have carried it.
Agent side: ciris-server 0.5.215, CIRISAgent five-platform gate run 35896050806. Canonical: 0.5.215 since 17:33Z.
Canonical side (operator, read-only mode=ro)
Agent side: the grant is written, and it's the right scope
From the agent's own database (federation_attestations, gate artifact db-android.db; db-ios.db is identical in shape):
consent:replication:v1
attesting_key_id qa-node-1790186668-… (the OWNER)
attested_key_id ciris-canonical-1-d7bdeu223k
cohort_scope federation
tier federation
admitted_at 2026-09-23T18:05:21.951Z
promoted_at NULL
So this isn't a scoping mistake — the grant is written the way peer.rs::emit_grant_row intends. And it exists six seconds before the round below.
All 19 rows on the agent after the run:
| dimension |
attester |
cohort_scope |
tier |
(3 rows with no dimension — key/occurrence envelopes) |
A1 / agent |
federation |
federation |
| accord:lifecycle:v1 |
A1 |
federation |
federation |
| ownership:responsible_party:node:v1 |
owner |
self |
federation |
| age_self_declared:adult:v1 |
owner |
federation |
federation |
| ownership:responsible_party:node:v1 |
owner |
federation |
federation |
| config:net.announce_ownership:v1 (×2) |
agent |
self |
federation |
| consent:replication:v1 |
owner |
federation |
federation |
| consent:state:granted:v1 (×2) |
owner |
federation |
federation |
| consent:community_trust:v1 (×2) |
agent |
self |
federation |
| consent:community_trust:v1 (×2) |
agent |
federation |
federation |
| consent:partnership_grant:v1 |
owner |
self |
local |
| consent:partnership_accept:v1 |
agent |
self |
local |
| self:delegates_to:agent_occurrence:v1 |
owner |
federation |
federation |
Eleven rows are federation-scoped and signed by keys the canonical now holds. None arrived.
The round that should have carried it (android node log)
18:05:21.951 consent:replication:v1 admitted locally (above)
18:05:27.687 anti_entropy_round{peer=canonical kind=Attestation kicked=true}
attestation send-set resolved (consent ∪ owner-bound ∪ self-collective)
consent=1 owner_routed=0 collective_routed=1 complete=true
18:05:27.698 attestation withheld — recipient not in the row's audience attester=qa-node-… audience="self"
18:05:27.699 attestation withheld — recipient not in the row's audience attester=ciris-agent-… audience="self"
18:05:27.700 attestation withheld — recipient not in the row's audience attester=ciris-agent-… audience="self"
18:05:28.683 CRPL reply ROUTED into our INITIATOR's round inbox kind=TransportDestination (×3)
— no reply routed for kind=Attestation in this window
round timed out waiting for peer reply: 7 over the run
The three withheld rows are correct to withhold. They're audience=self, and the self-scoped rows above match their attesters (owner ×1, agent ×2). A self row belongs on the owner's own nodes, not on the canonical. (The log names neither the row nor its dimension, so I can't say which self rows they were.)
The federation rows are invisible in that log either way. In bridge.rs the audience filter has Audience::Federation => true and only logs on withhold, so a federation row that passes produces no line. The log can't tell us whether the grant was in the offer.
The question
The grant was written, scoped to federation, before the round. So either:
- it was not in the round's offer — something between "admitted locally" and "advertised" (the publish-own set, the send-set's per-scope reach, CIRISPersist#884) doesn't include an owner-signed federation row on a split home; or
- it was offered and the round never completed — the Attestation round got no reply we can see (only
TransportDestination replies routed back) and rounds kept timing out, so nothing transferred.
Separating these needs one of:
- the canonical's view of what the
qa-node-*/agent peers offered in Attestation rounds after 17:44Z — any summary or inbound frame from them for kind=Attestation; or
- edge naming each row offered and each row withheld (row id + dimension) at debug. Today's withhold line carries
peer, attester, audience, site only, and rows that pass the filter aren't logged at all — so raising RUST_LOG on our side won't list them. We already run ciris_edge=debug.
Not this
- The grant's scope. It's
federation, as intended. The audience="self" lines are self-plane rows being withheld correctly.
- The
c3dc6f27… Key refusal. Still logged, confirmed non-blocking earlier.
- CIRISClient#66 — macOS stuck on Startup after the run-without-AI hand-off. That's a client issue and unrelated to this.
Refs #629, #628, CIRISPersist#884, CIRISAgent#1184.
Follow-on from #629, as its own ladder asked: step 1 passes, step 2 fails. The node keys now reach the canonical; no attestation row does — including a
consent:replication:v1grant that the agent did write, federation-scoped, before the round that should have carried it.Agent side: ciris-server 0.5.215, CIRISAgent five-platform gate run 35896050806. Canonical: 0.5.215 since 17:33Z.
Canonical side (operator, read-only
mode=ro)ciris-node-bootstrap-*), the agent key, and the owner (qa-node-*, stored as typeuser). The previousqa-node-*key was from 2026-09-08; on 0.5.214 only the agent key ever arrived. 0.5.214: the consent:replication grant is authored on the agent (prefixes include trace:) but never reaches the canonical — no kind=Attestation round is ever scheduled #629's fix works.Agent side: the grant is written, and it's the right scope
From the agent's own database (
federation_attestations, gate artifactdb-android.db;db-ios.dbis identical in shape):So this isn't a scoping mistake — the grant is written the way
peer.rs::emit_grant_rowintends. And it exists six seconds before the round below.All 19 rows on the agent after the run:
dimension— key/occurrence envelopes)Eleven rows are federation-scoped and signed by keys the canonical now holds. None arrived.
The round that should have carried it (android node log)
The three withheld rows are correct to withhold. They're
audience=self, and the self-scoped rows above match their attesters (owner ×1, agent ×2). Aselfrow belongs on the owner's own nodes, not on the canonical. (The log names neither the row nor its dimension, so I can't say which self rows they were.)The federation rows are invisible in that log either way. In
bridge.rsthe audience filter hasAudience::Federation => trueand only logs on withhold, so a federation row that passes produces no line. The log can't tell us whether the grant was in the offer.The question
The grant was written, scoped to federation, before the round. So either:
TransportDestinationreplies routed back) and rounds kept timing out, so nothing transferred.Separating these needs one of:
qa-node-*/agent peers offered in Attestation rounds after 17:44Z — any summary or inbound frame from them forkind=Attestation; orpeer,attester,audience,siteonly, and rows that pass the filter aren't logged at all — so raisingRUST_LOGon our side won't list them. We already runciris_edge=debug.Not this
federation, as intended. Theaudience="self"lines are self-plane rows being withheld correctly.c3dc6f27…Key refusal. Still logged, confirmed non-blocking earlier.Refs #629, #628, CIRISPersist#884, CIRISAgent#1184.