Conflicts without disclosure
Each member keeps a conflicts ledger of hashes only. A Task's parties are checked against it mechanically, and no one, the brand included, learns what matched.
How does a Pool keep a member off work they have a conflict on, without anyone learning the conflict?
clear.check names the party inputs a Task's parties come from. The legal example checks three:
cat pools/attorneys.ts clear: { attest: ['I checked conflicts across my full book, including my firm'], check: ['client', 'applicant', 'recipient'] },A member adds the parties they can't act against, in their own session. Each name, email and organization is hashed before anything is kept, with a key of the member's own made when they joined. So no two ledgers can be pooled, and the brand can neither read one nor test a name against it. A ledger only grows:
→ POST /me/ledger {"name":"Initech","org":"Initech Inc"} # as mbr_eligible{
"object": "list",
"data": [
{
"hash": "sha256:c54368f1ea6c537b0c017f2fdf6c2875087c2583225d9c1aa3542ead950c4436"
},
{
"hash": "sha256:2097647525c65b3e441ae863872c7050af5c6cdc95bf87c9aa92983eb4f19941"
}
],
"has_more": false,
"url": "/me/ledger",
"simulated": true
}The ledger is checked at every offer and again when the member clears the Task. A cascade skips a conflicted member, and a claim they try anyway is refused on the conflict predicate. Its cure is none, and it names no entry:
→ GET /reviews # as mbr_eligible← 0 Tasks: the cascade skipped a conflicted member
→ POST /reviews/tsk_7Hq2/claim # as mbr_eligible
← 403 ineligible · conflict: A party on this review matches an entry in mbr_eligible's conflicts ledger.
cure None for this Task: your ledger stays yours, and no one learns which entry matched.A member reads every check of their own ledger at GET /me/ledger/checks: the Task, when, how many parties, and whether one matched. No one else sees any.
Nothing of it. The ledger is a member's own, and the owner console holds no hash of it, on any Task, job, export or event:
→ GET /me/ledger # the owner console, with no member session← 403 needs_a_person: Only a signer, in their own session at http://localhost:8787/attorneys, does this. A key never can.
# what the owner reads: /owner/tasks no hash of it · /owner/jobs/job_7Hq2 no hash of it · /owner/jobs/job_7Hq2/export no hash of it · /owner/events?limit=1000 no hash of itA conflict found after the claim is a recusal: the member steps aside, nothing accrues and nothing is scored, and the parties they name join their ledger. The Task opens again for another member, and the one who stepped aside is never offered that subject's Tasks again: separation, the fifth predicate. The client reads that a professional stepped aside, never why. What a person can do has the call.
The mechanical check is the sixth predicate. The seventh is the member's own word: they attest each clear statement before the packet opens, as What a member sees shows.
When a member works in a firm, the firm's ledger joins the check: Pool.firms.
| Key | Written | Left out | Does |
|---|---|---|---|
clear | string[] | { attest: string[]; check?: string[] } | none | What a member attests before the packet opens, and the party inputs checked, hashed, against their ledger. |