yah-cloud 0.8.46

Declarative cloud substrate for yah-managed camps: .yah/cloud/ config schema, MachineProvider drivers (Hetzner + local containerd), cloud-init rendering, and the pond/mesofact reconcilers.
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
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
//! `kind = "mesofact-static"` reconciler arm for the pond-tier path:
//! miniflare (workerd subprocess) + MinIO container fronting a published
//! static surface. Mirrors the prod topology (Cloudflare Worker → R2) so
//! production-shape bugs surface locally.
//!
//! Bring-up sequence:
//!
//! 1. Look up the workspace's `local-container` provider (orbstack.toml),
//!    probe sockets via [`LocalRuntime::detect`], and pull the MinIO image.
//! 2. Start the MinIO container, wait for its HTTP health probe, and
//!    auto-create the configured bucket with a public-read policy (so the
//!    Worker can fetch assets unsigned).
//! 3. Write the compiled Worker JS + miniflare shim to the state dir, then
//!    spawn the miniflare process (workerd subprocess). Wait for the
//!    `[miniflare-sim] ready` stdout signal before returning.
//! 4. Persist endpoint + credentials to
//!    `.yah/infra/pond/<svc>-<env>/credentials` so R256-T4's
//!    purge-disabled publisher invocation can pick them up without
//!    re-deriving the contract.
//! 5. Return a [`RunningWorkload`] whose supervisor tears down both
//!    containers on shutdown.
//!
//! @yah:ticket(R256-F6, "sim tier = camp drives the shared Runtime backed by orbstack (not the yubaba binary, not a bespoke docker-CLI path)")
//! @yah:assignee(agent:claude)
//! @yah:at(2026-05-25T20:08:22Z)
//! @yah:status(review)
//! @yah:parent(R256)
//! @yah:depends_on(R256-F10)
//! @yah:next("SUPERSEDED by R374 — carveout retracted; reconcile/liveness moves into sim dogfood scope. Camp no longer drives container lifecycle in pond; yubaba does. The trait-routing intent below stands, but the camp-as-lifecycle-authority part is gone. See W142 §Liveness + readiness.")
//! @yah:next("sim host = camp embedding the shared Runtime trait pointed at orbstack's docker socket; yubaba hosts the SAME trait on containerd for cloud/ha. orbstack stays the sim backend — this UPHOLDS the dev-yah-static-demo locked decision; the only change is routing it through the shared trait (R256-F10) instead of a bespoke docker-CLI shortcut")
//! @yah:next("shared trinity that makes sim==cloud-at-container-level real: (1) one Runtime trait talking orbstack-docker OR containerd, (2) scheduler/almanac-precondition layer, (3) xlb-net discovery. camp embeds it for dev+sim; yubaba for cloud+ha")
//! @yah:next("dogfood at sim: the workload contract + xlb-net discovery. NOT dogfooded at sim: WG mesh + raft — correct, since those only exist at the ha tier")
//! @yah:gotcha("build profile (debug+telemetry for sim, release for cloud) is an OVERRIDABLE DEFAULT per tier, not a tier property — sim-in-release and an ha-in-debug+telemetry 'analysis cluster' are both legal")
//! @yah:assumes("sim's 'mesh' is just orbstack's bridge with xlb-net discovery on top; a real WG mesh only appears at cloud/ha")
//! @yah:handoff("Camp is now the lifecycle authority for sim-tier containers, mirroring how R274-F1 made camp the authority for dev-tier. spawn_local_sim + find_local_sim_mirrors in camp.rs scan CloudConfig for mesofact-static components with local-sim mirrors (caddy-container) and call up_pond at camp startup. CampSocketHandle gains a sim task alongside mesofact and almanac. Desktop mirror_run.rs sets adopt_only: true on PondOptions — the reconciler's up_pond does a TCP probe and either adopts running Caddy or returns 'camp not running' error. PondOptions.adopt_only: bool added (default false); camp always uses false, desktop always true. Architecture doc updated with the camp-embedded-sim section. All paths use cloud::local_runtime::LocalRuntime (orbstack-docker-CLI) — no bespoke docker path. The R256-F10 keystone (shared Runtime trait for camp+yubaba) is the follow-on; the camp/desktop adopt contract established here is trait-agnostic and will route through F10 without interface changes.")
//! @yah:verify("cargo check -p cloud -p yah -p desktop --locked  # expect zero errors")
//! @yah:verify("cargo test -p cloud --locked --lib reconciler::pond::tests  # 8/8 pass including adopt_only_errors_when_miniflare_not_running")
//! @yah:verify("cargo test -p cloud --locked --lib  # 165 passed")
//!
//! @yah:ticket(R327-F2, "miniflare (workerd subprocess) as the mesofact-static sim serve-layer, replacing the caddy stand-in")
//! @yah:assignee(agent:claude)
//! @yah:at(2026-05-26T16:34:05Z)
//! @yah:status(review)
//! @yah:parent(R327)
//! @arch:see(.yah/docs/working/W074-cloudflare-infra-provider.md)
//! @yah:handoff("Caddy container replaced by miniflare v3 (workerd subprocess) as the sim serve-layer. Changes: (1) miniflare-sim.mjs shim written to crates/yah/cloud/worker/ — embedded via include_str! in local_sim.rs as MINIFLARE_SIM_SCRIPT, written to state dir at spinup. (2) PondOptions: caddy_image removed, node_binary added; Default ready_timeout bumped to 30s for workerd startup. (3) PondState: caddyfile replaced by worker_js + miniflare_shim. (4) up_pond gains worker_script: &str param — MinIO container stays, Caddy container dropped, miniflare spawned via node with ASSET_ORIGIN=http://127.0.0.1:{api_port}/{bucket}, MF_MINIFLARE_IMPORT resolved from workspace/crates/yah/cloud/worker/node_modules (dev fast-path, no download needed). (5) supervise_pair → supervise_miniflare_and_minio: child process + MinIO container teardown. (6) WORKER_SCRIPT made pub, re-exported from cloud lib.rs. camp.rs call site updated. 220 tests pass, cargo check --workspace clean.")
//! @yah:verify("cargo test -p cloud --lib: 220 passed")
//! @yah:verify("cargo check --workspace: clean (warnings only)")
//! @yah:gotcha("miniflare v3 dropped its CLI — it is API-only. The shim (miniflare-sim.mjs) calls the JS API directly with script content (not scriptPath; workerd rejects absolute paths via scriptPath on this platform).")
//! @yah:gotcha("Prod path still needs asset_origin set in providers.static (prod.toml) to the R2 custom-domain URL before the Worker can serve assets. The code reads it and leaves ASSET_ORIGIN empty when unset — Worker 404s until set.")
//! @yah:gotcha("First miniflare run downloads the workerd binary (~tens of MB) — pre-cache/vendor it to stay inside the few-second-cold / sub-second-warm sim spinup budget. Dev machines with the monorepo avoid this (resolve_miniflare_import finds existing node_modules).")
//!
//! @yah:ticket(R335-T2, "Pond acceptance gate: same-mirror revalidate rebuilds; cross-mirror revalidate is REJECTED")
//! @yah:assignee(agent:claude)
//! @yah:at(2026-05-27T02:19:41Z)
//! @yah:status(review)
//! @yah:phase(P2)
//! @yah:parent(R335)
//! @yah:next("In the pond tier (OrbStack + MinIO + Caddy-today/miniflare-planned), prove BOTH: (positive) host `yah qed run` -> MinIO -> revalidate -> pond receiver -> reconciler rebuild reading releases.json -> served; (negative) a pond producer firing a CLOUD mirror's receiver/target is REJECTED, not silently honored. Demonstrating only same-mirror success proves nothing about pollution.")
//! @yah:next("Code seam: CloudReleasePublisher::sync (app/yah/cli/src/qed_publish.rs:65) hard-rejects provider!='r2' and calls publish_to_r2 with no endpoint override — branch to publish_to_local_sim for the pond tier so the producer targets MinIO.")
//! @yah:verify("pond smoke: same-mirror revalidate rebuilds + serves; cross-mirror revalidate rejected with a clear error")
//! @yah:depends_on(R335-S1)
//! @yah:depends_on(R330-F4)
//! @yah:handoff("Wrote pond acceptance gate tests in `crates/yah/almanac/src/serve.rs::tests` (R335-T2). Added `serve_receiver_on(TcpListener, ...)` alongside the existing `serve_receiver(port, ...)` so tests can bind port 0 and get the actual port before spawning. Two tests: `pond_same_mirror_revalidate_triggers_rebuild` (positive: 200 + on_feed fires) and `pond_cross_mirror_revalidate_is_rejected` (negative: 422 + on_feed never called). All 18 almanac tests pass.")
//! @yah:verify("cargo test -p almanac --lib")
//!
//! @yah:ticket(R362-B1, "Sim stop→start: 'Network connection lost' from miniflare entry.worker.js")
//! @yah:assignee(agent:claude)
//! @yah:at(2026-05-31T22:55:22Z)
//! @yah:status(review)
//! @yah:parent(R362)
//! @yah:severity(medium)
//! @yah:handoff("Two fixes in pond.rs: (1) Readiness race — replaced wait_for_port(4322) with a oneshot channel signaled by the stdout reader when it sees '[miniflare-sim] ready on …'. miniflare binds its listener before workerd is fully initialized, so port-based polling returned too early on warm restarts (JIT cache = faster bind, same workerd init time = larger race window). The stdout line is only printed after mf.ready resolves. (2) Orphaned workerd — replaced supervise_child (SIGKILL) with an inline SIGTERM-based supervisor. SIGTERM lets miniflare's handler call mf.dispose() which kills the workerd subprocess cleanly; falls back to SIGKILL after 5 s. 235/235 cloud tests pass.")
//! @yah:verify("Stop+start the dev-yah sim mirror in a loop (10x) and confirm Worker requests succeed every cycle")
//! @yah:gotcha("Repro (user 2026-05-31): in the Run tab, stop the sim mirror then start it again → error surfaces with stack:\n  Error: Network connection lost.\n    at async Object.fetch (file:///Users/user/ss/yah/crates/yah/cloud/worker/node_modules/miniflare/dist/src/workers/core/entry.worker.js:1171:22)")
//! @arch:see(.yah/docs/architecture/A046-yah-run-tab.md)
//!
//! @arch:see(.yah/docs/working/W142-pond.md)
//!
//! @arch:see(.yah/docs/working/W142-pond.md)
//!
//! @arch:see(.yah/docs/working/W142-pond.md)
//!
//! @yah:relay(R369, "Pond CI + robustness hygiene")
//! @yah:at(2026-06-01T03:27:01Z)
//! @yah:next("W142 surfaces three open follow-ups that aren't naming hygiene (R368) and aren't UI gaps (R367) — they're about defending the pond contract over time: Worker bundle freshness in CI, MinIO license posture, and workerd binary vendoring for spinup budget. File each as a child")
//! @arch:see(.yah/docs/working/W142-pond.md)
//!
//! @yah:ticket(R369-F2, "Vendor workerd binary to defend pond spinup budget")
//! @yah:assignee(agent:claude)
//! @yah:at(2026-06-01T03:27:14Z)
//! @yah:status(review)
//! @yah:parent(R369)
//! @yah:next("W142 §Spinup budget calls out: first miniflare run downloads workerd (~tens of MB). Monorepo developers avoid this via existing node_modules at crates/yah/cloud/worker/node_modules — but fresh checkout, CI, or a new operator's first pond up blows the few-second-cold target")
//! @yah:next("Options: (a) pre-cache workerd in CI artifact + extract on first up, (b) vendor via git-lfs or a checked-in binary under crates/yah/cloud/worker/.workerd-cache/, (c) make yah-camp's bootstrap warm the cache before pond is needed")
//! @yah:next("PondOptions should be able to point miniflare at a pre-warmed workerd location instead of relying on the default download path")
//! @yah:next("Same problem recurs in CI for worker tests (router.test.ts) — fix both with the same cache")
//! @yah:verify("Cold pond up on a fresh checkout completes in 'a few seconds' (the W142 budget), measured")
//! @yah:verify("CI run of router.test.ts doesn't re-download workerd on every job")
//! @arch:see(.yah/docs/working/W142-pond.md)
//! @yah:handoff("Two changes: (1) pond.rs — added resolve_workerd_binary(workspace_root) that looks for node_modules/workerd/bin/workerd and passes it as MINIFLARE_WORKERD_PATH env var when spawning miniflare. Also logs workerd_cached=true/false in the spawn span so you can tell at a glance whether the cached binary was found. (2) ci.yml worker job — added actions/cache@v4 for crates/yah/cloud/worker/node_modules keyed on bun.lock hash. Cache hit restores the 106MB node_modules (87MB is the workerd binary) and bun install becomes a no-op on subsequent runs.")
//! @yah:verify("cargo check -p cloud  # clean")
//! @yah:verify("cargo test -p cloud --lib reconciler  # 70 pass")
//! @yah:gotcha("MINIFLARE_WORKERD_PATH is redundant when node_modules is already populated (miniflare would find workerd via its own npm resolution). Its value is: (a) explicit and observable in logs, (b) bypasses miniflare's internal resolution in edge cases. It does NOT help the zero-node_modules case — bun install is still required for that.")
//! @yah:gotcha("actions/cache caches the whole node_modules including platform-specific workerd binary. The cache key includes runner.os so linux/mac don't collide. restore-keys fallback lets a stale cache partial-hit and bun install fills in the delta.")
//!
//! @yah:ticket(R369-S3, "Audit MinIO license posture + pinned image version")
//! @yah:assignee(agent:claude)
//! @yah:at(2026-06-01T03:27:20Z)
//! @yah:kind(spike)
//! @yah:status(review)
//! @yah:parent(R369)
//! @yah:next("MinIO relicensed to AGPL-3.0 in 2021 — sits outside the permissive-only license rule (CLAUDE.md). Today we use it as a standalone container, no linking, so only the AGPL network clause is relevant and only if we ship a modified MinIO")
//! @yah:next("Confirm the image tag in PondOptions::minio_image (pond.rs). If pre-2021 tag (still Apache-2.0), document and move on. If post-relicense, document that we ship the upstream image unmodified and only operators run it locally")
//! @yah:next("If yah ever hosts pond as a service (yah-cloud hosted Hetzner mirror, etc.), revisit — candidates per W142: LocalStack S3 (Apache-2.0), SeaweedFS (Apache-2.0)")
//! @yah:next("Low urgency — soft hygiene")
//! @yah:verify("W142 §MinIO license caveat documents: pinned tag is X, judgment is Y, revisit-trigger is Z")
//! @arch:see(.yah/docs/working/W142-pond.md)
//! @yah:handoff("Audited W142 §MinIO license caveat and updated in place. Pinned tag is RELEASE.2025-04-22T22-12-26Z (post-AGPL relicense, Jan 2021). Verdict: fine for current usage — AGPL §13 requires modification + hosted network service; we have neither. The permissive-only CLAUDE.md rule targets linked/vendored code deps, not external container runtime deps. No action needed today. Revisit trigger is clearly stated: if yah ever hosts pond as a service.")
//! @yah:verify("Read W142 §MinIO license caveat — contains pinned tag, post-relicense verdict, and revisit trigger")
//!
//! @yah:relay(R374, "Yubaba owns liveness in pond — retract R256-F6 camp-direct carveout")
//! @yah:at(2026-06-01T17:25:26Z)
//! @yah:assignee(agent:claude)
//! @yah:next("Frame: in pond today, camp directly drives container lifecycle and desktop adopts via a bare TCP probe of the miniflare port. Half-alive states (miniflare orphaned to launchd ppid=1, MinIO gone) get silently adopted, surfacing as 'Network connection lost' from entry.worker.js. R362-B1 patched two narrow symptoms but the shape keeps inviting the same bug class.")
//! @yah:next("Direction: yubaba becomes the liveness/readiness authority in pond too. Camp's job shrinks to 'ensure ONE yubaba is up'; desktop's job shrinks to 'ask yubaba for the workload's status'. Half-alive becomes structurally impossible because yubaba's reconciler only reports Ready when every slot's probe passes.")
//! @yah:next("Reframe of R256-F6: that carveout excluded WG mesh + raft from sim's dogfood scope (correct — multi-node concerns) but quietly excluded reconcile/liveness too (wrong — single-node, and exactly what broke). Reconcile/liveness moves INTO sim's dogfood scope; mesh + raft stay out.")
//! @yah:next("Realizes the R256-F10 keystone (one Runtime trait spanning sim+cloud+ha) instead of leaving sim on a parallel track. Removes ~500 LOC of container-lifecycle duplication between up_pond and the cloud/ha path. Gives desktop a single source of truth for workload health (matches the Services-tab live-state ambition).")
//! @yah:next("Cost surface: yubaba bootstrap adds to pond cold-start. S1 measures it vs the W142 'few-second cold / sub-second warm' budget before F3/F4 commit. If it doesn't fit, optimize yubaba — do NOT retreat to camp-owns-lifecycle.")
//! @yah:next("Adjacent: R256-F6 superseded (carveout retracted); R256-F10 realized; R362-F4 'orphan reconciliation on boot' folds into yubaba's reconciler; R362-B1's narrow fixes stay landed but the structural fix supersedes their preventive intent.")
//! @yah:next("Bootstrap: camp starts yubaba in pond (only candidate — yubaba can't bootstrap itself). Same shape as systemd-starts-yubaba in ha, substituted at the lowest layer.")
//! @yah:verify("End-to-end half-alive smoke: while pond is up, externally stop the MinIO container. Within one reconcile interval yubaba reports Degraded; desktop ServiceCard flips off Ready; yubaba restarts MinIO; status returns to Ready. No 'Network connection lost' during the transition.")
//! @yah:verify("Adopt-path correctness: with miniflare orphaned and MinIO dead (today's repro), desktop's adopt returns a clear slot-level error, not silent green.")
//! @yah:verify("Spinup budget held: cold and warm numbers captured by S1; remain inside W142's bar.")
//! @arch:see(.yah/docs/working/W142-pond.md)
//!
//! @arch:see(.yah/docs/working/W142-pond.md)
//!
//! @yah:ticket(R374-F2, "Yubaba workload-status API + camp/desktop become clients")
//! @yah:assignee(agent:claude)
//! @yah:at(2026-06-01T17:25:46Z)
//! @yah:status(review)
//! @yah:parent(R374)
//! @yah:next("Define the workload-status surface yubaba serves: per-workload phase (Pending|Running|Degraded|Failed), per-slot health (probe state, last error, restart count), endpoint info for clients. HTTP+JSON is the obvious first cut unless S1 surfaces a reason for gRPC.")
//! @yah:next("Camp's pond bring-up: start yubaba → POST the WorkloadSpec → poll status until Ready or timeout. Drop the direct LocalRuntime calls from up_pond.")
//! @yah:next("Desktop's adopt path (today's TCP probe on miniflare port 4322): replace with a yubaba status GET. Adopt only on Ready; surface slot-level error on Degraded/Failed; clear 'yubaba unreachable' error when yubaba itself is down.")
//! @yah:next("This is the smallest reasonable seam that lets F3/F4 move lifecycle code without breaking camp+desktop in flight.")
//! @yah:verify("up_pond no longer calls runtime.run / runtime.ensure_image / wait_for_port directly — those move behind the yubaba API.")
//! @yah:verify("Stop MinIO container externally; desktop ServiceCard reflects Degraded within the readiness-probe interval, not silently Ready.")
//! @yah:verify("cargo test -p cloud reconciler::pond passes.")
//! @arch:see(.yah/docs/working/W142-pond.md)
//! @yah:depends_on(R374-S1)
//! @yah:handoff("F2 lands the yubaba workload-status seam. Five changes: (1) new module crates/yah/yubaba/src/pond.rs with PondHandler callback type, PondLifecycle trait, PondRegistry, and 3 axum routes (POST /pond/deploy, GET /pond/state?ident=..., GET /pond). (2) yubaba::ServerState gains pond_handler + pond_registry fields + with_pond_handler() builder; lib.rs registers the routes + a serve_on_listener() fn so embedders can pre-bind on port 0. (3) app/yah/cli adds yubaba as a dep; spawn_pond rewritten to bind yubaba's listener on 127.0.0.1:0, write the port to <camp_root>/.yah/jit/yubaba-pond-port.json, build ServerState with a pond handler wrapping cloud::reconciler::pond::up_pond, then POST /pond/deploy for each declared miniflare-container mirror. (4) crates/yah/cloud/src/reconciler/pond.rs adopt_only branch now reads the yubaba-pond-port file + GETs /pond/state instead of TCP-probing miniflare's port — the half-alive bug R374 was filed against is structurally impossible on this path because yubaba only reports Running when the deploy handler returned Ok and the lifecycle is held. (5) cloud's dev-deps grow axum to drive in-process yubaba mocks for the adopt-path tests.")
//! @yah:handoff("What F2 ships vs defers: yubaba is the STATUS SURFACE in F2, but it does not yet ACTIVELY PROBE slot health — phase transitions to Running on a successful POST and never to Degraded. The 'Stop MinIO container externally; desktop ServiceCard reflects Degraded' verify line is F3's job (yubaba's reconciler loop). Lifecycle code physically still lives in cloud::reconciler::pond::up_pond; the change is that it's invoked through the yubaba API instead of from camp directly. F3 migrates the MinIO half into yubaba::runtime; F4 migrates miniflare via a process-shaped slot per S1's heterogeneity decision (option C).")
//! @yah:handoff("Tests: 5 new yubaba pond unit tests (PondRegistry mark_pending/insert_running/mark_failed/shutdown_all/redeploy). 4 new cloud adopt-path tests (missing port file, 404 from yubaba, Running adopts with dev_url + console_url, Failed bails with reason carried through). Existing R256-F6 test 'adopt_only_errors_when_miniflare_not_running' rewritten to 'adopt_only_errors_when_no_warden_port_file' — same intent, new shape. pond_smoke cold 1.18s / warm 503 ms (W142 budgets 15 s / 3 s) confirms F2 didn't regress the cold path.")
//! @yah:handoff("Verification commands: cargo test -p yubaba --lib (82 pass); cargo test -p cloud --lib (239 pass incl. 11 pond tests); cargo check -p yubaba -p cloud -p yah -p desktop (clean, warnings only). YAH_LOCAL_SIM_E2E=1 cargo test -p cloud --release --test pond_smoke after temporarily patching .get(\"dev-yah\") → .get(\"yah-marketing\") (the stale-service-name gotcha S1 flagged) reproduces the green run with the cold/warm numbers above.")
//! @yah:verify("cargo test -p yubaba --lib  # 82 pass incl. 5 pond_::tests")
//! @yah:verify("cargo test -p cloud --lib reconciler::pond  # 11 pass incl. 4 new adopt-path tests")
//! @yah:verify("cargo check -p yubaba -p cloud -p yah -p desktop  # clean (warnings only)")
//! @yah:verify("YAH_LOCAL_SIM_E2E=1 cargo test -p cloud --release --test pond_smoke -- --nocapture  # cold + warm inside W142 budget (after patching the stale 'dev-yah' service id to 'yah-marketing')")
//! @yah:gotcha("pond_smoke.rs:99 still references the stale 'dev-yah' service id and needs renaming before F3/F4 lean on it as a regression bar (carried over from S1).")
//! @yah:gotcha("yubaba::pond::PondPhase has Pending/Running/Degraded/Failed variants but F2 never transitions to Degraded — that's F3's reconciler-loop work. Today phase goes Pending → (Running | Failed) once and stays.")
//! @yah:gotcha("Camp's embedded yubaba writes a hostkey at <camp_root>/.yah/jit/yubaba-camp-state.json on first boot (ServerState::load auto-generates one). Inert at pond tier but the file is written; gitignored under .yah/jit/.")
//!
//! Note: R374-F3's canonical annotation lives in
//! oss/yah-base/crates/local-driver/src/lib.rs (where the extracted crate
//! landed). This file participates but carries no @yah: block for it.
//!
//! @yah:ticket(R374-F4, "Migrate miniflare lifecycle into yubaba (shape from S1)")
//! @yah:assignee(agent:claude)
//! @yah:at(2026-06-01T17:26:03Z)
//! @yah:status(review)
//! @yah:parent(R374)
//! @yah:next("Implement per S1's decision: either WorkloadSpec gains a process-shaped slot (yubaba manages bun/node + workerd PIDs) or miniflare gets containerized (yubaba manages it identically to MinIO).")
//! @yah:next("Either way, yubaba owns: spawn, stdout-ready signal (today's [miniflare-sim] ready oneshot), supervised teardown with the SIGTERM→SIGKILL pattern from R362-B1, restart-on-failure.")
//! @yah:next("Kill the orphan path: yubaba tracks miniflare so a camp/desktop crash can never leave a bun/workerd hanging on launchd. Today's repro (5+ day-old workerd at pid 92928) becomes impossible.")
//! @yah:next("Drop the R256-F6 adopt_only=true TCP probe completely — that path was the half-alive entry point.")
//! @yah:verify("Kill camp/desktop mid-pond (SIGKILL the parent); restart camp; no orphaned bun/workerd. Yubaba restarts cleanly and re-converges the workload.")
//! @yah:verify("miniflare-sim.mjs ready-line oneshot path is preserved or replaced by an equivalent yubaba-side readiness probe — not regressed.")
//! @yah:verify("cargo test -p cloud reconciler::pond + the cross-mirror reject + spinup-budget smoke all green.")
//! @arch:see(.yah/docs/working/W142-pond.md)
//! @yah:depends_on(R374-F3)
//! @yah:handoff("F4 complete. Miniflare lifecycle is now fully owned by yubaba. Removed PondHandler/PondLifecycle/PondDeployResult from yubaba; removed make_pond_handler from camp. New path: camp builds MiniflareSpec + MinioSpec and sends both in PondDeployReq; yubaba's deploy handler spawns miniflare via local_driver::pond_miniflare::spawn_miniflare and starts a MiniflareReconciler alongside the MinioReconciler. Both reconcilers run independent probe loops and restart their slot on failure. kill_on_drop(true) prevents orphans on abrupt yubaba exit. SIGTERM→SIGKILL pattern from R362-B1 preserved in kill_child().")
//! @yah:verify("cargo check -p local-driver -p cloud -p yubaba -p yah → clean (0 warnings from F4 changes)")
//! @yah:verify("cargo test -p local-driver --lib → 29/29 ok")
//! @yah:verify("cargo test -p yubaba --lib → 86/86 ok (includes pond::miniflare::tests::kill_child_terminates_sleeping_process)")
//! @yah:verify("cargo test -p cloud --lib reconciler::pond → 25/25 ok")
//! @yah:verify("YAH_LOCAL_SIM_E2E=1 cargo test -p yubaba --test pond_reconciler_smoke -- --nocapture → warden_reconciler_restarts_minio_and_miniflare (requires docker+bun; skipped in CI without env var)")
//!
//! @yah:ticket(R374-T5, "Docs: W142 rewrite + R256-F6 retraction + R256-F10 supersession markers")
//! @yah:assignee(agent:claude)
//! @yah:at(2026-06-01T17:26:13Z)
//! @yah:status(review)
//! @yah:parent(R374)
//! @yah:next("Rewrite W142-pond.md: replace the camp-drives-LocalRuntime topology diagram with the yubaba-mediated one (camp → yubaba → {MinIO container, miniflare process/container}). Move the 'Persistent volume' + 'Spinup budget' sections under the new shape.")
//! @yah:next("Add a 'Liveness + readiness' section to W142 documenting: workload-status surface, slot-level probes, restart policy, how desktop reflects state. Cite the half-alive failure mode this prevents.")
//! @yah:next("Edit R256-F6's annotations in pond.rs (file header) to add @yah:next('SUPERSEDED by R374 — carveout retracted; reconcile/liveness moves into sim dogfood scope') and a status note. Same for R256-F10 with 'Realized by R374'.")
//! @yah:next("Update A024 vocabulary doc to add a one-liner under the pond tier: 'pond runs yubaba as its liveness/readiness authority.'")
//! @yah:verify("W142 reads as canonical for the new shape — the topology diagram + 'Liveness + readiness' section match the code merged under F3/F4.")
//! @yah:verify("rg 'camp drives.*shared Runtime' in pond.rs returns either zero hits or hits inside an explicit SUPERSEDED marker.")
//! @yah:verify("R256-F6 board_show output carries the supersession note.")
//! @arch:see(.yah/docs/working/W142-pond.md)
//! @arch:see(.yah/docs/architecture/A024-vocabulary.md)
//! @yah:depends_on(R374-F3)
//! @yah:depends_on(R374-F4)
//! @yah:handoff("T5 complete (docs-only). Four edits: (1) W142-pond.md rewritten — topology diagram shows camp → yubaba(embedded) → {MinIO, miniflare} with the two reconcilers; new 'Liveness + readiness' section documents PondPhase, slot probes, restart policy, desktop reflection, and half-alive prevention. Persistent volume + Spinup budget sections preserved under the new shape (cold ~1.2s / warm ~500ms numbers from F3's pond_smoke). (2) Crate layout section added to W142 explaining cloud/local-driver/yubaba dep shape (R374-F3). (3) R256-F6's annotation block in pond.rs gains a leading @yah:next('SUPERSEDED by R374 — carveout retracted; reconcile/liveness moves into sim dogfood scope') — board_show confirms it surfaces as the first bullet. (4) R256-F10 in yubaba/src/runtime/mod.rs gains a @yah:next('REALIZED by R374 — keystone shipped end-to-end in pond …'). (5) A024 vocabulary tier-relationship list gains a one-liner: 'sim (pond) runs yubaba as its liveness/readiness authority.' Verify: rg 'camp drives.*shared Runtime' pond.rs hits the original ticket title (line 23); the SUPERSEDED marker is on line 29 in the same annotation block — satisfies 'hits inside an explicit SUPERSEDED marker'.")
//!
//! @yah:relay(R408, "Pond: dual-process yubaba-container adaptation")
//! @yah:at(2026-06-02T03:25:42Z)
//! @yah:phase(P3)
//! @yah:parent(Q405)
//! @arch:see(.yah/docs/working/W154-yubaba-dual-runtime.md)
//!
//! @yah:ticket(R408-T1, "Pond yubaba-container image: tini PID 1 + install Yubaba+Kamaji binaries + cgroupns config")
//! @yah:assignee(agent:claude)
//! @yah:at(2026-06-02T03:27:49Z)
//! @yah:status(review)
//! @yah:phase(P1)
//! @yah:parent(R408)
//! @arch:see(.yah/docs/working/W154-yubaba-dual-runtime.md)
//! @yah:depends_on(R406-T2,R406-T6)
//! @yah:handoff("Pond yubaba-container image landed as a bundled qed catalog entry. Three files: (1) crates/yah/qed/images/yah-yubaba/Dockerfile — multi-stage build (rust:1-slim-bookworm builder compiles --bin yah-yubaba + --bin kamaji with yubaba/containerd-integration feature; debian:bookworm-slim runtime ships tini + ca-certificates + iproute2 + procps + the two binaries + supervisor). tini installed via apt is wired as ENTRYPOINT ['/usr/bin/tini', '--']. Build context MUST be the workspace root (header documents this). (2) crates/yah/qed/images/yah-yubaba/pond-supervise.sh — bash launcher: cleans stale UDS, starts kamaji with --socket $KAMAJI_SOCK (default /run/kamaji/kamaji.sock), waits up to 5s for the socket to bind, then starts yah-yubaba with that env var. wait -n on both pids; SIGTERM trap forwards to both. First-sibling-to-die-exits-the-container is acceptable pond-tier policy (systemd siblings handle independent restart at cloud tier per R406-T13). (3) crates/yah/qed/images/catalog.toml + crates/yah/qed/src/images/catalog.rs — added yah-yubaba as the 8th bundled entry (base = debian:bookworm-slim; description references W154); EXPECTED_BUNDLED test array and the file docstring extended to match. Pre-existing per_camp_produces_* tests already use 'yah-yubaba' as the override name — upsert semantics keep them passing.")
//! @yah:handoff("Required docker run flags surfaced in the Dockerfile header (acceptance contract for T2): --cgroupns=private (cgroup namespace isolation so Kamaji can create child cgroups), --cap-add=SYS_ADMIN (cgroup/mount/unshare ops), -v /var/run/docker.sock:/var/run/docker.sock (T2 — sibling-container workloads), -v <state>:/var/lib/yah-yubaba (raft state per W105). The image itself does not enforce these — that's T2's pond reconciler wiring.")
//! @yah:handoff("Verification: cargo test -p qed --lib images::catalog::tests → 16/16 pass. cargo check -p qed → clean. bash -n on the supervisor script → ok. Image not yet built locally — that's release-pipeline territory (R381-T7 builds yah-base/yah-rust/yah-rust-bun today; adding image-yah-yubaba to .github/workflows/release.yml is the next concrete step, mirroring those jobs).")
//! @yah:next("T2 picks up here: pond reconciler must (a) pull/build yah-yubaba image, (b) docker run it with --cgroupns=private, --cap-add=SYS_ADMIN, -v /var/run/docker.sock:/var/run/docker.sock, -v <state>:/var/lib/yah-yubaba, (c) replace today's embedded yubaba in camp with a connection to the yubaba-container instance. The current camp-embedded yubaba path stays as a fallback until T2 lands the container-backed path.")
//! @yah:next("Release-pipeline wiring (separate ticket worthwhile): add image-yah-yubaba GHA job to .github/workflows/release.yml mirroring image-yah-rust-bun (context = workspace root, file = crates/yah/qed/images/yah-yubaba/Dockerfile, cosign sign, inject YAH_WARDEN_DIGEST). The W148 phase plan in release.yml's header comments lists yah-python/yah-bun/yah-node/yah-cuda as the P2/P3 backlog — yah-yubaba belongs in that growth queue.")
//! @yah:verify("cargo test -p qed --lib images::catalog::tests  # 16/16 pass; bundled_catalog_loads_with_all_entries now requires yah-yubaba")
//! @yah:verify("cargo check -p qed  # clean")
//! @yah:verify("bash -n crates/yah/qed/images/yah-yubaba/pond-supervise.sh  # syntax ok")
//! @yah:verify("docker buildx build --file crates/yah/qed/images/yah-yubaba/Dockerfile .  # builds from workspace root (heavy; not run in CI yet)")
//! @yah:gotcha("containerd-integration feature is pulled in unconditionally for the release stage (yubaba's own Cargo.toml note: stub mode without it). If pond ever wants the stub-mode yubaba for faster local rebuilds, add a build-arg to toggle the feature.")
//! @yah:gotcha("tini is installed via `apt install tini` rather than copied from krallin/tini-static — keeps the image purely debian-managed at the cost of glibc tini instead of musl. Fine for pond-tier; cloud-tier uses systemd anyway.")
//! @yah:gotcha("The supervisor exits as soon as either sibling dies — pond-tier 'whole container restarts' policy. Cloud-tier independent restart lives at R406-T13 (systemd sibling units).")
//!
//! @yah:ticket(R408-T2, "Pond docker socket mount + permission model for container-backend workloads")
//! @yah:assignee(agent:claude)
//! @yah:at(2026-06-02T03:27:50Z)
//! @yah:status(review)
//! @yah:phase(P1)
//! @yah:parent(R408)
//! @arch:see(.yah/docs/working/W154-yubaba-dual-runtime.md)
//! @yah:depends_on(R408-T1)
//! @yah:handoff("T2 lands the docker socket mount + permission model contract for the pond yubaba-container as a typed builder, no runtime behavior changes yet. Three pieces: (1) ContainerRunSpec gains cap_add: Vec<String> + cgroupns: Option<String>. argv emission factored into ContainerRunSpec::docker_run_args() so callers and tests can inspect the wiring without a live docker socket. All four existing struct-literal sites (pond_minio.rs, local_runtime.rs workload_spec_to_crs, local_runtime.rs run-test fixture, cloud/local_driver_glue.rs test fixture) extended with cap_add: vec![] / cgroupns: None. ContainerRunSpec::new() initializes both to empty. (2) NEW local-driver module crates/yah/local-driver/src/pond_warden.rs: WardenContainerSpec carrying image/service/env/http_port/docker_socket_path/state_dir/extra_env; build_warden_run_spec(&WardenContainerSpec) -> ContainerRunSpec encoding the W154 contract (--cgroupns=private, --cap-add=SYS_ADMIN, -v <docker.sock>:/var/run/docker.sock, -v <state>:/var/lib/yah-yubaba, port mapping, canonical name yah-pond-<svc>-<env>-yubaba). Constants DEFAULT_WARDEN_IMAGE (ghcr.io/yah-ai/yah-yubaba:latest), DEFAULT_DOCKER_SOCKET_PATH (/var/run/docker.sock), WARDEN_STATE_CONTAINER_PATH (/var/lib/yah-yubaba), DEFAULT_WARDEN_HTTP_PORT (8800), WARDEN_SLOT (yubaba). looks_like_docker_socket() helper for early-failure path classification (OrbStack + Linux + colima patterns). (3) Module-level doc block in pond_warden.rs documents the permission model exhaustively: container runs as root, host docker.sock is the trust boundary, OrbStack auto-proxies, Linux relies on root bypassing the docker group, NO --privileged (least-privilege), no host /proc or /sys mount. pond.rs imports the new module behind #[allow(unused_imports)] as a forward-pointer for the future containerise-yubaba-in-pond ticket.")
//! @yah:handoff("Tests: 8 new pond_warden unit tests (run_spec_has_canonical_name_and_label, run_spec_mounts_docker_socket, run_spec_mounts_state_dir, run_spec_requests_private_cgroupns_and_sys_admin, run_spec_exposes_http_port, run_spec_forwards_extra_env, docker_run_argv_carries_cgroupns_and_cap_add (exercises the new ContainerRunSpec::docker_run_args end-to-end), looks_like_docker_socket_classifies_common_paths). local-driver 37/37 lib tests pass (was 29 before T2 — 8 new pond_warden + 0 regression). cloud reconciler::pond 25/25 pass; yubaba pond 9/9 pass; cargo check -p local-driver -p cloud -p yubaba clean.")
//! @yah:handoff("Out of scope for T2 (and explicitly NOT implemented): the bring-up + reconciler lifecycle that consumes WardenContainerSpec to actually run the yah-yubaba image in pond. That's the 'replace embedded yubaba with yubaba-container' lift — a much bigger change that crosses camp + pond.rs + yubaba's PondHandler. T2's contract gives that ticket a typed handle to consume instead of a tribal-knowledge checklist.")
//! @yah:next("Wire the future 'containerise yubaba in pond' ticket: camp's pond bring-up (today: spawn_pond in app/yah/cli/src/camp.rs embeds yubaba in-process) replaces the embedded ServerState builder with: (a) WardenContainerSpec::new(...) + state_dir under .yah/infra/pond/<svc>-<env>/yubaba-state/, (b) local_driver::pond_warden::build_warden_run_spec, (c) LocalRuntime::ensure_image + run, (d) read the bound http_port via `docker port` and write it to .yah/jit/yubaba-pond-port.json. Desktop's adopt path (R374-F2) keeps working unchanged because it already reads that port file and GETs yubaba's /pond/state — the container-vs-embedded distinction is invisible at the desktop seam.")
//! @yah:next("T3 (W142-pond.md doc update) consumes T1+T2 together: outer container shape, internal supervisor split, docker socket mount + permission model section pointing at pond_warden's module docstring as the canonical contract source.")
//! @yah:verify("cargo test -p local-driver --lib  # 37/37 incl. 8 pond_warden::tests")
//! @yah:verify("cargo test -p cloud --lib reconciler::pond  # 25/25 — ContainerRunSpec extension didn't regress existing pond paths")
//! @yah:verify("cargo test -p yubaba --lib pond  # 9/9")
//! @yah:verify("cargo check -p local-driver -p cloud -p yubaba --tests  # clean")
//! @yah:gotcha("ContainerRunSpec field additions (cap_add, cgroupns) are not behind a feature flag — every struct-literal caller must populate them. The four existing sites are updated; future call-sites should prefer ContainerRunSpec::new() + assignment so adding more fields stays one-line.")
//! @yah:gotcha("pond_warden does not run a uid-gid mapping for the docker socket. macOS/OrbStack works because OrbStack proxies the socket as-is and root inside the container can use it. Linux dev boxes also work because container root bypasses the docker group check on connect. A future ticket that wants to run the yubaba-container as non-root must add --group-add <docker-gid> wiring — the module docstring calls this out as the extension point.")
//! @yah:gotcha("DEFAULT_WARDEN_IMAGE is ghcr.io/yah-ai/yah-yubaba:latest, but the release pipeline does NOT yet build this image (T1's handoff queues the image-yah-yubaba GHA job as next step). Local pond bring-up that consumes this default will fail to pull until the GHA job lands; operators can override the image field to a locally-built tag in the interim.")
//!
//! @yah:ticket(R456-T2, "Carry slot probes through cloud::AdoptPondRecord → desktop MirrorRuntimeView → UI cell disclosure")
//! @yah:at(2026-06-05T08:25:02Z)
//! @yah:status(review)
//! @yah:phase(E)
//! @yah:parent(R456)
//! @yah:handoff("AdoptProbeOutcome + AdoptSlotProbe added to cloud/src/reconciler/pond.rs alongside AdoptPondRecord. AdoptPondRecord.slots: Vec<AdoptSlotProbe> with serde(default) for pre-E compat. MirrorRuntimeView gains slot_probes: Vec<AdoptSlotProbe>; view_from_pond_record copies record.slots; all other construction paths use vec![]. RunningMirrorEntry gains slot_probes with serde(default). TS: WireSlotProbeOutcome (state-tagged union, not WireProbeOutcome which belongs to identity probes) + WireSlotProbe in env/types.ts; slotProbes?: WireSlotProbe[] on RunningMirrorEntry. TierCard in MirrorPanel.tsx: SlotDots component renders h-1.5 w-1.5 colored dots per slot (green=pass, red=fail, gray=pending). ServicesView EnvCell: same inline dots in provider_label row via slotProbesMap threaded through ServicesMatrix and MatrixRow.")
//! @yah:verify("cargo check -p cloud -p desktop  # clean")
//! @yah:verify("cargo test -p cloud --lib reconciler::pond  # 27/27")
//! @yah:verify("cargo test -p desktop --lib mirror_observation  # 6/6")
//! @yah:verify("bun run typecheck (packages/yah/ui)  # no new errors beyond pre-existing ChatSurface + vitest")
//! @arch:see(.yah/docs/working/W180-pond-richer-topology.md)
//! @yah:depends_on(R456-F1)
//!
//! @yah:ticket(R374-T6, "Pre-flight sim-port conflict guard on the unsupervised cloud-direct up_pond path")
//! @yah:at(2026-07-16T11:55:54Z)
//! @yah:status(review)
//! @yah:assignee(agent:bundle-anthropic-ashguard)
//! @yah:parent(R374)
//! @yah:handoff("Durable fix for the host-side workerd orphan class on the cloud-direct up_pond path (the one R455-F1 left on the in-process bun shim, outside yubaba supervision). Added ensure_sim_port_free(sim_port) as a pre-flight in spawn_miniflare_child: (1) port_has_listener() TCP-connect probe on 127.0.0.1:sim_port — a squatted port otherwise hid behind a 30s 'did not emit ready signal' ERR_RUNTIME_FAILURE; (2) self-heal: enumerate host procs via `ps -axww` and SIGTERM->SIGKILL any workerd whose argv binds our port on loopback (entry=127.0.0.1:PORT — the exact host-side signature; the containerised sim binds 0.0.0.0 and never matches, so the reap can never reach into a container); (3) if a foreign holder remains (running pond container / other process), bail with a named actionable error instead of hanging. +233 LOC in pond.rs, 9 new unit tests. Original root cause: orphaned workerd PID 3232 (PPID=1 since Jul 11) squatting 127.0.0.1:4323 -> `yah qed run publish-assets service=yah-dashboard env=pond` failed while yah-marketing (mesofact-static, no worker runtime) passed.")
//! @yah:next("MinIO bring-up was analyzed for the same symmetry and found ALREADY covered -- do NOT re-file: LocalRuntime::run idempotently replaces a same-named stale MinIO container, and a foreign port holder surfaces as docker's own 'port already allocated' error (not an opaque timeout). MinIO is fully container-managed so the host-side double-fork orphan class does not exist there.")
//! @yah:next("Deeper durable direction -- fold the cloud-direct up_pond path into yubaba's supervised lifecycle so host-side orphans become structurally impossible -- remains the R374 thesis; this guard hardens the residual unsupervised path R455-F1 explicitly left on the bun shim (pond_smoke + `yah cloud mirror up`).")
//! @yah:verify("cargo test -p cloud --lib reconciler::pond  # 36/36 pass (9 new sim-port tests: reapable host-vs-container-vs-wrong-port classification, ps-parse robustness, char-safe truncation, live-listener probe, ok-on-free, bail-on-foreign-holder)")
//! @yah:verify("Signature validated live: real orphan argv `--socket-addr=entry=127.0.0.1:4323` matches the reap filter; the container-published :4323 shows 0 host-ps matches (container binds 0.0.0.0) -> guard bails with the actionable message and never reaps a container")
//!
//! @yah:relay(R659, "Pond hostname + TLS front door (passway on :443, mkcert wildcard for *.pond.localhost)")
//! @yah:status(review)
//! @yah:at(2026-08-25T07:09:23Z)
//! @yah:kind(spike)
//! @yah:assignee(agent:bundle-anthropic-ashguard)
//! @yah:next("Frame: pond is plain HTTP end to end (dev_url = http://127.0.0.1:{sim_port}, pond.rs:602) with a hand-assigned miniflare port per <service,env> (4322 marketing, 4323 dashboard). Give it real hostnames + browser-trusted TLS so the operator hits https://yah-dashboard.pond.localhost instead of remembering a port.")
//! @yah:next("Direction: passway on :443 as the pond front door, one Host per <service,env> via its existing PASSWAY_UPSTREAMS=<hostname>=<addr> fan-in syntax; mkcert supplies a wildcard leaf that acme-engine structurally cannot issue for a non-public name. passway already takes the cert as opaque paths (PASSWAY_TLS_CERT / PASSWAY_TLS_KEY), so issuer-pluggability needs no new seam.")
//! @yah:next("Payoff beyond dev sugar: W267 'Two front doors, one render contract' records that the passway (grey/orange) door is NOT symmetric with the Worker door - no per-path routing, no bucket serving - and pond today rehearses only the Worker door. passway-in-pond makes the second front door locally testable.")
//! @yah:next("Spike decides: (a) *.pond.localhost (zero DNS config) vs a real *.pond.yah.dev A 127.0.0.1 record on the zone we already own (precedent: alias tiers net.yah.dev / com.yah.dev, domain.rs:256); (b) passway-in-front vs miniflare terminating directly - the pinned miniflare 3.20250718.3 already accepts https / httpsCertPath / httpsKeyPath, ~6 lines in miniflare-sim.mjs, but that buys https WITHOUT hostname routing; (c) cost against the W142 few-second-cold / sub-second-warm spinup budget.")
//! @yah:gotcha("SCOPE FENCE - browser-facing pond ONLY. This has zero mesh implications and must not grow any. W268 is explicit: 'Do not bolt rustls-mTLS onto yubaba's axum surface; move intra-mesh RPC onto mshr QUIC ... mutual machine authentication is intrinsic.' R593-T7 (raft/network.rs:25, parked on R277) adds 'no interim mTLS bolt-on'. mkcert is a browser-trust tool; every lane where both ends are our own code stays on NodeId pinning, not a CA. Adding a local CA to the mesh would introduce a third trust root exactly while W268 collapses three Ed25519 machine identities into one.")
//! @yah:gotcha("Do NOT use a .local hostname - macOS mDNSResponder claims *.local (RFC 6762) and /etc/hosts has no wildcards, so per-service hosts entries do not scale either.")
//! @yah:gotcha("mkcert is a Go binary, not a library: `mkcert -install` needs sudo once and writes to the macOS keychain + NSS/Firefox stores. Shell out and detect-and-instruct when absent; never auto-sudo from camp bootstrap. The pure-Rust alternative (mint a CA with rcgen, already in-tree via instant-acme's rcgen feature) makes issuance trivial and leaves cross-store trust install - mkcert's actual value - unsolved.")
//! @yah:gotcha("Key hygiene: CA stays in the operator's login keychain, leaf + key land gitignored under .yah/infra/pond/<svc>-<env>/. Never commit a key, and do not consider publishing a shared wildcard key (the localhost.direct pattern) - LE revokes those.")
//! @yah:verify("Resolution check before committing to *.pond.localhost: `dscacheutil -q host -a name yah-dashboard.pond.localhost` and `curl -sv https://yah-dashboard.pond.localhost` - browsers special-case *.localhost, non-browser clients going through getaddrinfo may not.")
//! @yah:verify("Two pond services up at once, each reachable by its own https:// hostname on :443, with no hand-assigned port anywhere in the operator-visible path.")
//! @yah:verify("Cold + warm pond spinup measured against the W142 budget (few-second cold / sub-second warm) with the front door in place.")
//! @yah:assumes("Pond keeps emulating a real front door rather than collapsing to a bare static server - i.e. W267's grey/orange path stays a live target, not a retired one.")
//! @yah:handoff("SPIKE ANSWERED + SHIPPED. New oss/yubaba/crates/cloud/src/reconciler/pond_door.rs derives one https hostname per pond mirror and runs passway in front of the set; `yah cloud pond door [--plan] [--port N] [--reissue-cert]` at app/yah/cli/src/cloud.rs:3110. Two derivation arms: (1) any mirror with a kind=miniflare-container static slot (marketing 4322, dashboard 4323); (2) a pond mirror with a bare kind=container component, port read from its workload.toml through container.rs parse_container_recipe (host_port over port) - covers yah-cloud-admin at 4326, the service where the port is hardest to remember since its dev tier is 4325. No opt-in field: the hostname derives from the service name.")
//! @yah:handoff("DECISION (a) *.pond.localhost, settled empirically not by argument: getaddrinfo on darwin 25.5.0 answers ANY depth under localhost with 127.0.0.1 + ::1, no /etc/hosts and no DNS server. Not a browser-only special case - curl and Rust clients resolve it too, which was the open question in the ticket. So a *.pond.yah.dev A record on the zone we own buys nothing and adds a real DNS dependency to a local tier. Every derived name is ONE label under pond.localhost because a wildcard leaf covers one level only; a non-default env flattens to <svc>-<env>.pond.localhost rather than nesting.")
//! @yah:handoff("DECISION (b) passway in front, not miniflare terminating TLS. Miniflare 3.20250718.3 does accept https/httpsCertPath/httpsKeyPath, but each miniflare binds its own port - that buys https WITH the port still in the URL and no hostname routing at all. One listener fanning in by Host is the whole feature and passway already does it (PASSWAY_UPSTREAMS host fan-in, R594-F10), exact-match, 503 for an unknown host, never another tenant's backends. passway builds and runs on macOS (pingora 0.8.1, verified 2026-08-24).")
//! @yah:handoff("DECISION (c) zero delta against the W142 few-second-cold / sub-second-warm budget, because the door is out of the per-pond path entirely: its upstream map comes from DECLARED mirrors, not running ones, so it starts once and ponds come and go behind its health check. Demonstrated, not asserted - with the door already up, a pond brought up afterwards on 4326 went 503 -> 200 with no door restart. Door start itself: 0.57s warm, 2.57s cold, measured start-to-ready around the CLI.")
//! @yah:handoff("DERIVED, NOT DECLARED - and the reason is worth keeping. The fleet arm declares ingress = passway in the mirror and plan_ingress turns zone+port into rules. Pond deliberately does not reuse that declaration path: a declared edge collates onto a MACHINE, and xtask/tests/mirror_ingress.rs every_front_door_placement_names_a_known_machine requires each such name to have a .yah/infra/machines/<name>.toml. The dev box is not in the machine registry and should not be - a localhost.toml manifest would put a fiction in the fleet infra tree to serve a local tier. So placement is derived and RENDERING is shared: the rules are real IngressRules and PASSWAY_UPSTREAMS comes from IngressRule::passway_upstream, the same function the fleet arm calls. One grammar, one place, two placement policies.")
//! @yah:handoff("EXTRA WORK BEYOND THE TITLE. (1) container.rs parse_container_recipe made pub(crate) so the bare-container arm reads ports through the reconciler's own parser instead of minting a second reader of workload.toml - the exact two-parsers-one-kind shape container.rs's own doc blames for R658-B2. (2) pond.rs port_has_listener made pub(crate) for the door's pre-flight. (3) The first cut probed readiness with a bare TCP connect, which against a TLS listener is a truncated handshake - passway rightly logged ERROR TLSHandshakeFailure on every clean startup, describing nothing but our own probe. Rewritten to read passway's own 'passway listening on' line off a relayed stderr; the relay also drains the pipe, which an undrained pipe would eventually have turned into a proxy hang that reads as a routing bug. Startup log is now ERROR-free.")
//! @yah:verify("yah cloud pond door --plan on this camp: exactly 3 ponds, yah-cloud-admin.pond.localhost=127.0.0.1:4326, yah-dashboard=:4323, yah-marketing=:4322, rendered into one PASSWAY_UPSTREAMS with no PASSWAY_ACME_* env.")
//! @yah:verify("End to end through the CLI-started door: yah-marketing.pond.localhost and yah-dashboard.pond.localhost each returned their own upstream's body over TLS with the right Host and path; yah-cloud-admin (pond not running) 503; unknown host nope.pond.localhost 503 - never another host's backend. Upstreams were stand-in HTTP servers on the real pond ports; mkcert is not installed on this box so the leaf was a throwaway openssl wildcard, DELETED afterwards (.yah/infra/pond/_door/ left empty) so the operator's first run issues through mkcert rather than silently reusing an untrusted cert.")
//! @yah:verify("cargo test -p yah-cloud --lib pond_door: 10 passed. cargo test -p xtask --test pond_door: 4 passed - that one runs against the camp's REAL .yah/services tree and guards hostname/port collisions, one-label-under-the-wildcard, loopback upstreams, and that the render parses as passway's host fan-in grammar. cargo build -p yah --bin yah clean.")
//! @yah:verify("mkcert-absent branch verified live: `yah cloud pond door` with no mkcert on PATH prints the plan then fails with the brew install mkcert nss / mkcert -install instruction rather than falling back to an untrusted self-signed cert. The mkcert-present-but-CA-not-installed branch is coded (checks rootCA.pem under mkcert -CAROOT) but NOT exercised - mkcert is not installed here and mkcert -install needs a password camp cannot supply.")
//! @yah:gotcha("Not yet done, deliberately: pond's own dev_url (pond.rs:619, format http://127.0.0.1:{sim_port}) is unchanged, so the desktop Run tab still shows the port even while the door is serving the hostname. Flipping it needs up_pond to know whether a door is running, which it cannot today - that is a separate ticket, not a loose end in this one. Same for auto-starting the door from camp: the command is foreground on purpose (no supervisor, no restart policy; backgrounding it would mint exactly the orphan class ensure_sim_port_free exists to clean up after).")
//! @yah:handoff("W142-pond.md gained a 'Front door' section carrying all three decisions with their evidence, the two derivation arms, the trust story and the port constraint - the doc is where this belongs, since a spike's answer outlives its ticket.")
//! @yah:verify("Operator's one-time step before first real use: brew install mkcert nss && mkcert -install (asks for a password once; writes the macOS login keychain plus the NSS/Firefox stores). Then `yah cloud pond door` issues the *.pond.localhost leaf into .yah/infra/pond/_door/ (gitignored) and serves.")
//! @yah:gotcha("PORT, RESOLVED by operator 2026-08-25: they want 443. Recipe is `yah cloud pond cert` (as yourself, once) then `sudo yah cloud pond door --port 443`. Default stays 8443 because that is the port needing no privilege at all. Why sudo is unavoidable: ports below 1024 need uid 0, and macOS has neither setcap CAP_NET_BIND_SERVICE nor a net.ipv4.ip_unprivileged_port_start equivalent (checked sysctl - Darwin's net.inet.ip.portrange.* are ephemeral SOURCE-port ranges, not a bind threshold). pf rdr 443->8443 was considered and is NOT recommended: rdr applies to packets arriving on an interface and locally-originated connections to 127.0.0.1 take the loopback path, widely reported not to hit rdr on macOS - which is exactly the pond door's traffic. UNTESTED (pfctl needs sudo). A root LaunchDaemon is the always-on version; launchd socket activation would be ideal but needs launch_activate_socket support passway does not have.")
//! @yah:handoff("TWO DEFECTS THE 443 DECISION EXPOSED, both fixed. (1) ensure_pond_cert would have issued under sudo against ROOT's HOME - mkcert keeps its CA under the operator's $HOME/Library/Application Support/mkcert and installs it into their LOGIN keychain, so a sudo first-run finds no CA there and would mint a leaf from a second CA nothing trusts, root-owned in the operator's tree. Now refuses when geteuid()==0 and names the unprivileged command; reusing an already-issued leaf as root is still allowed, since serving as root is the whole point of --port 443. Split into ensure_pond_cert_as(state_dir, reissue, running_as_root) so that branch is reachable from a test rather than shipping an error path nobody has run - sudo needs a password camp cannot supply. (2) PASSWAY_PID_FILE / PASSWAY_UPGRADE_SOCK are now keyed by port (pingora-443.pid vs pingora-8443.pid): the 443 door runs as root and leaves those root-owned, and a later unprivileged 8443 door could neither rewrite nor unlink them.")
//! @yah:handoff("New `yah cloud pond cert [--reissue]` - issues the leaf and exits, without serving. Exists specifically so the 443 path has an unprivileged issuance step to point at.")
//! @yah:verify("cargo test -p yah-cloud --lib pond_door: 12 passed, now including issuing_as_root_is_refused_but_reusing_an_existing_leaf_is_not (the sudo guard, executed rather than merely written) and the_pid_file_and_upgrade_sock_are_keyed_by_port. cargo build -p yah --bin yah clean; `yah cloud pond cert` prints the mkcert install instruction as designed.")
//! @yah:gotcha("SHARED-TREE INCIDENT, self-inflicted and fully reverted - worth knowing because the trap is easy to repeat. `rustfmt oss/yubaba/crates/cloud/src/reconciler/mod.rs` FOLLOWS THE MOD TREE and reformatted 10 sibling files in that directory, several holding peers' uncommitted edits. Reverted precisely against commit c4e5a80f2bf41119e50c261919d62537918aba16: for each file, compared on-disk content against rustfmt(c4e5a80f) - 7 matched exactly (so they held no one's edits, only my churn) and were restored from c4e5a80f; pond_publish.rs and static_asset_prune.rs were already rustfmt-clean at c4e5a80f so my run never touched them (their diffs are a peer's R630-B1 uri_encode_key work, left intact); static_asset.rs had both, so its 6 formatting hunks were hand-reverted one at a time, leaving only the peer's R630-B1 lines. Verified after: the reconciler/ diff is my files plus the peer's edits and nothing else. Rule: format a single file by path, never a mod.rs.")

