mergedhumanPR #290Trust
[Fellowship Challenge] trust: reputation.capped.v1, a per-observer influence cap
trust/reputation.v1 sums +1/-1 per receipt with no bound on how much any single observer can move a score. reputation_consistent is explicit that it checks the recorded claim, not whether the reporter told the truth or held authority.
Author
@adarsh-jha-dev
github profile →- Status
- Merged
- Merged on
- Oct 12
- Branch
- challenge/adarsh-jha-dev-capped-influence
Description
The pitch.
````md
# Submission for the Hexaware × Project NANDA Fellowship Technical Challenge
## The Gap
`trust/reputation.v1` sums `+1/-1` per receipt with no bound on how much any single observer can move a score. `reputation_consistent` is explicit that it checks the recorded claim, not whether the reporter told the truth or held authority.
One agent filing **N distinct bad receipts** against an honest seller drives that seller's score to `-N`, and every check still passes because each individual update follows the reference formula exactly. Volume from one voice, nothing forged.
This is not hypothetical. `registry_layer.py:51` sorts discovery by `-trust.score(name)`, and the reference buyer queries only the top two (`agents.py:105`). Five bad receipts from one agent that never trades, against three honest sellers:
```text
reputation.v1 s-honest -5 top2 ['s-rival-a','s-rival-b'] reached: NO
reputation.capped.v1 s-honest 0 top2 ['s-honest','s-rival-a'] reached: yes
````
The slandered seller is ranked last and never receives a quote request: an availability attack with no defence and no detection.
## This Is Not a Re-submission of Earlier Trust Work
No trust plugin other than `reputation.v1` exists on current `main` (`git ls-tree origin/main` shows only `layers/trust.py`).
The earlier submissions — EigenTrust (#2, #3, #6), TrustGuard (#27, #218), SybilResistantTrust (#139), WeightedTrust (#185), receipt-corroboration (#26), attested-peering (#149), and `bonded_trust` (#53) — live in `packages/nest-plugins-reference/` on `archive/legacy`, target `score_average`, and are `async`. None of that package tree or that reference plugin survives the rebuild.
The closest by mechanism is #53, `bonded_trust`, and it makes the opposite commitment on the same axis. Its docstring states that:
> a reporter holding a bond *majority* can dominate the sign of a score — that is the intended "most skin in the game, most say"
It bounds influence by **spent bond, independent of identity count**.
This plugin bounds influence **per observer, independent of standing**: no reporter can move a score by more than `1`, however much it has traded.
`bonded_trust` is a float bond-weighted mean over an injected `StakeLedger`; this is an integer sum of per-observer clamped contributions over an event the town already records.
One decides **who gets to dominate**; this one decides that **nobody does**.
They compose — an admission price and an influence bound are different questions — but they are not substitutes.
## The Layer
`trust`, and only `trust`.
New plugin: `reputation.capped.v1` (`src/nandatown/layers/trust_capped.py`), registered alongside `reputation.v1`, which is byte-identical to `origin/main`.
```text
score(subject) = sum over distinct observers of
weight(observer) * clamp(net(observer, subject), -1, +1)
net = goods minus bads that observer reported about subject
weight = 1 if a settled payment names the observer, else 0
```
One observer can move a score by at most `1`, regardless of how many receipts it files.
An observer with no settled trade of its own moves nothing.
Distinct observers still accumulate, so the cap limits **a voice**, not the score.
A discarded report is still emitted with:
```json
{
"delta": 0,
"reason": "observer_cap_reached"
}
```
or:
```json
{
"delta": 0,
"reason": "observer_has_no_settled_trade"
}
```
The suppression is therefore present in the trace rather than absent from it.
## The Fault Is the Participant, Not a `FaultRule`
Neither scenario declares a `faults:` key, so the report prints:
```text
Faults: none
```
That is deliberate.
The fault is a new `slanderer` role (`src/nandatown/sim/agents.py`) that:
* registers,
* never trades, and
* files five attributed bad receipts about `seller-honest` at `0.5` logical-second intervals.
`FaultRule` offers only `dro
…Try it
Open PR on GitHubView diffCheckout locally
git fetch origin pull/290/head:pr-290
git checkout pr-290