Single source: app/utils/voucher_guard.py (NOT EXISTS on voucher_void_marks,
key = entity_id+voucher_no+voucher_date and revoked_at IS NULL; same caliber as
the DB view cma.v_voucher_details_active). No hardcoded voucher numbers.
Consumers now guarded: cash.py import linkage (2 fns), reports.py subject/BS
amount (2 sites, also entity_id isolation added), dashboard.py _bep_sum_field,
alert_attribution.py build_subject_attribution. kpi_value_collector.py now
delegates to the shared guard (removes the previous duplicate implementation).
Tests: new tests/test_void_marker_consumers_20260914.py (6 cases).
- data_quality.py: remove GET /check-governance (no caller repo-wide; its
entity_id param had no session auth -> cross-tenant read; duplicate of
governance-check) -> the path now returns 404
- reports.py: /reports/dupont resolves the analysis target from the session
account (assert_entity_slug_scope / resolve_session_slug); explicit
cross-entity entity param -> 403, illegal value -> 400; the 2026-08-31
cross-entity exemption is revoked (docstring updated)
- frontend: drop the checkGovernance api definition; DupontAnalysis.vue
entity radio group -> read-only session entity tag, request without param
- tests: TestCheckGovernanceRetired (404 x2), TestDupontSessionScope (3),
TestDupont reworked to account-bound tokens (8 tests)
- docs/api-verification-split.md: drop the retired row, note 334/404 -> 333/403
pytest: 10 failed / 957 passed / 1 xfailed vs HEAD baseline 10 failed /
951 passed / 1 xfailed (identical failure set -> zero regression)
(cma-residual-cross-entity-cleanup-20260914)