use std::collections::BTreeMap;
use std::path::PathBuf;
use std::process::Stdio;
use std::time::Duration;

use anyhow::{bail, Context, Result};
use reqwest::StatusCode;
use tokio::process::Command;
use tokio::sync::oneshot;
use tracing::{info, warn};

use super::{into_running, slot_field_u16, LogBuffer, ReconcileCtx, RunningWorkload};
use crate::config::Provider;
use crate::local_container_spec_from_provider;
use crate::MirrorProviderSlot;
use local_driver::pond_minio::{ensure_minio_running, MinioSpec};
use local_driver::{canonical_label, canonical_name, LocalContainerSpec, LocalRuntime};
// R408-T2: docker socket mount + permission model for the pond yubaba-container
// is encoded as a builder in `local_driver::pond_warden`. The future
// "containerise yubaba in pond bring-up" ticket consumes
// `pond_warden::build_warden_run_spec` to produce the ContainerRunSpec for
// the yah-yubaba image landed in R408-T1.
#[allow(unused_imports)]
use local_driver::pond_warden::{build_warden_run_spec, WardenContainerSpec};

/// Default MinIO image. Pinned to a recent stable RELEASE tag so the image
/// cache is deterministic across operators.
pub const DEFAULT_MINIO_IMAGE: &str = "docker.io/minio/minio:RELEASE.2025-04-22T22-12-26Z";

