Skip to content

Commit 910fa59

Browse files
authored
docs(policy): contributor relationships and recourse, with the mechanism behind each claim (#9981)
Two things that should be written down before anyone needs them -- how contributor relationships are handled, and what recourse exists when a contributor believes a verdict was wrong -- existed only in practice and scattered discussion. This is the page to point at. Every claim names what enforces it, because a policy whose enforcement cannot be checked is a promise, and this project's whole posture is to publish fewer promises and more mechanisms. Each mechanism was read before being cited: uniform pipeline the gate's inputs contain no author identity field; where identity IS read it comes from the repo's own GitHub permissions at event time, never a maintained list -- priority-label-eligibility.ts, author-association.ts label eligibility priority-label-eligibility.ts (#9737) and priority-eligibility-window.ts (#9738), both already documented in full on the label-policy page immutability REEVALUATION_REASONS' closed set in decision-record.ts (#9742), and why closed: so re-evaluations can be COUNTED by cause without interpreting free text parity review-parity-rollups.ts (#9743), published under reviewParity at /v1/public/stats and recomputable from a ledger export reversal detection recordReversalSignals in outcomes-wire.ts, published on /fairness The recourse section is deliberately not an appeals process, and says so. It documents what exists: offline verification first (it does not depend on anyone agreeing with you), automatic detection of wrong closes via outcome confirmation (stronger than an appeals queue -- it measures the mistakes that happened, not the ones somebody contested), and resubmission, which is not a workaround but a property of the ledger key: a record is `record:<repo>#<pr>@<head sha>`, so a new head SHA is a fresh verdict by definition. It also states plainly why no human appeals queue exists -- timing, since open issues are typically re-solved before an appeal could conclude; and selection, since re-running only contested verdicts makes the published accuracy figure describe complaint volume rather than behaviour. Disclosure is called out as the one item a mechanism does NOT enforce, rather than being blended in with the ones that are. The rules above mean it needs no elevated trust anyway: priority eligibility is decided by issue authorship read from GitHub, and the window applies to every PR regardless of author. Linked from the label-policy page and CONTRIBUTING, per the issue's placement requirement, and registered in the docs sidebar (which docs-nav.test.tsx enforces for every published page). Closes #9746
1 parent 7ae72ae commit 910fa59

4 files changed

Lines changed: 179 additions & 0 deletions

File tree

CONTRIBUTING.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ closes the PR. Recover by opening a **fresh, corrected PR**. PRs touching guarde
4444
review engine, migrations, and similar — the set varies) are held for manual review rather than
4545
auto-acted.
4646

47+
**If you think a verdict was wrong.** Every verdict is independently verifiable offline, wrong closes
48+
are detected automatically by outcome confirmation rather than by anyone filing a report, and the
49+
remedy for a contested close is resubmission — a new head SHA earns a fresh verdict through the same
50+
gate. There is deliberately no human appeals queue; the reasons are written down rather than left
51+
implicit. See [relationships and recourse](https://loopover.ai/docs/contributor-relationships).
52+
4753
**If we close your PR by mistake, that's on us.** We may reopen or re-review at our discretion as time
4854
permits — there is no fixed window, and opening a fresh PR is usually fastest.
4955

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
---
2+
title: Contributor relationships and recourse — the policy, and what enforces each part of it
3+
description: How contributor relationships are handled, and what recourse exists when you believe a verdict was wrong. Every claim on this page names the mechanism that enforces it, and the honest limits are stated as plainly as the guarantees.
4+
eyebrow: Contributors
5+
---
6+
7+
Two things should be written down before anyone needs them: how contributor relationships are
8+
handled, and what you can do when you believe a verdict was wrong. Both existed in practice and in
9+
scattered discussion. This page is the one place to point at.
10+
11+
Everything below names the thing that enforces it. A policy whose enforcement you cannot check is a
12+
promise, and the whole point of this project is to publish fewer promises and more mechanisms.
13+
Where a guarantee does not exist, this page says so rather than describing an aspiration.
14+
15+
## The uniform pipeline
16+
17+
**Every pull request goes through the same gate.** There is no per-contributor configuration, no
18+
allowlist that skips a check, and no reviewer discretion applied to one author and not another.
19+
20+
That is not a matter of restraint. It is a property of the shape: the gate reads the diff, the
21+
linked issue, the repo's own `.loopover.yml`, and the calibrated thresholds — and none of those
22+
inputs contain the author's identity. There is no field for it to enter through.
23+
24+
Where identity *is* read, it is read from the repository's own permissions at the moment of the
25+
event, never from a list maintained by anyone:
26+
27+
- **Maintainer-of-record** is derived from the repo's GitHub permissions
28+
(`src/review/priority-label-eligibility.ts`), so the rule generalizes to any repo the Orb manages
29+
and cannot be edited to favour a person.
30+
- **Author class** — maintainer, contributor, or unknown — comes from GitHub's own
31+
`author_association` on the event (`src/github/author-association.ts`). As the parity module puts
32+
it: *no maintained list of people, and a permissions change upstream changes the class with no
33+
code change here.*
34+
35+
<Callout variant="note">
36+
The absence of a per-contributor override is the load-bearing part, and it is the hardest thing to
37+
prove by reading a policy page. The check that actually settles it is the published parity data
38+
below: if some contributors were being treated differently, the per-author-class comparison is
39+
where it would show up, and that comparison is computed from the ledger you can download.
40+
</Callout>
41+
42+
## Label eligibility, and why it is a rule rather than a judgement
43+
44+
`gittensor:priority` carries the highest scoring multiplier, which makes it the one label whose
45+
application cannot be left to discretion — otherwise the highest-value label is whatever anyone says
46+
it is. Two mechanical rules constrain it, both covered in full on the [label policy](/docs/label-policy)
47+
page:
48+
49+
| Rule | What it does | Enforced by |
50+
| --- | --- | --- |
51+
| **Author-based eligibility** | `gittensor:priority` is only valid on a maintainer-authored issue. Applied to anyone else's issue — *by anyone, including a maintainer* — it is stripped and the reason stated once. | `src/review/priority-label-eligibility.ts` |
52+
| **Open window** | A PR closing a priority-labeled issue becomes gate-eligible only once the label has been publicly visible for the configured window (30 minutes by default, per repo). | `src/review/priority-eligibility-window.ts` |
53+
54+
The window exists because first-come pickup is only fair if everyone can *see* an issue before
55+
anyone can act on it. A PR opened moments after the label lands means the gap between "this issue
56+
became valuable" and "this issue was claimed" was effectively zero for everyone else watching.
57+
58+
A PR that arrives inside the window is **held, not rejected** — it gets a neutral comment stating
59+
the moment it becomes eligible, and proceeds from there. Being early costs you nothing but time.
60+
61+
## Disclosure
62+
63+
Personal relationships between maintainers and active contributors are disclosed to the project
64+
record. Associated pull requests follow the standard pipeline, with **no elevated label
65+
eligibility** — which, given the rules above, is not a commitment anyone has to be trusted to keep:
66+
priority eligibility is decided by issue authorship read from GitHub, and the window applies to
67+
every PR closing a priority issue regardless of who opened it.
68+
69+
Disclosure is a process commitment rather than a mechanical one, and it is listed separately here
70+
for that reason. It is the one item on this page that a mechanism does not enforce.
71+
72+
## Verdict immutability
73+
74+
A verdict recorded against a given head SHA is not revised in place. Re-evaluating the *same* head
75+
SHA requires a declared cause from a closed set — `scheduled_recheck`, `pipeline_error`,
76+
`config_change`, `upstream_state_change`, `maintainer_request`
77+
(`REEVALUATION_REASONS`, `src/review/decision-record.ts`) — and the cause is written into the
78+
ledger row.
79+
80+
The set is closed deliberately, so an outsider can **count re-evaluations by cause** without
81+
interpreting free text. That count is published: see `reviewParity.reevaluations` and the
82+
`byReason` breakdown at `/v1/public/stats`.
83+
84+
This is the mechanism that makes the recourse section below honest rather than stingy. If verdicts
85+
could be quietly re-run on request, the selection problem returns immediately — re-running only the
86+
verdicts somebody complained about produces a published accuracy figure that means nothing.
87+
88+
## The parity data
89+
90+
Per-author-class rollups are computed from `decision_records` alone and published at
91+
`/v1/public/stats` under `reviewParity` (`src/review/review-parity-rollups.ts`). Because they are
92+
derived from the ledger and nothing else, you can recompute them yourself from an export rather than
93+
taking the published numbers on faith — that is what [verify this review](/docs/verify-this-review)
94+
walks through.
95+
96+
`unknown` is reported as its own class rather than folded into either side. The comparison *is* the
97+
product, so quietly bucketing unknowns would bias exactly the thing being measured.
98+
99+
The [automation rate](/docs/fairness-methodology) — the share of pull requests decided with no human
100+
in the path — is published on the same surface and from the same ledger.
101+
102+
## Recourse
103+
104+
Read this section as a description of what exists, not as an appeals process. Some of it is stronger
105+
than an appeals process and some of it is weaker, and both are stated plainly.
106+
107+
### 1. Check the verdict yourself, offline
108+
109+
Every verdict is independently verifiable without asking anyone's permission and without any
110+
credentials. Start at [verify this review](/docs/verify-this-review), or run:
111+
112+
```bash
113+
npx -p @loopover/mcp loopover-verify
114+
```
115+
116+
This is the first stop for "I think this is wrong", and it is deliberately first: it does not depend
117+
on anyone agreeing with you. If a published commitment does not recompute, that is a fact you can
118+
demonstrate rather than a position you have to argue.
119+
120+
### 2. Wrong closes are detected without anyone filing anything
121+
122+
The system audits its own mistakes. Outcome confirmation scans what actually happened to the pull
123+
requests the engine acted on — merged, reopened, reverted, superseded — and records a reversal when
124+
a human overturned a terminal engine action (`recordReversalSignals`, `src/review/outcomes-wire.ts`).
125+
Those reversal rates are published on [the fairness report](/fairness).
126+
127+
So a wrong close is counted against the published accuracy figure whether or not you say anything.
128+
Reopening a PR the gate closed in error *is* the signal — no separate report is needed for it to
129+
register.
130+
131+
<Callout variant="note">
132+
This is the part that is genuinely stronger than an appeals queue. An appeals queue measures the
133+
mistakes somebody bothered to contest; outcome confirmation measures the ones that actually
134+
happened, including the ones nobody complained about, and publishes the rate either way.
135+
</Callout>
136+
137+
### 3. The remedy for a contested close is resubmission
138+
139+
A new head SHA earns a fresh verdict through the same pipeline. This is not a workaround — it is how
140+
the ledger is keyed: a decision record is `record:<owner/repo>#<pr>@<head sha>`, so a force-push or
141+
new commits produce a new verdict by definition, and the decision-record module says so explicitly:
142+
*a new head SHA is NOT a re-evaluation and needs no code — that path is a fresh verdict by
143+
definition.*
144+
145+
Push a fix, or open a fresh PR. Both go through the identical gate.
146+
147+
### 4. There is no human appeals queue, and why
148+
149+
Two reasons, both structural:
150+
151+
- **Timing.** In a first-come issue market, an open issue is typically re-solved by somebody else
152+
before any appeal could conclude. An appeals process that resolves after the work has been redone
153+
has not helped the person who filed it.
154+
- **Selection.** On-demand re-evaluation of judgement verdicts reintroduces exactly the problem
155+
verdict immutability exists to prevent. If the verdicts that get re-run are the contested ones,
156+
the published accuracy figure stops describing the system's behaviour and starts describing its
157+
complaint volume.
158+
159+
The honest summary: recourse here is verification, automatic detection, and resubmission. It is not
160+
someone re-deciding your case on request, and this page would rather say that than imply otherwise.
161+
162+
## If something here is wrong
163+
164+
If a claim on this page does not match what the code does, that is a defect in the page and worth
165+
reporting as one. Every mechanism is named above precisely so the claim and the code can be compared
166+
without taking anyone's word for it.

apps/loopover-ui/content/docs/label-policy.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,9 @@ Rule id: `priority-eligibility-window`.
6767

6868
The multiplier *values* themselves are registry-side and are not set here. These two rules govern
6969
which issues may carry the label and when work on them opens — not what the label is worth.
70+
71+
## Related
72+
73+
Both rules above are part of the wider contributor-relationship policy — how relationships are
74+
handled, and what recourse exists when you believe a verdict was wrong. See
75+
[relationships and recourse](/docs/contributor-relationships).

apps/loopover-ui/src/components/site/docs-nav.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export const docsNav: DocsGroup[] = [
105105
{ to: "/docs/branch-analysis", label: "Branch analysis" },
106106
{ to: "/docs/scoreability", label: "Scoreability" },
107107
{ to: "/docs/label-policy", label: "Label policy" },
108+
{ to: "/docs/contributor-relationships", label: "Relationships & recourse" },
108109
{ to: "/docs/upstream-drift", label: "Upstream drift" },
109110
{ to: "/docs/backtest-calibration", label: "Backtest & calibration" },
110111
{ to: "/docs/verify-this-review", label: "Verify this review" },

0 commit comments

Comments
 (0)