Expand description
Who an actor is, from what the log already says about them (D63).
Nothing here is new state. Every number is counted out of the same
/api/view body the caller could fetch themselves; the point is that
nobody does, because the answer to “should I trust this reviewer” is
spread across four sections of a document that is mostly about
something else.
It derives from the view the caller may already see, never from the
raw one. That is the whole ACL story: a profile cannot disclose a
change, review or check that /api/view would have withheld, because
it is looking at the withheld copy. A second filter here would be a
second thing to keep right, and the first time the two disagreed the
profile would be the one that leaked.
D24’s Sybil resistance wants key age, vouches, scoped grants and
bonds. Two of the four are persisted now — key age as
KeyBinding::bound_at, and the vouch graph as View::vouches
(D65) — and this reads both. Bonds do not exist. Scoped grants do,
as of D66, but not in a form this can report: a time-locked grant
lives in the ACL file and the account store, never in the log, so it
is invisible to a reading of the view and stays named here rather
than counted.
There is deliberately no score. Two inputs are not more scoreable than one: any weighting of age against vouches is a claim about how much an endorsement is worth, which nothing here has measured, and a number would read as that measurement while being a guess. The reader gets the inputs.
Vouches are operator-scoped, and the profile says so. They are
edges between operator identities, so a page about the channel
ops/agent shows what was vouched to ops — which is the truth, and
is why the operator is named in the section rather than left for a
reader to infer from a name that does not match the heading.
§Examples
// Shaped the way `/api/view` really answers, which is the whole
// reason this example is worth reading: `next_seq` lives inside
// `log`, and an example that put it anywhere else would document a
// response no node sends.
let view = serde_json::json!({
"log": { "next_seq": 100 },
"bindings": {
"b3:aa": { "operator": "ops", "channel": "alice", "bound_at": 40 }
},
"changes": { "c1": { "owner": "alice" } },
"reviews": {},
"checks": {},
// Subject -> voucher, the direction the fold stores. `bob`
// vouches for `alice`, and `alice` does not vouch back.
"vouches": { "alice": { "bob": { "at": 55, "note": "shipped the parser" } } },
});
let profile = choir_node::profile::of(&view, "alice");
assert_eq!(profile["channel"], "alice");
assert_eq!(profile["changes"]["owned"], 1);
// 100 ops have been sequenced, 40 of them before this key existed.
assert_eq!(profile["keys"][0]["ops_since_binding"], 60);
assert_eq!(profile["vouches"]["operator"], "alice");
assert_eq!(profile["vouches"]["received"][0]["voucher"], "bob");
assert_eq!(profile["vouches"]["received"][0]["reciprocal"], false);
assert_eq!(profile["vouches"]["given"], 0);Functions§
- of
- Counts one actor’s standing out of a view body.