/// Default miniflare image (R455-F1). Operators override to a locally-built
/// tag until the release-pipeline `image-yah-miniflare` GHA job lands.
pub const DEFAULT_MINIFLARE_IMAGE: &str = "ghcr.io/yah-ai/yah-miniflare:latest";

/// Default operator-visible pond port. Matches the canonical pond.toml.
pub const DEFAULT_MINIFLARE_PORT: u16 = 4322;
pub const DEFAULT_MINIO_API_PORT: u16 = 9000;
pub const DEFAULT_MINIO_CONSOLE_PORT: u16 = 9001;
pub const DEFAULT_BUCKET: &str = "yah-dev";

/// MinIO root creds for the pond tier. Static defaults — operators never see
/// real credentials at this layer; the bucket is public-read for the Worker.
/// T4/T5 may surface an override knob if anyone needs it.
pub const DEFAULT_MINIO_USER: &str = "yahsim";
pub const DEFAULT_MINIO_PASSWORD: &str = "yahsim-local-only";

/// Slot role names this reconciler arm consumes.
const STATIC_SLOT: &str = "static";
const OBJECT_STORE_SLOT: &str = "object_store";

/// Canonical DNS aliases siblings on the per-cell bridge use to reach each
/// other (R455-F1). The Worker's `ASSET_ORIGIN` binding points at
/// `http://{MINIO_NETWORK_ALIAS}:9000/<bucket>` once the bridge is up.
pub const MINIO_NETWORK_ALIAS: &str = "minio";
pub const MINIFLARE_NETWORK_ALIAS: &str = "miniflare";

/// miniflare Node.js shim — embedded at compile time, written to the state dir
/// at spinup time. Reads config from env vars and runs the Worker under workerd.
/// Re-exported as `cloud::MINIFLARE_SIM_SCRIPT` so camp can embed it in
/// `MiniflareSpec` without a separate file read (R374-F4).
pub const MINIFLARE_SIM_SCRIPT: &str = include_str!("../../worker/miniflare-sim.mjs");

/// Knobs for the pond bring-up path.
#[derive(Debug, Clone)]
pub struct PondOptions {
    /// MinIO image ref. Pin a tag so image-cache hits are deterministic.
    pub minio_image: String,
    /// MinIO root user (becomes the S3 access key for publisher invocations).
    pub minio_user: String,
    /// MinIO root password (S3 secret key).
    pub minio_password: String,
    /// How long to wait for the MinIO container and miniflare process to
    /// become ready before declaring the up failed.
    pub ready_timeout: Duration,
    /// When `true`, probe the sim port and adopt already-running processes
    /// — never pull images or start new ones. Desktop sets this because camp
    /// owns the container lifecycle at startup (R256-F6). Camp itself always
    /// uses `adopt_only: false`.
    pub adopt_only: bool,
    /// JS runtime binary for the miniflare shim. Defaults to `bun` (then
    /// `node` as a fallback). Override via `BUN`/`NODE` env vars or this field.
    pub js_binary: Option<PathBuf>,
}

impl Default for PondOptions {
    fn default() -> Self {
        Self {
            minio_image: DEFAULT_MINIO_IMAGE.into(),
            minio_user: DEFAULT_MINIO_USER.into(),
            minio_password: DEFAULT_MINIO_PASSWORD.into(),
            ready_timeout: Duration::from_secs(30),
            adopt_only: false,
            js_binary: None,
        }
    }
}

/// The two JS files the miniflare door needs on disk, wherever a tier keeps
/// its state (R584-F4). Split out of [`PondState`] so the dev tier can reuse
/// [`spawn_miniflare_child`] without also inheriting pond's MinIO data dir.
#[derive(Debug, Clone)]
pub(super) struct DoorScripts {
    /// Worker JS file written from the compile-time embedded bundle.
    pub worker_js: PathBuf,
    /// miniflare shim written from the compile-time embedded script.
    pub miniflare_shim: PathBuf,
}

/// Per-bring-up state on disk.
#[derive(Debug, Clone)]
pub struct PondState {
    pub dir: PathBuf,
    /// Worker JS file written from the compile-time embedded script.
    pub worker_js: PathBuf,
    /// miniflare Node.js shim written from the compile-time embedded script.
    pub miniflare_shim: PathBuf,
    pub minio_data: PathBuf,
    pub credentials: PathBuf,
}

impl PondState {
    /// State dir layout: `<workspace>/.yah/infra/pond/<svc>-<env>/`.
    pub fn for_ctx(ctx: &ReconcileCtx<'_>) -> Self {
        let dir = ctx
            .workspace_root
            .join(".yah/infra/pond")
            .join(format!("{}-{}", ctx.service.name, ctx.env));
        Self {
            worker_js: dir.join("worker.js"),
            miniflare_shim: dir.join("miniflare-sim.mjs"),
            minio_data: dir.join("minio-data"),
            credentials: dir.join("credentials"),
            dir,
        }
    }

    fn scripts(&self) -> DoorScripts {
        DoorScripts {
            worker_js: self.worker_js.clone(),
            miniflare_shim: self.miniflare_shim.clone(),
        }
    }
}

/// Main entry point: dispatch the pond-tier path from
/// `MesofactStaticReconciler::up`. Brings up MinIO (object store) and
/// miniflare (CF Worker runtime), auto-creates the bucket with public-read
/// access, and returns the lifecycle handle.
///
/// `worker_script` is the compiled Worker JS content (injected by the caller
/// so the sim runs the same artifact as prod).
pub async fn up_pond(
    ctx: &ReconcileCtx<'_>,
    options: &PondOptions,
    static_fields: &BTreeMap<String, toml::Value>,
    worker_script: &str,
) -> Result<RunningWorkload> {
    // ── Adopt-only path (R374-F2, desktop) ───────────────────────────────────
    // Camp embeds yubaba as the pond workload-status authority. Desktop reads
    // `<camp_root>/.yah/jit/yubaba-pond-port.json` and GETs `/pond/state` for
    // the (service, env, component) tuple. Pre-R374 the desktop did a bare
    // TCP probe on the miniflare port — that probe could silently adopt a
    // half-alive workerd orphaned to launchd while MinIO was already gone,
    // surfacing later as "Network connection lost" from entry.worker.js. The
    // yubaba status surface makes that shape structurally impossible: yubaba
    // only reports Running when the deploy handler returned successfully and
    // its supervisor still holds the lifecycle.
    if options.adopt_only {
        let ident = pond_workload_ident(&ctx.service.name, ctx.env, &ctx.component.id);
        let port = read_warden_pond_port(ctx.workspace_root).with_context(|| {
            format!(
                "component {}: cannot read .yah/jit/yubaba-pond-port.json — \
                 ensure yah-camp is started with a service that declares a \
                 pond mirror (providers.static.kind = miniflare-container)",
                ctx.component.id,
            )
        })?;
        let record = match query_warden_pond_state(port, &ident).await? {
            Some(r) => r,
            None => anyhow::bail!(
                "component {}: pond workload {:?} is not registered with the \
                 camp-embedded yubaba (GET http://127.0.0.1:{}/pond/state → 404)",
                ctx.component.id,
                ident,
                port,
            ),
        };
        match record.phase {
            AdoptPondPhase::Running => {
                let dev_url = record.dev_url.unwrap_or_else(|| {
                    let sim_port =
                        slot_field_u16(static_fields, "port").unwrap_or(DEFAULT_MINIFLARE_PORT);
                    format!("http://localhost:{sim_port}")
                });
                info!(
                    dev_url = %dev_url,
                    ident = %ident,
                    "pond Running per yubaba; adopting",
                );
                let mut adopted =
                    RunningWorkload::adopted("mesofact-static", "static", Some(dev_url));
                if let Some(console) = record.console_url {
                    adopted = adopted.with_console_url(console);
                }
                return Ok(adopted);
            }
            AdoptPondPhase::Pending => anyhow::bail!(
                "component {}: pond workload {:?} is Pending in yubaba — \
                 deploy still in flight; retry shortly",
                ctx.component.id,
                ident,
            ),
            AdoptPondPhase::Degraded => anyhow::bail!(
                "component {}: pond workload {:?} is Degraded per yubaba{}",
                ctx.component.id,
                ident,
                record.error.map(|e| format!(": {e}")).unwrap_or_default(),
            ),
            AdoptPondPhase::Failed => anyhow::bail!(
                "component {}: pond workload {:?} Failed per yubaba{}",
                ctx.component.id,
                ident,
                record.error.map(|e| format!(": {e}")).unwrap_or_default(),
            ),
        }
    }

    // ── Non-adopt path (R374-F3) ─────────────────────────────────────────────
    // The pond bring-up shape became: bring MinIO up via yubaba's shared
    // primitives (`local_driver::pond_minio::ensure_minio_running`), then
    // spawn miniflare against that. Yubaba's HTTP path additionally wires
    // restart-on-failure via `yubaba::pond::minio::MinioReconciler`; this
    // direct-call entry point does not — it's only used by `pond_smoke` and
    // `yah cloud mirror up`. Production lifecycles run through
    // `yubaba::pond::deploy` and get reconciler-managed MinIO.
    let store_fields = require_object_store_slot(ctx)?;
    let sim_port = slot_field_u16(static_fields, "port").unwrap_or(DEFAULT_MINIFLARE_PORT);
    let bucket = resolve_bucket(static_fields, store_fields);
    let state = PondState::for_ctx(ctx);
    prepare_state_dir(ctx, &state)?;

    let local_spec = load_local_container_spec(ctx)?;
    let runtime = LocalRuntime::detect(&local_spec)
        .await
        .context("detecting local container runtime (orbstack/colima/docker)")?;
    info!(
        runtime = runtime.detected.as_str(),
        docker_host = %runtime.docker_host,
        "pond: using detected runtime",
    );

    let minio_spec = build_minio_spec(ctx, options, store_fields, &bucket, &state)?;
    // The spec names the per-cell bridge network (R455-F1) but only the
    // yubaba-deploy path ensured it existed — this direct-call path (pond_smoke
    // + `yah cloud mirror up`) must create it too or `docker run --network`
    // fails on a cell's first-ever bring-up.
    if let Some(ref network) = minio_spec.network {
        runtime
            .ensure_network(network)
            .await
            .with_context(|| format!("ensuring pond bridge network {network}"))?;
    }
    let minio_running = ensure_minio_running(&runtime, &minio_spec).await?;

    write_credentials_file(
        &state,
        &minio_running.endpoint,
        &minio_running.bucket,
        &minio_running.access_key,
        &minio_running.secret_key,
    )?;

    // Reconcile = sync + serve: publish the built dist into the bucket before
    // the Worker starts routing to it, mirroring the cloudflare arm (which
    // publishes to R2 inside the same `up`). Without this, a cell's first
    // bring-up serves an empty bucket and every request 404s. Skipped with a
    // warning when the workload has no built dist yet — the serve stack still
    // comes up and adopts whatever is already in the bucket.
    let out_dir = super::mesofact_static::read_workload_out_dir(&ctx.workload_dir())
        .unwrap_or_else(|| "dist".to_string());
    let dist_dir = ctx.workload_dir().join(&out_dir);
    if dist_dir.exists() {
        let report = super::pond_publish::publish_to_pond(
            &dist_dir,
            &minio_running.endpoint,
            &minio_running.bucket,
            &minio_running.access_key,
            &minio_running.secret_key,
            None,
        )
        .await
        .with_context(|| format!("publishing {} to pond bucket", dist_dir.display()))?;
        info!(
            uploaded = report.uploaded.len(),
            bucket = %minio_running.bucket,
            "pond publish complete",
        );
    } else {
        warn!(
            dist = %dist_dir.display(),
            "no built dist to publish — serving existing bucket contents",
        );
    }

    let worker_mode =
        super::mesofact_static::parse_worker_mode(&ctx.component.kind, static_fields);

    let (child, log_buf) = spawn_miniflare_child(
        ctx,
        options,
        sim_port,
        &state.scripts(),
        &format!("{}/{}", minio_running.endpoint, minio_running.bucket),
        worker_script,
        &worker_mode,
    )
    .await
    .map_err(|e| {
        // Tear down MinIO so we don't leak a half-up workload.
        let runtime = runtime.clone();
        let name = minio_running.container_name.clone();
        tokio::spawn(async move {
            let _ = runtime.stop_and_remove(&name, Duration::from_secs(2)).await;
        });
        e
    })?;

    let (shutdown_tx, shutdown_rx) = oneshot::channel::<()>();
    let supervisor = supervise_miniflare_and_minio(
        runtime.clone(),
        minio_running.container_name.clone(),
        child,
        shutdown_rx,
    );

    let dev_url = format!("http://127.0.0.1:{sim_port}");
    info!(
        dev_url = %dev_url,
        endpoint = %minio_running.endpoint,
        bucket = %minio_running.bucket,
        "pond ready (miniflare + MinIO via local_driver::pond_minio)",
    );

    Ok(into_running(
        super::mesofact_static::WORKLOAD_KIND,
        STATIC_SLOT,
        Some(dev_url),
        None,
        Some(log_buf),
        shutdown_tx,
        supervisor,
    )
    .with_console_url(minio_running.console_url.clone()))
}

/// Re-sync a running pond mirror: ensure its MinIO container is up (adopting
/// the already-running one) and re-publish the workload's built `dist/` into
/// the bucket — **without** touching the miniflare serve stack.
///
/// This is the "⟳ sync" affordance for local mirrors. `up_pond`'s desktop
/// adopt path (`adopt_only: true`) returns at the Running branch before the
/// publish step, so a re-click of ▶ never re-publishes; and re-running the
/// non-adopt path would collide on the already-bound miniflare port (the
/// R374 orphan-workerd class). `sync_pond` composes the same MinIO + publish
/// primitives as `up_pond`'s bring-up but stops short of the serve stack, so
/// it is safe to run against a live mirror.
///
/// Returns the number of assets uploaded; `0` when the workload has no built
/// `dist/` yet (the bucket is left serving whatever it already holds).
pub async fn sync_pond(
    ctx: &ReconcileCtx<'_>,
    options: &PondOptions,
    static_fields: &BTreeMap<String, toml::Value>,
) -> Result<usize> {
    let store_fields = require_object_store_slot(ctx)?;
    let bucket = resolve_bucket(static_fields, store_fields);
    let state = PondState::for_ctx(ctx);
    prepare_state_dir(ctx, &state)?;

    let local_spec = load_local_container_spec(ctx)?;
    let runtime = LocalRuntime::detect(&local_spec)
        .await
        .context("detecting local container runtime (orbstack/colima/docker)")?;

    let minio_spec = build_minio_spec(ctx, options, store_fields, &bucket, &state)?;
    if let Some(ref network) = minio_spec.network {
        runtime
            .ensure_network(network)
            .await
            .with_context(|| format!("ensuring pond bridge network {network}"))?;
    }
    let minio_running = ensure_minio_running(&runtime, &minio_spec).await?;

    write_credentials_file(
        &state,
        &minio_running.endpoint,
        &minio_running.bucket,
        &minio_running.access_key,
        &minio_running.secret_key,
    )?;

    let out_dir = super::mesofact_static::read_workload_out_dir(&ctx.workload_dir())
        .unwrap_or_else(|| "dist".to_string());
    let dist_dir = ctx.workload_dir().join(&out_dir);
    if !dist_dir.exists() {
        warn!(
            dist = %dist_dir.display(),
            "sync_pond: no built dist to publish — bucket left serving existing contents",
        );
        return Ok(0);
    }
    let report = super::pond_publish::publish_to_pond(
        &dist_dir,
        &minio_running.endpoint,
        &minio_running.bucket,
        &minio_running.access_key,
        &minio_running.secret_key,
        None,
    )
    .await
    .with_context(|| format!("publishing {} to pond bucket", dist_dir.display()))?;
    info!(
        uploaded = report.uploaded.len(),
        bucket = %minio_running.bucket,
        "sync_pond: re-publish complete",
    );
    Ok(report.uploaded.len())
}

/// Build a [`MinioSpec`] from the canonical pond options + the
/// `providers.object_store` slot fields. Used by both the direct-call path
/// (cloud's `up_pond`) and the yubaba-deploy path (camp's handler).
pub fn build_minio_spec(
    ctx: &ReconcileCtx<'_>,
    options: &PondOptions,
    store_fields: &BTreeMap<String, toml::Value>,
    bucket: &str,
    state: &PondState,
) -> Result<MinioSpec> {
    let api_port = slot_field_u16(store_fields, "api_port").unwrap_or(DEFAULT_MINIO_API_PORT);
    let console_port =
        slot_field_u16(store_fields, "console_port").unwrap_or(DEFAULT_MINIO_CONSOLE_PORT);
    // R455-F1: every pond MinIO joins the per-cell bridge with alias `minio`
    // so siblings on the bridge (miniflare, mesofact-dev) reach S3 via DNS
    // (`http://minio:9000/<bucket>`). The API + console ports still publish
    // to the host so the embedded yubaba + cloud-tier publisher can probe
    // without joining the bridge themselves.
    Ok(MinioSpec {
        image: options.minio_image.clone(),
        user: options.minio_user.clone(),
        password: options.minio_password.clone(),
        api_port,
        console_port,
        bucket: bucket.to_string(),
        data_dir: state.minio_data.clone(),
        container_name: canonical_name(&ctx.service.name, ctx.env, OBJECT_STORE_SLOT),
        container_label: canonical_label(&ctx.service.name, ctx.env, OBJECT_STORE_SLOT),
        ready_timeout: options.ready_timeout,
        network: Some(local_driver::pond_network_name(&ctx.service.name, ctx.env)),
        network_alias: Some(MINIO_NETWORK_ALIAS.into()),
    })
}

/// Resolve the `providers.object_store` slot and return its inline fields.
pub fn require_object_store_slot<'a>(
    ctx: &'a ReconcileCtx<'_>,
) -> Result<&'a BTreeMap<String, toml::Value>> {
    let store_slot = ctx.slot(OBJECT_STORE_SLOT).with_context(|| {
        format!(
            "mirror {svc}/{env} has providers.static.kind = miniflare-container but no \
             providers.object_store slot — pond requires both",
            svc = ctx.service.name,
            env = ctx.env,
        )
    })?;
    match store_slot {
        MirrorProviderSlot::Inline {
            kind: Provider::MinioContainer,
            fields,
        } => Ok(fields),
        MirrorProviderSlot::Inline { kind, .. } => {
            bail!("providers.object_store.kind = {kind:?}, expected minio-container for pond",)
        }
        MirrorProviderSlot::Reference { provider_id, .. } => bail!(
            "providers.object_store.use = {provider_id:?} — pond requires an inline \
             minio-container slot, not a reference",
        ),
    }
}

/// Idempotent state-dir setup: legacy migration from `infra/state/local-sim/`
/// + mkdir of the worker/shim/minio_data subtree.
fn prepare_state_dir(ctx: &ReconcileCtx<'_>, state: &PondState) -> Result<()> {
    // Auto-migrate legacy state from infra/state/local-sim/ on first up after
    // R368-F3. Handles two old path shapes: the env-renamed form (<svc>-pond,
    // present after R368-F2) and the original (<svc>-local-sim).
    if !state.dir.exists() {
        for legacy_env in &[ctx.env, "local-sim"] {
            let legacy = ctx
                .workspace_root
                .join(".yah/infra/state/local-sim")
                .join(format!("{}-{}", ctx.service.name, legacy_env));
            if legacy.exists() {
                if let Some(parent) = state.dir.parent() {
                    std::fs::create_dir_all(parent)
                        .with_context(|| format!("creating {}", parent.display()))?;
                }
                std::fs::rename(&legacy, &state.dir).with_context(|| {
                    format!(
                        "migrating pond state: {} → {}",
                        legacy.display(),
                        state.dir.display(),
                    )
                })?;
                info!(
                    from = %legacy.display(),
                    to = %state.dir.display(),
                    "migrated pond state dir to infra/pond/",
                );
                break;
            }
        }
    }
    std::fs::create_dir_all(&state.dir)
        .with_context(|| format!("creating {}", state.dir.display()))?;
    std::fs::create_dir_all(&state.minio_data)
        .with_context(|| format!("creating {}", state.minio_data.display()))?;
    Ok(())
}

/// The `ROUTE_TABLE` binding for a miniflare door configured by the
/// [`worker_mode_triple`] shape rather than by a [`WorkerMode`]
/// (super::mesofact_static::WorkerMode).
///
/// Camp's `build_miniflare_deploy_spec` lowers a mirror's slot fields to that
/// triple and then MUTATES it — the SSR-runtime container overrides the origin,
/// and the published manifest overrides the prefixes — so the table can only be
/// composed after those mutations, from the triple that survived them. It is
/// the same producer underneath ([`super::mesofact_static::worker_route_table_json`]);
/// this is the lowering back to the typed mode, in the one place that needs it.
///
/// `/uploads/*` points at the asset origin at this tier, as the pond
/// `UPLOAD_ORIGIN` binding did before R898-F3: upload keys resolve in-bucket
/// once a writer exists.
pub fn miniflare_route_table(
    worker_mode: &str,
    ssr_origin: &str,
    ssr_prefixes: &[String],
    asset_origin: &str,
) -> Result<String> {
    let mode = if worker_mode == "ssr" {
        super::mesofact_static::WorkerMode::Ssr {
            origin_url: ssr_origin.to_string(),
            prefixes: ssr_prefixes.to_vec(),
        }
    } else if worker_mode == "spa" {
        super::mesofact_static::WorkerMode::Spa
    } else {
        super::mesofact_static::WorkerMode::Static
    };
    super::mesofact_static::worker_route_table_json(
        &mode,
        crate::route_table::WorkerAssets::Deployed(asset_origin),
        asset_origin,
        &super::mesofact_static::BackendOrigins::default(),
        None,
    )
}

/// Lower a [`super::mesofact_static::WorkerMode`] to the three Worker
/// binding strings (`WORKER_MODE`, `SSR_ORIGIN`, `SSR_PREFIXES` as a Vec for
/// later JSON-encoding). Used by both the cloud-direct pond path and the
/// yubaba-side miniflare spec builder.
///
/// R898-F3: the last two are no longer Worker bindings — the door walks
/// `ROUTE_TABLE` — but they are still the shape camp's `MiniflareSpec` carries
/// over the wire, and [`miniflare_route_table`] is what turns them into one.
pub fn worker_mode_triple(
    mode: &super::mesofact_static::WorkerMode,
) -> (String, String, Vec<String>) {
    match mode {
        super::mesofact_static::WorkerMode::Static => ("static".to_string(), String::new(), vec![]),
        super::mesofact_static::WorkerMode::Spa => ("spa".to_string(), String::new(), vec![]),
        super::mesofact_static::WorkerMode::Ssr {
            origin_url,
            prefixes,
        } => ("ssr".to_string(), origin_url.clone(), prefixes.clone()),
    }
}

