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:
co-authored by
Claude Opus 5.5
parent
d834e5ac38
commit
a5dd503d9b
@@ -653,7 +653,7 @@ public sealed class AppHost : IAsyncDisposable
|
||||
|
||||
var (scanner, staging, board) = BuildTaskboard(
|
||||
instance, taskRepository, engine, tools, stateStore, audit,
|
||||
stagingRepository, dauerfreigaben, stagingGate, cases, loggerFactory, logger);
|
||||
stagingRepository, dauerfreigaben, stagingGate, cases, storage, loggerFactory, logger);
|
||||
|
||||
var host = new AppHost
|
||||
{
|
||||
@@ -732,6 +732,13 @@ public sealed class AppHost : IAsyncDisposable
|
||||
spotChecks.Start();
|
||||
host._shutdown.Add(spotChecks.DisposeAsync);
|
||||
|
||||
// #702: votes whose time is up are counted without waiting for the next ballot.
|
||||
if (engine.Votes is Core.Staging.Votes votes)
|
||||
{
|
||||
votes.Start();
|
||||
host._shutdown.Add(votes.DisposeAsync);
|
||||
}
|
||||
|
||||
// #699: costs per unit, and what changed in them.
|
||||
var costWatch = new Core.Accounting.CostWatch(
|
||||
storage, usage, () => Core.Organisation.OrgChart.From(instance), () => instance.CostWatch, board,
|
||||
@@ -838,6 +845,7 @@ public sealed class AppHost : IAsyncDisposable
|
||||
SqliteDauerfreigabeRepository dauerfreigaben,
|
||||
StagingGate stagingGate,
|
||||
Core.Cases.ICaseRepository cases,
|
||||
SqliteStorage storage,
|
||||
ILoggerFactory loggerFactory,
|
||||
ILogger logger)
|
||||
{
|
||||
@@ -858,9 +866,17 @@ public sealed class AppHost : IAsyncDisposable
|
||||
stagingRepository, board, () => engine.OrganisationProvider?.Invoke(),
|
||||
agent => Core.Organisation.ReportingLine.TrustOf(agent, tools.Get),
|
||||
loggerFactory.CreateLogger("ClawdDotNet.Core.Staging.Leads")) { Service = staging };
|
||||
stagingGate.Route = leadApprovals.RouteAsync;
|
||||
engine.LeadApprovals = leadApprovals;
|
||||
|
||||
// #702: What a unit puts to a blind vote goes there first; otherwise to the lead.
|
||||
var votes = new Votes(
|
||||
storage, stagingRepository, board, () => engine.OrganisationProvider?.Invoke(),
|
||||
agent => Core.Organisation.ReportingLine.TrustOf(agent, tools.Get),
|
||||
loggerFactory.CreateLogger("ClawdDotNet.Core.Staging.Votes")) { Service = staging, Audit = audit };
|
||||
stagingGate.Route = async (call, ct) => await votes.RouteAsync(call, ct) ?? await leadApprovals.RouteAsync(call, ct);
|
||||
engine.Votes = votes;
|
||||
|
||||
|
||||
var dispatcher = new EngineTaskDispatcher(
|
||||
engine, () => instance.Agents, instance.InstanceId, tools, stateStore, loggerFactory,
|
||||
tasks: taskRepository);
|
||||
|
||||
Reference in New Issue
Block a user