docs(campaign): document aggregate report baseline

This commit is contained in:
2026-07-22 15:20:04 +02:00
parent 1ab4e91ffd
commit 3075ef7f5b
2 changed files with 21 additions and 4 deletions

View File

@@ -144,10 +144,14 @@ paths, storage keys, worker claim tokens, and raw provider diagnostics require
the dedicated diagnostic permission and must not leak through ordinary campaign, the dedicated diagnostic permission and must not leak through ordinary campaign,
version, job, or report responses. version, job, or report responses.
The current Campaign Report Web UI additionally requires recipient-read access Campaign now provides a separate aggregate **Reports** surface for readers with
and does not yet hide every action control that the actor lacks. The server `campaigns:report:read` and access to the campaign. It loads only the safe
still authorizes each action, but an aggregate-only reader UI remains open aggregate projections, applies small-cell suppression, and offers no recipient
work; do not promise that experience from `campaigns:report:read` alone. rows, drill-down, filtering, export, or delivery actions. The recipient-aware
**Campaign Report** still requires recipient-read access and does not yet hide
every action control that the actor lacks. The server authorizes each action,
but permission-aware action visibility on that detailed surface remains open
work; do not confuse it with the aggregate reader experience.
### Deliver and resolve outcomes ### Deliver and resolve outcomes

View File

@@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path
from types import SimpleNamespace from types import SimpleNamespace
from unittest.mock import patch from unittest.mock import patch
@@ -364,6 +365,18 @@ def test_aggregate_report_task_never_implies_recipient_detail_or_export_authorit
assert "export" in topic.metadata["verification"].lower() assert "export" in topic.metadata["verification"].lower()
def test_handbook_distinguishes_shipped_aggregate_reports_from_detailed_report_gaps() -> None:
handbook = " ".join(
(
Path(__file__).resolve().parents[1] / "docs" / "CAMPAIGN_HANDBOOK.md"
).read_text(encoding="utf-8").lower().split()
)
assert "aggregate-only reader ui remains open" not in handbook
assert "separate aggregate **reports** surface" in handbook
assert "permission-aware action visibility on that detailed surface remains open work" in handbook
def test_static_campaign_handbook_has_unique_ids_help_contexts_and_no_planned_resend_claim() -> None: def test_static_campaign_handbook_has_unique_ids_help_contexts_and_no_planned_resend_claim() -> None:
from govoplan_campaign.backend.manifest import get_manifest from govoplan_campaign.backend.manifest import get_manifest