Methodology v1.0 · 2026-06-08

How every number is computed

The board pack, dashboards and exception summary are derived from a small number of formulas. Every input is a database column, every exclusion is explicit, and nothing is modelled or smoothed. If a regulator asks "where does this number come from?" the answer is on this page.

Coverage — % obligations on track

Surfaces: Board pack §1, Board Mode §1, Home tiles
Formula
coverage_green / coverage_total  (rounded to nearest integer percent)
Inputs
  • coverage_green = obligations with all linked controls effective and no open high/critical findings
  • coverage_amber = obligations with at least one watching signal (overdue test, medium finding, etc.) but no high/critical breach
  • coverage_red = obligations with at least one open high/critical finding OR no effective control mapped
  • coverage_total = green + amber + red (i.e. in-scope obligations only)
Excludes
  • Out-of-scope obligations (in_scope = false)
  • Obligations in draft, under_review, superseded or withdrawn lifecycle states
Cadence

Recomputed on every snapshot read; no caching.

Tamper-evident audit chain status

Surfaces: Board pack §1 + §7, Board Mode §1 + §6
Formula
verify_audit_chain(tenant_id) — recomputes each entry's SHA-256 hash of (previous_hash || canonical_payload) and confirms the linked chain matches the stored hashes.
Inputs
  • audit_trail_entries rows for this tenant in chronological order
  • Per-entry canonical payload (deterministic JSON serialisation)
Excludes
  • Entries from other tenants
  • Soft-deleted rows (audit trail is append-only — none exist)
Cadence

Verified live on every governance snapshot fetch.

Notes

A 'break' means the recomputed hash for at least one row no longer matches the stored hash — i.e. someone or something has bypassed the trigger that writes new entries. Investigate immediately.

Issues past deadline

Surfaces: Board pack §2, Board Mode §2, Exception summary
Formula
count(issues) WHERE status IN ('open','in_progress') AND target_close_at IS NOT NULL AND target_close_at < now()
Inputs
  • issues.status
  • issues.target_close_at
Excludes
  • Closed or waived issues
  • Issues without a target close date
Cadence

Live on every read.

Validated-closure rate (this period)

Surfaces: Board pack §2
Formula
validations.confirmed_this_period / max(issues.resolved_this_period, 1)
Inputs
  • validations rows with outcome = 'confirmed' and validated_at within the last 90 days
  • issues rows with status = 'closed' and closed_at within the last 90 days
Excludes
  • Validations for issues closed outside the 90-day window
  • Self-validations (validator_id = closer_id are not counted)
Cadence

Recomputed per snapshot. Rolling 90-day window.

Notes

A rate below 100% means some closures in the period have not yet been independently validated. Not necessarily wrong, but the gap should be closing, not widening.

Monitoring plan — pass rate

Surfaces: Board pack §5, Board Mode §4, Exception summary
Formula
round(100 * passed_tests / executed_tests) where executed_tests = passed + failed (waived excluded)
Inputs
  • monitoring_tests with status IN ('passed','failed') within the active plan window
Excludes
  • Tests with status = 'waived' (waivers require their own justification and are reported separately)
  • Tests scheduled but not yet executed
Cadence

Recomputed per snapshot. Plan window = plan.period_start → plan.period_end.

Monitoring plan — coverage gap

Surfaces: Board pack §5, Board Mode §4, Exception summary
Formula
round(100 * (accepted_items - covered_items) / max(accepted_items, 1))
Inputs
  • monitoring_plan_items with status = 'accepted'
  • covered_items = accepted items that have at least one monitoring_test scheduled or executed
Excludes
  • Plan items in 'proposed' or 'deferred' status
Cadence

Live on every plan read.

Committee attendance recorded

Surfaces: Board pack §3, Exception summary
Formula
ratifications_with_attendance / ratifications_in_window  (ratio, not %)
Inputs
  • ratifications in the last 90 days
  • committee_attendance rows linked to those ratifications
Excludes
  • Ratifications older than 90 days
Cadence

Recomputed per snapshot.

Notes

An approval without recorded attendees is not defensibly 'a board decision' — fix the data, not just the number.

Regulatory exposure score

Surfaces: Home, /risk/exposure
Formula
Σ ( obligation.weight × max_open_finding_severity_weight × (1 + age_days/180) ) for in-scope obligations with at least one open finding
Inputs
  • obligations.weight (default 1, max 5)
  • findings.severity → weight mapping: low=1, medium=2, high=4, critical=8
  • max age in days of any open finding against the obligation
Excludes
  • Out-of-scope obligations
  • Closed or waived findings
  • Findings with severity = 'info'
Cadence

Snapshotted daily into regulatory_exposure_snapshots; live recompute available.

Notes

The aging multiplier caps at +1.0 (i.e. 2x at 180 days and beyond) so a single very old finding cannot dominate the score indefinitely.

Sample selection

Surfaces: /monitoring/populations, /monitoring/tests
Formula
Deterministic mulberry32 RNG seeded with sha256(snapshot_content_hash || method || sample_size || strata_weights)
Inputs
  • population_snapshot.content_hash (SHA-256 of canonicalised row bytes)
  • sample_selection.method ∈ { random, stratified, risk_based }
  • sample_selection.sample_size
  • sample_selection.strata_weights (for stratified / risk-based)
Excludes
  • Rows excluded by the snapshot's filter expression (recorded on the snapshot row)
Cadence

One-shot. Re-running with the same inputs deterministically reproduces the exact selected IDs — verifiable from the audit trail.

Notes

Stratified / risk-based allocation uses largest-remainder to apportion the total sample size across strata.

Value realised dashboard

Surfaces: /value-realised
Formula
Sum of time saved (hours), automated decisions, and avoided rework, computed from concrete counters — never modelled.
Inputs
  • Findings auto-classified by Compass (with human accept rate)
  • Decisions ratified with full audit trail
  • Issues closed inside SLA
  • Tests executed via the platform vs uploaded externally
Excludes
  • Modelled or projected benefits
  • Anything that requires a human to estimate a percentage
Cadence

Live counters; rolling 90-day comparison.

Notes

Numbers come from concrete counters, not from converted estimates. The methodology section deliberately does not include a £-conversion — that is the firm's call, not the platform's.