facett-core 0.1.19

facett — visual kernel: render a node/edge Scene into egui (wgpu fast path to come)
Documentation
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
//! **ROOT LAW #0 — the rayon-free law**, and the machinery that can actually
//! report RED on it. Shared so korp and facett hold the *same* line from *one*
//! writer (LAW 5) instead of two drifting copies of a grep.
//!
//! # Why this module exists
//!
//! `znippy-zoomies/tests/rayon_free_law.rs` has guarded the law for the codec
//! tree for months. korp and facett had **no gate at all**: a `rayon = "1"` in
//! `facett-map/Cargo.toml` would have passed every test in both repos.
//!
//! # The hard part: which rayon?
//!
//! A naive lockfile grep is worse than no gate, because it is red on day one and
//! stays red forever. Measured on 2026-08-03, `Cargo.lock` in **both** repos
//! contains `rayon 1.12.0` — pulled in like this:
//!
//! ```text
//! rayon ← av-scenechange ← rav1e ← ravif ← image ← dify ← egui_kittest
//!       ← nornir-robotui "snapshot"  [dev-dependencies]  ← korp / facett-*
//! ```
//!
//! Nobody chose that. It is the AVIF encoder inside the image crate that the
//! screenshot-diff crate inside the robot-UI harness happens to enable. LAW 3
//! forbids **us** using rayon; it does not forbid a third-party image decoder in
//! the fourth ring from using it in a test harness. A gate that goes red on that
//! edge gets switched off within a week, and a gate that ignores the whole axis
//! cannot see the day it stops being test-only.
//!
//! So this module separates **three** things and says which one it tripped on:
//!
//! 1. [`scan_source`] — **our own code** calling rayon. Always red.
//! 2. [`scan_manifests`] — **our own manifests** declaring rayon, in any
//!    dependency table. Always red.
//! 3. [`shipped_rayon_tree`] — a **normal (non-dev, non-build) dependency
//!    edge** that reaches rayon, i.e. rayon linked into something we ship.
//!    Red. [`unshipped_rayon_chain`] finds the dev/build edge and is reported as
//!    *context*, never as a failure.
//!
//! Measured 2026-08-03 with `cargo tree -e normal -i rayon --target all`:
//! "nothing to print" in korp and in facett. Check 3 is therefore **green
//! today** and still able to go red — which is the only kind of green worth
//! having (LAW 2).
//!
//! It is one feature flag away from red, and that is the point of keeping it:
//! `image` **is** already a normal dependency of korp (via `eframe`→`arboard`,
//! and via `facett-about`), just without its `avif` feature. Turning `avif` on
//! anywhere in the graph puts `rayon` in the shipped korp binary. Under
//! `--all-features` that is exactly what happens, measured on the same day —
//! which is why [`rayon_tree_all_features_chain`] exists: check 3 demonstrates its own
//! red on **every run** instead of asserting that it still could.
//!
//! # Which instrument decides which axis
//!
//! Check 3 reads `cargo tree`, **not** `cargo metadata`. The first cut of this
//! module decided it from the metadata resolve, and pointed at korp that resolve
//! reported a violation — `korp -> image -> rayon` — that does not exist:
//! `cargo metadata` unifies dev-dependency features into one graph, so `image`
//! appears with `avif` on and its `ravif → rayon` edge looks normal. The
//! dependency-KIND walk was right; the FEATURE resolution under it was not, and
//! it errs towards inventing violations. `cargo metadata` is kept for kind
//! attribution and for the dev-route context chain, where over-approximating
//! costs nothing. See [`overapproximated_normal_chain`].
//!
//! # Self-honesty
//!
//! The forbidden tokens below are built with [`concat!`] so this file does not
//! contain them literally. The scanner therefore covers itself — there is no
//! path carve-out for the guard, which is how a guard quietly stops guarding.

use std::collections::VecDeque;
use std::path::{Path, PathBuf};
use std::process::Command;

/// One offending line, located.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Hit {
    /// Absolute path of the file the hit is in.
    pub file: PathBuf,
    /// 1-based line number.
    pub line: usize,
    /// The offending token that matched.
    pub token: String,
    /// The source line, trimmed (comments already stripped).
    pub text: String,
}

impl std::fmt::Display for Hit {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}:{}: `{}` — {}", self.file.display(), self.line, self.token, self.text)
    }
}

/// Tokens that can only appear when rayon is actually being **used**. Method
/// calls are matched with their leading `.` and trailing `(` so an unrelated
/// identifier such as `par_sorted` is not a false positive.
///
/// Written through [`concat!`] so the constant does not match itself — this file
/// is scanned like every other (see the module docs).
fn rayon_call_tokens() -> Vec<String> {
    [
        concat!("use ", "rayon"),
        concat!("extern crate ", "rayon"),
        concat!("rayon", "::"),
        concat!(".", "par_iter("),
        concat!(".", "into_par_iter("),
        concat!(".", "par_iter_mut("),
        concat!(".", "par_bridge("),
        concat!(".", "par_chunks("),
        concat!(".", "par_chunks_mut("),
        concat!(".", "par_sort("),
        concat!(".", "par_sort_by("),
        concat!(".", "par_sort_unstable("),
        concat!(".", "par_extend("),
        concat!("Parallel", "Iterator"),
        concat!("IntoParallel", "Iterator"),
        concat!("ThreadPool", "Builder"),
    ]
    .iter()
    .map(|s| (*s).to_string())
    .collect()
}

/// The crate name the manifest scan looks for as a dependency key.
fn rayon_dep_key() -> String {
    concat!("ray", "on").to_string()
}

/// Strip a `//`-to-end-of-line comment so only live code is scanned. The repos
/// are full of prose *about* the law (`// never rayon here`); commentary is not
/// a violation of it.
fn strip_line_comment(line: &str) -> &str {
    match line.find("//") {
        Some(i) => &line[..i],
        None => line,
    }
}

/// Walk up from `start` to the outermost directory whose `Cargo.toml` declares a
/// `[workspace]`. Handles both shapes in this tree: facett's virtual root and
/// korp's `[workspace]`-plus-`[package]` root.
pub fn workspace_root(start: &Path) -> PathBuf {
    let mut found = start.to_path_buf();
    let mut cursor = Some(start);
    while let Some(dir) = cursor {
        let manifest = dir.join("Cargo.toml");
        if std::fs::read_to_string(&manifest)
            .map(|text| text.lines().any(|l| l.trim() == "[workspace]"))
            .unwrap_or(false)
        {
            found = dir.to_path_buf();
        }
        cursor = dir.parent();
    }
    found
}

/// Every `Cargo.toml` this workspace owns: the root, plus one per member listed
/// in the root `members = [...]` array, plus one per `exclude = [...]` leaf.
///
/// The excluded leaves are ours too. korp's root manifest excludes
/// `crates/korp-ontology`, `crates/korp-embed` and `crates/korp-demo` because
/// they carry their own empty `[workspace]` tables — and korp *depends* on
/// `korp-demo` by path, so a `rayon = "1"` in that leaf ships. Reading only the
/// members would have left first-party manifests and first-party `src/`
/// unscanned while the count still looked healthy.
pub fn workspace_manifests(root: &Path) -> Vec<PathBuf> {
    let mut out = vec![root.join("Cargo.toml")];
    for member in first_party_dirs(root) {
        let m = root.join(&member).join("Cargo.toml");
        if m.exists() {
            out.push(m);
        }
    }
    out
}

/// The `members = [...]` entries of the root manifest. Tolerates the array being
/// written on one line or spread over many.
pub fn workspace_members(root: &Path) -> Vec<String> {
    manifest_string_array(root, "members")
}

/// The `exclude = [...]` entries of the root manifest — self-rooting leaves that
/// live in this repo and are therefore first-party even though cargo does not
/// call them members.
pub fn workspace_excludes(root: &Path) -> Vec<String> {
    manifest_string_array(root, "exclude")
}

/// Members and excluded leaves together: every directory in this repo that holds
/// a package of ours.
pub fn first_party_dirs(root: &Path) -> Vec<String> {
    let mut out = workspace_members(root);
    for e in workspace_excludes(root) {
        if !out.contains(&e) {
            out.push(e);
        }
    }
    out
}

/// Read a `key = [ "a", "b" ]` array out of the root manifest's `[workspace]`
/// table.
///
/// Two things this does that the first version did not, both of them defects
/// that were found by pointing the guard at korp:
///
/// 1. **It anchors on a LINE, not on the first occurrence of the word.** korp's
///    root manifest says "are NOT pulled in as members" in its header comment
///    three lines above `[workspace]`. A bare `text.find("members")` landed
///    there, then took `[workspace]`'s own brackets as the array and returned
///    `["workspace"]` — one member that does not exist and none of the real
///    ones. The manifest scan read 1 file where it should read 2.
/// 2. **It stays inside `[workspace]`.** `exclude` is also a `[package]` key
///    (packaging excludes), and korp's root manifest carries both tables.
///
/// Comments are `#` here, not `//` — this is TOML, and an entry may be followed
/// by a trailing `# why`.
fn manifest_string_array(root: &Path, key: &str) -> Vec<String> {
    let Ok(text) = std::fs::read_to_string(root.join("Cargo.toml")) else {
        return Vec::new();
    };
    let mut cursor = 0usize;
    let mut start = None;
    let mut in_workspace = false;
    for line in text.split_inclusive('\n') {
        let trimmed = line.trim_start();
        if trimmed.starts_with('[') {
            in_workspace = trimmed.starts_with("[workspace]");
        } else if in_workspace {
            if let Some(rest) = trimmed.strip_prefix(key) {
                if rest.trim_start().starts_with('=') {
                    start = Some(cursor + (line.len() - trimmed.len()));
                    break;
                }
            }
        }
        cursor += line.len();
    }
    let Some(start) = start else { return Vec::new() };
    // Strip `#`-to-end-of-line on every line BEFORE locating the brackets, so a
    // trailing `"a", # the first one` cannot swallow the rest of the array. The
    // first cut of this function stripped per comma-separated piece instead, and
    // its own new test caught it eating `"b"`.
    let rest: String = text[start..]
        .lines()
        .map(|l| l.split('#').next().unwrap_or(""))
        .collect::<Vec<_>>()
        .join("\n");
    let Some(open) = rest.find('[') else { return Vec::new() };
    let Some(close) = rest[open..].find(']') else { return Vec::new() };
    rest[open + 1..open + close]
        .split(',')
        .map(|s| s.trim().trim_matches('"').to_string())
        .filter(|s| !s.is_empty())
        .collect()
}

/// Every directory of ours that holds first-party Rust: each member's `src`,
/// `tests`, `benches` and `examples`, plus the root package's own if the root
/// manifest carries a `[package]`. `target/` is never walked.
pub fn source_roots(root: &Path) -> Vec<PathBuf> {
    const SUBDIRS: &[&str] = &["src", "tests", "benches", "examples"];
    let mut dirs: Vec<PathBuf> = Vec::new();
    let push_for = |base: PathBuf, dirs: &mut Vec<PathBuf>| {
        for sub in SUBDIRS {
            let p = base.join(sub);
            if p.is_dir() {
                dirs.push(p);
            }
        }
    };
    push_for(root.to_path_buf(), &mut dirs);
    for member in first_party_dirs(root) {
        push_for(root.join(member), &mut dirs);
    }
    dirs
}

fn rs_files(dir: &Path, out: &mut Vec<PathBuf>) {
    let Ok(rd) = std::fs::read_dir(dir) else { return };
    for entry in rd.flatten() {
        let path = entry.path();
        if path.is_dir() {
            if path.file_name().map(|n| n == "target").unwrap_or(false) {
                continue;
            }
            rs_files(&path, out);
        } else if path.extension().and_then(|e| e.to_str()) == Some("rs") {
            out.push(path);
        }
    }
}

/// What a source scan found, plus how much it looked at — a scan that found
/// nothing because it read nothing is the hollow green this whole module is
/// about, so the count travels with the verdict.
#[derive(Debug, Clone, Default)]
pub struct Scan {
    /// Offending lines.
    pub hits: Vec<Hit>,
    /// How many files were actually read.
    pub scanned: usize,
}

/// Scan every first-party `.rs` file under `root` for live rayon usage.
pub fn scan_source(root: &Path) -> Scan {
    let tokens = rayon_call_tokens();
    let mut files = Vec::new();
    for dir in source_roots(root) {
        rs_files(&dir, &mut files);
    }
    let mut hits = Vec::new();
    for file in &files {
        let Ok(text) = std::fs::read_to_string(file) else { continue };
        for (i, raw) in text.lines().enumerate() {
            let code = strip_line_comment(raw);
            for tok in &tokens {
                if code.contains(tok.as_str()) {
                    hits.push(Hit {
                        file: file.clone(),
                        line: i + 1,
                        token: tok.clone(),
                        text: code.trim().to_string(),
                    });
                }
            }
        }
    }
    Scan { hits, scanned: files.len() }
}

/// Scan every first-party `Cargo.toml` for a `rayon` dependency key, in any
/// dependency table (`[dependencies]`, `[dev-dependencies]`,
/// `[build-dependencies]`, `[target.'…'.dependencies]`,
/// `[workspace.dependencies]`). Comments are stripped: a manifest may freely
/// explain *why* rayon is banned.
pub fn scan_manifests(root: &Path) -> Scan {
    let key = rayon_dep_key();
    let manifests = workspace_manifests(root);
    let mut hits = Vec::new();
    for manifest in &manifests {
        let Ok(text) = std::fs::read_to_string(manifest) else { continue };
        let mut in_deps = false;
        for (i, raw) in text.lines().enumerate() {
            let line = raw.trim();
            if line.starts_with('[') {
                in_deps = line.contains("dependencies]");
                continue;
            }
            if !in_deps {
                continue;
            }
            let code = strip_line_comment(line);
            let name = code.split('=').next().unwrap_or("").trim().trim_matches('"');
            if name == key {
                hits.push(Hit {
                    file: manifest.clone(),
                    line: i + 1,
                    token: key.clone(),
                    text: code.trim().to_string(),
                });
            }
        }
    }
    Scan { hits, scanned: manifests.len() }
}

/// Run `cargo metadata` for `root` and return the parsed document.
///
/// `--offline --locked` on purpose: the guard must never mutate `Cargo.lock`
/// (LAW 6) and must never reach the network from a test. A stale lock is a hard
/// error, not a skip — a guard that skips itself is the disease.
pub fn cargo_metadata(root: &Path) -> Result<serde_json::Value, String> {
    let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into());
    let out = Command::new(cargo)
        .args(["metadata", "--format-version", "1", "--offline", "--locked"])
        .current_dir(root)
        .output()
        .map_err(|e| format!("could not run `cargo metadata` in {}: {e}", root.display()))?;
    if !out.status.success() {
        let stderr = String::from_utf8_lossy(&out.stderr);
        return Err(format!(
            "`cargo metadata --offline --locked` failed in {} ({}):\n{}",
            root.display(),
            out.status,
            stderr.lines().take(8).collect::<Vec<_>>().join("\n"),
        ));
    }
    serde_json::from_slice(&out.stdout).map_err(|e| format!("cargo metadata is not JSON: {e}"))
}

/// Package-id → package-name index from a `cargo metadata` document.
fn id_to_name(md: &serde_json::Value) -> std::collections::HashMap<String, String> {
    md["packages"]
        .as_array()
        .map(|ps| {
            ps.iter()
                .filter_map(|p| {
                    Some((p["id"].as_str()?.to_string(), p["name"].as_str()?.to_string()))
                })
                .collect()
        })
        .unwrap_or_default()
}

/// Which dependency kinds an edge carries. `cargo metadata` spells a normal
/// dependency as `kind: null`.
fn edge_kinds(dep: &serde_json::Value) -> Vec<String> {
    dep["dep_kinds"]
        .as_array()
        .map(|ks| {
            ks.iter()
                .map(|k| k["kind"].as_str().unwrap_or("normal").to_string())
                .collect()
        })
        .unwrap_or_default()
}

/// Breadth-first walk from the workspace members to `target_name`.
///
/// `require_non_normal` is what keeps the two answers from collapsing into one:
/// with it set, a chain only counts if it crosses at least one `dev` or `build`
/// edge, so "the dev-only route" cannot be silently answered with the shipped
/// route. The BFS state therefore carries that flag, and a package is re-visited
/// once per flag value.
///
/// Returns the shortest qualifying chain of package names, workspace member
/// first.
fn chain_to(
    md: &serde_json::Value,
    target_name: &str,
    require_non_normal: bool,
) -> Option<Vec<String>> {
    let names = id_to_name(md);
    let nodes: std::collections::HashMap<&str, &serde_json::Value> = md["resolve"]["nodes"]
        .as_array()?
        .iter()
        .filter_map(|n| Some((n["id"].as_str()?, n)))
        .collect();

    let members: Vec<&str> =
        md["workspace_members"].as_array()?.iter().filter_map(|m| m.as_str()).collect();

    let mut seen: std::collections::HashSet<(&str, bool)> = std::collections::HashSet::new();
    let mut queue: VecDeque<(&str, bool, Vec<String>)> = VecDeque::new();
    for m in members {
        if seen.insert((m, false)) {
            let label = names.get(m).cloned().unwrap_or_else(|| m.to_string());
            queue.push_back((m, false, vec![label]));
        }
    }

    while let Some((id, crossed, path)) = queue.pop_front() {
        if names.get(id).map(|n| n == target_name).unwrap_or(false)
            && path.len() > 1
            && (crossed || !require_non_normal)
        {
            return Some(path);
        }
        let Some(node) = nodes.get(id) else { continue };
        let Some(deps) = node["deps"].as_array() else { continue };
        for dep in deps {
            let kinds = edge_kinds(dep);
            // A single dependency can carry several kinds at once (normal AND
            // dev). Take the cheapest interpretation: if it is normal at all,
            // the shipped walk may use it without crossing.
            let has_normal = kinds.iter().any(|k| k == "normal");
            let has_other = kinds.iter().any(|k| k == "dev" || k == "build");
            let Some(pkg) = dep["pkg"].as_str() else { continue };

            // Which flag values this edge can hand on. The shipped walk only
            // ever follows a normal edge and never sets the flag, so it can
            // never answer with a dev route.
            let mut onward: Vec<bool> = Vec::new();
            if has_normal {
                onward.push(crossed);
            }
            if require_non_normal && has_other {
                onward.push(true);
            }

            for next_crossed in onward {
                if !seen.insert((pkg, next_crossed)) {
                    continue;
                }
                let mut next = path.clone();
                next.push(names.get(pkg).cloned().unwrap_or_else(|| pkg.to_string()));
                queue.push_back((pkg, next_crossed, next));
            }
        }
    }
    None
}

/// A **normal** dependency path from this workspace to rayon, as `cargo
/// metadata` sees it.
///
/// **Do not decide the shipped axis with this.** It over-approximates and it was
/// measured doing so: pointed at korp on 2026-08-03 it reported
/// `korp -> image -> rayon` while `cargo tree -e normal -i rayon --target all`
/// said "nothing to print". `cargo metadata`'s resolve unifies
/// dev-dependency features into one graph, so `image` shows up with `avif` on
/// and its `ravif -> rayon` edge looks normal. The dependency-KIND walk under
/// this function is right; the FEATURE resolution beneath it is not, and it errs
/// in the direction that invents violations. Kept for kind attribution and for
/// [`unshipped_rayon_chain`] (where over-approximating a *context* chain is
/// harmless); the verdict belongs to [`shipped_rayon_tree`].
pub fn overapproximated_normal_chain(md: &serde_json::Value) -> Option<Vec<String>> {
    chain_to(md, &rayon_dep_key(), false)
}

/// A path to rayon that crosses at least one **dev** or **build** edge: real,
/// known, and **not** a violation — third-party test-harness weight, nothing we
/// chose and nothing that ships. Reported as context so the gate can say which
/// of the two axes it tripped on, and used as the walker's own liveness check.
pub fn unshipped_rayon_chain(md: &serde_json::Value) -> Option<Vec<String>> {
    chain_to(md, &rayon_dep_key(), true)
}

// ───────────────────────── the shipped verdict, from cargo tree ──────────────
//
// `cargo tree -e normal -i rayon --target all` is the command that was actually
// measured on 2026-08-03, and it is the one that resolves features the way a
// build does. Everything below reads ITS output. `cargo metadata` stays where it
// belongs: dependency-kind attribution and the dev-route context chain.

/// Run `cargo tree -i <crate> --target all -e <edges>` in `root` and hand back
/// stdout.
///
/// `--offline --locked` for the same reason [`cargo_metadata`] uses them: a
/// guard must never mutate `Cargo.lock` (LAW 6) and never reach the network. A
/// stale lock is a hard error, not a skip.
///
/// `extra` carries the feature selection — `["--all-features"]`,
/// `["--no-default-features", "--features", "robot-watch"]`, or nothing for the
/// default shape. It is a parameter and not a bool because **the default shape
/// is not the only shape that ships**: measured on oden 2026-08-03, korp is
/// clean at default features and at five of its six single-feature builds, and
/// `--no-default-features --features robot-watch` puts rayon on a NORMAL edge —
/// and that is the build `.nornir/ingest-tab-app-robot.md:27` tells people to
/// make. A gate that only ever asks about the default answer is blind to
/// exactly the binary the documentation recommends.
pub fn rayon_tree(root: &Path, edges: &str, extra: &[&str]) -> Result<String, String> {
    dep_tree(root, &rayon_dep_key(), edges, extra)
}

/// [`rayon_tree`], generalized to ANY banned crate — the ONE `cargo tree -i`
/// runner every law shares (LAW 5). LAW 3's guard asks it about rayon; LAW 4's
/// (`webgl_free_law.rs`, here and in korp) asks it about `glow` / `khronos-egl`,
/// with the identical `--offline --locked --target all` discipline and the same
/// "stderr is part of the answer" contract.
pub fn dep_tree(root: &Path, krate: &str, edges: &str, extra: &[&str]) -> Result<String, String> {
    let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into());
    let mut cmd = Command::new(cargo);
    cmd.args(["tree", "-i", krate, "--target", "all", "-e", edges])
        .args(["--offline", "--locked"])
        .args(extra)
        .current_dir(root);
    let out = cmd
        .output()
        .map_err(|e| format!("could not run `cargo tree` in {}: {e}", root.display()))?;
    let stdout = String::from_utf8_lossy(&out.stdout).to_string();
    let stderr = String::from_utf8_lossy(&out.stderr).to_string();
    if !out.status.success() {
        return Err(format!(
            "`cargo tree -e {edges} -i {krate} --target all {}` failed in {} ({}):\n{}",
            extra.join(" "),
            root.display(),
            out.status,
            stderr.lines().take(8).collect::<Vec<_>>().join("\n"),
        ));
    }
    // Exit code is not the answer here. `cargo tree` says "nothing to print" on
    // stderr and exits 0, and a command that failed to name a crate at all would
    // also exit 0 with empty stdout. The caller gets stderr folded in so
    // "nothing to print" is a fact it can read, not an absence it must guess at.
    Ok(if stdout.trim().is_empty() { stderr } else { stdout })
}

/// Did `cargo tree -i` find no path at all? True for the "nothing to print"
/// notice and for genuinely empty output.
pub fn tree_found_nothing(out: &str) -> bool {
    out.trim().is_empty() || out.contains("nothing to print")
}

/// The chain `cargo tree -i` drew, from the first package of OURS back up to
/// rayon.
///
/// `cargo tree -i` prints the inverted tree: rayon at depth 0, its dependents
/// below it. A package is ours when the path cargo printed in parentheses is
/// under `root`. Returns e.g.
/// `["korp", "eframe", "egui-winit", "arboard", "image", "ravif", "rav1e",
///   "av-scenechange", "rayon"]`.
///
/// `None` means the tree named nothing of ours — either it is empty (clean) or
/// the format changed, and the caller must not read those two as the same thing.
pub fn tree_chain_to_first_party(out: &str, root: &Path) -> Option<Vec<String>> {
    let here = format!("({}", root.display());
    let mut stack: Vec<String> = Vec::new();
    for line in out.lines() {
        // The tree prefix is drawn from these five characters, four per level.
        let prefix: String =
            line.chars().take_while(|c| matches!(c, '' | ' ' | '' | '' | '')).collect();
        let body = &line[prefix.len()..];
        if body.is_empty() || body.starts_with('[') {
            // `[dev-dependencies]` / `[build-dependencies]` markers carry no
            // package of their own.
            continue;
        }
        let depth = prefix.chars().count() / 4;
        let Some(name) = body.split_whitespace().next().map(str::to_string) else { continue };
        stack.truncate(depth);
        stack.push(name);
        if body.contains(&here) {
            let mut chain = stack.clone();
            chain.reverse();
            return Some(chain);
        }
    }
    None
}

/// The verdict: is rayon reachable from this workspace over **normal** edges?
///
/// `Ok(None)` is clean. `Ok(Some(chain))` is a LAW 3 violation on a shipped
/// edge.
pub fn shipped_rayon_tree(root: &Path) -> Result<Option<Vec<String>>, String> {
    shipped_rayon_tree_with(root, &[])
}

/// [`shipped_rayon_tree`] for ONE feature selection — the build shape is a
/// parameter, because rayon can sit behind a feature and in korp it does.
///
/// Pass `&[]` for the default shape, or e.g.
/// `&["--no-default-features", "--features", "server"]`.
pub fn shipped_rayon_tree_with(
    root: &Path,
    features: &[&str],
) -> Result<Option<Vec<String>>, String> {
    let out = rayon_tree(root, "normal", features)?;
    if tree_found_nothing(&out) {
        return Ok(None);
    }
    Ok(Some(tree_chain_to_first_party(&out, root).unwrap_or_else(|| {
        out.lines().map(str::trim).filter(|l| !l.is_empty()).map(str::to_string).collect()
    })))
}

/// The `--no-default-features --features <name>` argv for one feature.
pub fn only_feature(name: &str) -> Vec<String> {
    vec!["--no-default-features".into(), "--features".into(), name.into()]
}

/// The same instrument and the same parser, asked a question this tree is
/// **known** to answer yes to: reach rayon over edges of *any* kind.
///
/// Both repos really do carry rayon in `Cargo.lock`, through
/// `nornir-robotui`'s snapshot harness (`egui_kittest → dify → image → ravif →
/// rav1e → av-scenechange`), and every edge of that is a `[dev-dependencies]`
/// edge. So this call must always come back with a chain that ends at one of
/// OUR packages — and [`shipped_rayon_tree`] is the identical command with the
/// single `-e` flag narrowed to `normal`.
///
/// What it proves: cargo ran, rayon is in the graph, the parser read real
/// cargo output, and the walk reaches this workspace. What it does **not**
/// prove: that a *normal* edge would be detected — that is what
/// `the_tree_parser_reads_a_real_violation_chain_all_the_way_to_us` is for,
/// which is proven red against a captured violation. Stated plainly because a
/// liveness check dressed up as a red proof is the disease this module is about.
///
/// A guard whose clean answer is `None` cannot tell "clean" from "the command
/// stopped working". This makes it say which, on every run.
pub fn rayon_tree_liveness_chain(root: &Path) -> Result<Option<Vec<String>>, String> {
    let out = rayon_tree(root, "normal,dev,build", &[])?;
    if tree_found_nothing(&out) {
        return Ok(None);
    }
    Ok(tree_chain_to_first_party(&out, root))
}

/// The `-e normal` query under `--all-features`, which in **korp** really does
/// produce a shipped violation: `--all-features` turns on `image`'s `avif` and
/// `ravif → rav1e → av-scenechange → rayon` becomes a normal edge reaching korp
/// itself. Measured on oden 2026-08-03 — the same command that says "nothing to
/// print" at default features prints that chain.
///
/// This is the strongest available proof for check 3, because the failing query
/// is byte-for-byte the query the verdict uses. It is **not** universal:
/// measured the same day, facett answers "nothing to print" even under
/// `--all-features`, because `--all-features` applies to workspace members only
/// and no facett member turns `avif` on. Callers that cannot get a chain here
/// must fall back to [`rayon_tree_liveness_chain`], not skip the axis.
pub fn rayon_tree_all_features_chain(root: &Path) -> Result<Option<Vec<String>>, String> {
    let out = rayon_tree(root, "normal", &["--all-features"])?;
    if tree_found_nothing(&out) {
        return Ok(None);
    }
    Ok(tree_chain_to_first_party(&out, root))
}

/// The feature set cargo resolves for `pkg` when the **whole workspace** is
/// selected — exactly what `cargo test --workspace` compiles with.
///
/// This asks cargo rather than re-implementing feature unification, because a
/// hand-rolled resolver that quietly disagrees with cargo is a guard that
/// reports on a build nobody runs.
pub fn workspace_features(md: &serde_json::Value, pkg: &str) -> Option<Vec<String>> {
    let names = id_to_name(md);
    let mut out: Vec<String> = Vec::new();
    let mut found = false;
    for node in md["resolve"]["nodes"].as_array()? {
        let id = node["id"].as_str()?;
        if names.get(id).map(|n| n != pkg).unwrap_or(true) {
            continue;
        }
        found = true;
        if let Some(fs) = node["features"].as_array() {
            out.extend(fs.iter().filter_map(|f| f.as_str().map(str::to_string)));
        }
    }
    if !found {
        return None;
    }
    out.sort();
    out.dedup();
    Some(out)
}

/// A test the default build never runs, because a `cfg` switches it off.
///
/// Two shapes, both silent, told apart by [`whole_file`](Self::whole_file):
///
/// * a crate-level `#![cfg(feature = "…")]` — the WHOLE target compiles to an
///   empty binary that prints `0 tests, 0 benchmarks`;
/// * a per-`fn` `#[cfg(feature = "…")]` on `#[test]` inside a file that otherwise
///   runs — libtest never lists the fn at all, so it does not even reach the
///   `filtered out` count.
///
/// The second shape is the more dangerous one: the target's OTHER tests report a
/// cheerful `ok`, so the file looks alive while the arm that needed the feature is
/// gone. MEASURED in this workspace 2026-08-22 — facett-map alone carries 3 files
/// of that shape (`cull_envelope`, `fill_extent_gate`, `paint_order_pixels`).
#[derive(Debug, Clone)]
pub struct GatedTestFile {
    /// The file.
    pub file: PathBuf,
    /// The feature the `cfg` demands.
    pub feature: String,
    /// How many `#[test]`/`#[tokio::test]` functions this entry silences — the
    /// number that disappears when the feature is off.
    pub tests: usize,
    /// `true` when a crate-level `#![cfg(…)]` takes the whole target down;
    /// `false` when only the individual `#[test]` fns counted here are gated.
    pub whole_file: bool,
}

/// Find every `tests/*.rs` under `crate_dir` that a feature `cfg` can silence —
/// crate-level and per-`fn` alike.
///
/// A gated file whose feature is off compiles to an empty binary that prints
/// `0 tests, 0 benchmarks` and exits 0 — indistinguishable from a passing file.
/// That is the exact shape of a green nobody has seen red. A per-`fn` gate is
/// quieter still: the target runs, reports `ok`, and the gated fns are not even
/// counted as `filtered out`.
///
/// One entry per (file, feature). A crate-level `#![cfg(all(feature = "a",
/// not(target_arch = "wasm32")))]` yields one entry for `a` — every feature the
/// `cfg` REQUIRES is a separate entry, because each one alone can silence the file.
/// `any(feature = …)` is deliberately NOT modelled (a file behind `any` is reachable
/// through either arm, which this shape cannot express); [`any_feature_cfgs`] finds
/// them so the day one is written it is a visible decision and not a silent miss.
pub fn gated_test_files(crate_dir: &Path) -> Vec<GatedTestFile> {
    let mut out = Vec::new();
    let Ok(rd) = std::fs::read_dir(crate_dir.join("tests")) else { return out };
    for entry in rd.flatten() {
        let path = entry.path();
        if path.extension().and_then(|e| e.to_str()) != Some("rs") {
            continue;
        }
        let Ok(text) = std::fs::read_to_string(&path) else { continue };
        let lines: Vec<&str> = text.lines().collect();

        let is_test_attr =
            |l: &str| l.trim().starts_with("#[test]") || l.trim().starts_with("#[tokio::test");

        // ── crate-level: the whole target goes silent ────────────────────────
        let crate_feats: Vec<String> = lines
            .iter()
            .filter(|l| l.trim_start().starts_with("#![cfg("))
            .flat_map(|l| required_features_of_cfg(l))
            .collect();
        if !crate_feats.is_empty() {
            let tests = lines.iter().filter(|l| is_test_attr(l)).count();
            let mut seen: Vec<String> = Vec::new();
            for f in crate_feats {
                if seen.contains(&f) {
                    continue;
                }
                seen.push(f.clone());
                out.push(GatedTestFile { file: path.clone(), feature: f, tests, whole_file: true });
            }
            // A file already dead at the top cannot ALSO be counted per fn.
            continue;
        }

        // ── per-fn: the target runs and the gated fns are simply not there ───
        // Attributes may sit on either side of `#[test]`, so the contiguous run of
        // `#[…]` lines around it is the attribute block to read.
        let mut per_feature: Vec<(String, usize)> = Vec::new();
        for (i, l) in lines.iter().enumerate() {
            if !is_test_attr(l) {
                continue;
            }
            let mut feats: Vec<String> = Vec::new();
            let mut j = i;
            while j > 0 && lines[j - 1].trim_start().starts_with("#[") {
                j -= 1;
                feats.extend(required_features_of_cfg(lines[j]));
            }
            let mut k = i + 1;
            while k < lines.len() && lines[k].trim_start().starts_with("#[") {
                feats.extend(required_features_of_cfg(lines[k]));
                k += 1;
            }
            feats.sort();
            feats.dedup();
            for f in feats {
                match per_feature.iter_mut().find(|(g, _)| *g == f) {
                    Some((_, n)) => *n += 1,
                    None => per_feature.push((f, 1)),
                }
            }
        }
        for (feature, tests) in per_feature {
            out.push(GatedTestFile { file: path.clone(), feature, tests, whole_file: false });
        }
    }
    out.sort_by(|a, b| (&a.file, &a.feature).cmp(&(&b.file, &b.feature)));
    out
}

/// Every `cfg` line under `crate_dir/tests` that uses `any(feature = …)`.
///
/// [`gated_test_files`] models a `cfg` as a set of features that are ALL required.
/// `any(...)` breaks that: the file is reachable through either arm, and reporting
/// it as "needs feature A" would be a lie that could send someone declaring an arm
/// nobody needs. There are none in this workspace today; this is what says so, and
/// what will say otherwise the day one is written.
pub fn any_feature_cfgs(crate_dir: &Path) -> Vec<(PathBuf, String)> {
    let mut out = Vec::new();
    let Ok(rd) = std::fs::read_dir(crate_dir.join("tests")) else { return out };
    for entry in rd.flatten() {
        let path = entry.path();
        if path.extension().and_then(|e| e.to_str()) != Some("rs") {
            continue;
        }
        let Ok(text) = std::fs::read_to_string(&path) else { continue };
        for l in text.lines() {
            let t = l.trim_start();
            if (t.starts_with("#[cfg(") || t.starts_with("#![cfg(")) && t.contains("any(") && t.contains("feature") {
                out.push((path.clone(), t.to_string()));
            }
        }
    }
    out
}

/// Every feature a `cfg` attribute line REQUIRES: each `feature = "x"` that is not
/// inside a `not(…)` and not inside an `any(…)`.
///
/// `#![cfg(feature = "wgpu")]`                                   → `["wgpu"]`
/// `#![cfg(all(feature = "gfx-v2-gpu", not(target_arch = "…")))]` → `["gfx-v2-gpu"]`
/// `#![cfg(not(target_arch = "wasm32"))]`                        → `[]` (no feature)
/// `#[cfg(any(feature = "a", feature = "b"))]`                   → `[]` (see
/// [`any_feature_cfgs`])
fn required_features_of_cfg(line: &str) -> Vec<String> {
    let t = line.trim();
    if !(t.starts_with("#[cfg(") || t.starts_with("#![cfg(")) {
        return Vec::new();
    }
    let mut out = Vec::new();
    // Walk the line tracking whether we are inside a `not(` or `any(` group. Both
    // make a `feature = "x"` inside them NOT a requirement.
    let bytes = t.as_bytes();
    let mut depth_stack: Vec<bool> = Vec::new(); // true = this group negates/relaxes
    let mut i = 0usize;
    while i < bytes.len() {
        if bytes[i] == b'(' {
            let before = &t[..i];
            let neg = before.ends_with("not") || before.ends_with("any");
            depth_stack.push(neg);
            i += 1;
            continue;
        }
        if bytes[i] == b')' {
            depth_stack.pop();
            i += 1;
            continue;
        }
        if t[i..].starts_with("feature") {
            let rest = t[i + "feature".len()..].trim_start();
            if let Some(rest) = rest.strip_prefix('=') {
                let rest = rest.trim_start();
                if let Some(rest) = rest.strip_prefix('"') {
                    if let Some(end) = rest.find('"') {
                        // Skip the outermost `cfg(` group itself: it is never a
                        // negation, and `depth_stack` already carries it.
                        let relaxed = depth_stack.iter().skip(1).any(|n| *n);
                        if !relaxed {
                            out.push(rest[..end].to_string());
                        }
                    }
                }
            }
            i += "feature".len();
            continue;
        }
        i += 1;
    }
    out
}
// ── The attribute-owner law ───────────────────────────────────────────────────
//
// **An attribute binds to the NEXT item.** Anything inserted between the two —
// a doc comment, a doc comment plus a whole new item — silently re-parents it.
// The code compiles, the tests stay green, and something stops existing.
//
// Three independent instances were measured on 2026-08-22, all found by
// accident:
//
// 1. `nornir/src/lib.rs` — a doc comment landed between `#[cfg(feature = "mcp")]`
//    and `pub mod mcp_stdio;`. `mcp_stdio` became UNCONDITIONAL (281 rmcp/schemars
//    errors in every default build) and the new `lens_chain` module inherited the
//    gate, so it compiled ONLY with `mcp` — which is what hid the fact that it did
//    not compile at all.
// 2. `edda/crates/nornir-service` — the same wedge moved `#[cfg(feature =
//    "auth-provider")]` onto a `pub use`, and every default build of the crate
//    failed on an unresolved `provider`.
// 3. `korp/src/main.rs` — a new test was pasted between an existing `#[test]` and
//    its function. One function then carried two `#[test]`s and
//    `korp_state_exposes_all_views` carried none: it had not run for months, with
//    the whole suite green. The only signal was one `duplicate_macro_attributes`
//    warning.
//
// Instance 3 is why this is a source scan and not only a lint switch. `rustc`
// does warn on the duplicate, but a warning in a 20 000-line build log is not a
// gate, and neither `duplicate_macro_attributes` nor `unused_attributes` says
// anything about instances 1 and 2 — there the attribute is *used*, just by the
// wrong item.
//
// Measured cost of the three rules over the whole constellation on 2026-08-22
// (26 repos, ~1.1 M lines of first-party Rust): 3 duplicate blocks, 9
// gate-before-doc blocks, 1 orphaned test function. Small enough to be a hard
// gate rather than a report.

/// Attributes that decide whether an item **exists**, or whether a function is a
/// test. These are the ones whose owner is worth a build failure: a re-parented
/// `#[derive]` fails to compile, a re-parented `#[cfg]` or `#[test]` does not.
fn attr_changes_existence(name: &str) -> bool {
    matches!(name, "cfg" | "cfg_attr") || attr_is_test(name)
}

/// A test-declaring attribute, in any of the spellings this constellation uses.
/// Matched on the last `::` segment so `tokio::test` and a bare `test` are one
/// answer.
fn attr_is_test(name: &str) -> bool {
    let last = name.rsplit("::").next().unwrap_or(name);
    // `wasm_bindgen_test` is how garmr-webui declares all seventeen of its browser
    // tests; a set of exact names missed every one of them and called the file
    // seventeen dead tests.
    last == "test"
        || last.ends_with("_test")
        || matches!(last, "bench" | "rstest" | "proptest" | "test_case" | "quickcheck")
        || matches!(name, "ignore" | "should_panic")
}

/// Attributes that may not legally appear twice on one item. `cfg`, `allow`,
/// `derive`, `serde` and friends repeat all the time and are not on this list —
/// a duplicate of those is caught by the byte-identical rule instead, which
/// cannot produce a false positive.
fn attr_is_non_repeatable(name: &str) -> bool {
    let last = name.rsplit("::").next().unwrap_or(name);
    matches!(
        last,
        "test"
            | "bench"
            | "rstest"
            | "ignore"
            | "should_panic"
            | "no_mangle"
            | "global_allocator"
            | "panic_handler"
            | "proc_macro"
            | "proc_macro_derive"
            | "proc_macro_attribute"
    )
}

/// The attribute path at the head of `#[…]` / `#![…]`, e.g. `cfg`, `tokio::test`.
fn attr_path(line: &str) -> Option<String> {
    let t = line.trim_start();
    let rest = t.strip_prefix("#[").or_else(|| t.strip_prefix("#!["))?;
    let mut out = String::new();
    for c in rest.chars() {
        if c.is_alphanumeric() || c == '_' || c == ':' {
            out.push(c);
        } else if c.is_whitespace() && out.is_empty() {
            continue;
        } else {
            break;
        }
    }
    if out.is_empty() { None } else { Some(out) }
}

/// One entry of an attribute block, in source order.
#[derive(Debug, Clone, PartialEq, Eq)]
enum Piece {
    /// An outer `#[…]` attribute: (line, path, full text).
    Attr(usize, String, String),
    /// A `///` doc comment line.
    Doc(usize),
}

/// Parse the attribute/doc block that starts at `lines[i]`, returning its pieces
/// and the index of the ITEM line it binds to.
///
/// Multi-line attributes are followed by bracket balance, which is what the first
/// cut of this scanner got wrong: `#[ignore = "…"]` spread over four lines made
/// the walk stop early and report two perfectly attributed heavy tests in
/// `nornir-build-thing` as orphans. Blank lines are also legal between an
/// attribute and its item (`znippy-zoomies/src/stree.rs` writes them), and
/// stopping there produced three more phantom orphans.
fn parse_block(lines: &[&str], start: usize) -> (Vec<Piece>, usize) {
    let mut pieces = Vec::new();
    let mut i = start;
    while i < lines.len() {
        let t = lines[i].trim_start();
        if t.starts_with("#[") {
            // Anything after the closing bracket on the same line means this is an
            // item line carrying an inline attribute (`#[serde(default)] pub a: u8,`),
            // not a block entry — otherwise struct fields read as one long block.
            let mut depth: i32 = 0;
            let mut end = i;
            let mut tail_is_clean = false;
            'outer: for (k, l) in lines.iter().enumerate().skip(i) {
                for (ci, c) in l.char_indices() {
                    if c == '[' {
                        depth += 1;
                    } else if c == ']' {
                        depth -= 1;
                        if depth == 0 {
                            end = k;
                            let tail = l[ci + 1..].trim();
                            tail_is_clean = tail.is_empty() || tail.starts_with("//");
                            break 'outer;
                        }
                    }
                }
            }
            if !tail_is_clean {
                break;
            }
            let text: String = lines[i..=end].join(" ").split_whitespace().collect::<Vec<_>>().join(" ");
            let path = attr_path(t).unwrap_or_default();
            pieces.push(Piece::Attr(i + 1, path, text));
            i = end + 1;
            continue;
        }
        if t.starts_with("///") {
            pieces.push(Piece::Doc(i + 1));
            i += 1;
            continue;
        }
        if t.starts_with("//") || t.is_empty() {
            i += 1;
            continue;
        }
        break;
    }
    (pieces, i)
}

/// Line ranges of every `#[cfg(test)] mod … { … }` in a file, by brace balance.
fn cfg_test_mod_ranges(lines: &[&str]) -> Vec<(usize, usize)> {
    let mut out = Vec::new();
    for (i, l) in lines.iter().enumerate() {
        if !l.trim_start().starts_with("#[cfg(test)]") {
            continue;
        }
        let (_, item) = parse_block(lines, i);
        let Some(head) = lines.get(item) else { continue };
        let h = head.trim_start();
        if !(h.starts_with("mod ") || h.starts_with("pub mod ")) {
            continue;
        }
        let mut depth: i32 = 0;
        let mut opened = false;
        for (k, l) in lines.iter().enumerate().skip(item) {
            depth += l.matches('{').count() as i32 - l.matches('}').count() as i32;
            if l.contains('{') {
                opened = true;
            }
            if opened && depth <= 0 {
                out.push((item, k));
                break;
            }
        }
    }
    out
}

/// `fn some_name()` — a zero-argument free function, the shape every test has.
fn zero_arg_fn_name(line: &str) -> Option<&str> {
    let t = line.trim_start();
    let t = t.strip_prefix("pub ").unwrap_or(t).trim_start();
    let t = t.strip_prefix("async ").unwrap_or(t).trim_start();
    let t = t.strip_prefix("unsafe ").unwrap_or(t).trim_start();
    let rest = t.strip_prefix("fn ")?;
    let name_end = rest.find(|c: char| !(c.is_alphanumeric() || c == '_'))?;
    let (name, tail) = rest.split_at(name_end);
    let tail = tail.trim_start();
    if !tail.starts_with("()") {
        return None;
    }
    if name.is_empty() { None } else { Some(name) }
}

/// The three shapes, found in one `.rs` file. `path` is only used to label the
/// hits and to decide whether the file is a test surface.
///
/// Public so a guard can plant a shape in a string and watch this name it — a
/// scanner that has never been seen red is exactly the hollow green the module
/// docs are about.
pub fn attribute_hits(path: &Path, text: &str) -> Vec<Hit> {
    let lines: Vec<&str> = text.lines().collect();
    let mut hits = Vec::new();
    let p = path.to_string_lossy().replace('\\', "/");
    // cargo compiles `tests/*.rs` as test binaries and everything DEEPER as a shared
    // helper module that sibling binaries pull in with `mod support;`. In a helper,
    // "nothing in this file calls it" says nothing at all — `nornir`'s
    // `tests/support/mcp_harness.rs` is called only from the binaries that include it.
    let is_support = ["/tests/", "/benches/"].iter().any(|d| {
        p.rsplit_once(d).is_some_and(|(_, rest)| rest.contains('/'))
    });
    let is_test_surface = p.contains("/tests/") || p.contains("/benches/");
    let test_mods = cfg_test_mod_ranges(&lines);

    let mut i = 0usize;
    while i < lines.len() {
        let t = lines[i].trim_start();
        let starts_block = t.starts_with("#[") || t.starts_with("///");
        if !starts_block {
            // R3 — a test-shaped function that carries no attribute block at all.
            if let Some(name) = zero_arg_fn_name(lines[i]) {
                maybe_orphan_test(
                    path, &lines, text, i, name, &[], is_support, is_test_surface, &test_mods,
                    &mut hits,
                );
            }
            i += 1;
            continue;
        }
        let (pieces, item) = parse_block(&lines, i);
        if pieces.is_empty() {
            i += 1;
            continue;
        }
        let item_line = lines.get(item).copied().unwrap_or("<end of file>");

        // R1 — the same attribute twice on one item: either a non-repeatable
        // attribute by name, or a byte-identical repeat of any attribute.
        let mut by_name: Vec<(usize, &str)> = Vec::new();
        let mut by_text: Vec<(usize, &str)> = Vec::new();
        for piece in &pieces {
            let Piece::Attr(ln, name, txt) = piece else { continue };
            if attr_is_non_repeatable(name) {
                if let Some((first, _)) = by_name.iter().find(|(_, n)| *n == name) {
                    hits.push(Hit {
                        file: path.to_path_buf(),
                        line: *ln,
                        token: format!("duplicate #[{name}]"),
                        text: format!(
                            "`{item_line}` carries #[{name}] twice (also line {first}) — the first \
                             one lost its item: whatever it was written for is now unattributed"
                        ),
                    });
                }
                by_name.push((*ln, name));
            }
            if let Some((first, _)) = by_text.iter().find(|(_, x)| *x == txt) {
                hits.push(Hit {
                    file: path.to_path_buf(),
                    line: *ln,
                    token: format!("duplicate {txt}"),
                    text: format!(
                        "`{item_line}` carries the identical attribute twice (also line {first}) — \
                         the first one was written for a different item"
                    ),
                });
            }
            by_text.push((*ln, txt));
        }

        // R2 — an existence-gating attribute above a doc comment. Docs come
        // first, gates come last, so that pasting `/// doc` + a new item under an
        // existing gate is impossible to do silently.
        let mut gate: Option<(usize, &str)> = None;
        for piece in &pieces {
            match piece {
                Piece::Attr(ln, name, txt) if attr_changes_existence(name) => {
                    gate = Some((*ln, txt));
                }
                Piece::Doc(ln) => {
                    if let Some((gl, gtxt)) = gate {
                        hits.push(Hit {
                            file: path.to_path_buf(),
                            line: gl,
                            token: format!("gate above a doc comment {gtxt}"),
                            text: format!(
                                "{gtxt} at line {gl} sits ABOVE the doc comment at line {ln}, and \
                                 therefore gates `{item_line}` — check that is the item it was \
                                 written for, then put the gate directly on it, below its doc"
                            ),
                        });
                        break;
                    }
                }
                _ => {}
            }
        }

        // R3 — the function this block binds to, with no test attribute on it.
        if let Some(name) = zero_arg_fn_name(item_line) {
            maybe_orphan_test(
                path, &lines, text, item, name, &pieces, is_support, is_test_surface, &test_mods,
                &mut hits,
            );
        }
        // Continue AFTER the item, or the item line is re-read as a bare line with no
        // attribute block — which reported every properly attributed test in
        // `facet-wrapped` as an orphan the first time this ran.
        i = item + 1;
    }
    hits
}

/// R3: a zero-argument function in a test scope, with a sentence-shaped name, no
/// test attribute, no `allow(dead_code)`, and no other mention of its own name in
/// the file — i.e. a test that stopped being a test and that nothing calls.
///
/// `korp_state_exposes_all_views` had been in exactly this state for months.
#[allow(clippy::too_many_arguments)]
fn maybe_orphan_test(
    path: &Path,
    lines: &[&str],
    text: &str,
    item: usize,
    name: &str,
    pieces: &[Piece],
    is_support: bool,
    is_test_surface: bool,
    test_mods: &[(usize, usize)],
    hits: &mut Vec<Hit>,
) {
    if is_support {
        return;
    }
    if !is_test_surface && !test_mods.iter().any(|(a, b)| item >= *a && item <= *b) {
        return;
    }
    // Test names in this constellation are sentences; a two-word `fn setup()` is a
    // helper, and guessing at helpers is how a guard earns its way to being off.
    if name.matches('_').count() < 2 {
        return;
    }
    for piece in pieces {
        let Piece::Attr(_, attr_name, txt) = piece else { continue };
        if attr_is_test(attr_name) || txt.contains("dead_code") {
            return;
        }
    }
    // Called from somewhere in this file ⇒ a helper, not a stranded test.
    let mentions = text.match_indices(name).filter(|(i, _)| {
        let before = text[..*i].chars().next_back();
        let after = text[i + name.len()..].chars().next();
        !before.is_some_and(|c| c.is_alphanumeric() || c == '_')
            && !after.is_some_and(|c| c.is_alphanumeric() || c == '_')
    });
    if mentions.count() > 1 {
        return;
    }
    let _ = lines;
    hits.push(Hit {
        file: path.to_path_buf(),
        line: item + 1,
        token: "test function with no #[test]".to_string(),
        text: format!(
            "`fn {name}()` sits in a test scope, is named like a test, carries no test \
             attribute and is called by nothing — it does not run, and the suite is green"
        ),
    });
}

/// Scan every first-party `.rs` file under `root` for the attribute-owner law.
///
/// Reuses [`source_roots`], so it reads exactly the files the rayon law reads —
/// one walker, one definition of "ours" (LAW 5). `scanned` travels with the
/// verdict for the same reason it does there: a scan that read nothing finds
/// nothing, and that is the false green this constellation keeps producing.
pub fn scan_attributes(root: &Path) -> Scan {
    let mut files = Vec::new();
    for dir in source_roots(root) {
        rs_files(&dir, &mut files);
    }
    let mut hits = Vec::new();
    for file in &files {
        let Ok(text) = std::fs::read_to_string(file) else { continue };
        hits.extend(attribute_hits(file, &text));
    }
    Scan { hits, scanned: files.len() }
}


// ── The checkout-surface law ──────────────────────────────────────────────────
//
// Measured on oden 2026-08-22/23: **737 repo-escaping `path =` dependencies
// across 17 repos** (nornir 174, korp 127, dwarves 125). Every one of them is a
// build reaching *out of its own checkout* into a sibling directory, and cargo
// resolves it by PATH — it has no opinion at all about which commit that sibling
// is parked on.
//
// The consequence is not theoretical. Three separate "findings" filed the same
// night were phantoms of stale primary checkouts: a dwarves red that was a
// 10-commit-behind edda, a "`facett_core::law::dep_tree` does not exist" that
// was a 4-commit-behind facett (the fn is right here in this file), and a third.
// While thirteen lanes built against them the primaries stood at facett −4,
// korp −27, edda −10, dwarves −7, znippy-zoomies −7, knut −3 — and
// `/home/rickard/git/facett`, the checkout every facett path dep in the
// constellation lands in, was sitting on *another lane's branch*, 400 lines of
// this file behind `origin/main`.
//
// A compile error is what that looks like from the inside, so the reflex is to
// go fix the code. The check below is the cheap thing that would have said the
// true sentence instead: **your sibling is not at the ref you think.**
//
// It deliberately answers about the CHECKOUT, not about the code. [`sibling_survey`]
// walks the repo-escaping path deps of a workspace, resolves each to the git
// checkout that actually contains it, and reports how that checkout's `HEAD`
// stands against its own `origin/HEAD`. [`sibling_offenders`] is the assertable
// form: empty means every sibling this build links against is at its remote's
// default ref, and anything else is the phantom, named, before it becomes a
// mystery compile failure.
//
// Why `origin/HEAD` and not `origin/main`: znippy's canonical branch is
// `master` and znippy-zoomies' is `main`, so the branch name is not knowable
// from outside the repo. `git symbolic-ref refs/remotes/origin/HEAD` asks the
// repo instead of a table — which is the same correction LAW 6 already makes in
// prose.
//
// This shells out to `git`, the way [`cargo_metadata`] shells out to cargo: the
// question is "what does the tool that owns this state say", and re-implementing
// ref resolution would be a second writer of it (LAW 5).

/// A `path = "…"` dependency whose target lies outside the repo that declared it.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EscapingDep {
    /// The dependency name as the manifest spells it.
    pub name: String,
    /// The manifest that declared it.
    pub manifest: PathBuf,
    /// The literal `path = "…"` value.
    pub declared: String,
    /// `declared`, resolved against the manifest's directory and normalised.
    /// Lexical only — the target may not exist, and that is a finding, not an error.
    pub resolved: PathBuf,
}

/// What a sibling checkout is actually doing, as opposed to what the builder assumed.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SiblingState {
    /// The path does not exist. This is the "the build dies outright" case: it is
    /// why one `cargo check` from a worktree needed twelve sibling worktrees,
    /// discovered one cargo error at a time.
    Missing,
    /// The path exists but is in no git checkout — nothing pins it at all.
    Untracked,
    /// A detached HEAD. Not necessarily wrong, but nothing says which ref it means.
    Detached { head: String },
    /// The checkout has no `origin/HEAD`, so it cannot say what its own canonical
    /// branch is. Ask the repo, not a table — and this repo declines to answer.
    NoOriginHead,
    /// HEAD and `origin/HEAD` name different commits. **This is the phantom.**
    Drifted { head: String, expected: String, behind: usize, ahead: usize },
    /// HEAD is exactly `origin/HEAD`. `dirty` still travels, because an aligned
    /// ref with uncommitted source in it is a different build from the one the ref names.
    Aligned { head: String, dirty: usize },
}

impl SiblingState {
    /// Is this a state a build may rely on? Only [`SiblingState::Aligned`] with a
    /// clean tree is. Everything else means the linked code is not the code the
    /// ref names.
    pub fn is_trustworthy(&self) -> bool {
        matches!(self, SiblingState::Aligned { dirty: 0, .. })
    }
}

/// One repo-escaping dependency, and the state of the checkout it landed in.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Sibling {
    pub dep: EscapingDep,
    /// The checkout root that contains [`EscapingDep::resolved`], if any.
    pub checkout: Option<PathBuf>,
    pub state: SiblingState,
}

impl Sibling {
    /// One line, in the shape the report asks for: subject, status, detail.
    pub fn describe(&self) -> String {
        let where_ = self.checkout.clone().unwrap_or_else(|| self.dep.resolved.clone());
        match &self.state {
            SiblingState::Missing => {
                format!("{} — MISSING — {} declares path {:?}, nothing is there", self.dep.name, self.dep.manifest.display(), self.dep.declared)
            }
            SiblingState::Untracked => {
                format!("{} — UNTRACKED — {} is in no git checkout, so no ref pins it", self.dep.name, where_.display())
            }
            SiblingState::Detached { head } => {
                format!("{} — DETACHED — {} is at {head} with no branch; nothing says which ref that is", self.dep.name, where_.display())
            }
            SiblingState::NoOriginHead => {
                format!("{} — NO-ORIGIN-HEAD — {} cannot name its own canonical branch", self.dep.name, where_.display())
            }
            SiblingState::Drifted { head, expected, behind, ahead } => {
                format!(
                    "{} — DRIFTED — {} is at {head}, origin/HEAD is {expected} (behind {behind}, ahead {ahead}); this build links THAT, not the ref you think",
                    self.dep.name,
                    where_.display()
                )
            }
            SiblingState::Aligned { head, dirty } => {
                format!("{} — DIRTY — {} is at origin/HEAD {head} but carries {dirty} uncommitted change(s)", self.dep.name, where_.display())
            }
        }
    }
}

/// Every `path = "…"` dependency declared anywhere in `root`'s manifests, in
/// declaration order, without deduplication.
///
/// Text-based on purpose. `cargo metadata` would answer this too, but it needs a
/// resolvable graph — and the whole failure mode being guarded here is a graph
/// that does not resolve because a sibling is missing or stale. A check that can
/// only run once the build works is not a pre-build check.
pub fn declared_path_deps(root: &Path) -> Vec<EscapingDep> {
    let mut out = Vec::new();
    for manifest in workspace_manifests(root) {
        let Ok(text) = std::fs::read_to_string(&manifest) else { continue };
        let dir = manifest.parent().unwrap_or(root).to_path_buf();
        for (name, declared) in path_deps_in_manifest(&text) {
            let resolved = normalise(&dir.join(&declared));
            out.push(EscapingDep { name, manifest: manifest.clone(), declared, resolved });
        }
    }
    out
}

/// The subset of [`declared_path_deps`] that leaves `root` — the ones cargo
/// resolves into somebody else's checkout.
pub fn escaping_path_deps(root: &Path) -> Vec<EscapingDep> {
    let root = normalise(root);
    declared_path_deps(&root).into_iter().filter(|d| !d.resolved.starts_with(&root)).collect()
}

/// Parse `path = "…"` out of one manifest's text, pairing each with the
/// dependency name it belongs to.
///
/// Handles the three shapes this constellation actually writes: an inline table
/// (`edda = { path = "../edda" }`), a dotted section
/// (`[dependencies.edda]` … `path = "../edda"`), and a `[patch.crates-io]` entry —
/// which is the same escape wearing a different hat and is the one a
/// dependency-name-only parser silently drops.
pub fn path_deps_in_manifest(text: &str) -> Vec<(String, String)> {
    let mut out = Vec::new();
    let mut section_key: Option<String> = None;
    for line in text.lines() {
        let t = line.trim();
        if t.starts_with('#') {
            continue;
        }
        if t.starts_with('[') {
            // `[dependencies.edda]`, `[target.'cfg(x)'.dependencies.edda]`,
            // `[patch.crates-io.edda]` → the last segment is the dep name.
            // A bare `[dependencies]` / `[patch.crates-io]` has no name of its own.
            let head = t.trim_start_matches('[').trim_end_matches(']');
            let last = head.rsplit('.').next().unwrap_or("").trim().trim_matches('"');
            section_key = match last {
                "dependencies" | "dev-dependencies" | "build-dependencies" | "crates-io"
                | "workspace" | "package" | "features" | "lib" | "bin" | "patch" => None,
                other if other.is_empty() => None,
                other => Some(other.to_string()),
            };
            continue;
        }
        let Some(value) = quoted_value_of(t, "path") else { continue };
        // Inline table: the key before the first `=` is the dep name.
        let name = match t.split_once('=') {
            Some((k, rest)) if rest.trim_start().starts_with('{') => {
                k.trim().trim_matches('"').to_string()
            }
            _ => section_key.clone().unwrap_or_else(|| "<unnamed>".to_string()),
        };
        out.push((name, value));
    }
    out
}

/// `key = "value"` anywhere in `line`, returning `value`. Refuses to match a
/// longer key that merely ends in `key` (`rustc-path = "…"` is not `path`).
fn quoted_value_of(line: &str, key: &str) -> Option<String> {
    let mut from = 0usize;
    while let Some(i) = line[from..].find(key) {
        let at = from + i;
        let before_ok = at == 0 || !matches!(line.as_bytes()[at - 1], b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'-' | b'_' | b'.');
        let rest = &line[at + key.len()..];
        let after = rest.trim_start();
        if before_ok && after.starts_with('=') {
            let v = after[1..].trim_start();
            if let Some(stripped) = v.strip_prefix('"') {
                if let Some(end) = stripped.find('"') {
                    return Some(stripped[..end].to_string());
                }
            }
        }
        from = at + key.len();
    }
    None
}

/// Lexical path normalisation: fold away `.` and `..` without touching the disk,
/// so a dep pointing at a directory that does not exist still gets an answer.
fn normalise(p: &Path) -> PathBuf {
    let mut out = PathBuf::new();
    for c in p.components() {
        match c {
            std::path::Component::CurDir => {}
            // `..` above the root is still the root (POSIX): `/a/../../b` is `/b`,
            // not `/../b`. Only a RELATIVE path may keep a leading `..`.
            std::path::Component::ParentDir => {
                if !out.pop() && !out.has_root() {
                    out.push("..");
                }
            }
            other => out.push(other.as_os_str()),
        }
    }
    out
}

/// The git checkout that contains `p`: the nearest ancestor holding a `.git`
/// entry. A worktree's `.git` is a file, not a directory — both count, which is
/// the whole point on a box with 264 registered worktrees.
pub fn checkout_root(p: &Path) -> Option<PathBuf> {
    let mut cursor = Some(p);
    while let Some(dir) = cursor {
        if dir.join(".git").exists() {
            return Some(dir.to_path_buf());
        }
        cursor = dir.parent();
    }
    None
}

fn git(repo: &Path, args: &[&str]) -> Option<String> {
    let out = Command::new("git").arg("-C").arg(repo).args(args).output().ok()?;
    if !out.status.success() {
        return None;
    }
    Some(String::from_utf8_lossy(&out.stdout).trim().to_string())
}

/// Where one checkout stands against its own `origin/HEAD`.
///
/// The SHA decides, not the branch. A lane worktree created with
/// `git worktree add --detach <repo> origin/main` is detached *and* exactly right,
/// and that is the standard shape on this box — grading it red would train
/// everyone to ignore the check. [`SiblingState::Detached`] therefore means
/// "detached **and** not at `origin/HEAD`", which is a real unknown.
pub fn checkout_state(repo: &Path) -> SiblingState {
    let branch = git(repo, &["symbolic-ref", "--quiet", "--short", "HEAD"]);
    let head = git(repo, &["rev-parse", "HEAD"]).unwrap_or_default();
    let Some(origin_head) = git(repo, &["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"]) else {
        return SiblingState::NoOriginHead;
    };
    let expected = git(repo, &["rev-parse", &origin_head]).unwrap_or_default();
    let dirty = git(repo, &["status", "--porcelain"])
        .map(|s| s.lines().filter(|l| !l.trim().is_empty()).count())
        .unwrap_or(0);
    if head == expected && !head.is_empty() {
        return SiblingState::Aligned { head: short(&head), dirty };
    }
    if branch.is_none() {
        return SiblingState::Detached { head: short(&head) };
    }
    let (ahead, behind) = git(repo, &["rev-list", "--left-right", "--count", &format!("HEAD...{origin_head}")])
        .and_then(|s| {
            let mut it = s.split_whitespace();
            Some((it.next()?.parse().ok()?, it.next()?.parse().ok()?))
        })
        .unwrap_or((0usize, 0usize));
    SiblingState::Drifted { head: short(&head), expected: short(&expected), behind, ahead }
}

fn short(sha: &str) -> String {
    sha.chars().take(12).collect()
}

/// Every repo-escaping path dep of `root`, with the state of the checkout it
/// resolves into. Deduplicated by checkout, because 127 escapes into the same
/// eight siblings is one answer repeated 127 times.
pub fn sibling_survey(root: &Path) -> Vec<Sibling> {
    let mut seen: Vec<PathBuf> = Vec::new();
    let mut out = Vec::new();
    for dep in escaping_path_deps(root) {
        let checkout = checkout_root(&dep.resolved);
        let state = match &checkout {
            _ if !dep.resolved.exists() => SiblingState::Missing,
            None => SiblingState::Untracked,
            Some(repo) => {
                if seen.contains(repo) {
                    continue;
                }
                seen.push(repo.clone());
                checkout_state(repo)
            }
        };
        out.push(Sibling { dep, checkout, state });
    }
    out
}

/// The assertable form: every sibling this build links against that is **not**
/// at its remote's default ref with a clean tree.
///
/// ```no_run
/// # use std::path::Path;
/// # use facett_core::law;
/// let bad = law::sibling_offenders(Path::new("."));
/// assert!(bad.is_empty(), "{}", bad.iter().map(|s| s.describe()).collect::<Vec<_>>().join("\n"));
/// ```
pub fn sibling_offenders(root: &Path) -> Vec<Sibling> {
    sibling_survey(root).into_iter().filter(|s| !s.state.is_trustworthy()).collect()
}

// ─── does the repo RESOLVE at all ──────────────────────────────────────────

/// A repo whose dependency graph cannot be resolved, and the first line cargo
/// gave as the reason.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Unresolvable {
    /// The repo root that failed.
    pub root: PathBuf,
    /// Cargo's own first diagnostic line, kept verbatim.
    pub reason: String,
}

impl Unresolvable {
    /// One line for a failure message.
    #[must_use]
    pub fn describe(&self) -> String {
        format!("{} does not resolve: {}", self.root.display(), self.reason)
    }
}

/// **Does this repo's dependency graph resolve?** `cargo metadata --no-deps`,
/// which reads manifests and answers without compiling anything.
///
/// It exists because a repo that does not RESOLVE is invisible to everything
/// else. It is not red — a compile-coverage sweep cannot compile a target it
/// cannot enumerate, a dep-graph tool has no graph, and the warehouse indexer
/// skips it. MEASURED 2026-08-23: **modgunn and ordning could not resolve for
/// nine days** and nothing in the constellation said so. modgunn's cause was a
/// feature naming a feature that no longer existed (`skade/sql`, dropped
/// 2026-08-14) — which is a *resolution* error, not a build error, so no amount
/// of building would have found it.
///
/// Cheap on purpose: ~4 s per repo, no network (`--offline` is NOT passed —
/// a repo that needs the registry to resolve genuinely does not resolve
/// offline, and pretending otherwise would trade one blindness for another).
///
/// `Ok(())` means cargo answered. Anything else is the first line of why not.
pub fn resolves(root: &Path) -> Result<(), String> {
    let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".into());
    let out = Command::new(cargo)
        .args(["metadata", "--no-deps", "--format-version", "1"])
        .current_dir(root)
        .output()
        .map_err(|e| format!("could not run `cargo metadata` in {}: {e}", root.display()))?;
    if out.status.success() {
        return Ok(());
    }
    let stderr = String::from_utf8_lossy(&out.stderr);
    // Cargo's first `error:` line is the cause; the rest is the trace. Fall back
    // to the first non-empty line so an unfamiliar failure is still named rather
    // than reported as an empty string, which would read like success.
    let reason = stderr
        .lines()
        .find(|l| l.trim_start().starts_with("error"))
        .or_else(|| stderr.lines().find(|l| !l.trim().is_empty()))
        .unwrap_or("cargo metadata failed with no output")
        .trim()
        .to_string();
    Err(reason)
}

/// [`resolves`] over many repo roots — the constellation sweep.
///
/// Returns only the failures, so an empty vec is the assertion. A root that is
/// not a cargo repo at all (no `Cargo.toml`) is skipped, not reported: this
/// guard is about repos that USED to resolve, not about directories.
pub fn unresolvable(roots: &[PathBuf]) -> Vec<Unresolvable> {
    roots
        .iter()
        .filter(|r| r.join("Cargo.toml").is_file())
        .filter_map(|r| resolves(r).err().map(|reason| Unresolvable { root: r.clone(), reason }))
        .collect()
}

#[cfg(test)]
mod resolution_tests {
    use super::*;

    /// Write a minimal cargo repo and hand back its root.
    fn repo(dir: &Path, manifest: &str) -> PathBuf {
        std::fs::create_dir_all(dir.join("src")).unwrap();
        std::fs::write(dir.join("Cargo.toml"), manifest).unwrap();
        std::fs::write(dir.join("src/lib.rs"), "").unwrap();
        dir.to_path_buf()
    }

