451ea08414
web/handlers/standing.go: GET /standing/{reachID} renders standing score
+ bucket + 4-signal progress + Freeholder-eligible badge. Store extensions:
ListRatings/ListVouches/ListSlashes/ComputeStandingScore (simplified, from
locked x/standing/types constants PriorMean/PriorWeight/ComputeDiversityBonus/
GetVoucherWeight/GetStandingBucket — NOT hardcoded)/ComputeFreeholderSignals
(real FreeholderSignals struct + IsFreeholderEligible). Seed: holder-alia
(12 ratings, 4 cats, 1 Vouch, mature Stash -> eligible) vs holder-bryn
(3 ratings, 1 cat, no Vouch, immature -> not eligible). standing_test.go:
computed-from-locked-constants regression guard (PriorMean=4.0, PriorWeight=
10, DiversityBonus4Cats=0.10), Freeholder-eligible badge reflects
IsFreeholderEligible() (the real method), G-026 error lexicon check.
Coverage: store 98.0%, handlers 88.7%.
---ci---
project: oy
phase: 4
milestone: v0.6
status: execute
---/ci---
89 lines
3.5 KiB
HTML
89 lines
3.5 KiB
HTML
{{define "title"}}Standing — OpenYield{{end}}
|
|
|
|
{{define "content"}}
|
|
<section class="panel">
|
|
<h1>Standing — {{.ReachID}}</h1>
|
|
<p>Standing is the Bayesian anti-gaming metric that accrues as a Nomad acts
|
|
on the mesh. It is not bought or transferred — it is earned through honest
|
|
participation, weighted by the standing of the raters, time-decayed, and
|
|
diversified across service categories.</p>
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<h2>Score</h2>
|
|
<table class="kv">
|
|
<tr><th>Reach ID</th><td>{{.ReachID}}</td></tr>
|
|
<tr><th>Standing score</th><td>{{printf "%.1f" .Score}}</td></tr>
|
|
<tr><th>Bucket</th><td>
|
|
{{if eq (string .Bucket) "New"}}<span class="badge grey">New</span>{{end}}
|
|
{{if eq (string .Bucket) "Trusted"}}<span class="badge blue">Trusted</span>{{end}}
|
|
{{if eq (string .Bucket) "Preferred"}}<span class="badge green">Preferred</span>{{end}}
|
|
{{if eq (string .Bucket) "Top"}}<span class="badge green">Top</span>{{end}}
|
|
{{if eq (string .Bucket) "Slashed"}}<span class="badge red">Slashed</span>{{end}}
|
|
</td></tr>
|
|
</table>
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<h2>Freeholder signals</h2>
|
|
<p>The four signals (§9.1) — all four must be present to be Freeholder-eligible.
|
|
No application, no committee, no form.</p>
|
|
<table>
|
|
<thead><tr><th>Signal</th><th>Status</th></tr></thead>
|
|
<tbody>
|
|
<tr><td>Stash maturity (90 days, gap ≤ 30)</td><td>{{if .Signals.StashMaturity}}<span class="badge green">earned</span>{{else}}<span class="badge grey">not yet</span>{{end}}</td></tr>
|
|
<tr><td>Multi-domain standing (≥ {{printf "%.1f" .MinScore}} in ≥ {{.MinCats}} cats)</td><td>{{if .Signals.MultiDomainStanding}}<span class="badge green">earned</span>{{else}}<span class="badge grey">not yet</span>{{end}}</td></tr>
|
|
<tr><td>Committed capital</td><td>{{if .Signals.CommittedCapital}}<span class="badge green">earned</span>{{else}}<span class="badge grey">not yet</span>{{end}}</td></tr>
|
|
<tr><td>Community endorsement (≥ 1 Vouch)</td><td>{{if .Signals.CommunityEndorsement}}<span class="badge green">earned</span>{{else}}<span class="badge grey">not yet</span>{{end}}</td></tr>
|
|
</tbody>
|
|
</table>
|
|
<p>Freeholder-eligible:
|
|
{{if .Eligible}}<span class="badge green">yes</span>
|
|
{{else}}<span class="badge grey">not yet</span>{{end}}
|
|
</p>
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<h2>Ratings ({{len .Ratings}})</h2>
|
|
{{if .Ratings}}
|
|
<table>
|
|
<thead><tr><th>Rater</th><th>Category</th><th>Score</th><th>Timestamp</th></tr></thead>
|
|
<tbody>
|
|
{{range .Ratings}}
|
|
<tr><td>{{.RaterID}}</td><td>{{.Category}}</td><td>{{printf "%.1f" .Score}}</td><td>{{.Timestamp}}</td></tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
{{else}}<p>No ratings yet.</p>{{end}}
|
|
</section>
|
|
|
|
<section class="panel">
|
|
<h2>Vouches ({{len .Vouches}})</h2>
|
|
{{if .Vouches}}
|
|
<table>
|
|
<thead><tr><th>Voucher</th><th>Category</th><th>Bond (Grain)</th></tr></thead>
|
|
<tbody>
|
|
{{range .Vouches}}
|
|
<tr><td>{{.VoucherID}}</td><td>{{.Category}}</td><td>{{.BondAmount}}</td></tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
{{else}}<p>No Vouches yet.</p>{{end}}
|
|
</section>
|
|
|
|
{{if .Slashes}}
|
|
<section class="panel">
|
|
<h2>Slashes ({{len .Slashes}})</h2>
|
|
<table>
|
|
<thead><tr><th>Reason</th><th>Amount</th><th>Attester</th></tr></thead>
|
|
<tbody>
|
|
{{range .Slashes}}
|
|
<tr><td>{{.Reason}}</td><td>{{.Amount}}</td><td>{{.Attester}}</td></tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</section>
|
|
{{end}}
|
|
|
|
<p><a href="/reach/{{.ReachID}}">Back to Reach</a></p>
|
|
{{end}} |