Finalizes the docs section after an adversarial audit (code review + per-page fact-check + coherence critic) and two content requests. - Accuracy: fixed 10 invented cross-link slugs, the admin-vs-board gating claims the verifiers caught (permissions matrix, /settings, invites, onboarding, connect-payments, proposal withdraw, Stripe reconciliation, member fields, door.operate), and 2 issues in the new pages (project area-at-creation, forum thread-delete role). - Coverage: added 5 how-to pages so every module is documented (recurring Stripe dues, tasks & chores, projects, comms & forum, ops knowledge base + secrets vault). 34 pages total. - Screenshots: 12 captioned app screenshots under public/docs-media/, embedded as figures. Each tutorial now has 2-3 step screenshots. - Style: removed all em-dashes/en-dashes/ellipses from the docs (natural ASCII punctuation). - Handoff (docs/HANDOFF-audit-cleanup.md) updated with the current state. typecheck 0 · lint 0 errors · build ok (all 34 /docs pages prerendered)
6.7 KiB
The governance kernel is three linked entities (proposals, incidents, and policies) plus the enums and computed fields that drive async voting, code-of-conduct tracking, and versioned bylaws. This page enumerates every enum value, field, and lifecycle state defined in the schema. It backs the app screens at /proposals, /incidents, and /policies, and the how-to guides Run a proposal, Handle incidents, and Publish a policy.
Proposals
A proposal is an async vote in a space. Members read and cast; admin and board members transition status. Tallies are recomputed by trigger on every vote.
proposal_type
| Value | Meaning |
|---|---|
bylaw_change |
Amend a policy; usually cites a clause via policy_ref_id |
board_action |
A board decision put to a vote |
membership_vote |
A vote on a membership matter |
advisory_poll |
Non-binding poll (the default) |
recall |
Vote of confidence / recall |
budget |
Budget or spending decision |
The column default is advisory_poll.
proposal_status
| Value | Meaning |
|---|---|
draft |
Editable by the proposer; not yet open for votes |
open |
Voting window active; votes accepted |
decided |
Closed with a recorded outcome |
withdrawn |
Retracted before decision |
expired |
Voting window elapsed without a decision |
The column default is draft. Votes are only accepted while status = 'open' and the current time is within voting_opens_at and voting_closes_at.
threshold_rule
Determines what fraction of yes-plus-no votes is required to pass.
| Value | Passes when |
|---|---|
simple_majority |
yes > no |
two_thirds |
yes * 3 >= (yes + no) * 2 |
three_fourths |
yes * 4 >= (yes + no) * 3 |
unanimous |
no = 0 and yes > 0 |
A proposal passes only if quorum is met and at least one non-abstain vote exists. The column default is simple_majority.
vote_position
| Value | Counts toward quorum | Counts toward threshold |
|---|---|---|
yes |
Yes | Yes |
no |
Yes | Yes |
abstain |
Yes | No |
recused |
No | No |
A vote of recused requires a non-empty recusal_reason (enforced by a check constraint). One vote per member per proposal (UNIQUE (proposal_id, member_id)); votes are never deleted.
Quorum and outcome fields
Quorum is computed by trigger when a proposal moves to open. The member count includes only space_members with status in current or late and approved = true.
| Field | Type | Notes |
|---|---|---|
quorum_percent |
integer | Percentage from space settings at open time |
quorum_floor |
integer | Minimum absolute count |
quorum_required |
integer | GREATEST(quorum_floor, ceil(members * quorum_percent / 100)) |
voting_opens_at |
timestamptz | Defaults to now() at open |
voting_closes_at |
timestamptz | Defaults to open plus the space voting window |
outcome_yes / outcome_no / outcome_abstain / outcome_recused |
integer | Live tallies, refreshed per vote |
total_voters |
integer | Total votes cast |
quorum_met |
boolean | (yes + no + abstain) >= quorum_required |
passed |
boolean | Applies the threshold_rule |
Incidents
An incident is a code-of-conduct complaint, safety report, or conflict. Admin and board members see all incidents; the reporter sees their own. Incidents are never deleted.
incident_status
| Value | Meaning |
|---|---|
received |
Filed, not yet acknowledged (the default) |
under_review |
Acknowledged by board; acknowledged_at set |
decided |
Disposition recorded; decided_at set |
appealed |
Reporter filed an appeal, linked via appeal_proposal_id |
closed |
Resolved; closed_at set |
incident_severity
| Value |
|---|
low |
medium (default) |
high |
critical |
incident_update_visibility
Each entry in an incident's update thread carries its own visibility. Admin and board can always read.
| Value | Visible to |
|---|---|
reporter_only |
The reporter |
all_parties |
Reporter and board (the default) |
board_only |
Admin and board only |
Other incident fields
| Field | Type | Notes |
|---|---|---|
reporter_id |
uuid | Null when anonymous |
reporter_token |
text | Opaque token for anonymous status lookup; unique |
is_anonymous |
boolean | Default false |
subjects |
uuid[] | Members the report concerns |
category |
text | Free-form; default general |
disposition |
text | The recorded decision |
decision_maker_ids |
uuid[] | Members who decided |
sla_response_by |
timestamptz | Computed as created_at + incident_sla_hours |
Policies
A policy is a versioned document, bylaws, code of conduct, station rules. Members read; admin and board create. Rows are immutable: a new version is a new row pointing back via prior_version_id, uniqueness enforced by UNIQUE (space_id, slug, version).
policy_status
| Value | Meaning |
|---|---|
draft |
Not yet in force (the default) |
active |
In effect |
deprecated |
Retired without a replacement |
superseded |
Replaced by a newer version |
Other policy fields
| Field | Type | Notes |
|---|---|---|
slug |
text | Stable identifier, e.g. code-of-conduct |
section_ref |
text | Free-form clause reference, e.g. 8.4 |
parent_policy_id |
uuid | Nests a policy under another |
body_formal |
text | Formal text |
body_plain |
text | Plain-language summary |
version |
integer | Starts at 1 |
effective_at |
timestamptz | When the version takes effect |
adopted_by_proposal_id |
uuid | The proposal that adopted it, if any |
Space-level defaults
Six columns on spaces seed governance behavior. Proposals copy the quorum, window, and threshold values at open time; incidents copy the SLA at creation.
| Column | Default | Purpose |
|---|---|---|
default_quorum_percent |
10 | Quorum as a percent of eligible members |
default_quorum_floor |
1 | Minimum quorum count |
default_voting_window_hours |
216 | Voting window (9 days) |
default_threshold |
simple_majority |
Default threshold_rule |
incident_sla_hours |
72 | Response SLA (3 days) |
mission_statement |
null | Space mission text |
Cross-references
The three entities link to each other:
- A bylaw-change proposal cites a policy via
proposals.policy_ref_id. - An incident appeal becomes a proposal; the proposal carries
parent_incident_idand the incident carriesappeal_proposal_id. - An adopted policy version records the proposal that passed it via
policies.adopted_by_proposal_id.
See also the Modules reference for where governance sits among the platform's modules.