Concepts

Compare one source against a group.

Cohorts turn many member sources into one derived comparison lane before comparators run. That avoids overcounting pairwise residuals when the real question is whether the group covered the target.

Problem

Pairwise comparisons overcount group coverage.

If a target should be covered by any two of three replicas, comparing the target to each replica separately creates three disagreement stories. The real question is whether the group, as a group, satisfied the rule over each segment.

var result = pipeline.History
    .Compare("Source A vs quorum")
    .Target("source-a", selector => selector.Source("source-a"))
    .AgainstCohort("quorum", cohort => cohort
        .Sources("source-b", "source-c", "source-d")
        .Activity(CohortActivity.AtLeast(2)))
    .Within(scope => scope.Window("DeviceOffline"))
    .Using(comparators => comparators.Residual().Coverage())
    .Run();

var uncovered = result
    .CohortEvidence()
    .Where(evidence => !evidence.IsActive);

Solution

Materialize the group as one derived lane.

Spanfold evaluates cohort activity over each aligned segment before residual, missing, coverage, or overlap rows are emitted. The result still exposes evidence metadata: active count, required count, active sources, and whether the cohort lane was active.

How it works

The cohort is evaluated segment by segment.

Spanfold first aligns the member source windows into temporal segments. For each segment, it counts active members, applies the cohort rule, records the active sources, and emits a derived against lane. Comparators then run against that derived lane, not against each member individually.

Rules

Model the group explicitly.

Any

At least one member source makes the cohort active.

All

Every declared member must be active.

None

No member source may be active.

At least

A quorum-style minimum active count.

At most

A ceiling on how many members may be active.

Exactly

A precise active count for strict agreement rules.

Evidence

Keep the group decision explainable.

Cohort rows carry metadata that explains why the derived lane was active or inactive. That metadata is useful when a quorum fails: it shows the rule, required count, observed active count, and member sources that contributed to the segment.

var inactiveSegments = result.CohortEvidence()
    .Where(evidence => !evidence.IsActive)
    .Select(evidence => new
    {
        evidence.Rule,
        evidence.RequiredCount,
        evidence.ActiveCount,
        evidence.ActiveSources
    })
    .ToArray();

Use it for

Quorum, fallback coverage, and group consensus.

Use cohorts when the comparison side is a policy over many sources: any fallback can cover the primary, all checks must agree before a release gate passes, no source may report an unsafe condition, or at least two replicas must confirm a state before it is trusted.