/// Write the worker JS + miniflare shim to the state dir, spawn the JS
/// runtime, then wait for the `[miniflare-sim] ready` stdout line. Returns
/// the live child + log buffer for the caller's supervisor.
/// Spawn the miniflare door in front of an already-reachable object store.
///
/// Tier-agnostic on purpose (R584-F4): the door is the same compiled Worker
/// bundle at dev, pond and cloud, so the only thing a caller varies is
/// `asset_origin` — `<endpoint>/<bucket>` of whatever implements the `s3`
/// capability at that tier.
pub(super) async fn spawn_miniflare_child(
    ctx: &ReconcileCtx<'_>,
    options: &PondOptions,
    sim_port: u16,
    state: &DoorScripts,
    asset_origin: &str,
    worker_script: &str,
    mode: &super::mesofact_static::WorkerMode,
) -> Result<(tokio::process::Child, LogBuffer)> {
    // Fail fast (and self-heal our own orphans) on a squatted port — otherwise
    // a bind conflict hides behind a 30s "did not emit ready signal" timeout.
    ensure_sim_port_free(sim_port).await?;

    std::fs::write(&state.worker_js, worker_script.as_bytes())
        .with_context(|| format!("writing {}", state.worker_js.display()))?;
    std::fs::write(&state.miniflare_shim, MINIFLARE_SIM_SCRIPT.as_bytes())
        .with_context(|| format!("writing {}", state.miniflare_shim.display()))?;

    // ASSET_ORIGIN points miniflare at the bound object store's HTTP endpoint
    // — the Worker fetches assets over plain HTTP, mirroring the prod path (R2
    // custom domain). Which store that is depends on the tier and is the
    // caller's business: MinIO at pond, the `yah-s3-fs` driver at dev.
    let node_binary = resolve_js_binary(options.js_binary.as_deref());
    let miniflare_import =
        resolve_miniflare_import(ctx.workspace_root).unwrap_or_else(|| "miniflare".to_string());
    let workerd_binary = resolve_workerd_binary(ctx.workspace_root);

    info!(
        port = sim_port,
        asset_origin,
        node_binary = %node_binary.display(),
        workerd_cached = workerd_binary.is_some(),
        "spawning miniflare (workerd)",
    );

    // R898-F3: the door walks ONE table instead of four hardcoded prefixes.
    // Pond points the `/uploads/*` entry at the same MinIO bucket as
    // ASSET_ORIGIN, so upload keys resolve in-bucket once a writer exists —
    // the reserved seam (R490-T8) is now an entry rather than a binding.
    // `None` domain: the local tier has never carried the manifest's per-route
    // response headers, and this change is not the place to start.
    let route_table = super::mesofact_static::worker_route_table_json(
        mode,
        crate::route_table::WorkerAssets::Deployed(asset_origin),
        asset_origin,
        &super::mesofact_static::BackendOrigins::default(),
        None,
    )?;
    let (worker_mode, _, _) = worker_mode_triple(mode);
    // `PORT` / `PORT_HTTP`, not the retired `MF_PORT` (R844-T13): the sim serves
    // the same Worker bundle a fleet node serves, so it must not be the one tier
    // that spells "what port did I get" its own way. `MF_SCRIPT` and the other
    // `MF_*` bindings stay — those configure the shim, they are not the port.
    let port_env = kamaji::ports::port_env(&kamaji::name_anonymous_ports(&[sim_port]));
    let mut cmd = Command::new(&node_binary);
    cmd.arg(&state.miniflare_shim)
        .envs(&port_env)
        .env("MF_SCRIPT", &state.worker_js)
        .env("MF_MINIFLARE_IMPORT", &miniflare_import)
        .env("ASSET_ORIGIN", asset_origin)
        .env("WORKER_MODE", &worker_mode)
        .env("ROUTE_TABLE", &route_table)
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .kill_on_drop(true);
    if let Some(ref wb) = workerd_binary {
        cmd.env("MINIFLARE_WORKERD_PATH", wb);
    }

    let mut child = cmd.spawn().map_err(|e| {
        anyhow::anyhow!(e).context(format!(
            "spawning miniflare via `{}` — ensure bun (or Node.js ≥18) is on PATH, \
             or set BUN/NODE env var",
            node_binary.display(),
        ))
    })?;

    let log_buf = LogBuffer::new();
    let (ready_tx, ready_rx) = oneshot::channel::<()>();
    if let Some(stdout) = child.stdout.take() {
        let buf = log_buf.clone();
        tokio::spawn(async move {
            use tokio::io::{AsyncBufReadExt, BufReader};
            let mut lines = BufReader::new(stdout).lines();
            let mut ready_tx = Some(ready_tx);
            while let Ok(Some(line)) = lines.next_line().await {
                if let Some(tx) = ready_tx.take() {
                    if line.contains("[miniflare-sim] ready on ") {
                        let _ = tx.send(());
                    } else {
                        ready_tx = Some(tx);
                    }
                }
                buf.push(line).await;
            }
        });
    }
    if let Some(stderr) = child.stderr.take() {
        let buf = log_buf.clone();
        tokio::spawn(async move {
            use tokio::io::{AsyncBufReadExt, BufReader};
            let mut lines = BufReader::new(stderr).lines();
            while let Ok(Some(line)) = lines.next_line().await {
                buf.push(line).await;
            }
        });
    }

    match tokio::time::timeout(options.ready_timeout, ready_rx).await {
        Ok(Ok(())) => Ok((child, log_buf)),
        Ok(Err(_)) | Err(_) => {
            let _ = child.start_kill();
            let _ = child.wait().await;
            // Give the reader tasks a beat to drain, then surface what the
            // shim actually said — an opaque timeout hides the real error
            // (missing miniflare import, port conflict, workerd crash, …).
            tokio::time::sleep(Duration::from_millis(100)).await;
            let (lines, _) = log_buf.since(0).await;
            let tail = if lines.is_empty() {
                "(no output captured)".to_string()
            } else {
                lines
                    .iter()
                    .rev()
                    .take(15)
                    .rev()
                    .cloned()
                    .collect::<Vec<_>>()
                    .join("\n  ")
            };
            bail!(
                "miniflare did not emit ready signal within {:?} — via `{}`, last output:\n  {}",
                options.ready_timeout,
                node_binary.display(),
                tail,
            );
        }
    }
}

/// Look up the workspace's `local-container` provider and turn it into a
/// [`LocalContainerSpec`]. Returns a friendly error when the workspace has
/// no such provider declared.
fn load_local_container_spec(ctx: &ReconcileCtx<'_>) -> Result<LocalContainerSpec> {
    let cfg = crate::config::CloudConfig::load(ctx.workspace_root)
        .context("loading CloudConfig for local-container provider lookup")?;
    let provider = cfg
        .providers
        .iter()
        .find(|p| matches!(p.kind, Provider::LocalContainer))
        .with_context(|| {
            format!(
                "no `kind = \"local-container\"` provider declared in {}/.yah/infra/providers/ — \
                 pond mirror needs orbstack.toml or equivalent",
                ctx.workspace_root.display(),
            )
        })?;
    local_container_spec_from_provider(provider)
}

/// Resolve the bucket name from the static + object_store slot field maps.
/// Falls back to a default when neither slot declares one; logs a warning
/// when the two slots disagree (static wins).
fn resolve_bucket(
    static_fields: &BTreeMap<String, toml::Value>,
    store_fields: &BTreeMap<String, toml::Value>,
) -> String {
    let from_static = static_fields.get("bucket").and_then(|v| v.as_str());
    let from_store = store_fields.get("bucket").and_then(|v| v.as_str());
    match (from_static, from_store) {
        (Some(a), Some(b)) if a != b => {
            warn!(
                static_bucket = a,
                object_store_bucket = b,
                "providers.static.bucket disagrees with providers.object_store.bucket; using static's",
            );
            a.to_string()
        }
        (Some(s), _) | (_, Some(s)) => s.to_string(),
        _ => DEFAULT_BUCKET.to_string(),
    }
}

/// Write the `.env`-shaped creds file R256-T4's publisher invocation reads.
/// Format chosen so it's directly sourceable from a shell.
fn write_credentials_file(
    state: &PondState,
    endpoint: &str,
    bucket: &str,
    user: &str,
    password: &str,
) -> Result<()> {
    let body = format!(
        "# Auto-generated by yah pond reconciler. Do not edit.\n\
         # Sourceable by mesofact-publish wrappers (R256-T4) to talk to the\n\
         # local MinIO endpoint without hitting Cloudflare.\n\
         MESOFACT_ENDPOINT={endpoint}\n\
         MESOFACT_BUCKET={bucket}\n\
         MESOFACT_S3_ACCESS_KEY_ID={user}\n\
         MESOFACT_S3_SECRET_ACCESS_KEY={password}\n",
    );
    std::fs::write(&state.credentials, body)
        .with_context(|| format!("writing {}", state.credentials.display()))
}

/// Supervisor task: owns the miniflare child + tears down the MinIO
/// container when the workload shuts down. Used by cloud's direct-call
/// path (`up_pond` non-adopt branch) where cloud owns MinIO's teardown.
fn supervise_miniflare_and_minio(
    runtime: LocalRuntime,
    minio_name: String,
    miniflare: tokio::process::Child,
    shutdown_rx: oneshot::Receiver<()>,
) -> tokio::task::JoinHandle<Result<()>> {
    tokio::spawn(async move {
        run_miniflare_supervisor(miniflare, shutdown_rx).await;
        if let Err(e) = runtime
            .stop_and_remove(&minio_name, Duration::from_secs(3))
            .await
        {
            warn!(container = %minio_name, error = %e, "pond minio teardown");
        }
        Ok(())
    })
}

/// Shared miniflare child supervision shape. SIGTERM lets the miniflare
/// shim call `mf.dispose()` (which kills the workerd subprocess cleanly);
/// falls back to SIGKILL after 5 s.
pub(super) async fn run_miniflare_supervisor(
    mut miniflare: tokio::process::Child,
    shutdown_rx: oneshot::Receiver<()>,
) {
    tokio::select! {
        res = miniflare.wait() => {
            if let Ok(status) = res {
                if !status.success() {
                    warn!(?status, "miniflare exited non-zero");
                }
            }
        }
        _ = shutdown_rx => {
            #[cfg(unix)]
            if let Some(pid) = miniflare.id() {
                let _ = std::process::Command::new("kill")
                    .arg(pid.to_string())
                    .status();
            }
            match tokio::time::timeout(Duration::from_secs(5), miniflare.wait()).await {
                Ok(_) => {}
                Err(_) => {
                    warn!("miniflare did not exit after SIGTERM; sending SIGKILL");
                    let _ = miniflare.start_kill();
                    let _ = miniflare.wait().await;
                }
            }
            #[cfg(not(unix))]
            {
                let _ = miniflare.start_kill();
                let _ = miniflare.wait().await;
            }
        }
    }
}

/// Resolve the JS runtime binary for the miniflare shim.
/// Priority: explicit field > `BUN` env var > `bun` on PATH > `NODE` env var > `node`.
pub fn resolve_js_binary(js_binary: Option<&std::path::Path>) -> PathBuf {
    if let Some(p) = js_binary {
        return p.to_path_buf();
    }
    if let Some(p) = std::env::var_os("BUN") {
        return PathBuf::from(p);
    }
    // Prefer bun as the workspace default; fall back to node if absent.
    if which_bun_on_path() {
        return PathBuf::from("bun");
    }
    if let Some(p) = std::env::var_os("NODE") {
        return PathBuf::from(p);
    }
    PathBuf::from("node")
}

pub fn which_bun_on_path() -> bool {
    std::process::Command::new("bun")
        .arg("--version")
        .stdout(std::process::Stdio::null())
        .stderr(std::process::Stdio::null())
        .status()
        .map(|s| s.success())
        .unwrap_or(false)
}

/// Locate the worker directory's node_modules under the workspace root. Two
/// live layouts: the yah monorepo (cloud vendored at `oss/yubaba/crates/cloud`)
/// and the standalone yubaba export (`crates/cloud`).
fn resolve_worker_node_modules(workspace_root: &std::path::Path) -> Option<PathBuf> {
    [
        "oss/yubaba/crates/cloud/worker/node_modules",
        "crates/cloud/worker/node_modules",
    ]
    .iter()
    .map(|rel| workspace_root.join(rel))
    // Canonicalize: workspace_root is often relative (CLI `--path` defaults
    // to `.`), but the path is handed to the shim as an import specifier,
    // which bun/node resolve against the shim's dir — it must be absolute.
    .find_map(|p| p.canonicalize().ok())
}

/// Return an absolute path to miniflare's CJS entry point if the monorepo
/// worker directory is present under the workspace root. Operators who have
/// the yah source tree get zero-download spinup; those who don't fall back to
/// the bare `"miniflare"` specifier (which requires a lazy npm install).
pub fn resolve_miniflare_import(workspace_root: &std::path::Path) -> Option<String> {
    let index = resolve_worker_node_modules(workspace_root)?.join("miniflare/dist/src/index.js");
    if index.exists() {
        Some(index.to_string_lossy().into_owned())
    } else {
        None
    }
}

/// Return the workerd binary path from the monorepo's worker node_modules, if
/// present. Passed to miniflare as `MINIFLARE_WORKERD_PATH` so the 83 MB
/// binary is never re-downloaded when it's already on disk. Falls back to
/// miniflare's own resolution (from the `workerd` npm package) when absent.
pub fn resolve_workerd_binary(workspace_root: &std::path::Path) -> Option<PathBuf> {
    let bin = resolve_worker_node_modules(workspace_root)?.join(if cfg!(windows) {
        "workerd/bin/workerd.exe"
    } else {
        "workerd/bin/workerd"
    });
    if bin.exists() {
        Some(bin)
    } else {
        None
    }
}

// ── Sim-port pre-flight: surface (and self-heal) serve-layer conflicts ───────
//
// A stale serve-layer squatting `sim_port` otherwise fails opaquely: workerd
// dies on `bind(): Address already in use`, never emits the ready line, and
// the caller only learns about it as `ERR_RUNTIME_FAILURE` after the full
// `ready_timeout` (30s). We turn that into an immediate, actionable signal.
//
// The recurring offender (R362-B1 / R374) is a host-side `workerd` orphaned to
// pid 1: bun double-forks workerd, so `kill_on_drop` misses the grandchild and
// it survives an abnormal parent exit still holding the port. That specific
// orphan — identified by its argv binding OUR port on loopback — is reaped and
// retried. Any other holder (a running pond container, a foreign process) is
// reported by name instead of hanging.

/// True if something is accepting TCP connections on `host:port` right now. A
/// live listener is the real conflict; a lingering `TIME_WAIT` socket has no
/// listener and refuses the connect, so this avoids the false positives a
/// bind-probe would hit.
pub(crate) fn port_has_listener(host: &str, port: u16) -> bool {
    use std::net::{TcpStream, ToSocketAddrs};
    let Ok(addrs) = (host, port).to_socket_addrs() else {
        return false;
    };
    addrs
        .into_iter()
        .any(|addr| TcpStream::connect_timeout(&addr, Duration::from_millis(200)).is_ok())
}

/// `(pid, cmdline)` for every host `workerd` process whose argv references
/// `port`. Source for both reaping (loopback-bound orphans) and the
/// human-readable holder list in the conflict error. Best-effort: a missing or
/// failing `ps` yields an empty vec and the caller falls through to its bail.
async fn workerd_procs_on_port(port: u16) -> Vec<(i32, String)> {
    // `-axww`: all processes, no-tty included, unlimited width so a deep argv
    // (the `entry=127.0.0.1:PORT` signature) is never truncated. Portable
    // across macOS (BSD ps) and Linux (procps).
    let out = match Command::new("ps")
        .args(["-axww", "-o", "pid=,command="])
        .output()
        .await
    {
        Ok(o) if o.status.success() => o.stdout,
        _ => return vec![],
    };
    scan_workerd_procs(&String::from_utf8_lossy(&out), port)
}

/// Pure parser for `ps -o pid=,command=` output. macOS right-justifies the pid
/// column, so lines are left-trimmed before the pid/command split.
fn scan_workerd_procs(ps_stdout: &str, port: u16) -> Vec<(i32, String)> {
    let needle = format!(":{port}");
    ps_stdout
        .lines()
        .filter_map(|line| {
            let (pid_str, cmd) = line.trim_start().split_once(char::is_whitespace)?;
            let pid: i32 = pid_str.parse().ok()?;
            (cmd.contains("workerd") && cmd.contains(&needle)).then(|| (pid, cmd.to_string()))
        })
        .collect()
}

/// A workerd is a reapable host-side pond-sim orphan iff its argv binds our sim
/// port on loopback — the host-side shim's default `MF_HOST=127.0.0.1`. The
/// containerised sim binds `0.0.0.0` inside its netns and is published by
/// docker, so it never matches: we never reach into a container this way.
fn is_reapable_sim_workerd(cmdline: &str, sim_port: u16) -> bool {
    cmdline.contains(&format!("entry=127.0.0.1:{sim_port}"))
}

/// Trim an argv for a log/error line — long enough to show the binding, capped
/// on a char boundary so multi-byte paths never panic the slice.
fn truncate_cmd(cmd: &str) -> String {
    const MAX: usize = 160;
    if cmd.chars().count() <= MAX {
        return cmd.to_string();
    }
    format!("{}…", cmd.chars().take(MAX).collect::<String>())
}

/// Best-effort SIGTERM→SIGKILL of a pid via the `kill` binary. Reaping a stale
/// dev-sim orphan is not worth a direct `libc`/`nix` dependency in this crate.
fn signal_pid(pid: i32, sig: &str) {
    let _ = std::process::Command::new("kill")
        .arg(format!("-{sig}"))
        .arg(pid.to_string())
        .status();
}

