Skip to content

Attribution requires Rooted, no production agent can root, and the self-attribution hole that hid it is closed: the trace plane has been dark since 2026-09-18 #659

Description

@emooreatx

Attribution requires Rooted, no production agent can be Rooted, and the hole that hid it is now closed — the trace plane has been dark since 2026-09-18

Full RCA with the read-only evidence: CIRISAI/CIRISServer#632 (comment of 2026-09-23). The short form, and the ask.

What happened

The ask: separate attribution from rooting

Attribution answers who sent this frame. Rooting answers what this peer may be served. The gate conflates them, and your own comments already draw the line ("routing ≠ trust", "served no trace:*").

Proposed rule — a frame is attributed to key K when:

  1. the link's proven transport identity equals the transport identity in a hybrid-verified SignedTransportDestination for K (today's item 2), and
  2. K's registered pubkey matched at cold start (owns_key, i.e. any rejection after the pubkey match, or Confirmed).

provenance (Rooted / Advisory) is carried on the attributed source and gates serving exactly as it does now; the trace:* serve gate stays Rooted-only. ResolvedToSelf stays a drop. Admission stays the trust boundary — persist hybrid-verifies every row against the directory under Strict and refuses an unregistered attester regardless of which link carried it, so attributing on the transport binding widens nothing at rest.

This makes the bootstrap carve-out the general case rather than an exception: a peer whose Key + TransportDestination crossed (both verified at admission) is thereby attributable; a peer that never proved control of its transport identity is not.

Three observability asks, from the same day

They each cost an inference step that the log should simply have stated:

  1. the cold-start rooting rejection is logged only at debug — an operator never learns why a peer is Advisory (UnknownKeyId vs NotRootedAtSteward is the whole story here);
  2. link_attribution_miss_log throttles per key, so after the first miss every further drop is silent (suppressed_prev=22 on a canonical that was dropping every frame);
  3. the (Advisory, owns_key=true) hint says "a churn downgrade (owner reroute overwrote a Rooted binding)" — for a peer that was never Rooted (stored_provenance=None), which sent the first read of feat(25.4.0): adopt CIRISPersist v44.8.0 — the consent scope grammar; the transfer grant's principle is pinned to propagate #632 the wrong way.

The unthrottled DIAG#632 lines used for this RCA (attribution operands incl. item 2; every advisory admit with its rejection; every door decision with both identities) are on a throwaway worktree at v29.5.0; happy to send them as a PR if you want them as the permanent shape.

Refs: CIRISServer#632 (RCA), CIRISServer#607, #621/#623, #636, #393.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions