1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//! The **cohort** — V2's fan, derived (VISION V2.3, §5.1 #32).
//!
//! *"A fan renders as a group: siblings-of-one-ref, each with its state badge,
//! terminal response preview, and usage figure side by side — anchored at the
//! birth notch (one card, N columns)."* V1.7 reserved that anchor; this is it.
//!
//! **Membership is a grouping, not a record.** A cohort is the children that
//! hang on one notch — `provenance_notch`, which V1's [`ChildCard`] already
//! computes from the child's own first commit. Nothing is stored, nothing is
//! registered, and no gesture declares a group: firing the fork twice from one
//! mark *is* firing a cohort, and firing it once *is* a cohort of one. That is
//! why [`cohorts`] is total and has no arm for N — the fan and the single
//! attempt come out of the same fold, differing only in `members.len()`.
//!
//! **Common ancestry is the same fact said once.** Each member already wears
//! its fork label (`from here` / `from config/<name>` / `from <Name>@<oid>`),
//! itself derived from the shared commit prefix. When every member wears the
//! same one, the cohort states it as [`Cohort::common`] and the columns stop
//! repeating it; when they differ — an operator who tried the same question
//! from two different config branches at one mark — there is no common
//! ancestry to state, so the columns say their own. Absence is a value here,
//! not a special case.
use ;
/// One cohort: the children born at one notch, and the ancestry they share.
/// Group a rail's cards into cohorts, in notch order. Every card lands in
/// exactly one cohort, so this is a partition of [`Rail::cards`] and never a
/// second copy of the membership fact: the cards are the truth and this is
/// their ordering by birth.
/// The fork label shared by every member, or `None` when they disagree. A
/// cohort of one shares its own label with itself, which is the general path
/// with one input rather than an arm: the render then has one column and one
/// header line, exactly V1's card.