Back to Simocracy

org.simocracy.ballot

One sim's elicited ballot in a funding-mechanism run (S-Process, Quadratic Voting, …). Ballots are the public, replayable elicitation layer of a run: anyone can recompute the outcome by feeding a run's ballots through the mechanism's deterministic aggregator. The `payload` union carries the mechanism-specific ballot shape; new mechanisms extend the union without breaking existing readers. Written by the run initiator; the sim that cast the ballot is attributed via `simUri`. Fixed-point convention: fields ending in `Milli` store real numbers ×1000 (lexicons have no float type).

record · key tid

One sim's elicited ballot in a funding-mechanism run (S-Process, Quadratic Voting, …). Ballots are the public, replayable elicitation layer of a run: anyone can recompute the outcome by feeding a run's ballots through the mechanism's deterministic aggregator. The `payload` union carries the mechanism-specific ballot shape; new mechanisms extend the union without breaking existing readers. Written by the run initiator; the sim that cast the ballot is attributed via `simUri`. Fixed-point convention: fields ending in `Milli` store real numbers ×1000 (lexicons have no float type).

run*

Run identifier this ballot belongs to. Matches the run's org.simocracy.history `hearingId` and the published decision's `runId`.

string · max 64
mechanism*

Versioned mechanism id that elicited this ballot, e.g. "s-process@1" or "quadratic-voting@1".

string · max 64
gatheringUri*

Scope identifier: usually the AT-URI of an org.simocracy.gathering record; a sentinel string for built-in scopes (e.g. "ftc-sf:tower").

string
simUri*

AT-URI of the org.simocracy.sim that cast this ballot.

string
simName

Display name of the sim at cast time (denormalised for cheap rendering).

string · max 200
round

Deliberation round this ballot was cast in (0-based). Omitted for single-round runs.

integer · ≥ 0
payload*

Mechanism-specific ballot content.

union<#mvfBallot | #creditsBallot | #meritBallot> · #mvfBallot · #creditsBallot · #meritBallot
model

