P3_WP12_METERING_SHOWBACK_EVIDENCE.md 9.8 KB

P3-WP12 Metering and Showback Engineering Evidence

Boundary

  • Local engineering evidence only: local-metering-fixture-v1@1; no external cost, billing, finance, email or collaboration provider was accessed.
  • Enterprise input remains cost=TBD_EXTERNAL, owner enterprise_finance_owner. This is not enterprise billing, UAT or production acceptance.

TDD evidence (2026-08-18)

  • RED: tests/core/governance/test_wp12_metering_showback.py initially failed because the WP12 module was absent.
  • GREEN: PYTHONPATH=. .venv/bin/pytest -q tests/core/governance/test_wp12_metering_showback.py passed 6 tests for closed eight-kind events, Decimal unit conversion, exact replay/conflict, correction chain, allocation replay, budget alert and Chargeback denial.
  • RED: migration contract initially failed because revision 20260818_546 and mirror were absent.
  • GREEN: PYTHONPATH=. .venv/bin/pytest -q tests/test_wp12_metering_showback_migration_contract.py passed the base 2 tests.
  • RED: Flask/OpenAPI contract initially failed because the route/spec were absent.
  • GREEN: PYTHONPATH=. .venv/bin/pytest -q tests/test_wp12_metering_showback_api.py passed the base 2 tests after generator output.
  • RED (follow-up): the control-route/OpenAPI/mirror tests failed with the allocation and budget routes, generated paths and revision 20260818_547 deployment mirror absent.
  • GREEN (follow-up): PYTHONPATH=. .venv/bin/pytest -q tests/test_wp12_metering_showback_api.py tests/test_wp12_metering_showback_migration_contract.py passed 6 tests after the closed control gateway, API routes, OpenAPI generator entries and mirror were added.
  • RED (self-review follow-up): 547 persisted rules but the read path did not yet replay an allocation from persisted facts; no completion claim was made at that point.
  • GREEN (self-review follow-up): 20260818_548 adds a runtime-only persisted allocation-replay function and closed no-store read endpoint. Its missing API/mirror RED failed in 2 expected places; after the mirror/generator update the API/migration contracts passed 7 tests.
  • Final targeted non-integration run: PYTHONPATH=. .venv/bin/pytest -q tests/core/governance/test_wp12_metering_showback.py tests/test_wp12_metering_showback_api.py tests/test_wp12_metering_showback_migration_contract.py passed 13 tests; git diff --check and all required source/deployment byte comparisons passed.
  • Final controlled PostgreSQL run: TEST_DATABASE_URL=<controlled local Docker DSN> PYTHONPATH=. .venv/bin/pytest -q tests/integration/test_wp12_metering_showback_postgres.py passed 2 tests. Before the shared round trip, its head was 20260818_548 and exact WP12 fact-row sum was 0; the test restored head 20260818_548 with fact-row sum 0.

Real PostgreSQL evidence

  • Local Docker PostgreSQL was available at the controlled project test endpoint. An isolated database was stamped to verified 545 and actually migrated 545→548. It passed distinct runtime/control-login Flask commits for allocation, budget and persisted allocation replay, closed control-body/RBAC/no-store handling, direct runtime-facts ACL denial, runtime denial of the control function, lease contention/fence, exact replay, concurrent exact-once disabled outbox insert, allocation replay/conflict, cross-domain rejection, new-connection read, Chargeback DB denial and nonempty downgrade refusal.
  • Shared local test DB was read-checked as head 20260818_547 with zero WP12 fact rows, then executed 547→548→547→548. A real role-init replay with temporary runtime/control identities preserved no direct runtime table privilege and retained only control-side claim/control-function execution. Temporary roles were removed. The shared DB remains at 548 with no WP12 facts.
  • A full empty-database historical chain run as the cluster administrator correctly stopped at the pre-existing WP06 restricted-migrator identity gate; it is not WP12 chain evidence.

State

Specification-review follow-up (2026-08-18)

  • RED: review found the old Showback aggregate did not consume rules, correction scope was incomplete, duplicate/zero allocation targets and overlapping windows were not rejected, evidence references admitted script-like segments, and OpenAPI omitted required query/body/nested closure details.
  • GREEN: 20260818_549 adds gateway-only event-time rollup with persisted rule/version/digest details, strict deterministic integer-micros conservation, explicit unallocated_micros/variance_micros, correction/event evidence guards, non-overlapping effective windows and duplicate/zero target rejection. The OpenAPI generator now declares required WP12 query parameters, required request bodies and closed nested evidence/mapping/allocation objects.
  • Validation: targeted core/API/migration suite passed 14; isolated controlled PostgreSQL 545→549 passed allocation-rollup, expired-window variance, correction/domain/chain, duplicate/zero/overlap and script-reference database attacks; the shared empty database passed 548→549→548→549 plus role-init replay and ended at head 20260818_549 with zero WP12 fact rows.