/// Pre-flight guard for [`spawn_miniflare_child`]: ensure the miniflare Worker
/// runtime can actually bind `sim_port` before we spawn it. Reaps a stale
/// host-side sim orphan on that exact port and retries; if a foreign holder (a
/// running container, an unrelated process) remains, bails with a crisp,
/// actionable error rather than a silent 30s `ERR_RUNTIME_FAILURE`.
pub(super) async fn ensure_sim_port_free(sim_port: u16) -> Result<()> {
    if !port_has_listener("127.0.0.1", sim_port) {
        return Ok(());
    }

    let reapable: Vec<i32> = workerd_procs_on_port(sim_port)
        .await
        .into_iter()
        .filter(|(_, cmd)| is_reapable_sim_workerd(cmd, sim_port))
        .map(|(pid, _)| pid)
        .collect();

    if !reapable.is_empty() {
        for &pid in &reapable {
            signal_pid(pid, "TERM");
        }
        tokio::time::sleep(Duration::from_millis(300)).await;
        for &pid in &reapable {
            signal_pid(pid, "KILL");
        }
        warn!(
            port = sim_port,
            pids = ?reapable,
            "reaped stale host-side miniflare (workerd) orphan(s) squatting the pond sim port",
        );
        // Give the OS a beat to release the listener socket before re-probing.
        tokio::time::sleep(Duration::from_millis(250)).await;
        if !port_has_listener("127.0.0.1", sim_port) {
            return Ok(());
        }
    }

    let holders = workerd_procs_on_port(sim_port).await;
    let detail = if holders.is_empty() {
        "(no host-side workerd found on this port via `ps` — most likely a \
         running pond container publishing it, or a foreign process)"
            .to_string()
    } else {
        holders
            .iter()
            .map(|(pid, cmd)| format!("pid {pid}: {}", truncate_cmd(cmd)))
            .collect::<Vec<_>>()
            .join("\n  ")
    };
    bail!(
        "pond sim port {sim_port} is already in use on 127.0.0.1 — miniflare's \
         Worker runtime cannot bind it (this otherwise surfaces as an opaque \
         ERR_RUNTIME_FAILURE only after the ready timeout elapses). Holder(s):\n  {detail}\n\
         Stop the other pond mirror on this port (`docker stop` its container, \
         or kill a stale host-side serve-layer), then retry.",
    );
}

// ── R374-F2: yubaba status query (desktop adopt path) ────────────────────────

/// Workload identity convention shared between camp (the producer) and
/// desktop (the consumer). Kept short to fit the yubaba `MeshIdent` regex.
pub fn pond_workload_ident(service: &str, env: &str, component_id: &str) -> String {
    format!("{service}-{env}-{component_id}")
}

/// Per-workload phase reported by `GET /pond/state`. Mirrors
/// `yubaba::pond::PondPhase` on the wire — kept local to avoid taking a
/// runtime dep on the yubaba crate from cloud.
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AdoptPondPhase {
    Pending,
    Running,
    Degraded,
    Failed,
}

/// Liveness/readiness outcome for one slot — mirrors
/// `yubaba::pond::ProbeOutcome` without a direct crate dependency.
#[derive(Debug, Clone, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "snake_case", tag = "state")]
pub enum AdoptProbeOutcome {
    Pass,
    Fail { reason: String },
    Pending,
}

/// Per-slot probe snapshot — mirrors `yubaba::pond::SlotProbe`.
/// `#[serde(default)]` on `url` keeps deserialization lenient for
/// pre-E yubaba responses that omit the field.
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct AdoptSlotProbe {
    pub slot: String,
    pub liveness: AdoptProbeOutcome,
    pub readiness: AdoptProbeOutcome,
    pub last_checked_at: u64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub url: Option<String>,
}

/// Subset of `yubaba::pond::PondStateRecord` the desktop adopt path and
/// the observation seam (`desktop::mirror_observation`) need. Field set
/// kept narrow to avoid taking a runtime dep on the yubaba crate from
/// cloud — extend it (and add a matching field to yubaba's record) when
/// a new bit of state needs to ride to the desktop.
#[derive(Debug, Clone, serde::Deserialize)]
pub struct AdoptPondRecord {
    pub phase: AdoptPondPhase,
    /// Identity fields — populated by yubaba so list-all consumers can
    /// correlate without re-deriving the ident scheme. `#[serde(default)]`
    /// because the per-ident `GET /pond/state` response is canonical only
    /// for `phase`, `dev_url`, `console_url`, and `error` today; adding
    /// `default` here keeps the per-ident path lenient.
    #[serde(default)]
    pub service: String,
    #[serde(default)]
    pub env: String,
    #[serde(default)]
    pub component_id: String,
    #[serde(default)]
    pub dev_url: Option<String>,
    #[serde(default)]
    pub console_url: Option<String>,
    #[serde(default)]
    pub error: Option<String>,
    /// Unix epoch **milliseconds** when the workload entered Running (mirrors
    /// `PondStateRecord::started_at`). `None` while Pending/Failed or from a
    /// pre-uptime yubaba. Feeds the Run-tab Live scoreboard's uptime column.
    #[serde(default)]
    pub started_at: Option<u64>,
    /// Per-slot probe snapshots from yubaba (R456-F1 Phase E). Empty for
    /// pre-E yubaba responses — callers treat an empty vec as "no probe
    /// data yet" rather than "all slots failed".
    #[serde(default)]
    pub slots: Vec<AdoptSlotProbe>,
}

/// Read the embedded yubaba's bound port from
/// `<camp_root>/.yah/jit/yubaba-pond-port.json`. The file is written by
/// `ensure_pond_running` in `app/yah/cli/src/camp.rs` (camp startup AND the
/// `pond.ensure_running` RPC recovery path).
pub fn read_warden_pond_port(workspace_root: &std::path::Path) -> Result<u16> {
    let path = workspace_root.join(".yah/jit/yubaba-pond-port.json");
    let body =
        std::fs::read_to_string(&path).with_context(|| format!("reading {}", path.display()))?;
    let v: serde_json::Value =
        serde_json::from_str(&body).with_context(|| format!("parsing {}", path.display()))?;
    let port = v
        .get("port")
        .and_then(|x| x.as_u64())
        .and_then(|p| u16::try_from(p).ok())
        .with_context(|| format!("{}: missing or invalid 'port' field", path.display()))?;
    Ok(port)
}

/// R876-T23: the operator signer for camp-pond calls — the same key file as
/// every CloudClient. The camp spawns its pond trusting that key's public
/// half (`YUBABA_OPERATOR_KEYS`), so these sign rather than stay an exception.
fn pond_signer() -> Result<yubaba_auth_token::OperatorSigner> {
    yubaba_auth_token::default_operator_signer().map_err(|e| anyhow::anyhow!(e))
}

/// `GET http://127.0.0.1:{port}/pond/state?ident=...`. Returns `Ok(None)`
/// when yubaba replies 404 (no registration for that ident — clear "pond
/// not running" signal). Bails on connection errors / non-404 non-2xx.
pub async fn query_warden_pond_state(port: u16, ident: &str) -> Result<Option<AdoptPondRecord>> {
    let client = reqwest::Client::builder()
        .timeout(Duration::from_secs(3))
        .build()
        .context("building reqwest client for yubaba status query")?;
    let url = format!("http://127.0.0.1:{port}/pond/state");
    let resp = pond_signer()?
        .sign(client.get(&url))
        .query(&[("ident", ident)])
        .send()
        .await
        .with_context(|| format!("GET {url}?ident={ident}"))?;
    match resp.status() {
        StatusCode::OK => {
            let record: AdoptPondRecord = resp
                .json()
                .await
                .context("parsing yubaba /pond/state response")?;
            Ok(Some(record))
        }
        StatusCode::NOT_FOUND => Ok(None),
        s => {
            let body = resp.text().await.unwrap_or_default();
            anyhow::bail!("yubaba /pond/state returned {s}: {body}")
        }
    }
}

/// `GET http://127.0.0.1:{port}/pond` — list every pond workload yubaba
/// is currently tracking. Always 200 from yubaba (empty `workloads` when
/// nothing is registered). Used by the desktop observation seam so a
/// single GET answers "what's up?" across every declared pond cell,
/// instead of one GET per ident.
#[derive(Debug, serde::Deserialize)]
struct WardenPondListResponse {
    workloads: Vec<AdoptPondRecord>,
}

/// `POST http://127.0.0.1:{port}/pond/teardown` — stop+remove one pond
/// workload's containers and drop its registry entry (R626-F4). Returns the
/// `removed` flag yubaba reports: `true` if a registration was present,
/// `false` if the ident was already absent (idempotent success, not an
/// error). Bails on connection errors / non-2xx.
///
/// This is the actuation half of a desired-state stop. The camp daemon
/// records intent `stopped` FIRST (durable), then calls this. The intent —
/// not this call — is what keeps the workload down across reconciles, so a
/// teardown of something already gone is fine.
pub async fn teardown_warden_pond(port: u16, ident: &str) -> Result<bool> {
    let client = reqwest::Client::builder()
        .timeout(Duration::from_secs(10))
        .build()
        .context("building reqwest client for yubaba teardown")?;
    let url = format!("http://127.0.0.1:{port}/pond/teardown");
    let resp = pond_signer()?
        .sign(client.post(&url))
        .json(&serde_json::json!({ "ident": ident }))
        .send()
        .await
        .with_context(|| format!("POST {url} ident={ident}"))?;
    match resp.status() {
        StatusCode::OK => {
            let body: serde_json::Value = resp
                .json()
                .await
                .context("parsing yubaba /pond/teardown response")?;
            Ok(body
                .get("removed")
                .and_then(|v| v.as_bool())
                .unwrap_or(false))
        }
        s => {
            let body = resp.text().await.unwrap_or_default();
            anyhow::bail!("yubaba /pond/teardown returned {s}: {body}")
        }
    }
}