    /// A repo that resolves answers `Ok`; one whose feature names a feature that
    /// does not exist does not — **and that is the exact shape that hid modgunn
    /// for nine days** (`warehouse-sql = [..., "skade/sql"]` after skade dropped
    /// `sql` on 2026-08-14). It is a RESOLUTION failure, so no amount of
    /// building finds it: cargo cannot even enumerate the targets.
    #[test]
    fn a_feature_naming_a_feature_that_does_not_exist_does_not_resolve() {
        let tmp = std::env::temp_dir().join(format!("law-resolves-{}", std::process::id()));
        let _ = std::fs::remove_dir_all(&tmp);

        let good = repo(
            &tmp.join("good"),
            "[package]\nname = \"good\"\nversion = \"0.0.0\"\nedition = \"2021\"\n",
        );
        assert!(resolves(&good).is_ok(), "a plain repo resolves");

        // The mutation: a feature that forwards to one its own dependency table
        // cannot supply. Nothing else about the manifest changes.
        let bad = repo(
            &tmp.join("bad"),
            "[package]\nname = \"bad\"\nversion = \"0.0.0\"\nedition = \"2021\"\n\
             [features]\nwarehouse-sql = [\"nope/sql\"]\n",
        );
        let err = resolves(&bad).expect_err("a feature naming a missing dependency cannot resolve");
        assert!(
            err.to_lowercase().contains("error"),
            "the reason is cargo's own first line, kept verbatim: {err}"
        );

        // The sweep reports only the failure, and reports it by name.
        let bad_list = unresolvable(&[good.clone(), bad.clone()]);
        assert_eq!(bad_list.len(), 1, "one of the two does not resolve: {bad_list:?}");
        assert_eq!(bad_list[0].root, bad);
        assert!(bad_list[0].describe().contains("does not resolve"));

        // A directory that is not a cargo repo is SKIPPED, not reported — this
        // guard is about repos that used to resolve, not about directories.
        let plain = tmp.join("not-a-repo");
        std::fs::create_dir_all(&plain).unwrap();
        assert!(unresolvable(&[plain]).is_empty(), "a non-repo directory is not a failure");

        let _ = std::fs::remove_dir_all(&tmp);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    /// The `cfg` parser, on the four shapes this workspace actually contains plus
    /// the two it must refuse to guess about.
    ///
    /// This is the part that used to be a `strip_prefix("#![cfg(feature")`, which
    /// meant `#![cfg(all(feature = "gfx-v2-gpu", …))]` — facett-demo's
    /// `tests/gfx_v2_device.rs`, six test fns — was invisible to the whole
    /// gated-test guard.
    #[test]
    fn a_cfg_names_the_features_it_requires_and_no_others() {
        let f = |l: &str| required_features_of_cfg(l);
        assert_eq!(f(r#"#![cfg(feature = "wgpu")]"#), ["wgpu"]);
        assert_eq!(f(r#"#[cfg(feature = "wgpu")]"#), ["wgpu"]);
        assert_eq!(
            f(r#"#![cfg(all(feature = "gfx-v2-gpu", not(target_arch = "wasm32")))]"#),
            ["gfx-v2-gpu"]
        );
        assert_eq!(f(r#"#![cfg(all(feature = "a", feature = "b"))]"#), ["a", "b"]);
        // NOT requirements: a negated feature, and an `any` alternative.
        assert!(f(r#"#![cfg(not(feature = "wgpu"))]"#).is_empty());
        assert!(f(r#"#[cfg(any(feature = "a", feature = "b"))]"#).is_empty());
        // Not a cfg at all.
        assert!(f(r#"#![cfg(not(target_arch = "wasm32"))]"#).is_empty());
        assert!(f(r#"#[test]"#).is_empty());
        assert!(f(r#"// #![cfg(feature = "wgpu")]"#).is_empty());
    }

    /// The scanner sees BOTH shapes, and tells them apart.
    ///
    /// A per-`fn` gate is the quiet one: the target still reports `ok`, and the
    /// gated fn is not even counted as `filtered out`. Before this, only the
    /// crate-level shape was ever counted.
    #[test]
    fn the_scanner_finds_per_fn_gates_as_well_as_whole_file_ones() {
        let dir = std::env::temp_dir().join(format!("facett_law_gated_{}", std::process::id()));
        let tests = dir.join("tests");
        std::fs::create_dir_all(&tests).expect("scratch dir");

        std::fs::write(
            tests.join("whole.rs"),
            "#![cfg(all(feature = \"gfx\", not(target_arch = \"wasm32\")))]\n\
             #[test]\nfn a() {}\n#[test]\nfn b() {}\n",
        )
        .unwrap();
        std::fs::write(
            tests.join("partial.rs"),
            "#[test]\nfn cpu_one() {}\n\
             #[cfg(feature = \"wgpu\")]\n#[test]\nfn gpu_before() {}\n\
             #[test]\n#[cfg(feature = \"wgpu\")]\nfn gpu_after() {}\n\
             #[test]\nfn cpu_two() {}\n",
        )
        .unwrap();
        std::fs::write(tests.join("plain.rs"), "#[test]\nfn only() {}\n").unwrap();

        let found = gated_test_files(&dir);
        let _ = std::fs::remove_dir_all(&dir);

        assert_eq!(found.len(), 2, "one whole-file entry and one per-fn entry: {found:#?}");

        let whole = found.iter().find(|g| g.whole_file).expect("the crate-level cfg was seen");
        assert_eq!(whole.feature, "gfx", "an `all(feature = …, not(…))` still names its feature");
        assert_eq!(whole.tests, 2, "the whole target's fns go silent");

        let partial = found.iter().find(|g| !g.whole_file).expect("the per-fn cfgs were seen");
        assert_eq!(partial.feature, "wgpu");
        assert_eq!(
            partial.tests, 2,
            "both `#[cfg]`-before-`#[test]` and `#[test]`-before-`#[cfg]` are gated fns"
        );
        assert!(
            found.iter().all(|g| !g.file.ends_with("plain.rs")),
            "an ungated file must not be reported as gated — that would make the guard cry wolf"
        );
    }

    #[test]
    fn comment_stripping_keeps_code_and_drops_prose() {
        assert_eq!(strip_line_comment("let x = 1; // rayon::scope is banned").trim(), "let x = 1;");
        assert_eq!(strip_line_comment("//! never rayon").trim(), "");
        assert_eq!(strip_line_comment("let y = 2;").trim(), "let y = 2;");
    }

    #[test]
    fn the_forbidden_tokens_are_not_spelled_literally_in_this_file() {
        // The scanner covers its own source (no path carve-out), so the tokens
        // must be assembled rather than written out — otherwise this module
        // trips the law it enforces, and someone "fixes" it by adding an
        // exemption that then hides real hits.
        let me = include_str!("law.rs");
        for tok in rayon_call_tokens() {
            let literal_uses = me
                .lines()
                .filter(|l| !strip_line_comment(l).trim().is_empty())
                .filter(|l| strip_line_comment(l).contains(&tok))
                .count();
            assert_eq!(literal_uses, 0, "`{tok}` appears literally in live code in law.rs");
        }
    }

    /// **This test used to REQUIRE the blindness.** It asserted
    /// `crate_level_cfg_feature("#[cfg(feature = \"wgpu\")]") == None` — i.e. that a
    /// per-`fn` gate is not a gate — and so it was the reason nothing ever counted
    /// the quiet shape. Both are gates; only the blast radius differs, and
    /// [`GatedTestFile::whole_file`] carries that.
    #[test]
    fn both_gate_shapes_are_read_and_a_non_cfg_line_is_not() {
        assert_eq!(required_features_of_cfg("#![cfg(feature = \"wgpu\")]"), ["wgpu"]);
        assert_eq!(required_features_of_cfg("  #![cfg(feature=\"gpu\")]  "), ["gpu"]);
        assert_eq!(required_features_of_cfg("#[cfg(feature = \"wgpu\")]"), ["wgpu"]);
        assert!(required_features_of_cfg("fn main() {}").is_empty());
    }

    /// The `guard-7(a)` case, verbatim in shape: korp's root manifest names
    /// "members" in a header comment three lines above `[workspace]`. The old
    /// `text.find("members")` landed in that comment, took `[workspace]`'s own
    /// brackets as the array and returned `["workspace"]` — so korp's manifest
    /// scan read 1 file where it should read 2, and the liveness assert in the
    /// gate refused the green it could not stand behind.
    #[test]
    fn the_word_members_in_a_header_comment_is_not_the_members_key() {
        let dir = scratch("header-comment");
        std::fs::write(
            dir.join("Cargo.toml"),
            "# korp is the workspace ROOT. The `crates/*` leaves are NOT pulled in\n\
             # as members — they are self-rooting.\n\
             [workspace]\n\
             resolver = \"3\"\n\
             members = [\"xtask\"]\n\
             exclude = [\"crates/korp-ontology\", \"crates/korp-demo\"]\n\
             \n\
             [package]\n\
             name = \"korp\"\n\
             exclude = [\"docs/*\"]\n",
        )
        .unwrap();
        assert_eq!(workspace_members(&dir), vec!["xtask".to_string()]);
        // `exclude` must come from `[workspace]`, not from `[package]`.
        assert_eq!(
            workspace_excludes(&dir),
            vec!["crates/korp-ontology".to_string(), "crates/korp-demo".to_string()]
        );
        // Both, because korp *depends on* `crates/korp-demo` by path: a
        // `rayon = "1"` there ships.
        assert_eq!(
            first_party_dirs(&dir),
            vec![
                "xtask".to_string(),
                "crates/korp-ontology".to_string(),
                "crates/korp-demo".to_string()
            ]
        );
        std::fs::remove_dir_all(&dir).ok();
    }

    #[test]
    fn a_trailing_toml_comment_inside_the_array_is_not_a_member() {
        let dir = scratch("array-comment");
        std::fs::write(
            dir.join("Cargo.toml"),
            "[workspace]\nmembers = [\n  \"a\", # the first one\n  \"b\",\n]\n",
        )
        .unwrap();
        assert_eq!(workspace_members(&dir), vec!["a".to_string(), "b".to_string()]);
        std::fs::remove_dir_all(&dir).ok();
    }

    fn scratch(tag: &str) -> PathBuf {
        let dir = std::env::temp_dir()
            .join(format!("facett-law-{tag}-{}-{:?}", std::process::id(), std::thread::current().id()));
        std::fs::create_dir_all(&dir).unwrap();
        dir
    }

    /// The complete, verbatim stdout of
    /// `cargo tree -e normal -i rayon --target all --all-features --offline
    /// --locked`, run in korp on oden 2026-08-03. Not a hand-drawn tree: this is
    /// the shape the guard has to read, dedupe markers (`(*)`), branch points
    /// and all. A parser tested only against the clean case is a parser that has
    /// never been asked to find anything.
    const KORP_ALL_FEATURES_TREE: &str = "\
rayon v1.12.0
├── av-scenechange v0.14.1
│   └── rav1e v0.8.1
│       └── ravif v0.13.0
│           └── image v0.25.10
│               ├── arboard v3.6.1
│               │   └── egui-winit v0.35.0
│               │       └── eframe v0.35.0
│               │           ├── korp v0.1.0 (/home/rickard/scratch/lawfix/korp)
│               │           └── nornir-robotui v0.3.0
│               │               └── korp v0.1.0 (/home/rickard/scratch/lawfix/korp)
│               ├── dify v0.8.0
│               │   └── egui_kittest v0.35.0
│               │       └── nornir-robotui v0.3.0 (*)
│               ├── eframe v0.35.0 (*)
│               ├── egui_kittest v0.35.0 (*)
│               ├── facett-about v0.1.13 (/home/rickard/scratch/lawfix/facett/facett-about)
│               │   └── korp v0.1.0 (/home/rickard/scratch/lawfix/korp)
│               ├── korp v0.1.0 (/home/rickard/scratch/lawfix/korp)
│               ├── nornir-robotui v0.3.0 (*)
│               └── webp v0.3.1
│                   └── nornir-robotui v0.3.0 (*)
├── dify v0.8.0 (*)
├── image v0.25.10 (*)
├── maybe-rayon v0.1.1
│   └── rav1e v0.8.1 (*)
└── ravif v0.13.0 (*)
";

    #[test]
    fn the_tree_parser_reads_a_real_violation_chain_all_the_way_to_us() {
        assert!(!tree_found_nothing(KORP_ALL_FEATURES_TREE));

        // (1) A straight descent: rayon down to korp, first hit in the file.
        let korp = Path::new("/home/rickard/scratch/lawfix/korp");
        let chain = tree_chain_to_first_party(KORP_ALL_FEATURES_TREE, korp)
            .expect("the chain reaches korp and must be readable");
        assert_eq!(
            chain,
            vec![
                "korp",
                "eframe",
                "egui-winit",
                "arboard",
                "image",
                "ravif",
                "rav1e",
                "av-scenechange",
                "rayon"
            ]
        );

        // (2) The same capture read as FACETT's workspace. This is the case that
        // makes the test able to fail: `facett-about` sits at depth 5, but the
        // three lines before it descend to depth 7, so the walker must POP back
        // up. A depth arithmetic that never pops still answers (1) correctly —
        // every line in that path goes one level deeper — and answers this one
        // with the stale `dify/egui_kittest/nornir-robotui` branch still on the
        // stack. Measured: with the divisor wrong, (1) stayed green and this
        // assert went red.
        let facett = Path::new("/home/rickard/scratch/lawfix/facett");
        let via_facett = tree_chain_to_first_party(KORP_ALL_FEATURES_TREE, facett)
            .expect("facett-about is first-party to the facett workspace");
        assert_eq!(
            via_facett,
            vec!["facett-about", "image", "ravif", "rav1e", "av-scenechange", "rayon"]
        );

        // (3) …and it must not claim a chain for a workspace it is not looking at.
        assert_eq!(tree_chain_to_first_party(KORP_ALL_FEATURES_TREE, Path::new("/nowhere")), None);
    }

    #[test]
    fn nothing_to_print_is_the_clean_answer_and_empty_is_not_silently_the_same() {
        // The literal notice cargo emits (on stderr) when `-i` finds no path.
        let clean = "warning: nothing to print.\n\nTo find dependencies that require \
                     specific target platforms, try to use option `--target all` first.\n";
        assert!(tree_found_nothing(clean));
        assert!(tree_found_nothing("   \n"));
        assert!(!tree_found_nothing(KORP_ALL_FEATURES_TREE));
        // A clean tree names nothing of ours — the two answers must not collapse.
        assert_eq!(tree_chain_to_first_party(clean, Path::new("/home/rickard/scratch/lawfix/korp")), None);
    }

    #[test]
    fn members_parse_from_a_multi_line_array() {
        let dir = scratch("multiline");
        std::fs::write(
            dir.join("Cargo.toml"),
            "[workspace]\nmembers = [\n  \"a\",\n  \"b\",\n]\n",
        )
        .unwrap();
        assert_eq!(workspace_members(&dir), vec!["a".to_string(), "b".to_string()]);
        std::fs::remove_dir_all(&dir).ok();
    }

    // ── the checkout-surface law ──────────────────────────────────────────────

    /// The three manifest shapes this constellation actually writes, plus the two
    /// this parser must not guess about.
    ///
    /// The `[patch.crates-io]` case is the one that makes this test able to fail:
    /// a parser that only reads `[dependencies]` tables drops every patch entry,
    /// and a `[patch.crates-io]` path override is precisely the escape that
    /// silently rebinds a build to a sibling checkout. `rustc-path` is the other
    /// direction — a substring match on `path` claims it and invents an escape.
    #[test]
    fn a_manifest_names_the_paths_it_escapes_through_and_no_others() {
        let text = r#"
[package]
name = "consumer"
# edda = { path = "../commented-out" }

[dependencies]
edda = { path = "../edda" }
facett-core = { version = "0.1", path = "../facett/facett-core" }
in-repo = { path = "crates/in-repo" }
plain = "1.0"

[dependencies.knut]
version = "0.2"
path = "../knut"

[target.'cfg(unix)'.dependencies.tunnr]
path = "../tunnr"

[patch.crates-io]
znippy = { path = "../znippy" }

[build]
rustc-path = "/usr/bin/rustc"
"#;
        let got = path_deps_in_manifest(text);
        assert_eq!(
            got,
            vec![
                ("edda".to_string(), "../edda".to_string()),
                ("facett-core".to_string(), "../facett/facett-core".to_string()),
                ("in-repo".to_string(), "crates/in-repo".to_string()),
                ("knut".to_string(), "../knut".to_string()),
                ("tunnr".to_string(), "../tunnr".to_string()),
                ("znippy".to_string(), "../znippy".to_string()),
            ],
            "the commented line, the plain version dep and rustc-path must not appear"
        );
    }

    /// `..` is folded lexically, because the target of a broken path dep does not
    /// exist and `canonicalize` would only be able to say so by returning an error.
    #[test]
    fn a_path_that_does_not_exist_still_normalises() {
        assert_eq!(normalise(Path::new("/a/b/../c/./d")), PathBuf::from("/a/c/d"));
        assert_eq!(normalise(Path::new("/a/../../b")), PathBuf::from("/b"));
    }

    /// Run `git` with a fixed identity so the fixture does not depend on whatever
    /// the box's global config happens to be.
    fn gitx(repo: &Path, args: &[&str]) {
        let out = Command::new("git")
            .arg("-C")
            .arg(repo)
            .args(args)
            .env("GIT_AUTHOR_NAME", "law fixture")
            .env("GIT_AUTHOR_EMAIL", "law@example.invalid")
            .env("GIT_COMMITTER_NAME", "law fixture")
            .env("GIT_COMMITTER_EMAIL", "law@example.invalid")
            .output()
            .expect("git runs");
        assert!(
            out.status.success(),
            "git {args:?} in {} failed: {}",
            repo.display(),
            String::from_utf8_lossy(&out.stderr)
        );
    }

    fn write(p: &Path, text: &str) {
        std::fs::create_dir_all(p.parent().unwrap()).unwrap();
        std::fs::write(p, text).unwrap();
    }

    /// **The red proof.** A consumer workspace with one repo-escaping path dep,
    /// pointed at a sibling checkout that is deliberately one commit behind its
    /// own `origin/HEAD` — the exact shape of the three phantom findings of
    /// 2026-08-22, where a stale primary checkout was read as a code defect.
    ///
    /// The test asserts the guard reports **red first** and only then that the
    /// same guard goes green once the sibling is fast-forwarded. A check proven
    /// only in its green state cannot be told apart from a check that returns
    /// the empty vector unconditionally — which is what nine guards on this box
    /// were doing (LAW 2).
    #[test]
    fn a_sibling_parked_off_origin_head_is_named_before_the_build_can_lie_about_it() {
        let root = scratch("siblings");
        std::fs::remove_dir_all(&root).ok();
        std::fs::create_dir_all(&root).unwrap();

        // The sibling's remote: a normal repo we clone from, so `origin/HEAD` is
        // set the way every real checkout on this box has it set.
        let upstream = root.join("upstream-sib");
        std::fs::create_dir_all(&upstream).unwrap();
        gitx(&upstream, &["init", "-q", "-b", "main"]);
        write(&upstream.join("Cargo.toml"), "[package]\nname = \"sib\"\nversion = \"0.1.0\"\n");
        write(&upstream.join("src/lib.rs"), "pub fn v() -> u32 { 1 }\n");
        gitx(&upstream, &["add", "Cargo.toml", "src/lib.rs"]);
        gitx(&upstream, &["commit", "-qm", "sib v1"]);

        // The sibling checkout the consumer's path dep will land in.
        let sib = root.join("sib");
        std::fs::remove_dir_all(&sib).ok();
        gitx(&root, &["clone", "-q", upstream.to_str().unwrap(), "sib"]);

        // Upstream moves on. The sibling does not — this is the whole disease.
        write(&upstream.join("src/lib.rs"), "pub fn v() -> u32 { 2 }\npub fn added() {}\n");
        gitx(&upstream, &["commit", "-qam", "sib v2"]);
        gitx(&sib, &["fetch", "-q", "origin"]);

        // The consumer: one escaping dep (`../sib`) and one in-repo dep, so the
        // filter has something to be wrong about in both directions.
        let consumer = root.join("consumer");
        write(
            &consumer.join("Cargo.toml"),
            "[workspace]\nmembers = [\"crates/app\"]\n\n[package]\nname = \"consumer\"\n\n\
             [dependencies]\nsib = { path = \"../sib\" }\napp = { path = \"crates/app\" }\n",
        );
        write(&consumer.join("crates/app/Cargo.toml"), "[package]\nname = \"app\"\n");

        let escaping = escaping_path_deps(&consumer);
        assert_eq!(escaping.len(), 1, "only `../sib` leaves the consumer repo, got {escaping:?}");
        assert_eq!(escaping[0].name, "sib");
        assert_eq!(escaping[0].resolved, normalise(&root.join("sib")));

        // ── RED ──────────────────────────────────────────────────────────────
        let bad = sibling_offenders(&consumer);
        assert_eq!(bad.len(), 1, "the stale sibling must be reported, got {bad:?}");
        match &bad[0].state {
            SiblingState::Drifted { behind, ahead, .. } => {
                assert_eq!((*behind, *ahead), (1, 0), "one commit behind origin/HEAD, none ahead");
            }
            other => panic!("expected Drifted, got {other:?}"),
        }
        assert!(
            bad[0].describe().contains("DRIFTED"),
            "the one-liner must say which way it failed: {}",
            bad[0].describe()
        );
        assert_eq!(bad[0].checkout.as_deref(), Some(normalise(&root.join("sib")).as_path()));

        // ── GREEN, and only now ──────────────────────────────────────────────
        gitx(&sib, &["merge", "-q", "--ff-only", "origin/main"]);
        let good = sibling_offenders(&consumer);
        assert!(good.is_empty(), "a fast-forwarded sibling is clean, got {good:?}");
        assert!(matches!(
            checkout_state(&sib),
            SiblingState::Aligned { dirty: 0, .. }
        ));

        // ── the standard lane shape: DETACHED, and exactly right ─────────────
        // `git worktree add --detach <repo> origin/main` is how nearly every lane
        // on this box checks a sibling out. Grading that red would make the whole
        // guard noise, so the SHA decides and only a detached HEAD that is NOT at
        // origin/HEAD is unknown. Both directions asserted, or "detached is fine"
        // would silently mean "detached is never checked".
        gitx(&sib, &["checkout", "-q", "--detach", "origin/main"]);
        assert!(
            sibling_offenders(&consumer).is_empty(),
            "a worktree detached AT origin/HEAD is the sanctioned lane shape"
        );
        gitx(&sib, &["checkout", "-q", "--detach", "origin/main~1"]);
        let det = sibling_offenders(&consumer);
        assert_eq!(det.len(), 1);
        assert!(matches!(det[0].state, SiblingState::Detached { .. }), "{}", det[0].describe());
        gitx(&sib, &["checkout", "-q", "main"]);

        // ── and dirt on an aligned ref is still not the ref ───────────────────
        write(&sib.join("src/lib.rs"), "pub fn v() -> u32 { 99 }\n");
        let dirty = sibling_offenders(&consumer);
        assert_eq!(dirty.len(), 1, "uncommitted source under an aligned ref is a different build");
        assert!(dirty[0].describe().contains("DIRTY"), "{}", dirty[0].describe());

        // ── and a sibling that is not there at all is the other real failure ──
        std::fs::remove_dir_all(&sib).unwrap();
        let gone = sibling_offenders(&consumer);
        assert_eq!(gone.len(), 1);
        assert_eq!(gone[0].state, SiblingState::Missing, "{}", gone[0].describe());

        std::fs::remove_dir_all(&root).ok();
    }

}