A proposer offers options with stated consequences; an audience responds; the result authorizes nothing unless it was said in advance that it would.
Version: 0.0.0 — STUB, not yet specified
Package: @medicine-wheel/community-choice (does not exist)
Document ID: rispec-community-choice-v0
Last Updated: 2026-09-08
Status: stub for reflection — depends on community-identity, which has a held question
From William, 2026-08-31: “use of my miadi-review within a process where I expose what I’ve reviewed to try to help or process evolve and have people choose within the community in advance.”
That has no type today. Measured on the chronicle store: 0 occurrences of
“poll”, 0 of “vote”. Episode 340 drafted a four-layer packet ending in an
audience poll; it ran once, and its own RETURN-TO-EP339.md asks William to
choose A/B/C — two companion responses later, through 2026-08-31, nobody
answered it.
A review William has made becomes a set of options a community can respond to, where every option states its consequence, at least one path is “don’t act yet”, and the result is a count — never a permission.
community-review — the argument, for challengingThey run in opposite directions.
community-review |
community-choice |
|
|---|---|---|
| participants | bounded, named, role-carrying | unbounded or loosely identified |
| options | none — the circle forms its own outcome | authored in advance by the proposer |
| result | authorizes (a blessing, a merge permit) | authorizes nothing by default |
| consensus | seekConsensus = every reviewer has spoken |
attendance has no denominator here |
ReviewOutcomeType is a closed five-enum and every producer in outcomes.ts
returns the circle’s decision carrying elderBlessing and wilsonCheck.
Adding a poll outcome would make an Elder’s blessing apply to a Facebook
audience.
And seekConsensus (src/community-review/src/consensus.ts:26-33) computes
consensus as all reviewers having spoken — attendance. For a named circle
that is a defensible proxy. For an open audience the denominator does not exist.
Why not consent-lifecycle: a poll response is not a grant. Modelling it
there makes “the audience chose B” readable as “the audience consented to B” —
the single conflation Episode 340 names twice. It is the right owner of the
precondition, hence consentGate below.
type ChoiceAuthority = 'influence-only' | 'advisory' | 'binding'; // default: influence-only
interface SubjectRef { // a reference, never a coupling
kind: 'review' | 'episode' | 'node';
service?: string; // e.g. 'miadi-review'
id: string; version?: number;
url?: string; sha256?: string; // the receipt ep340 computes by hand today
}
interface ChoiceOption {
id: string; label: string;
consequence: string; // REQUIRED — an option without a stated cost is a leading question
deferral: boolean; // at least one path must be "don't act yet"
}
interface ChoiceSet {
id: string; subject: SubjectRef; question: string;
options: ChoiceOption[]; // >= 2
authority: ChoiceAuthority;
boundaries: string[]; // REQUIRED, non-empty — what a response does NOT authorize
consentGate?: string; // a ConsentRecord that must be 'active' before opening
state: 'draft' | 'open' | 'closed' | 'withdrawn';
readingRef?: string; // path to the packet holding the reasoning
}
interface ChoiceResponse { choiceSetId: string; optionId: string; respondent: RespondentRef; at: string }
interface ChoiceResult { counts: Record<string, number>; total: number; byRespondentKind: Record<string, number>; unresolvedDivergence: string[] }
Both are William’s own corrections, made by hand in the only exercise that
has ever run (RETURN-TO-EP339.md: “Challenge two replaced a leading
adopt/reject question with pilot, gather-first, and defer options whose
consequences and limited authority are explicit”):
validateChoiceSet rejects fewer than two options, any option missing
consequence, and an empty boundaries.closeChoiceSet returns a ChoiceResult, never a permission. binding
authority requires an explicit consentGate resolved to active.byRespondentKind exists so an anonymous connector tally can never be silently
added to a count of named members. Facebook and other connectors report
numbers; they never produce a kind: 'member' respondent.
Episode 340’s shape is practitioner source / William’s reading / Miadi proposition / audience poll. Half of each:
What the type takes from 1–3 is not their text but their provenance —
SubjectRef plus readingRef.
community-identity. Without a RespondentRef there is no
way to tell one response from two by the same person, and every count is
unbacked. That package has a held question of its own.storage-provider with jsonl + neon, copying
inquiry-weaves.ts and plan-perspectives.ts? Or in the app that collects
them, with the wheel holding only the ChoiceSet?miadi-review absorbed, referenced, or mirrored? The investigation
concluded stay put, build the seam — the service’s public URLs are
already cited as durable receipts inside the chronicle, and moving the store
orphans every receipt already written.ChoiceSet a wheel node? mw_register_review was proposed so a
review becomes a knowledge node with metadata.kind. A ChoiceSet could
follow, or stay a record. The NodeType union stays closed either way (at eight since 0.17.0).community-review issue #105 proposes binding consensus to a PR
lifecycle. Same verb “choose”, opposite authority. Siblings over the same
storage — and both need the missing MCP verbs that leave a circle stuck in
gathering..guillaume/work/L1-review-to-choice.md — the full argument, 506 lines.guillaume/work/EXECUTION.md step 4rispecs/community-identity.spec.md — the chooser this depends onrispecs/community-review.spec.md — the sibling, not the parentrispecs/consent-lifecycle.spec.md — the gate, not the record