pub async fn query_warden_pond_list(port: u16) -> Result<Vec<AdoptPondRecord>> {
    let client = reqwest::Client::builder()
        .timeout(Duration::from_secs(3))
        .build()
        .context("building reqwest client for yubaba list query")?;
    let url = format!("http://127.0.0.1:{port}/pond");
    let resp = pond_signer()?
        .sign(client.get(&url))
        .send()
        .await
        .with_context(|| format!("GET {url}"))?;
    match resp.status() {
        StatusCode::OK => {
            let body: WardenPondListResponse = resp
                .json()
                .await
                .context("parsing yubaba /pond list response")?;
            Ok(body.workloads)
        }
        s => {
            let body = resp.text().await.unwrap_or_default();
            anyhow::bail!("yubaba /pond returned {s}: {body}")
        }
    }
}

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

    // ── sim-port pre-flight ──────────────────────────────────────────────

    const HOST_SIDE_WORKERD: &str = "/ws/oss/yubaba/crates/cloud/worker/node_modules/workerd/bin/workerd serve --binary --experimental --socket-addr=entry=127.0.0.1:4323 --external-addr=loopback=127.0.0.1:59934 --control-fd=3";
    const CONTAINER_WORKERD: &str = "/usr/local/bin/workerd serve --binary --experimental --socket-addr=entry=0.0.0.0:4322 --control-fd=3";

    #[test]
    fn reapable_matches_host_side_sim_on_its_port() {
        assert!(is_reapable_sim_workerd(HOST_SIDE_WORKERD, 4323));
    }

    #[test]
    fn reapable_rejects_container_bound_sim() {
        // Container binds 0.0.0.0, never loopback — must never be reaped.
        assert!(!is_reapable_sim_workerd(CONTAINER_WORKERD, 4322));
    }

    #[test]
    fn reapable_rejects_workerd_on_a_different_port() {
        assert!(!is_reapable_sim_workerd(HOST_SIDE_WORKERD, 4322));
    }

    #[test]
    fn scan_extracts_workerd_pids_on_port_only() {
        let ps = "\
  3232 /ws/node_modules/workerd/bin/workerd serve --socket-addr=entry=127.0.0.1:4323 --control-fd=3
  4100 /usr/bin/minio server /data --address :4323
  5000 /ws/node_modules/workerd/bin/workerd serve --socket-addr=entry=127.0.0.1:4322 --control-fd=3
 99999 /bin/some-daemon --port 4323";
        let hits = scan_workerd_procs(ps, 4323);
        // Only the workerd whose argv mentions :4323 — minio + the 4322 workerd
        // + the non-workerd daemon are excluded.
        assert_eq!(
            hits,
            vec![(
                3232,
                ps.lines()
                    .next()
                    .unwrap()
                    .trim_start()
                    .split_once(' ')
                    .unwrap()
                    .1
                    .to_string()
            )]
        );
    }

    #[test]
    fn scan_tolerates_blank_and_malformed_lines() {
        let ps = "\n   \nnotanumber /ws/workerd serve entry=127.0.0.1:4323\n";
        assert!(scan_workerd_procs(ps, 4323).is_empty());
    }

    #[test]
    fn truncate_cmd_caps_and_is_char_safe() {
        let short = "workerd serve :4323";
        assert_eq!(truncate_cmd(short), short);
        let long = "é".repeat(500);
        let out = truncate_cmd(&long);
        assert!(out.ends_with('…'));
        assert_eq!(out.chars().count(), 161); // 160 kept + ellipsis
    }

    #[test]
    fn port_has_listener_true_for_live_listener_false_for_free_port() {
        use std::net::TcpListener;
        let listener = TcpListener::bind(("127.0.0.1", 0)).unwrap();
        let bound = listener.local_addr().unwrap().port();
        assert!(port_has_listener("127.0.0.1", bound));
        drop(listener);

        // A now-unbound ephemeral port refuses connects — but only if nothing
        // else grabbed it in between. Cargo runs this module's tests in parallel
        // threads and `ensure_sim_port_free_ok_when_unbound` below draws from the
        // same ephemeral range, so a single-shot assertion here loses that race
        // often enough to make the crate's suite intermittently red (R706 drive-by:
        // it passed in isolation and failed in the full run).
        //
        // Re-drawing a fresh port on collision keeps exactly what this asserts —
        // that `port_has_listener` says false when nothing listens — while making
        // the check independent of who else is binding concurrently.
        let mut port = bound;
        for _ in 0..16 {
            if !port_has_listener("127.0.0.1", port) {
                return;
            }
            let l = TcpListener::bind(("127.0.0.1", 0)).unwrap();
            port = l.local_addr().unwrap().port();
            drop(l);
        }
        panic!("no free ephemeral port observed in 16 draws (last tried {port})");
    }

    #[tokio::test]
    async fn ensure_sim_port_free_ok_when_unbound() {
        // Reserve then release an ephemeral port to get one that is almost
        // certainly free, and confirm the guard passes without a holder.
        //
        // "Almost certainly" is not "certainly", and the gap is a real race
        // rather than a theoretical one: the OS may hand the just-released
        // port straight to a concurrently-running test in this same binary —
        // `ensure_sim_port_free_bails_with_holder_on_foreign_listener` below
        // binds an ephemeral port too. So a single draw makes this test's
        // result depend on scheduling, and it duly went red the moment an
        // unrelated change altered the test count (R742-F3).
        //
        // Re-draw on collision, which keeps exactly what this asserts — the
        // guard passes when nothing listens — while making it independent of
        // who else is binding. Same discipline, and the same reasoning, as
        // `port_has_listener_is_false_when_idle` directly above.
        for _ in 0..16 {
            let port = {
                let l = std::net::TcpListener::bind(("127.0.0.1", 0)).unwrap();
                l.local_addr().unwrap().port()
            };
            if ensure_sim_port_free(port).await.is_ok() {
                return;
            }
        }
        panic!("no free ephemeral port observed in 16 draws");
    }

    #[tokio::test]
    async fn ensure_sim_port_free_bails_with_holder_on_foreign_listener() {
        // A plain TcpListener (not a reapable sim workerd) holds the port —
        // the guard must refuse to touch it and surface an actionable error.
        let listener = std::net::TcpListener::bind(("127.0.0.1", 0)).unwrap();
        let port = listener.local_addr().unwrap().port();
        let err = ensure_sim_port_free(port).await.unwrap_err().to_string();
        assert!(
            err.contains(&format!("pond sim port {port} is already in use")),
            "got: {err}"
        );
        assert!(err.contains("Stop the other pond mirror"), "got: {err}");
    }

    #[test]
    fn resolve_bucket_static_wins_on_disagreement() {
        let mut s = BTreeMap::new();
        s.insert("bucket".into(), toml::Value::String("from-static".into()));
        let mut o = BTreeMap::new();
        o.insert(
            "bucket".into(),
            toml::Value::String("from-object-store".into()),
        );
        assert_eq!(resolve_bucket(&s, &o), "from-static");
    }

    #[test]
    fn resolve_bucket_falls_back_to_either_set_field() {
        let s = BTreeMap::new();
        let mut o = BTreeMap::new();
        o.insert(
            "bucket".into(),
            toml::Value::String("from-object-store".into()),
        );
        assert_eq!(resolve_bucket(&s, &o), "from-object-store");

        let mut s = BTreeMap::new();
        s.insert("bucket".into(), toml::Value::String("from-static".into()));
        let o = BTreeMap::new();
        assert_eq!(resolve_bucket(&s, &o), "from-static");
    }

    #[test]
    fn resolve_bucket_uses_default_when_unset() {
        let s = BTreeMap::new();
        let o = BTreeMap::new();
        assert_eq!(resolve_bucket(&s, &o), DEFAULT_BUCKET);
    }

    #[test]
    fn pond_state_layout_under_workspace_root() {
        let tmp = tempfile::TempDir::new().unwrap();
        let svc = crate::ServiceConfig {
            schema_version: 1,
            name: "dev-yah".into(),
            address: crate::config::ServiceAddress::front_door("yah.dev"),
            description: None,
            components: vec![],
        };
        let comp = crate::ServiceComponent {
            mount: None,
            id: "site".into(),
            kind: "mesofact-static".into(),
            path: "app/yah/web".into(),
            role: "static".into(),
            publishes: None,
            wave: 0,
            git: None,
            deploy: Default::default(),
            workload: None,
        };
        let mirror = crate::MirrorConfig {
            schema_version: 1,
            shape: crate::MirrorShape::Local,
            providers: BTreeMap::new(),
            ingress: Default::default(),
            ingress_machines: Vec::new(),
            drivers: Default::default(),
            asset_aliases: Default::default(),
            build: Default::default(),
            workload: Default::default(),
        };
        let ctx = ReconcileCtx {
            workspace_root: tmp.path(),
            service: &svc,
            component: &comp,
            mirror: &mirror,
            env: "pond",
            scope: crate::reconciler::ProviderScope::singleton(),
        };
        let state = PondState::for_ctx(&ctx);
        assert_eq!(state.dir, tmp.path().join(".yah/infra/pond/dev-yah-pond"),);
        assert_eq!(state.worker_js, state.dir.join("worker.js"));
        assert_eq!(state.miniflare_shim, state.dir.join("miniflare-sim.mjs"));
        assert_eq!(state.minio_data, state.dir.join("minio-data"));
        assert_eq!(state.credentials, state.dir.join("credentials"));
    }

    #[test]
    fn pond_options_default_pins_image_tags() {
        let opts = PondOptions::default();
        // Image refs must carry a `:tag` for cache determinism — schemars
        // schemas don't enforce this, so the default contract is the load-
        // bearing piece.
        assert!(
            opts.minio_image.contains(':'),
            "minio image must be tag-pinned"
        );
        assert!(opts.ready_timeout >= Duration::from_secs(10));
        assert!(
            !opts.adopt_only,
            "default must not be adopt_only; camp uses false"
        );
        assert!(
            opts.js_binary.is_none(),
            "default js_binary is None (resolved at spawn time)"
        );
    }

    #[tokio::test]
    async fn adopt_only_errors_when_no_warden_port_file() {
        // R374-F2: adopt_only now requires camp to have written the embedded
        // yubaba's port to .yah/jit/yubaba-pond-port.json. With no file the
        // adopt path returns a clear "start yah-camp" error — the pre-R374
        // TCP probe (which could silently adopt half-alive workerd orphans)
        // is gone.
        let tmp = tempfile::TempDir::new().unwrap();
        let svc = crate::ServiceConfig {
            schema_version: 1,
            name: "test-svc".into(),
            address: crate::config::ServiceAddress::front_door("test.dev"),
            description: None,
            components: vec![],
        };
        let comp = crate::ServiceComponent {
            mount: None,
            id: "site".into(),
            kind: "mesofact-static".into(),
            path: "app/web".into(),
            role: "static".into(),
            publishes: None,
            wave: 0,
            git: None,
            deploy: Default::default(),
            workload: None,
        };
        let mirror = crate::MirrorConfig {
            schema_version: 1,
            shape: crate::MirrorShape::Local,
            providers: BTreeMap::new(),
            ingress: Default::default(),
            ingress_machines: Vec::new(),
            drivers: Default::default(),
            asset_aliases: Default::default(),
            build: Default::default(),
            workload: Default::default(),
        };
        let ctx = ReconcileCtx {
            workspace_root: tmp.path(),
            service: &svc,
            component: &comp,
            mirror: &mirror,
            env: "pond",
            scope: crate::reconciler::ProviderScope::singleton(),
        };
        let mut fields = BTreeMap::new();
        fields.insert("port".into(), toml::Value::Integer(19423));
        let opts = PondOptions {
            adopt_only: true,
            ..PondOptions::default()
        };
        let err = up_pond(&ctx, &opts, &fields, "").await.unwrap_err();
        let msg = format!("{err:#}");
        assert!(
            msg.contains("yubaba-pond-port.json"),
            "expected 'yubaba-pond-port.json' in error, got: {msg}"
        );
        assert!(
            msg.contains("yah-camp"),
            "expected 'yah-camp' guidance in error, got: {msg}"
        );
    }

    #[tokio::test]
    async fn adopt_only_returns_404_signal_when_warden_has_no_record() {
        // R374-F2: when the port file exists but yubaba returns 404 for the
        // workload ident, the adopt path bails with "not registered with the
        // camp-embedded yubaba" — a different (and more informative) error
        // than the no-port-file case above.
        let tmp = tempfile::TempDir::new().unwrap();
        // Stand up a mini yubaba-like server that always returns 404 on
        // /pond/state.
        let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
        let port = listener.local_addr().unwrap().port();
        let app = axum::Router::new().route(
            "/pond/state",
            axum::routing::get(|| async {
                (
                    axum::http::StatusCode::NOT_FOUND,
                    axum::Json(serde_json::json!({"error": "no such workload"})),
                )
            }),
        );
        let server = tokio::spawn(async move {
            let _ = axum::serve(listener, app).await;
        });
        // Write the port file so read_warden_pond_port succeeds.
        std::fs::create_dir_all(tmp.path().join(".yah/jit")).unwrap();
        std::fs::write(
            tmp.path().join(".yah/jit/yubaba-pond-port.json"),
            serde_json::json!({ "port": port }).to_string(),
        )
        .unwrap();

        let svc = crate::ServiceConfig {
            schema_version: 1,
            name: "test-svc".into(),
            address: crate::config::ServiceAddress::front_door("test.dev"),
            description: None,
            components: vec![],
        };
        let comp = crate::ServiceComponent {
            mount: None,
            id: "site".into(),
            kind: "mesofact-static".into(),
            path: "app/web".into(),
            role: "static".into(),
            publishes: None,
            wave: 0,
            git: None,
            deploy: Default::default(),
            workload: None,
        };
        let mirror = crate::MirrorConfig {
            schema_version: 1,
            shape: crate::MirrorShape::Local,
            providers: BTreeMap::new(),
            ingress: Default::default(),
            ingress_machines: Vec::new(),
            drivers: Default::default(),
            asset_aliases: Default::default(),
            build: Default::default(),
            workload: Default::default(),
        };
        let ctx = ReconcileCtx {
            workspace_root: tmp.path(),
            service: &svc,
            component: &comp,
            mirror: &mirror,
            env: "pond",
            scope: crate::reconciler::ProviderScope::singleton(),
        };
        let fields = BTreeMap::new();
        let opts = PondOptions {
            adopt_only: true,
            ..PondOptions::default()
        };
        let err = up_pond(&ctx, &opts, &fields, "").await.unwrap_err();
        let msg = format!("{err:#}");
        assert!(
            msg.contains("not registered with the camp-embedded yubaba"),
            "expected 'not registered with the camp-embedded yubaba' in error, got: {msg}"
        );
        server.abort();
    }

    #[tokio::test]
    async fn adopt_only_adopts_on_running_phase() {
        // R374-F2: yubaba returns phase=running with dev_url → up_pond returns
        // a RunningWorkload::adopted carrying that URL.
        let tmp = tempfile::TempDir::new().unwrap();
        let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
        let port = listener.local_addr().unwrap().port();
        let app = axum::Router::new().route(
            "/pond/state",
            axum::routing::get(|| async {
                (
                    axum::http::StatusCode::OK,
                    axum::Json(serde_json::json!({
                        "ident": "test-svc-pond-site",
                        "service": "test-svc",
                        "env": "pond",
                        "component_id": "site",
                        "phase": "running",
                        "dev_url": "http://localhost:4322",
                        "console_url": "http://localhost:9001",
                    })),
                )
            }),
        );
        let server = tokio::spawn(async move {
            let _ = axum::serve(listener, app).await;
        });
        std::fs::create_dir_all(tmp.path().join(".yah/jit")).unwrap();
        std::fs::write(
            tmp.path().join(".yah/jit/yubaba-pond-port.json"),
            serde_json::json!({ "port": port }).to_string(),
        )
        .unwrap();
        let svc = crate::ServiceConfig {
            schema_version: 1,
            name: "test-svc".into(),
            address: crate::config::ServiceAddress::front_door("test.dev"),
            description: None,
            components: vec![],
        };
        let comp = crate::ServiceComponent {
            mount: None,
            id: "site".into(),
            kind: "mesofact-static".into(),
            path: "app/web".into(),
            role: "static".into(),
            publishes: None,
            wave: 0,
            git: None,
            deploy: Default::default(),
            workload: None,
        };
        let mirror = crate::MirrorConfig {
            schema_version: 1,
            shape: crate::MirrorShape::Local,
            providers: BTreeMap::new(),
            ingress: Default::default(),
            ingress_machines: Vec::new(),
            drivers: Default::default(),
            asset_aliases: Default::default(),
            build: Default::default(),
            workload: Default::default(),
        };
        let ctx = ReconcileCtx {
            workspace_root: tmp.path(),
            service: &svc,
            component: &comp,
            mirror: &mirror,
            env: "pond",
            scope: crate::reconciler::ProviderScope::singleton(),
        };
        let fields = BTreeMap::new();
        let opts = PondOptions {
            adopt_only: true,
            ..PondOptions::default()
        };
        let result = up_pond(&ctx, &opts, &fields, "").await.unwrap();
        assert_eq!(result.dev_url.as_deref(), Some("http://localhost:4322"));
        assert_eq!(result.console_url.as_deref(), Some("http://localhost:9001"));
        server.abort();
    }

    #[tokio::test]
    async fn adopt_only_bails_on_failed_phase_with_reason() {
        let tmp = tempfile::TempDir::new().unwrap();
        let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
        let port = listener.local_addr().unwrap().port();
        let app = axum::Router::new().route(
            "/pond/state",
            axum::routing::get(|| async {
                (
                    axum::http::StatusCode::OK,
                    axum::Json(serde_json::json!({
                        "ident": "test-svc-pond-site",
                        "service": "test-svc",
                        "env": "pond",
                        "component_id": "site",
                        "phase": "failed",
                        "error": "MinIO did not bind port",
                    })),
                )
            }),
        );
        let server = tokio::spawn(async move {
            let _ = axum::serve(listener, app).await;
        });
        std::fs::create_dir_all(tmp.path().join(".yah/jit")).unwrap();
        std::fs::write(
            tmp.path().join(".yah/jit/yubaba-pond-port.json"),
            serde_json::json!({ "port": port }).to_string(),
        )
        .unwrap();
        let svc = crate::ServiceConfig {
            schema_version: 1,
            name: "test-svc".into(),
            address: crate::config::ServiceAddress::front_door("test.dev"),
            description: None,
            components: vec![],
        };
        let comp = crate::ServiceComponent {
            mount: None,
            id: "site".into(),
            kind: "mesofact-static".into(),
            path: "app/web".into(),
            role: "static".into(),
            publishes: None,
            wave: 0,
            git: None,
            deploy: Default::default(),
            workload: None,
        };
        let mirror = crate::MirrorConfig {
            schema_version: 1,
            shape: crate::MirrorShape::Local,
            providers: BTreeMap::new(),
            ingress: Default::default(),
            ingress_machines: Vec::new(),
            drivers: Default::default(),
            asset_aliases: Default::default(),
            build: Default::default(),
            workload: Default::default(),
        };
        let ctx = ReconcileCtx {
            workspace_root: tmp.path(),
            service: &svc,
            component: &comp,
            mirror: &mirror,
            env: "pond",
            scope: crate::reconciler::ProviderScope::singleton(),
        };
        let fields = BTreeMap::new();
        let opts = PondOptions {
            adopt_only: true,
            ..PondOptions::default()
        };
        let err = up_pond(&ctx, &opts, &fields, "").await.unwrap_err();
        let msg = format!("{err:#}");
        assert!(
            msg.contains("Failed per yubaba"),
            "expected 'Failed per yubaba' in error, got: {msg}"
        );
        assert!(
            msg.contains("MinIO did not bind port"),
            "expected error reason from yubaba carried through, got: {msg}"
        );
        server.abort();
    }

    #[test]
    fn miniflare_sim_script_is_embedded_and_contains_key_landmarks() {
        // Verify the compile-time include_str! picked up the shim.
        assert!(
            !MINIFLARE_SIM_SCRIPT.is_empty(),
            "MINIFLARE_SIM_SCRIPT must not be empty"
        );
        assert!(
            MINIFLARE_SIM_SCRIPT.contains("MF_MINIFLARE_IMPORT"),
            "shim must support absolute import override for out-of-tree deploys",
        );
        assert!(
            MINIFLARE_SIM_SCRIPT.contains("ASSET_ORIGIN"),
            "shim must read ASSET_ORIGIN from env",
        );
        assert!(
            MINIFLARE_SIM_SCRIPT.contains("new Miniflare"),
            "shim must instantiate Miniflare",
        );
    }

    #[tokio::test]
    async fn query_warden_pond_list_parses_workloads_envelope() {
        // Phase A: the desktop observation seam reads `GET /pond` once and
        // matches records to declared cells. Mirror yubaba's actual response
        // shape — { "workloads": [PondStateRecord, ...] } — and verify
        // identity fields, phase, and the optional URLs round-trip.
        let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
        let port = listener.local_addr().unwrap().port();
        let app = axum::Router::new().route(
            "/pond",
            axum::routing::get(|| async {
                (
                    axum::http::StatusCode::OK,
                    axum::Json(serde_json::json!({
                        "workloads": [
                            {
                                "ident": "yah-marketing-pond-site",
                                "service": "yah-marketing",
                                "env": "pond",
                                "component_id": "site",
                                "phase": "running",
                                "dev_url": "http://127.0.0.1:4322",
                                "console_url": "http://localhost:9001",
                            },
                            {
                                "ident": "yah-dashboard-pond-site",
                                "service": "yah-dashboard",
                                "env": "pond",
                                "component_id": "site",
                                "phase": "degraded",
                                "error": "miniflare probe timeout",
                            },
                        ],
                    })),
                )
            }),
        );
        let server = tokio::spawn(async move {
            let _ = axum::serve(listener, app).await;
        });

        let records = query_warden_pond_list(port).await.unwrap();
        assert_eq!(records.len(), 2);

        let marketing = records
            .iter()
            .find(|r| r.service == "yah-marketing")
            .unwrap();
        assert_eq!(marketing.env, "pond");
        assert_eq!(marketing.component_id, "site");
        assert!(matches!(marketing.phase, AdoptPondPhase::Running));
        assert_eq!(marketing.dev_url.as_deref(), Some("http://127.0.0.1:4322"));
        assert_eq!(
            marketing.console_url.as_deref(),
            Some("http://localhost:9001")
        );
        assert!(marketing.error.is_none());

        let dashboard = records
            .iter()
            .find(|r| r.service == "yah-dashboard")
            .unwrap();
        assert!(matches!(dashboard.phase, AdoptPondPhase::Degraded));
        assert_eq!(dashboard.error.as_deref(), Some("miniflare probe timeout"));
        assert!(dashboard.dev_url.is_none());

        server.abort();
    }

    #[tokio::test]
    async fn query_warden_pond_list_returns_empty_when_nothing_registered() {
        let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
        let port = listener.local_addr().unwrap().port();
        let app = axum::Router::new().route(
            "/pond",
            axum::routing::get(|| async {
                (
                    axum::http::StatusCode::OK,
                    axum::Json(serde_json::json!({ "workloads": [] })),
                )
            }),
        );
        let server = tokio::spawn(async move {
            let _ = axum::serve(listener, app).await;
        });
        let records = query_warden_pond_list(port).await.unwrap();
        assert!(records.is_empty());
        server.abort();
    }

    #[test]
    fn resolve_miniflare_import_finds_monorepo_worker_dir() {
        // If the monorepo is checked out (we're running tests inside it), the
        // worker dir should be found relative to CARGO_MANIFEST_DIR's ancestor.
        let manifest = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
        // CARGO_MANIFEST_DIR = crates/yah/cloud → workspace root is 3 up
        let workspace = manifest.ancestors().nth(3).unwrap();
        let result = resolve_miniflare_import(workspace);
        // Only assert the path shape when the dir is present; CI without
        // node_modules will get None, which is the correct fallback.
        if let Some(path) = result {
            assert!(
                path.ends_with("index.js"),
                "import path should end with index.js: {path}"
            );
            assert!(
                std::path::Path::new(&path).exists(),
                "resolved path must exist: {path}"
            );
        }
    }
}