Abstimmung: mehrere Agenten pruefen unabhaengig und stimmen blind ab (#702)

A unit can put operations to a blind vote instead of its lead. Not opinions
are counted but independent checks enforced.

- UnitConfig.votes: operations, voters, approveAt, rejectAt, quorum, hours,
  perDay - set only by a human (OrgAdministration.SetVotes).
- Core/Staging/Votes: routes a covered staged call before the lead; one task
  per voter with the frozen call and nothing else; cast_vote needs reasoning
  and evidence. Counted as soon as the result is settled; in between and
  without the quorum a human decides. The proposer does not vote, voters that
  read foreign content get no ballot, changes to agents never go to a vote.
- Escalation tool: list_ballots, cast_vote.
- Approvals view shows each vote with every ballot and the voters' costs;
  organisation view sets the rule and lists the votes held.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-10-01 12:04:33 +02:00
co-authored by Claude Opus 5.5
parent d834e5ac38
commit a5dd503d9b
23 changed files with 1238 additions and 11 deletions
@@ -342,6 +342,37 @@ public sealed class SqliteStorage
TaskId TEXT NULL
);
-- #702: blind votes on staged calls, one ballot per voter with reasoning, evidence and run.
CREATE TABLE IF NOT EXISTS Votes (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
CallId INTEGER NOT NULL,
UnitId TEXT NOT NULL,
Proposer TEXT NOT NULL,
Operation TEXT NOT NULL,
ApproveAt INTEGER NOT NULL,
RejectAt INTEGER NOT NULL,
Quorum INTEGER NOT NULL,
Until TEXT NOT NULL,
CreatedAt TEXT NOT NULL,
Outcome TEXT NULL,
DecidedAt TEXT NULL
);
CREATE INDEX IF NOT EXISTS IX_Votes_Call ON Votes (CallId);
CREATE INDEX IF NOT EXISTS IX_Votes_Open ON Votes (Outcome);
CREATE TABLE IF NOT EXISTS VoteBallots (
VoteId INTEGER NOT NULL,
Voter TEXT NOT NULL,
TaskId TEXT NULL,
Yes INTEGER NULL,
Reasoning TEXT NOT NULL DEFAULT '',
Evidence TEXT NOT NULL DEFAULT '',
RunId TEXT NULL,
CastAt TEXT NULL,
PRIMARY KEY (VoteId, Voter)
);
CREATE TABLE IF NOT EXISTS StagedCalls (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
RunId TEXT NOT NULL,