Unified replay and legacy ACL follow-up (2026-08-18)

  • RED: review demonstrated the old standalone replay could allocate an event outside a specified rule's effective window; the renamed legacy read function also retained runtime execute privilege.
  • GREEN: 20260818_550 replaces allocation replay with a claim-bound event-time coverage gate. A specified rule returns allocations only when it covers every matching event; expired/partial/multi-version coverage is denied instead of reporting an inconsistent total. Superseded replay/read/control functions are explicitly revoked from PUBLIC, dataops_app, dataops_app_runtime and the control role.
  • Upgrade preflight: before enabling the fence, 550 scans persisted correction scope/chain, evidence references, rule overlaps and allocation weights/sums. A real nonempty 548→549→550 migration with a legacy cross-domain correction failed closed; clean 549 data upgrades and the empty shared 549→550→549→550 round trip passed.
  • Validation: targeted core/API/migration suite passed 15; controlled PostgreSQL integration passed 3 tests covering expired and partial/multi-rule replay denial, direct legacy function ACL denial, role-init replay and the nonempty upgrade preflight refusal. Shared head is 20260818_550 with zero WP12 fact rows.
  • Final re-run after the explicit post-role-init legacy ACL assertion: target suite remained 15 passed; real PostgreSQL integration remained 3 passed after shared 549→550→549→550, ending at head 20260818_550 with metering_events=0. Regenerated OpenAPI matched docs/architecture/OPENAPI.yaml (493 operations), all WP12 source/deployment mirrors matched byte-for-byte, JSON validation, Python compilation and git diff --check passed.

HTTP failure boundary and allocation atomicity follow-up (2026-08-18)

  • RED: a real Flask changed-idempotency POST raised PostgreSQL metering_replay_conflict through the route as HTTP 500. The quality review also reproduced concurrent same-version changed allocation and concurrent overlapping effective-window races against the prior gateway.
  • GREEN: routes now convert all SQLAlchemy gateway/connection/commit failures to generic no-store 4xx responses; record_for_principal writes the lease claim and event in one runtime transaction, so a failed changed replay rolls the lease transaction back and the next POST commits. The request mapping remains closed to department, project, cost_center; business_domain remains server-derived and a supplied field is rejected.
  • GREEN: 20260818_551 adds same-rule and scope advisory transaction locks, post-lock digest replay/conflict checking, a deferred exact-total allocation trigger and btree_gist scope/window exclusion constraint. Real two-connection Barrier tests produced exactly one changed winner, exact replay only for the winner, a single persisted 1,000,000-micros allocation, and one overlapping-window rejection.
  • Validation: real Docker PostgreSQL integration passed 3; target core/API/migration suite passed 16. The shared database completed empty 550→551→550→551, is at head 20260818_551, and has metering_events=0; source/deployment mirrors and git diff --check passed.

Fixed definer-owner follow-up (2026-08-18)

  • RED: a restricted-migrator review found metering_showback_allocation_total_guard() could retain the transient migration-login owner. That owner could not safely be removed and violated the fixed NOLOGIN SECURITY DEFINER boundary.
  • GREEN: 20260818_552 transfers every metering_showback_% SECURITY DEFINER function, including the total-weight trigger and all renamed legacy paths, to dataops_tenant_foundation_owner; it first revokes PUBLIC, app/runtime and control execution, then grants only the current approved gateways. It refuses upgrade unless role-init has a NOLOGIN/NOSUPER/NOCREATEROLE owner with required public CREATE capability.
  • Validation: targeted core/API/migration suite passed 17; real Docker PostgreSQL integration passed 4, including a temporary NOSUPER/NOCREATEROLE migrator that owned 551 functions, owner census, temporary-role cleanup, isolated 545→552, allocation concurrency/ACL/restart and shared empty 551→552→551→552 role-init replay. Scoped Ruff, Python compilation, source/deployment mirror comparison and git diff --check passed. The shared database ends at 20260818_552 with zero WP12 facts.

Current engineering state is ENGINEERING_BASELINE_COMPLETE_SHOWBACK_ACTIVATION_BLOCKED: Showback, reconciliation and replay now share event-time persisted allocation semantics; all remaining behavior is local engineering evidence only. Enterprise activation remains separately blocked pending approved cost-center/master data, sources, pricing method, budget, Showback decision, finance approval and enterprise UAT.