feat: integrate confidential ballot provider evidence
This commit is contained in:
@@ -73,6 +73,11 @@ Approval, and evidence.
|
||||
|
||||
A governed ballot is delegated to `voting.ballots` when Voting is installed;
|
||||
Committee retains the meeting/agendum linkage and verified aggregate result.
|
||||
For provider-backed Voting ballots, Committee also snapshots the assurance
|
||||
profile, provider and ballot references, and sanitized provider evidence. A
|
||||
reference `local_confidential` result remains explicitly uncertified; its
|
||||
server-encrypted casts do not satisfy secret-ballot, anonymity,
|
||||
coercion-resistance, or legal-certification requirements.
|
||||
The following direct provider path remains a 0.1 compatibility contract only.
|
||||
A provider-bound vote on that path is finalized through
|
||||
`committee.ballot_adapter.<provider>`. The adapter receives tenant, vote,
|
||||
|
||||
@@ -275,6 +275,13 @@ class CommitteeBallotFinalizer:
|
||||
expected_revision=voting_expected_revision,
|
||||
idempotency_key=f"committee:{idempotency_key}",
|
||||
)
|
||||
assurance_profile = str(
|
||||
ballot.get("assurance_profile") or "recorded"
|
||||
).strip()
|
||||
if assurance_profile != "recorded" and not result.evidence:
|
||||
raise CommitteeWorkspaceError(
|
||||
"Provider-backed Voting results require sanitized provider evidence."
|
||||
)
|
||||
choices = tuple(str(item) for item in current.attributes.get("choices", ()))
|
||||
if set(result.counts) != set(choices):
|
||||
raise CommitteeWorkspaceError(
|
||||
@@ -301,6 +308,12 @@ class CommitteeBallotFinalizer:
|
||||
"voting_ballot_id": voting_ballot_id,
|
||||
"voting_ballot_revision": result.revision,
|
||||
"voting_result_sha256": result.result_sha256,
|
||||
"voting_assurance_profile": assurance_profile,
|
||||
"voting_provider_id": ballot.get("provider_id"),
|
||||
"voting_provider_ballot_ref": ballot.get("provider_ballot_ref"),
|
||||
"voting_provider_evidence": [
|
||||
dict(item) for item in result.evidence
|
||||
],
|
||||
"counts": {key: int(value) for key, value in result.counts.items()},
|
||||
"weighted_counts": {
|
||||
key: int(value) for key, value in result.weighted_counts.items()
|
||||
|
||||
@@ -219,7 +219,9 @@ DOCUMENTATION = (
|
||||
"effects. Committee does not own generic Mandate or Decision persistence; optional "
|
||||
"providers resolve and record those objects when installed, while a protected local "
|
||||
"projection preserves the bounded fallback. Provider-bound ballots are finalized "
|
||||
"through adapter capabilities without retaining individual ballots."
|
||||
"through adapter capabilities without retaining individual ballots. Voting-backed "
|
||||
"results preserve sanitized provider assurance evidence and never promote the "
|
||||
"uncertified local confidential reference provider to a certified profile."
|
||||
),
|
||||
layer="available",
|
||||
documentation_types=("admin", "user"),
|
||||
|
||||
@@ -90,6 +90,9 @@ class VotingBallots:
|
||||
"id": ballot_id,
|
||||
"revision": 2,
|
||||
"state": "open",
|
||||
"assurance_profile": "confidential",
|
||||
"provider_id": "local_confidential",
|
||||
"provider_ballot_ref": "local-confidential:ballot-1",
|
||||
"context": {"module": "committee", "resource_id": "vote-voting"},
|
||||
}
|
||||
|
||||
@@ -117,6 +120,13 @@ class VotingBallots:
|
||||
threshold_met=True,
|
||||
winning_options=("yes",),
|
||||
result_sha256="c" * 64,
|
||||
evidence=(
|
||||
{
|
||||
"kind": "reference_provider_result",
|
||||
"provider_id": "local_confidential",
|
||||
"certified": False,
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
def certify_ballot(self, *args, **kwargs):
|
||||
@@ -732,6 +742,11 @@ class CommitteeWorkspaceTests(unittest.TestCase):
|
||||
self.assertEqual("closed", closed.state)
|
||||
self.assertEqual({"yes": 2, "no": 1}, closed.attributes["counts"])
|
||||
self.assertEqual("c" * 64, closed.attributes["voting_result_sha256"])
|
||||
self.assertEqual(
|
||||
"confidential",
|
||||
closed.attributes["voting_assurance_profile"],
|
||||
)
|
||||
self.assertFalse(closed.attributes["voting_provider_evidence"][0]["certified"])
|
||||
self.assertEqual("voting", closed.evidence[0].owner_module)
|
||||
self.assertNotIn("selections", closed.attributes)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user