Id of the AI model that generated this ballot (e.g. an OpenRouter slug like "deepseek/deepseek-v4-flash-0731", or a subscription model id when the run initiator's linked Claude/ChatGPT plan served the call). Recorded at elicitation time for reproducibility: replaying a run against a different model is a different experiment, and this field makes that visible. Absent on ballots cast before model provenance existed.

string · max 128
recusalPolicy

Conflict-of-interest rule in force when this ballot was elicited, copied from the gathering at run time so the ballot stays independently replayable. Absent means no policy was applied.

string
values: owner · sim · disclose · none
recusals

Proposals this sim was recused from, and why. These proposals are absent from the payload's evaluations/credits/scores by construction: a recusal is the absence of a judgement, NOT a zero-valued one. Readers replaying a run must skip these pairs when computing pairwise disagreement, and aggregators must renormalise the sim's remaining weight (e.g. quadratic-voting redistributes the full 100 voice credits across the unrecused slate) rather than letting the masked share evaporate.

#recusal[] · max 1000 · #recusal
createdAt*
datetime

Definitions

#recusalobject

One proposal this ballot's sim was barred from directing budget to. The sim's judgements on every other proposal in the run remain fully weighted.

proposal*

AT-URI of the proposal (org.hypercerts.claim.activity), or a "title:<title>" fallback key, matching the key convention used by the payload entries.

string
proposalTitle

Display title at cast time.

string · max 500
reason*

Why the sim was recused. owner=the sim's owner DID matches the proposal's submitting repo DID. sim=the sim is credited as an author via an org.simocracy.history sidecar. manual=excluded by hand by the run initiator.

string
values: owner · sim · manual

#mvfBallotobject

S-Process ballot: one marginal-value function per proposal.

evaluations*
#mvfEvaluation[] · max 1000 · #mvfEvaluation
outsideOptionMilli

Marginal value of keeping a dollar for future rounds, ×1000 (fixed-point: 500 = 0.5).

integer · ≥ 0

#mvfEvaluationobject

proposal*

AT-URI of the evaluated proposal (org.hypercerts.claim.activity), or a "title:<title>" fallback key when the URI could not be resolved.

string
proposalTitle

Display title at cast time.

string · max 500
reasoning

The sim's in-character reasoning for this curve.

string · max 5000
mvf*

Piecewise-linear marginal value function, points sorted ascending by dollars.

#mvfPoint[] · max 20 · #mvfPoint

#mvfPointobject

dollars*

Funding level in whole USD.

integer · ≥ 0
marginalValueMilli*

Value-per-dollar of the next dollar at this funding level, ×1000 (fixed-point: 1500 = 1.5).

integer · ≥ 0

#creditsBallotobject

Quadratic Voting ballot: voice credits spent per proposal. Effective votes are the square root of credits; a sim spends at most 100 credits per run.

reasoning

The sim's in-character reasoning for this spread.

string · max 5000
credits*
#creditEntry[] · max 1000 · #creditEntry

#meritBallotobject

Merit-Curve ballot: one rubric level per proposal, plus the round policy the levels were cast under. Merit-Curve is a selection mechanism for prize rounds — proposals are scored on a published 0–8 rubric and a closed-form water-fill splits the pot against a quality bar, holding back anything below it. The policy travels with the ballot so a run is replayable from its ballots alone.

scores*
#meritScore[] · max 1000 · #meritScore
policy*

Round policy in force when this ballot was cast.

#meritPolicy · #meritPolicy
reasoning

The sim's in-character reading of the slate as a whole.

string · max 5000

#meritScoreobject

proposal*

AT-URI of the scored proposal (org.hypercerts.claim.activity), or a "title:<title>" fallback key.

string
proposalTitle

Display title at cast time.

string · max 500
level*

Rubric level. 0 = noise, 2 = restates the thread, 4 = well-argued but not new, 6 = novel defensible argument, 8 = would plausibly change how a delegate votes.

integer · ≥ 0 · ≤ 8
note

One-line justification for this level.

string · max 1000

#meritPolicyobject

Round policy for a Merit-Curve run. Set by the gathering admin, never by the model.

bar*

Rubric level at or below which a proposal earns nothing; that money is held back.

integer · ≥ 0 · ≤ 8
maxShareMilli*

Maximum share of the round budget any one proposal may receive, ×1000 (400 = 40%).

integer · ≥ 1 · ≤ 1000
minAwardUsd

Awards below this many whole USD are swept back to the reserve.

integer · ≥ 0
rubricVersion

Identifier of the rubric text these levels were scored against.

string · max 64

#creditEntryobject

proposal*

AT-URI of the proposal (org.hypercerts.claim.activity), or a "title:<title>" fallback key.

string
proposalTitle

Display title at cast time.

string · max 500
credits*

Voice credits spent on this proposal (integer, whole credits).

integer · ≥ 0 · ≤ 100
Raw lexicon JSON
{
  "lexicon": 1,
  "id": "org.simocracy.ballot",
  "defs": {
    "main": {
      "type": "record",
      "description": "One sim's elicited ballot in a funding-mechanism run (S-Process, Quadratic Voting, …). Ballots are the public, replayable elicitation layer of a run: anyone can recompute the outcome by feeding a run's ballots through the mechanism's deterministic aggregator. The `payload` union carries the mechanism-specific ballot shape; new mechanisms extend the union without breaking existing readers. Written by the run initiator; the sim that cast the ballot is attributed via `simUri`. Fixed-point convention: fields ending in `Milli` store real numbers ×1000 (lexicons have no float type).",
      "key": "tid",
      "record": {
        "type": "object",
        "required": [
          "run",
          "mechanism",
          "gatheringUri",
          "simUri",
          "payload",
          "createdAt"
        ],
        "properties": {
          "run": {
            "type": "string",
            "maxLength": 64,
            "description": "Run identifier this ballot belongs to. Matches the run's org.simocracy.history `hearingId` and the published decision's `runId`."
          },
          "mechanism": {
            "type": "string",
            "maxLength": 64,
            "description": "Versioned mechanism id that elicited this ballot, e.g. \"s-process@1\" or \"quadratic-voting@1\"."
          },
          "gatheringUri": {
            "type": "string",
            "description": "Scope identifier: usually the AT-URI of an org.simocracy.gathering record; a sentinel string for built-in scopes (e.g. \"ftc-sf:tower\")."
          },
          "simUri": {
            "type": "string",
            "description": "AT-URI of the org.simocracy.sim that cast this ballot."
          },
          "simName": {
            "type": "string",
            "maxLength": 200,
            "description": "Display name of the sim at cast time (denormalised for cheap rendering)."
          },
          "round": {
            "type": "integer",
            "minimum": 0,
            "description": "Deliberation round this ballot was cast in (0-based). Omitted for single-round runs."
          },
          "payload": {
            "type": "union",
            "refs": [
              "#mvfBallot",
              "#creditsBallot",
              "#meritBallot"
            ],
            "description": "Mechanism-specific ballot content."
          },
          "model": {
            "type": "string",
            "maxLength": 128,
            "description": "Id of the AI model that generated this ballot (e.g. an OpenRouter slug like \"deepseek/deepseek-v4-flash-0731\", or a subscription model id when the run initiator's linked Claude/ChatGPT plan served the call). Recorded at elicitation time for reproducibility: replaying a run against a different model is a different experiment, and this field makes that visible. Absent on ballots cast before model provenance existed."
          },
          "recusalPolicy": {
            "type": "string",
            "description": "Conflict-of-interest rule in force when this ballot was elicited, copied from the gathering at run time so the ballot stays independently replayable. Absent means no policy was applied.",
            "knownValues": [
              "owner",
              "sim",
              "disclose",
              "none"
            ]
          },
          "recusals": {
            "type": "array",
            "maxLength": 1000,
            "items": {
              "type": "ref",
              "ref": "#recusal"
            },
            "description": "Proposals this sim was recused from, and why. These proposals are absent from the payload's evaluations/credits/scores by construction: a recusal is the absence of a judgement, NOT a zero-valued one. Readers replaying a run must skip these pairs when computing pairwise disagreement, and aggregators must renormalise the sim's remaining weight (e.g. quadratic-voting redistributes the full 100 voice credits across the unrecused slate) rather than letting the masked share evaporate."
          },
          "createdAt": {
            "type": "string",
            "format": "datetime"
          }
        }
      }
    },
    "recusal": {
      "type": "object",
      "description": "One proposal this ballot's sim was barred from directing budget to. The sim's judgements on every other proposal in the run remain fully weighted.",
      "required": [
        "proposal",
        "reason"
      ],
      "properties": {
        "proposal": {
          "type": "string",
          "description": "AT-URI of the proposal (org.hypercerts.claim.activity), or a \"title:<title>\" fallback key, matching the key convention used by the payload entries."
        },
        "proposalTitle": {
          "type": "string",
          "maxLength": 500,
          "description": "Display title at cast time."
        },
        "reason": {
          "type": "string",
          "description": "Why the sim was recused. owner=the sim's owner DID matches the proposal's submitting repo DID. sim=the sim is credited as an author via an org.simocracy.history sidecar. manual=excluded by hand by the run initiator.",
          "knownValues": [
            "owner",
            "sim",
            "manual"
          ]
        }
      }
    },
    "mvfBallot": {
      "type": "object",
      "description": "S-Process ballot: one marginal-value function per proposal.",
      "required": [
        "evaluations"
      ],
      "properties": {
        "evaluations": {
          "type": "array",
          "maxLength": 1000,
          "items": {
            "type": "ref",
            "ref": "#mvfEvaluation"
          }
        },
        "outsideOptionMilli": {
          "type": "integer",
          "minimum": 0,
          "description": "Marginal value of keeping a dollar for future rounds, ×1000 (fixed-point: 500 = 0.5)."
        }
      }
    },
    "mvfEvaluation": {
      "type": "object",
      "required": [
        "proposal",
        "mvf"
      ],
      "properties": {
        "proposal": {
          "type": "string",
          "description": "AT-URI of the evaluated proposal (org.hypercerts.claim.activity), or a \"title:<title>\" fallback key when the URI could not be resolved."
        },
        "proposalTitle": {
          "type": "string",
          "maxLength": 500,
          "description": "Display title at cast time."
        },
        "reasoning": {
          "type": "string",
          "maxLength": 10000,
          "maxGraphemes": 5000,
          "description": "The sim's in-character reasoning for this curve."
        },
        "mvf": {
          "type": "array",
          "maxLength": 20,
          "items": {
            "type": "ref",
            "ref": "#mvfPoint"
          },
          "description": "Piecewise-linear marginal value function, points sorted ascending by dollars."
        }
      }
    },
    "mvfPoint": {
      "type": "object",
      "required": [
        "dollars",
        "marginalValueMilli"
      ],
      "properties": {
        "dollars": {
          "type": "integer",
          "minimum": 0,
          "description": "Funding level in whole USD."
        },
        "marginalValueMilli": {
          "type": "integer",
          "minimum": 0,
          "description": "Value-per-dollar of the next dollar at this funding level, ×1000 (fixed-point: 1500 = 1.5)."
        }
      }
    },
    "creditsBallot": {
      "type": "object",
      "description": "Quadratic Voting ballot: voice credits spent per proposal. Effective votes are the square root of credits; a sim spends at most 100 credits per run.",
      "required": [
        "credits"
      ],
      "properties": {
        "reasoning": {
          "type": "string",
          "maxLength": 10000,
          "maxGraphemes": 5000,
          "description": "The sim's in-character reasoning for this spread."
        },
        "credits": {
          "type": "array",
          "maxLength": 1000,
          "items": {
            "type": "ref",
            "ref": "#creditEntry"
          }
        }
      }
    },
    "meritBallot": {
      "type": "object",
      "description": "Merit-Curve ballot: one rubric level per proposal, plus the round policy the levels were cast under. Merit-Curve is a selection mechanism for prize rounds — proposals are scored on a published 0–8 rubric and a closed-form water-fill splits the pot against a quality bar, holding back anything below it. The policy travels with the ballot so a run is replayable from its ballots alone.",
      "required": [
        "scores",
        "policy"
      ],
      "properties": {
        "scores": {
          "type": "array",
          "maxLength": 1000,
          "items": {
            "type": "ref",
            "ref": "#meritScore"
          }
        },
        "policy": {
          "type": "ref",
          "ref": "#meritPolicy",
          "description": "Round policy in force when this ballot was cast."
        },
        "reasoning": {
          "type": "string",
          "maxLength": 10000,
          "maxGraphemes": 5000,
          "description": "The sim's in-character reading of the slate as a whole."
        }
      }
    },
    "meritScore": {
      "type": "object",
      "required": [
        "proposal",
        "level"
      ],
      "properties": {
        "proposal": {
          "type": "string",
          "description": "AT-URI of the scored proposal (org.hypercerts.claim.activity), or a \"title:<title>\" fallback key."
        },
        "proposalTitle": {
          "type": "string",
          "maxLength": 500,
          "description": "Display title at cast time."
        },
        "level": {
          "type": "integer",
          "minimum": 0,
          "maximum": 8,
          "description": "Rubric level. 0 = noise, 2 = restates the thread, 4 = well-argued but not new, 6 = novel defensible argument, 8 = would plausibly change how a delegate votes."
        },
        "note": {
          "type": "string",
          "maxLength": 2000,
          "maxGraphemes": 1000,
          "description": "One-line justification for this level."
        }
      }
    },
    "meritPolicy": {
      "type": "object",
      "description": "Round policy for a Merit-Curve run. Set by the gathering admin, never by the model.",
      "required": [
        "bar",
        "maxShareMilli"
      ],
      "properties": {
        "bar": {
          "type": "integer",
          "minimum": 0,
          "maximum": 8,
          "description": "Rubric level at or below which a proposal earns nothing; that money is held back."
        },
        "maxShareMilli": {
          "type": "integer",
          "minimum": 1,
          "maximum": 1000,
          "description": "Maximum share of the round budget any one proposal may receive, ×1000 (400 = 40%)."
        },
        "minAwardUsd": {
          "type": "integer",
          "minimum": 0,
          "description": "Awards below this many whole USD are swept back to the reserve."
        },
        "rubricVersion": {
          "type": "string",
          "maxLength": 64,
          "description": "Identifier of the rubric text these levels were scored against."
        }
      }
    },
    "creditEntry": {
      "type": "object",
      "required": [
        "proposal",
        "credits"
      ],
      "properties": {
        "proposal": {
          "type": "string",
          "description": "AT-URI of the proposal (org.hypercerts.claim.activity), or a \"title:<title>\" fallback key."
        },
        "proposalTitle": {
          "type": "string",
          "maxLength": 500,
          "description": "Display title at cast time."
        },
        "credits": {
          "type": "integer",
          "minimum": 0,
          "maximum": 100,
          "description": "Voice credits spent on this proposal (integer, whole credits)."
        }
      }
    }
  }
}
org.simocracy.ballot