Coherent derived statistics¶
Phase 4C supplies ProjectStatisticsDerivedSummaries, a read-side composer over
existing authorized reader results. It adds no persisted counters, source writers, API endpoints or
consumer cutover. Phase 4D report/export compatibility remains separate.
Delivered boundary¶
The approved calculation catalogue §3.9 identifies these configuration-independent views:
- Membership screening's five
Percent*values andNumberVerification. - The project study denominator from an annotation stage's unexcluded and excluded totals.
- Each inclusion class's
InsufficientlyCompletedCandidateSessions, defined by the existingMembershipAnnotationSessionStatsasTotal - CandidateAnnotationSessionsGloballyCompleted.
Screening percentages reuse the existing value object: decimal arithmetic, truncate to two places, never round, exactly zero when the denominator is zero. Signed legacy availability is preserved. Annotation differences are not clamped: retained session tallies can produce a negative difference.
The caller passes the original source selector and either one ProjectStatisticsBundleReadResult
or one exact ProjectStatisticsCheckpointReadResult. Current output carries that read's revision
identity; it does not claim a persisted historical checkpoint exists at that identity. Historical
output carries its one resolved root's identity. Historical composition never reads current Project
or Stage state and never fills a missing observation from current or adjacent-root data.
Source selection authorization is retained. There is no use of the broader derived-summary key's
Project.View permission to expose graph-protected inputs. A denied source, tombstone, missing row,
history gap or unavailable bundle produces DependencyUnavailable with no values.
The decoder accepts only the implemented catalogue/source versions and validates project, family, canonical scope and revision bounds. Rows from a future revision or another project fail closed. Present scalar values must fit the legacy integer domain and recognized catalogue keys. Negative source counts, malformed tally keys and overflowed totals are rejected; only documented signed availability and derived differences survive. Omitted recognized scalars retain the projection's normalized-zero meaning. Corruption is never interpreted as an empty population.
Acceptance and verification¶
Tests use the real bundle reader and authorization filter, plus replica-set integration through the production snapshot reader and backfill/checkpoint services. They compare percentages with the live legacy query, distinguish 66.66 from rounding to 66.67, cover empty populations and signed differences, reject malformed and incompatible inputs, and verify a newer current denominator cannot change an older checkpoint's derived values. Revoked own membership denies both current and retained history.
Captured grouping and capacity¶
Membership annotation composition requires both StageAnnotation and MembershipStageAnnotation selections in one authorized current bundle or one resolved historical root. It reuses the legacy session decoder, merged/separated grouping constructors and capacity calculation; no historical Stage object is loaded to perform those formulas. Percentage arithmetic retains decimal truncation to two places and the legacy zero denominator rule.
StageStatisticsDefinitionSnapshot captures the stage identity, ExcludedSessionStatsGrouping,
MaxInProgress, AllowSelfReconciliation and HideExcludedStudiesFromReviewers. Current scope
results obtain this immutable value from the Project already loaded inside the authorization
snapshot, only after the source selection is authorized and available. Historical observations
carry the versioned value in DefinitionDisplayMetadata from the authoritative calculator's pinned
source snapshot. Both contributing observations must contain matching complete definitions.
Missing metadata, unknown versions and mismatched stage identities produce unavailable summaries;
old roots are never upgraded using current settings.
The StageAnnotation and MembershipStageAnnotation lifecycle calculators use the session-aware legacy FullStats facet and capture counters, configuration and control revisions together. The membership calculator enumerates every project member and stage, including members without work, and reports absent scopes as absent. These calculators are not registered for runtime administration in this slice. Registration and annotation administrative rebuild routes remain in the stage consumer slice (#3300); the screening-only bootstrap contract is unchanged. A historical summary requires a checkpoint requested with both source selections; separate family bootstrap roots are not combined.
Observation reuse now compares definition metadata as well as counters, so a configuration-only change produces a new occurrence even when all counters remain equal. Metadata UTF-8 bytes count against observation admission. Real reader tests cover all three grouping modes, current versus retained historical capacity, grouping and self-reconciliation after configuration-only changes, and revoked membership.
These read-side formulas do not enable stage/reviewer consumers or complete their activation gates. Sustainable family maintenance, consumer-specific authorization, guarded fallback and measured performance remain required in their respective ordered consumer slices. Phase 4D report/export compatibility remains separate.
Retained definition integrity: metadata-bearing observations bind both counters and the exact
serialized stage definition into the observation-definition.v1 payload digest. That digest is
part of the immutable observation ID referenced by the checkpoint page and its Merkle proof.
Reads reject changed metadata even if its stored digest is changed with it. Counter-only
observations retain their existing digest and identity. Earlier metadata-bearing observations
without this binding are unavailable; retained history is never rewritten. A new checkpoint
captures the current definition with the new binding and cannot repair an old historical root.
Current rows published by rebuilds carry a content digest, which the composer verifies before
using their counters. Incrementally maintained rows may deliberately carry no digest. Screening
number verification also checks the sum for integer overflow; malformed inputs return the typed
InvalidCounters result rather than a wrapped, apparently valid total. These corrections use the
existing default-off statistics gates and introduce no new consumer or activation flag.
Only StageAnnotation and MembershipStageAnnotation selections capture a current stage definition; unrelated stage-scoped families neither serialize nor charge for that metadata. Current response budgeting includes the serialized UTF-8 bytes of each returned stage definition alongside the row's encoded estimate. The reader refuses an oversized whole bundle before adding the scope, using the same response ceiling as historical metadata. Existing dark gates remain in place; these integrity and admission corrections introduce no consumer cutover.
The checkpoint resolver validates the digest and observation identity for every retained payload,
including counter-only observations. Removing definition metadata cannot bypass the identity
bound by a published reference. Legacy counter-only observations still use the unchanged
OfCounters digest and remain readable when their payload and identity agree.