#0 building with "default" instance using docker driver

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 2.02kB done
#1 DONE 0.0s

#2 [internal] load metadata for docker.io/library/node:22-bookworm-slim
#2 DONE 0.0s

#3 [internal] load .dockerignore
#3 transferring context: 2B done
#3 DONE 0.0s

#4 [ 1/11] FROM docker.io/library/node:22-bookworm-slim@sha256:d649c27dae7ba0137b3cef5dd75baa422c08dc3d9e3fc0c23dfb172dc3cc6436
#4 resolve docker.io/library/node:22-bookworm-slim@sha256:d649c27dae7ba0137b3cef5dd75baa422c08dc3d9e3fc0c23dfb172dc3cc6436 0.0s done
#4 CACHED

#5 [internal] load build context
#5 transferring context: 2.64MB 0.1s done
#5 DONE 0.1s

#6 [ 2/11] RUN apt-get update   && apt-get install -y --no-install-recommends bash build-essential ca-certificates cron curl python3 unzip util-linux   && rm -rf /var/lib/apt/lists/*
#6 0.265 Get:1 http://deb.debian.org/debian bookworm InRelease [151 kB]
#6 0.277 Get:2 http://deb.debian.org/debian bookworm-updates InRelease [55.4 kB]
#6 0.277 Get:3 http://deb.debian.org/debian-security bookworm-security InRelease [34.8 kB]
#6 0.364 Get:4 http://deb.debian.org/debian bookworm/main amd64 Packages [8790 kB]
#6 0.454 Get:5 http://deb.debian.org/debian bookworm-updates/main amd64 Packages [6924 B]
#6 0.522 Get:6 http://deb.debian.org/debian-security bookworm-security/main amd64 Packages [335 kB]
#6 1.791 Fetched 9374 kB in 2s (6127 kB/s)
#6 1.791 Reading package lists...
#6 2.576 Reading package lists...
#6 3.336 Building dependency tree...
#6 3.562 Reading state information...
#6 3.843 bash is already the newest version (5.2.15-2+b13).
#6 3.843 bash set to manually installed.
#6 3.843 util-linux is already the newest version (2.38.1-5+deb12u3).
#6 3.843 util-linux set to manually installed.
#6 3.843 The following additional packages will be installed:
#6 3.843   binutils binutils-common binutils-x86-64-linux-gnu bzip2 cpp cpp-12
#6 3.843   cron-daemon-common dpkg-dev g++ g++-12 gcc gcc-12 libasan8 libatomic1
#6 3.843   libbinutils libbrotli1 libc-dev-bin libc6-dev libcc1-0 libcrypt-dev
#6 3.843   libctf-nobfd0 libctf0 libcurl4 libdpkg-perl libexpat1 libgcc-12-dev
#6 3.844   libgdbm-compat4 libgdbm6 libgomp1 libgprofng0 libgssapi-krb5-2 libisl23
#6 3.844   libitm1 libjansson4 libk5crypto3 libkeyutils1 libkrb5-3 libkrb5support0
#6 3.844   libldap-2.5-0 liblsan0 libmpc3 libmpfr6 libncursesw6 libnghttp2-14
#6 3.844   libnsl-dev libnsl2 libperl5.36 libpsl5 libpython3-stdlib
#6 3.844   libpython3.11-minimal libpython3.11-stdlib libquadmath0 libreadline8
#6 3.845   librtmp1 libsasl2-2 libsasl2-modules-db libsqlite3-0 libssh2-1 libssl3
#6 3.845   libstdc++-12-dev libtirpc-common libtirpc-dev libtirpc3 libtsan2 libubsan1
#6 3.845   linux-libc-dev make media-types openssl patch perl perl-modules-5.36
#6 3.845   python3-minimal python3.11 python3.11-minimal readline-common rpcsvc-proto
#6 3.846   sensible-utils xz-utils
#6 3.848 Suggested packages:
#6 3.848   binutils-doc bzip2-doc cpp-doc gcc-12-locales cpp-12-doc anacron logrotate
#6 3.848   checksecurity debian-keyring g++-multilib g++-12-multilib gcc-12-doc
#6 3.848   gcc-multilib manpages-dev autoconf automake libtool flex bison gdb gcc-doc
#6 3.848   gcc-12-multilib glibc-doc gnupg | sq | sqop | pgpainless-cli git bzr
#6 3.848   gdbm-l10n krb5-doc krb5-user libstdc++-12-doc make-doc ed diffutils-doc
#6 3.848   perl-doc libterm-readline-gnu-perl | libterm-readline-perl-perl
#6 3.848   libtap-harness-archive-perl python3-doc python3-tk python3-venv
#6 3.848   python3.11-venv python3.11-doc binfmt-support readline-doc zip
#6 3.848 Recommended packages:
#6 3.848   default-mta | mail-transport-agent fakeroot gnupg | sq | sqop
#6 3.848   | pgpainless-cli libalgorithm-merge-perl manpages manpages-dev libc-devtools
#6 3.848   libfile-fcntllock-perl liblocale-gettext-perl krb5-locales libldap-common
#6 3.848   libgpm2 publicsuffix libsasl2-modules netbase
#6 4.457 The following NEW packages will be installed:
#6 4.457   binutils binutils-common binutils-x86-64-linux-gnu build-essential bzip2
#6 4.457   ca-certificates cpp cpp-12 cron cron-daemon-common curl dpkg-dev g++ g++-12
#6 4.457   gcc gcc-12 libasan8 libatomic1 libbinutils libbrotli1 libc-dev-bin libc6-dev
#6 4.457   libcc1-0 libcrypt-dev libctf-nobfd0 libctf0 libcurl4 libdpkg-perl libexpat1
#6 4.458   libgcc-12-dev libgdbm-compat4 libgdbm6 libgomp1 libgprofng0 libgssapi-krb5-2
#6 4.458   libisl23 libitm1 libjansson4 libk5crypto3 libkeyutils1 libkrb5-3
#6 4.458   libkrb5support0 libldap-2.5-0 liblsan0 libmpc3 libmpfr6 libncursesw6
#6 4.458   libnghttp2-14 libnsl-dev libnsl2 libperl5.36 libpsl5 libpython3-stdlib
#6 4.458   libpython3.11-minimal libpython3.11-stdlib libquadmath0 libreadline8
#6 4.459   librtmp1 libsasl2-2 libsasl2-modules-db libsqlite3-0 libssh2-1 libssl3
#6 4.459   libstdc++-12-dev libtirpc-common libtirpc-dev libtirpc3 libtsan2 libubsan1
#6 4.459   linux-libc-dev make media-types openssl patch perl perl-modules-5.36 python3
#6 4.459   python3-minimal python3.11 python3.11-minimal readline-common rpcsvc-proto
#6 4.460   sensible-utils unzip xz-utils
#6 4.493 0 upgraded, 85 newly installed, 0 to remove and 0 not upgraded.
#6 4.493 Need to get 86.7 MB of archives.
#6 4.493 After this operation, 355 MB of additional disk space will be used.
#6 4.493 Get:1 http://deb.debian.org/debian bookworm/main amd64 cron-daemon-common all 3.0pl1-162 [12.7 kB]
#6 4.495 Get:2 http://deb.debian.org/debian bookworm/main amd64 sensible-utils all 0.0.17+nmu1 [19.0 kB]
#6 4.497 Get:3 http://deb.debian.org/debian bookworm/main amd64 cron amd64 3.0pl1-162 [73.1 kB]
#6 4.508 Get:4 http://deb.debian.org/debian bookworm/main amd64 perl-modules-5.36 all 5.36.0-7+deb12u3 [2815 kB]
#6 4.530 Get:5 http://deb.debian.org/debian bookworm/main amd64 libgdbm6 amd64 1.23-3 [72.2 kB]
#6 4.530 Get:6 http://deb.debian.org/debian bookworm/main amd64 libgdbm-compat4 amd64 1.23-3 [48.2 kB]
#6 4.531 Get:7 http://deb.debian.org/debian bookworm/main amd64 libperl5.36 amd64 5.36.0-7+deb12u3 [4196 kB]
#6 4.565 Get:8 http://deb.debian.org/debian bookworm/main amd64 perl amd64 5.36.0-7+deb12u3 [239 kB]
#6 4.568 Get:9 http://deb.debian.org/debian bookworm/main amd64 libssl3 amd64 3.0.20-1~deb12u2 [2036 kB]
#6 4.583 Get:10 http://deb.debian.org/debian bookworm/main amd64 libpython3.11-minimal amd64 3.11.2-6+deb12u8 [818 kB]
#6 4.590 Get:11 http://deb.debian.org/debian bookworm/main amd64 libexpat1 amd64 2.5.0-1+deb12u2 [99.9 kB]
#6 4.591 Get:12 http://deb.debian.org/debian bookworm/main amd64 python3.11-minimal amd64 3.11.2-6+deb12u8 [2065 kB]
#6 4.610 Get:13 http://deb.debian.org/debian bookworm/main amd64 python3-minimal amd64 3.11.2-1+b1 [26.3 kB]
#6 4.610 Get:14 http://deb.debian.org/debian bookworm/main amd64 media-types all 10.0.0 [26.1 kB]
#6 4.611 Get:15 http://deb.debian.org/debian bookworm/main amd64 libncursesw6 amd64 6.4-4 [134 kB]
#6 4.613 Get:16 http://deb.debian.org/debian bookworm/main amd64 libkrb5support0 amd64 1.20.1-2+deb12u5 [33.2 kB]
#6 4.613 Get:17 http://deb.debian.org/debian bookworm/main amd64 libk5crypto3 amd64 1.20.1-2+deb12u5 [79.7 kB]
#6 4.615 Get:18 http://deb.debian.org/debian bookworm/main amd64 libkeyutils1 amd64 1.6.3-2 [8808 B]
#6 4.615 Get:19 http://deb.debian.org/debian bookworm/main amd64 libkrb5-3 amd64 1.20.1-2+deb12u5 [332 kB]
#6 4.619 Get:20 http://deb.debian.org/debian bookworm/main amd64 libgssapi-krb5-2 amd64 1.20.1-2+deb12u5 [135 kB]
#6 4.620 Get:21 http://deb.debian.org/debian bookworm/main amd64 libtirpc-common all 1.3.3+ds-1 [14.0 kB]
#6 4.620 Get:22 http://deb.debian.org/debian bookworm/main amd64 libtirpc3 amd64 1.3.3+ds-1 [85.2 kB]
#6 4.621 Get:23 http://deb.debian.org/debian bookworm/main amd64 libnsl2 amd64 1.3.0-2 [39.5 kB]
#6 4.622 Get:24 http://deb.debian.org/debian bookworm/main amd64 readline-common all 8.2-1.3 [69.0 kB]
#6 4.623 Get:25 http://deb.debian.org/debian bookworm/main amd64 libreadline8 amd64 8.2-1.3 [166 kB]
#6 4.624 Get:26 http://deb.debian.org/debian bookworm/main amd64 libsqlite3-0 amd64 3.40.1-2+deb12u2 [839 kB]
#6 4.631 Get:27 http://deb.debian.org/debian bookworm/main amd64 libpython3.11-stdlib amd64 3.11.2-6+deb12u8 [1799 kB]
#6 4.690 Get:28 http://deb.debian.org/debian bookworm/main amd64 python3.11 amd64 3.11.2-6+deb12u8 [574 kB]
#6 4.733 Get:29 http://deb.debian.org/debian bookworm/main amd64 libpython3-stdlib amd64 3.11.2-1+b1 [9312 B]
#6 4.733 Get:30 http://deb.debian.org/debian bookworm/main amd64 python3 amd64 3.11.2-1+b1 [26.3 kB]
#6 4.736 Get:31 http://deb.debian.org/debian bookworm/main amd64 bzip2 amd64 1.0.8-5+b1 [49.8 kB]
#6 4.742 Get:32 http://deb.debian.org/debian bookworm/main amd64 openssl amd64 3.0.20-1~deb12u2 [1439 kB]
#6 4.895 Get:33 http://deb.debian.org/debian-security bookworm-security/main amd64 ca-certificates all 20250419~deb12u1 [162 kB]
#6 4.896 Get:34 http://deb.debian.org/debian bookworm/main amd64 xz-utils amd64 5.4.1-1+deb12u1 [471 kB]
#6 4.907 Get:35 http://deb.debian.org/debian bookworm/main amd64 binutils-common amd64 2.40-2 [2487 kB]
#6 5.106 Get:36 http://deb.debian.org/debian bookworm/main amd64 libbinutils amd64 2.40-2 [572 kB]
#6 5.151 Get:37 http://deb.debian.org/debian bookworm/main amd64 libctf-nobfd0 amd64 2.40-2 [153 kB]
#6 5.164 Get:38 http://deb.debian.org/debian bookworm/main amd64 libctf0 amd64 2.40-2 [89.8 kB]
#6 5.172 Get:39 http://deb.debian.org/debian bookworm/main amd64 libgprofng0 amd64 2.40-2 [812 kB]
#6 5.237 Get:40 http://deb.debian.org/debian bookworm/main amd64 libjansson4 amd64 2.14-2 [40.8 kB]
#6 5.241 Get:41 http://deb.debian.org/debian bookworm/main amd64 binutils-x86-64-linux-gnu amd64 2.40-2 [2246 kB]
#6 5.418 Get:42 http://deb.debian.org/debian bookworm/main amd64 binutils amd64 2.40-2 [65.0 kB]
#6 5.423 Get:43 http://deb.debian.org/debian bookworm/main amd64 libc-dev-bin amd64 2.36-9+deb12u14 [48.1 kB]
#6 5.426 Get:44 http://deb.debian.org/debian-security bookworm-security/main amd64 linux-libc-dev amd64 6.1.180-1 [2332 kB]
#6 5.616 Get:45 http://deb.debian.org/debian bookworm/main amd64 libcrypt-dev amd64 1:4.4.33-2 [118 kB]
#6 5.623 Get:46 http://deb.debian.org/debian bookworm/main amd64 libtirpc-dev amd64 1.3.3+ds-1 [191 kB]
#6 5.637 Get:47 http://deb.debian.org/debian bookworm/main amd64 libnsl-dev amd64 1.3.0-2 [66.4 kB]
#6 5.643 Get:48 http://deb.debian.org/debian bookworm/main amd64 rpcsvc-proto amd64 1.4.3-1 [63.3 kB]
#6 5.648 Get:49 http://deb.debian.org/debian bookworm/main amd64 libc6-dev amd64 2.36-9+deb12u14 [1904 kB]
#6 5.800 Get:50 http://deb.debian.org/debian bookworm/main amd64 libisl23 amd64 0.25-1.1 [683 kB]
#6 5.857 Get:51 http://deb.debian.org/debian bookworm/main amd64 libmpfr6 amd64 4.2.0-1 [701 kB]
#6 5.911 Get:52 http://deb.debian.org/debian bookworm/main amd64 libmpc3 amd64 1.3.1-1 [51.5 kB]
#6 5.915 Get:53 http://deb.debian.org/debian bookworm/main amd64 cpp-12 amd64 12.2.0-14+deb12u1 [9768 kB]
#6 6.705 Get:54 http://deb.debian.org/debian bookworm/main amd64 cpp amd64 4:12.2.0-3 [6836 B]
#6 6.705 Get:55 http://deb.debian.org/debian bookworm/main amd64 libcc1-0 amd64 12.2.0-14+deb12u1 [41.7 kB]
#6 6.706 Get:56 http://deb.debian.org/debian bookworm/main amd64 libgomp1 amd64 12.2.0-14+deb12u1 [116 kB]
#6 6.713 Get:57 http://deb.debian.org/debian bookworm/main amd64 libitm1 amd64 12.2.0-14+deb12u1 [26.1 kB]
#6 6.714 Get:58 http://deb.debian.org/debian bookworm/main amd64 libatomic1 amd64 12.2.0-14+deb12u1 [9376 B]
#6 6.715 Get:59 http://deb.debian.org/debian bookworm/main amd64 libasan8 amd64 12.2.0-14+deb12u1 [2193 kB]
#6 6.891 Get:60 http://deb.debian.org/debian bookworm/main amd64 liblsan0 amd64 12.2.0-14+deb12u1 [969 kB]
#6 6.965 Get:61 http://deb.debian.org/debian bookworm/main amd64 libtsan2 amd64 12.2.0-14+deb12u1 [2197 kB]
#6 7.139 Get:62 http://deb.debian.org/debian bookworm/main amd64 libubsan1 amd64 12.2.0-14+deb12u1 [883 kB]
#6 7.208 Get:63 http://deb.debian.org/debian bookworm/main amd64 libquadmath0 amd64 12.2.0-14+deb12u1 [145 kB]
#6 7.222 Get:64 http://deb.debian.org/debian bookworm/main amd64 libgcc-12-dev amd64 12.2.0-14+deb12u1 [2437 kB]
#6 7.414 Get:65 http://deb.debian.org/debian bookworm/main amd64 gcc-12 amd64 12.2.0-14+deb12u1 [19.3 MB]
#6 8.963 Get:66 http://deb.debian.org/debian bookworm/main amd64 gcc amd64 4:12.2.0-3 [5216 B]
#6 8.963 Get:67 http://deb.debian.org/debian bookworm/main amd64 libstdc++-12-dev amd64 12.2.0-14+deb12u1 [2047 kB]
#6 9.119 Get:68 http://deb.debian.org/debian bookworm/main amd64 g++-12 amd64 12.2.0-14+deb12u1 [10.7 MB]
#6 9.983 Get:69 http://deb.debian.org/debian bookworm/main amd64 g++ amd64 4:12.2.0-3 [1356 B]
#6 9.983 Get:70 http://deb.debian.org/debian bookworm/main amd64 make amd64 4.3-4.1 [396 kB]
#6 10.00 Get:71 http://deb.debian.org/debian bookworm/main amd64 libdpkg-perl all 1.21.23 [604 kB]
#6 10.05 Get:72 http://deb.debian.org/debian bookworm/main amd64 patch amd64 2.7.6-7 [128 kB]
#6 10.06 Get:73 http://deb.debian.org/debian bookworm/main amd64 dpkg-dev all 1.21.23 [1354 kB]
#6 10.17 Get:74 http://deb.debian.org/debian bookworm/main amd64 build-essential amd64 12.9 [7704 B]
#6 10.17 Get:75 http://deb.debian.org/debian bookworm/main amd64 libbrotli1 amd64 1.0.9-2+b6 [275 kB]
#6 10.19 Get:76 http://deb.debian.org/debian bookworm/main amd64 libsasl2-modules-db amd64 2.1.28+dfsg-10 [20.3 kB]
#6 10.19 Get:77 http://deb.debian.org/debian bookworm/main amd64 libsasl2-2 amd64 2.1.28+dfsg-10 [59.7 kB]
#6 10.20 Get:78 http://deb.debian.org/debian bookworm/main amd64 libldap-2.5-0 amd64 2.5.13+dfsg-5 [183 kB]
#6 10.21 Get:79 http://deb.debian.org/debian bookworm/main amd64 libnghttp2-14 amd64 1.52.0-1+deb12u3 [72.4 kB]
#6 10.22 Get:80 http://deb.debian.org/debian bookworm/main amd64 libpsl5 amd64 0.21.2-1 [58.7 kB]
#6 10.23 Get:81 http://deb.debian.org/debian bookworm/main amd64 librtmp1 amd64 2.4+20151223.gitfa8646d.1-2+b2 [60.8 kB]
#6 10.23 Get:82 http://deb.debian.org/debian bookworm/main amd64 libssh2-1 amd64 1.10.0-3+b1 [179 kB]
#6 10.24 Get:83 http://deb.debian.org/debian bookworm/main amd64 libcurl4 amd64 7.88.1-10+deb12u15 [392 kB]
#6 10.27 Get:84 http://deb.debian.org/debian bookworm/main amd64 curl amd64 7.88.1-10+deb12u15 [316 kB]
#6 10.31 Get:85 http://deb.debian.org/debian-security bookworm-security/main amd64 unzip amd64 6.0-28+deb12u1 [167 kB]
#6 10.54 debconf: delaying package configuration, since apt-utils is not installed
#6 10.59 Fetched 86.7 MB in 6s (14.9 MB/s)
#6 10.62 Selecting previously unselected package cron-daemon-common.
#6 10.62 (Reading database ... 
(Reading database ... 5%
(Reading database ... 10%
(Reading database ... 15%
(Reading database ... 20%
(Reading database ... 25%
(Reading database ... 30%
(Reading database ... 35%
(Reading database ... 40%
(Reading database ... 45%
(Reading database ... 50%
(Reading database ... 55%
(Reading database ... 60%
(Reading database ... 65%
(Reading database ... 70%
(Reading database ... 75%
(Reading database ... 80%
(Reading database ... 85%
(Reading database ... 90%
(Reading database ... 95%
(Reading database ... 100%
(Reading database ... 6096 files and directories currently installed.)
#6 10.62 Preparing to unpack .../cron-daemon-common_3.0pl1-162_all.deb ...
#6 10.63 Unpacking cron-daemon-common (3.0pl1-162) ...
#6 10.66 Selecting previously unselected package sensible-utils.
#6 10.67 Preparing to unpack .../sensible-utils_0.0.17+nmu1_all.deb ...
#6 10.67 Unpacking sensible-utils (0.0.17+nmu1) ...
#6 10.71 Setting up cron-daemon-common (3.0pl1-162) ...
#6 10.78 Adding group `crontab' (GID 101) ...
#6 10.81 Done.
#6 10.85 Selecting previously unselected package cron.
#6 10.85 (Reading database ... 
(Reading database ... 5%
(Reading database ... 10%
(Reading database ... 15%
(Reading database ... 20%
(Reading database ... 25%
(Reading database ... 30%
(Reading database ... 35%
(Reading database ... 40%
(Reading database ... 45%
(Reading database ... 50%
(Reading database ... 55%
(Reading database ... 60%
(Reading database ... 65%
(Reading database ... 70%
(Reading database ... 75%
(Reading database ... 80%
(Reading database ... 85%
(Reading database ... 90%
(Reading database ... 95%
(Reading database ... 100%
(Reading database ... 6141 files and directories currently installed.)
#6 10.85 Preparing to unpack .../0-cron_3.0pl1-162_amd64.deb ...
#6 10.86 Unpacking cron (3.0pl1-162) ...
#6 10.90 Selecting previously unselected package perl-modules-5.36.
#6 10.90 Preparing to unpack .../1-perl-modules-5.36_5.36.0-7+deb12u3_all.deb ...
#6 10.91 Unpacking perl-modules-5.36 (5.36.0-7+deb12u3) ...
#6 11.30 Selecting previously unselected package libgdbm6:amd64.
#6 11.30 Preparing to unpack .../2-libgdbm6_1.23-3_amd64.deb ...
#6 11.31 Unpacking libgdbm6:amd64 (1.23-3) ...
#6 11.35 Selecting previously unselected package libgdbm-compat4:amd64.
#6 11.35 Preparing to unpack .../3-libgdbm-compat4_1.23-3_amd64.deb ...
#6 11.35 Unpacking libgdbm-compat4:amd64 (1.23-3) ...
#6 11.39 Selecting previously unselected package libperl5.36:amd64.
#6 11.39 Preparing to unpack .../4-libperl5.36_5.36.0-7+deb12u3_amd64.deb ...
#6 11.39 Unpacking libperl5.36:amd64 (5.36.0-7+deb12u3) ...
#6 11.87 Selecting previously unselected package perl.
#6 11.87 Preparing to unpack .../5-perl_5.36.0-7+deb12u3_amd64.deb ...
#6 11.88 Unpacking perl (5.36.0-7+deb12u3) ...
#6 11.94 Selecting previously unselected package libssl3:amd64.
#6 11.94 Preparing to unpack .../6-libssl3_3.0.20-1~deb12u2_amd64.deb ...
#6 11.94 Unpacking libssl3:amd64 (3.0.20-1~deb12u2) ...
#6 12.16 Selecting previously unselected package libpython3.11-minimal:amd64.
#6 12.16 Preparing to unpack .../7-libpython3.11-minimal_3.11.2-6+deb12u8_amd64.deb ...
#6 12.16 Unpacking libpython3.11-minimal:amd64 (3.11.2-6+deb12u8) ...
#6 12.28 Selecting previously unselected package libexpat1:amd64.
#6 12.28 Preparing to unpack .../8-libexpat1_2.5.0-1+deb12u2_amd64.deb ...
#6 12.28 Unpacking libexpat1:amd64 (2.5.0-1+deb12u2) ...
#6 12.33 Selecting previously unselected package python3.11-minimal.
#6 12.33 Preparing to unpack .../9-python3.11-minimal_3.11.2-6+deb12u8_amd64.deb ...
#6 12.34 Unpacking python3.11-minimal (3.11.2-6+deb12u8) ...
#6 12.58 Setting up libssl3:amd64 (3.0.20-1~deb12u2) ...
#6 12.59 Setting up libpython3.11-minimal:amd64 (3.11.2-6+deb12u8) ...
#6 12.60 Setting up libexpat1:amd64 (2.5.0-1+deb12u2) ...
#6 12.61 Setting up python3.11-minimal (3.11.2-6+deb12u8) ...
#6 13.45 Selecting previously unselected package python3-minimal.
#6 13.45 (Reading database ... 
(Reading database ... 5%
(Reading database ... 10%
(Reading database ... 15%
(Reading database ... 20%
(Reading database ... 25%
(Reading database ... 30%
(Reading database ... 35%
(Reading database ... 40%
(Reading database ... 45%
(Reading database ... 50%
(Reading database ... 55%
(Reading database ... 60%
(Reading database ... 65%
(Reading database ... 70%
(Reading database ... 75%
(Reading database ... 80%
(Reading database ... 85%
(Reading database ... 90%
(Reading database ... 95%
(Reading database ... 100%
(Reading database ... 8500 files and directories currently installed.)
#6 13.46 Preparing to unpack .../00-python3-minimal_3.11.2-1+b1_amd64.deb ...
#6 13.46 Unpacking python3-minimal (3.11.2-1+b1) ...
#6 13.50 Selecting previously unselected package media-types.
#6 13.50 Preparing to unpack .../01-media-types_10.0.0_all.deb ...
#6 13.50 Unpacking media-types (10.0.0) ...
#6 13.53 Selecting previously unselected package libncursesw6:amd64.
#6 13.53 Preparing to unpack .../02-libncursesw6_6.4-4_amd64.deb ...
#6 13.54 Unpacking libncursesw6:amd64 (6.4-4) ...
#6 13.58 Selecting previously unselected package libkrb5support0:amd64.
#6 13.58 Preparing to unpack .../03-libkrb5support0_1.20.1-2+deb12u5_amd64.deb ...
#6 13.59 Unpacking libkrb5support0:amd64 (1.20.1-2+deb12u5) ...
#6 13.62 Selecting previously unselected package libk5crypto3:amd64.
#6 13.62 Preparing to unpack .../04-libk5crypto3_1.20.1-2+deb12u5_amd64.deb ...
#6 13.63 Unpacking libk5crypto3:amd64 (1.20.1-2+deb12u5) ...
#6 13.67 Selecting previously unselected package libkeyutils1:amd64.
#6 13.67 Preparing to unpack .../05-libkeyutils1_1.6.3-2_amd64.deb ...
#6 13.67 Unpacking libkeyutils1:amd64 (1.6.3-2) ...
#6 13.71 Selecting previously unselected package libkrb5-3:amd64.
#6 13.71 Preparing to unpack .../06-libkrb5-3_1.20.1-2+deb12u5_amd64.deb ...
#6 13.71 Unpacking libkrb5-3:amd64 (1.20.1-2+deb12u5) ...
#6 13.78 Selecting previously unselected package libgssapi-krb5-2:amd64.
#6 13.78 Preparing to unpack .../07-libgssapi-krb5-2_1.20.1-2+deb12u5_amd64.deb ...
#6 13.78 Unpacking libgssapi-krb5-2:amd64 (1.20.1-2+deb12u5) ...
#6 13.82 Selecting previously unselected package libtirpc-common.
#6 13.83 Preparing to unpack .../08-libtirpc-common_1.3.3+ds-1_all.deb ...
#6 13.83 Unpacking libtirpc-common (1.3.3+ds-1) ...
#6 13.86 Selecting previously unselected package libtirpc3:amd64.
#6 13.87 Preparing to unpack .../09-libtirpc3_1.3.3+ds-1_amd64.deb ...
#6 13.87 Unpacking libtirpc3:amd64 (1.3.3+ds-1) ...
#6 13.91 Selecting previously unselected package libnsl2:amd64.
#6 13.91 Preparing to unpack .../10-libnsl2_1.3.0-2_amd64.deb ...
#6 13.91 Unpacking libnsl2:amd64 (1.3.0-2) ...
#6 13.95 Selecting previously unselected package readline-common.
#6 13.95 Preparing to unpack .../11-readline-common_8.2-1.3_all.deb ...
#6 13.96 Unpacking readline-common (8.2-1.3) ...
#6 13.99 Selecting previously unselected package libreadline8:amd64.
#6 14.00 Preparing to unpack .../12-libreadline8_8.2-1.3_amd64.deb ...
#6 14.00 Unpacking libreadline8:amd64 (8.2-1.3) ...
#6 14.05 Selecting previously unselected package libsqlite3-0:amd64.
#6 14.05 Preparing to unpack .../13-libsqlite3-0_3.40.1-2+deb12u2_amd64.deb ...
#6 14.05 Unpacking libsqlite3-0:amd64 (3.40.1-2+deb12u2) ...
#6 14.14 Selecting previously unselected package libpython3.11-stdlib:amd64.
#6 14.14 Preparing to unpack .../14-libpython3.11-stdlib_3.11.2-6+deb12u8_amd64.deb ...
#6 14.15 Unpacking libpython3.11-stdlib:amd64 (3.11.2-6+deb12u8) ...
#6 14.37 Selecting previously unselected package python3.11.
#6 14.37 Preparing to unpack .../15-python3.11_3.11.2-6+deb12u8_amd64.deb ...
#6 14.37 Unpacking python3.11 (3.11.2-6+deb12u8) ...
#6 14.41 Selecting previously unselected package libpython3-stdlib:amd64.
#6 14.42 Preparing to unpack .../16-libpython3-stdlib_3.11.2-1+b1_amd64.deb ...
#6 14.42 Unpacking libpython3-stdlib:amd64 (3.11.2-1+b1) ...
#6 14.45 Setting up python3-minimal (3.11.2-1+b1) ...
#6 14.65 Selecting previously unselected package python3.
#6 14.65 (Reading database ... 
(Reading database ... 5%
(Reading database ... 10%
(Reading database ... 15%
(Reading database ... 20%
(Reading database ... 25%
(Reading database ... 30%
(Reading database ... 35%
(Reading database ... 40%
(Reading database ... 45%
(Reading database ... 50%
(Reading database ... 55%
(Reading database ... 60%
(Reading database ... 65%
(Reading database ... 70%
(Reading database ... 75%
(Reading database ... 80%
(Reading database ... 85%
(Reading database ... 90%
(Reading database ... 95%
(Reading database ... 100%
(Reading database ... 9008 files and directories currently installed.)
#6 14.66 Preparing to unpack .../00-python3_3.11.2-1+b1_amd64.deb ...
#6 14.66 Unpacking python3 (3.11.2-1+b1) ...
#6 14.70 Selecting previously unselected package bzip2.
#6 14.70 Preparing to unpack .../01-bzip2_1.0.8-5+b1_amd64.deb ...
#6 14.70 Unpacking bzip2 (1.0.8-5+b1) ...
#6 14.74 Selecting previously unselected package openssl.
#6 14.74 Preparing to unpack .../02-openssl_3.0.20-1~deb12u2_amd64.deb ...
#6 14.75 Unpacking openssl (3.0.20-1~deb12u2) ...
#6 14.91 Selecting previously unselected package ca-certificates.
#6 14.91 Preparing to unpack .../03-ca-certificates_20250419~deb12u1_all.deb ...
#6 14.92 Unpacking ca-certificates (20250419~deb12u1) ...
#6 14.98 Selecting previously unselected package xz-utils.
#6 14.98 Preparing to unpack .../04-xz-utils_5.4.1-1+deb12u1_amd64.deb ...
#6 14.99 Unpacking xz-utils (5.4.1-1+deb12u1) ...
#6 15.06 Selecting previously unselected package binutils-common:amd64.
#6 15.06 Preparing to unpack .../05-binutils-common_2.40-2_amd64.deb ...
#6 15.07 Unpacking binutils-common:amd64 (2.40-2) ...
#6 15.35 Selecting previously unselected package libbinutils:amd64.
#6 15.36 Preparing to unpack .../06-libbinutils_2.40-2_amd64.deb ...
#6 15.36 Unpacking libbinutils:amd64 (2.40-2) ...
#6 15.45 Selecting previously unselected package libctf-nobfd0:amd64.
#6 15.45 Preparing to unpack .../07-libctf-nobfd0_2.40-2_amd64.deb ...
#6 15.45 Unpacking libctf-nobfd0:amd64 (2.40-2) ...
#6 15.50 Selecting previously unselected package libctf0:amd64.
#6 15.50 Preparing to unpack .../08-libctf0_2.40-2_amd64.deb ...
#6 15.51 Unpacking libctf0:amd64 (2.40-2) ...
#6 15.55 Selecting previously unselected package libgprofng0:amd64.
#6 15.55 Preparing to unpack .../09-libgprofng0_2.40-2_amd64.deb ...
#6 15.55 Unpacking libgprofng0:amd64 (2.40-2) ...
#6 15.67 Selecting previously unselected package libjansson4:amd64.
#6 15.67 Preparing to unpack .../10-libjansson4_2.14-2_amd64.deb ...
#6 15.67 Unpacking libjansson4:amd64 (2.14-2) ...
#6 15.70 Selecting previously unselected package binutils-x86-64-linux-gnu.
#6 15.71 Preparing to unpack .../11-binutils-x86-64-linux-gnu_2.40-2_amd64.deb ...
#6 15.71 Unpacking binutils-x86-64-linux-gnu (2.40-2) ...
#6 15.99 Selecting previously unselected package binutils.
#6 15.99 Preparing to unpack .../12-binutils_2.40-2_amd64.deb ...
#6 16.00 Unpacking binutils (2.40-2) ...
#6 16.03 Selecting previously unselected package libc-dev-bin.
#6 16.03 Preparing to unpack .../13-libc-dev-bin_2.36-9+deb12u14_amd64.deb ...
#6 16.04 Unpacking libc-dev-bin (2.36-9+deb12u14) ...
#6 16.07 Selecting previously unselected package linux-libc-dev:amd64.
#6 16.07 Preparing to unpack .../14-linux-libc-dev_6.1.180-1_amd64.deb ...
#6 16.07 Unpacking linux-libc-dev:amd64 (6.1.180-1) ...
#6 16.27 Selecting previously unselected package libcrypt-dev:amd64.
#6 16.28 Preparing to unpack .../15-libcrypt-dev_1%3a4.4.33-2_amd64.deb ...
#6 16.29 Unpacking libcrypt-dev:amd64 (1:4.4.33-2) ...
#6 16.32 Selecting previously unselected package libtirpc-dev:amd64.
#6 16.33 Preparing to unpack .../16-libtirpc-dev_1.3.3+ds-1_amd64.deb ...
#6 16.33 Unpacking libtirpc-dev:amd64 (1.3.3+ds-1) ...
#6 16.38 Selecting previously unselected package libnsl-dev:amd64.
#6 16.38 Preparing to unpack .../17-libnsl-dev_1.3.0-2_amd64.deb ...
#6 16.38 Unpacking libnsl-dev:amd64 (1.3.0-2) ...
#6 16.42 Selecting previously unselected package rpcsvc-proto.
#6 16.42 Preparing to unpack .../18-rpcsvc-proto_1.4.3-1_amd64.deb ...
#6 16.42 Unpacking rpcsvc-proto (1.4.3-1) ...
#6 16.46 Selecting previously unselected package libc6-dev:amd64.
#6 16.46 Preparing to unpack .../19-libc6-dev_2.36-9+deb12u14_amd64.deb ...
#6 16.46 Unpacking libc6-dev:amd64 (2.36-9+deb12u14) ...
#6 16.71 Selecting previously unselected package libisl23:amd64.
#6 16.71 Preparing to unpack .../20-libisl23_0.25-1.1_amd64.deb ...
#6 16.71 Unpacking libisl23:amd64 (0.25-1.1) ...
#6 16.83 Selecting previously unselected package libmpfr6:amd64.
#6 16.83 Preparing to unpack .../21-libmpfr6_4.2.0-1_amd64.deb ...
#6 16.83 Unpacking libmpfr6:amd64 (4.2.0-1) ...
#6 16.91 Selecting previously unselected package libmpc3:amd64.
#6 16.91 Preparing to unpack .../22-libmpc3_1.3.1-1_amd64.deb ...
#6 16.91 Unpacking libmpc3:amd64 (1.3.1-1) ...
#6 16.94 Selecting previously unselected package cpp-12.
#6 16.95 Preparing to unpack .../23-cpp-12_12.2.0-14+deb12u1_amd64.deb ...
#6 16.95 Unpacking cpp-12 (12.2.0-14+deb12u1) ...
#6 17.81 Selecting previously unselected package cpp.
#6 17.82 Preparing to unpack .../24-cpp_4%3a12.2.0-3_amd64.deb ...
#6 17.82 Unpacking cpp (4:12.2.0-3) ...
#6 17.85 Selecting previously unselected package libcc1-0:amd64.
#6 17.85 Preparing to unpack .../25-libcc1-0_12.2.0-14+deb12u1_amd64.deb ...
#6 17.86 Unpacking libcc1-0:amd64 (12.2.0-14+deb12u1) ...
#6 17.89 Selecting previously unselected package libgomp1:amd64.
#6 17.90 Preparing to unpack .../26-libgomp1_12.2.0-14+deb12u1_amd64.deb ...
#6 17.90 Unpacking libgomp1:amd64 (12.2.0-14+deb12u1) ...
#6 17.94 Selecting previously unselected package libitm1:amd64.
#6 17.94 Preparing to unpack .../27-libitm1_12.2.0-14+deb12u1_amd64.deb ...
#6 17.95 Unpacking libitm1:amd64 (12.2.0-14+deb12u1) ...
#6 17.98 Selecting previously unselected package libatomic1:amd64.
#6 17.98 Preparing to unpack .../28-libatomic1_12.2.0-14+deb12u1_amd64.deb ...
#6 17.99 Unpacking libatomic1:amd64 (12.2.0-14+deb12u1) ...
#6 18.02 Selecting previously unselected package libasan8:amd64.
#6 18.02 Preparing to unpack .../29-libasan8_12.2.0-14+deb12u1_amd64.deb ...
#6 18.02 Unpacking libasan8:amd64 (12.2.0-14+deb12u1) ...
#6 18.28 Selecting previously unselected package liblsan0:amd64.
#6 18.28 Preparing to unpack .../30-liblsan0_12.2.0-14+deb12u1_amd64.deb ...
#6 18.29 Unpacking liblsan0:amd64 (12.2.0-14+deb12u1) ...
#6 18.42 Selecting previously unselected package libtsan2:amd64.
#6 18.42 Preparing to unpack .../31-libtsan2_12.2.0-14+deb12u1_amd64.deb ...
#6 18.42 Unpacking libtsan2:amd64 (12.2.0-14+deb12u1) ...
#6 18.68 Selecting previously unselected package libubsan1:amd64.
#6 18.68 Preparing to unpack .../32-libubsan1_12.2.0-14+deb12u1_amd64.deb ...
#6 18.69 Unpacking libubsan1:amd64 (12.2.0-14+deb12u1) ...
#6 18.81 Selecting previously unselected package libquadmath0:amd64.
#6 18.81 Preparing to unpack .../33-libquadmath0_12.2.0-14+deb12u1_amd64.deb ...
#6 18.82 Unpacking libquadmath0:amd64 (12.2.0-14+deb12u1) ...
#6 18.86 Selecting previously unselected package libgcc-12-dev:amd64.
#6 18.86 Preparing to unpack .../34-libgcc-12-dev_12.2.0-14+deb12u1_amd64.deb ...
#6 18.86 Unpacking libgcc-12-dev:amd64 (12.2.0-14+deb12u1) ...
#6 19.10 Selecting previously unselected package gcc-12.
#6 19.10 Preparing to unpack .../35-gcc-12_12.2.0-14+deb12u1_amd64.deb ...
#6 19.11 Unpacking gcc-12 (12.2.0-14+deb12u1) ...
#6 20.07 Selecting previously unselected package gcc.
#6 20.08 Preparing to unpack .../36-gcc_4%3a12.2.0-3_amd64.deb ...
#6 20.08 Unpacking gcc (4:12.2.0-3) ...
#6 20.11 Selecting previously unselected package libstdc++-12-dev:amd64.
#6 20.11 Preparing to unpack .../37-libstdc++-12-dev_12.2.0-14+deb12u1_amd64.deb ...
#6 20.12 Unpacking libstdc++-12-dev:amd64 (12.2.0-14+deb12u1) ...
#6 20.39 Selecting previously unselected package g++-12.
#6 20.39 Preparing to unpack .../38-g++-12_12.2.0-14+deb12u1_amd64.deb ...
#6 20.39 Unpacking g++-12 (12.2.0-14+deb12u1) ...
#6 21.29 Selecting previously unselected package g++.
#6 21.29 Preparing to unpack .../39-g++_4%3a12.2.0-3_amd64.deb ...
#6 21.30 Unpacking g++ (4:12.2.0-3) ...
#6 21.32 Selecting previously unselected package make.
#6 21.32 Preparing to unpack .../40-make_4.3-4.1_amd64.deb ...
#6 21.33 Unpacking make (4.3-4.1) ...
#6 21.39 Selecting previously unselected package libdpkg-perl.
#6 21.39 Preparing to unpack .../41-libdpkg-perl_1.21.23_all.deb ...
#6 21.40 Unpacking libdpkg-perl (1.21.23) ...
#6 21.48 Selecting previously unselected package patch.
#6 21.48 Preparing to unpack .../42-patch_2.7.6-7_amd64.deb ...
#6 21.49 Unpacking patch (2.7.6-7) ...
#6 21.53 Selecting previously unselected package dpkg-dev.
#6 21.53 Preparing to unpack .../43-dpkg-dev_1.21.23_all.deb ...
#6 21.53 Unpacking dpkg-dev (1.21.23) ...
#6 21.66 Selecting previously unselected package build-essential.
#6 21.66 Preparing to unpack .../44-build-essential_12.9_amd64.deb ...
#6 21.67 Unpacking build-essential (12.9) ...
#6 21.70 Selecting previously unselected package libbrotli1:amd64.
#6 21.70 Preparing to unpack .../45-libbrotli1_1.0.9-2+b6_amd64.deb ...
#6 21.70 Unpacking libbrotli1:amd64 (1.0.9-2+b6) ...
#6 21.76 Selecting previously unselected package libsasl2-modules-db:amd64.
#6 21.76 Preparing to unpack .../46-libsasl2-modules-db_2.1.28+dfsg-10_amd64.deb ...
#6 21.76 Unpacking libsasl2-modules-db:amd64 (2.1.28+dfsg-10) ...
#6 21.80 Selecting previously unselected package libsasl2-2:amd64.
#6 21.80 Preparing to unpack .../47-libsasl2-2_2.1.28+dfsg-10_amd64.deb ...
#6 21.80 Unpacking libsasl2-2:amd64 (2.1.28+dfsg-10) ...
#6 21.84 Selecting previously unselected package libldap-2.5-0:amd64.
#6 21.85 Preparing to unpack .../48-libldap-2.5-0_2.5.13+dfsg-5_amd64.deb ...
#6 21.85 Unpacking libldap-2.5-0:amd64 (2.5.13+dfsg-5) ...
#6 21.90 Selecting previously unselected package libnghttp2-14:amd64.
#6 21.91 Preparing to unpack .../49-libnghttp2-14_1.52.0-1+deb12u3_amd64.deb ...
#6 21.91 Unpacking libnghttp2-14:amd64 (1.52.0-1+deb12u3) ...
#6 21.95 Selecting previously unselected package libpsl5:amd64.
#6 21.95 Preparing to unpack .../50-libpsl5_0.21.2-1_amd64.deb ...
#6 21.95 Unpacking libpsl5:amd64 (0.21.2-1) ...
#6 21.99 Selecting previously unselected package librtmp1:amd64.
#6 21.99 Preparing to unpack .../51-librtmp1_2.4+20151223.gitfa8646d.1-2+b2_amd64.deb ...
#6 22.00 Unpacking librtmp1:amd64 (2.4+20151223.gitfa8646d.1-2+b2) ...
#6 22.03 Selecting previously unselected package libssh2-1:amd64.
#6 22.03 Preparing to unpack .../52-libssh2-1_1.10.0-3+b1_amd64.deb ...
#6 22.04 Unpacking libssh2-1:amd64 (1.10.0-3+b1) ...
#6 22.09 Selecting previously unselected package libcurl4:amd64.
#6 22.09 Preparing to unpack .../53-libcurl4_7.88.1-10+deb12u15_amd64.deb ...
#6 22.09 Unpacking libcurl4:amd64 (7.88.1-10+deb12u15) ...
#6 22.15 Selecting previously unselected package curl.
#6 22.15 Preparing to unpack .../54-curl_7.88.1-10+deb12u15_amd64.deb ...
#6 22.16 Unpacking curl (7.88.1-10+deb12u15) ...
#6 22.21 Selecting previously unselected package unzip.
#6 22.21 Preparing to unpack .../55-unzip_6.0-28+deb12u1_amd64.deb ...
#6 22.22 Unpacking unzip (6.0-28+deb12u1) ...
#6 22.27 Setting up media-types (10.0.0) ...
#6 22.28 Setting up libkeyutils1:amd64 (1.6.3-2) ...
#6 22.29 Setting up libpsl5:amd64 (0.21.2-1) ...
#6 22.30 Setting up libtirpc-common (1.3.3+ds-1) ...
#6 22.31 Setting up unzip (6.0-28+deb12u1) ...
#6 22.32 Setting up libbrotli1:amd64 (1.0.9-2+b6) ...
#6 22.33 Setting up libsqlite3-0:amd64 (3.40.1-2+deb12u2) ...
#6 22.34 Setting up binutils-common:amd64 (2.40-2) ...
#6 22.35 Setting up libnghttp2-14:amd64 (1.52.0-1+deb12u3) ...
#6 22.36 Setting up linux-libc-dev:amd64 (6.1.180-1) ...
#6 22.37 Setting up libctf-nobfd0:amd64 (2.40-2) ...
#6 22.38 Setting up libgomp1:amd64 (12.2.0-14+deb12u1) ...
#6 22.39 Setting up bzip2 (1.0.8-5+b1) ...
#6 22.40 Setting up libjansson4:amd64 (2.14-2) ...
#6 22.41 Setting up libkrb5support0:amd64 (1.20.1-2+deb12u5) ...
#6 22.41 Setting up libsasl2-modules-db:amd64 (2.1.28+dfsg-10) ...
#6 22.42 Setting up perl-modules-5.36 (5.36.0-7+deb12u3) ...
#6 22.43 Setting up rpcsvc-proto (1.4.3-1) ...
#6 22.44 Setting up make (4.3-4.1) ...
#6 22.45 Setting up libmpfr6:amd64 (4.2.0-1) ...
#6 22.46 Setting up librtmp1:amd64 (2.4+20151223.gitfa8646d.1-2+b2) ...
#6 22.47 Setting up xz-utils (5.4.1-1+deb12u1) ...
#6 22.48 update-alternatives: using /usr/bin/xz to provide /usr/bin/lzma (lzma) in auto mode
#6 22.48 update-alternatives: warning: skip creation of /usr/share/man/man1/lzma.1.gz because associated file /usr/share/man/man1/xz.1.gz (of link group lzma) doesn't exist
#6 22.48 update-alternatives: warning: skip creation of /usr/share/man/man1/unlzma.1.gz because associated file /usr/share/man/man1/unxz.1.gz (of link group lzma) doesn't exist
#6 22.48 update-alternatives: warning: skip creation of /usr/share/man/man1/lzcat.1.gz because associated file /usr/share/man/man1/xzcat.1.gz (of link group lzma) doesn't exist
#6 22.48 update-alternatives: warning: skip creation of /usr/share/man/man1/lzmore.1.gz because associated file /usr/share/man/man1/xzmore.1.gz (of link group lzma) doesn't exist
#6 22.48 update-alternatives: warning: skip creation of /usr/share/man/man1/lzless.1.gz because associated file /usr/share/man/man1/xzless.1.gz (of link group lzma) doesn't exist
#6 22.48 update-alternatives: warning: skip creation of /usr/share/man/man1/lzdiff.1.gz because associated file /usr/share/man/man1/xzdiff.1.gz (of link group lzma) doesn't exist
#6 22.48 update-alternatives: warning: skip creation of /usr/share/man/man1/lzcmp.1.gz because associated file /usr/share/man/man1/xzcmp.1.gz (of link group lzma) doesn't exist
#6 22.48 update-alternatives: warning: skip creation of /usr/share/man/man1/lzgrep.1.gz because associated file /usr/share/man/man1/xzgrep.1.gz (of link group lzma) doesn't exist
#6 22.48 update-alternatives: warning: skip creation of /usr/share/man/man1/lzegrep.1.gz because associated file /usr/share/man/man1/xzegrep.1.gz (of link group lzma) doesn't exist
#6 22.48 update-alternatives: warning: skip creation of /usr/share/man/man1/lzfgrep.1.gz because associated file /usr/share/man/man1/xzfgrep.1.gz (of link group lzma) doesn't exist
#6 22.49 Setting up libquadmath0:amd64 (12.2.0-14+deb12u1) ...
#6 22.50 Setting up libmpc3:amd64 (1.3.1-1) ...
#6 22.51 Setting up libatomic1:amd64 (12.2.0-14+deb12u1) ...
#6 22.51 Setting up patch (2.7.6-7) ...
#6 22.52 Setting up libncursesw6:amd64 (6.4-4) ...
#6 22.53 Setting up libk5crypto3:amd64 (1.20.1-2+deb12u5) ...
#6 22.54 Setting up libsasl2-2:amd64 (2.1.28+dfsg-10) ...
#6 22.55 Setting up libubsan1:amd64 (12.2.0-14+deb12u1) ...
#6 22.56 Setting up sensible-utils (0.0.17+nmu1) ...
#6 22.57 Setting up libcrypt-dev:amd64 (1:4.4.33-2) ...
#6 22.58 Setting up libasan8:amd64 (12.2.0-14+deb12u1) ...
#6 22.59 Setting up libssh2-1:amd64 (1.10.0-3+b1) ...
#6 22.60 Setting up libkrb5-3:amd64 (1.20.1-2+deb12u5) ...
#6 22.61 Setting up libtsan2:amd64 (12.2.0-14+deb12u1) ...
#6 22.62 Setting up libbinutils:amd64 (2.40-2) ...
#6 22.63 Setting up libisl23:amd64 (0.25-1.1) ...
#6 22.64 Setting up libc-dev-bin (2.36-9+deb12u14) ...
#6 22.65 Setting up openssl (3.0.20-1~deb12u2) ...
#6 22.66 Setting up readline-common (8.2-1.3) ...
#6 22.67 Setting up libcc1-0:amd64 (12.2.0-14+deb12u1) ...
#6 22.68 Setting up liblsan0:amd64 (12.2.0-14+deb12u1) ...
#6 22.69 Setting up libitm1:amd64 (12.2.0-14+deb12u1) ...
#6 22.70 Setting up libgdbm6:amd64 (1.23-3) ...
#6 22.71 Setting up libctf0:amd64 (2.40-2) ...
#6 22.72 Setting up cpp-12 (12.2.0-14+deb12u1) ...
#6 22.73 Setting up libreadline8:amd64 (8.2-1.3) ...
#6 22.73 Setting up cron (3.0pl1-162) ...
#6 22.78 invoke-rc.d: could not determine current runlevel
#6 22.78 invoke-rc.d: policy-rc.d denied execution of start.
#6 22.96 Setting up libldap-2.5-0:amd64 (2.5.13+dfsg-5) ...
#6 22.97 Setting up ca-certificates (20250419~deb12u1) ...
#6 23.07 debconf: unable to initialize frontend: Dialog
#6 23.07 debconf: (TERM is not set, so the dialog frontend is not usable.)
#6 23.07 debconf: falling back to frontend: Readline
#6 23.08 debconf: unable to initialize frontend: Readline
#6 23.08 debconf: (This frontend requires a controlling tty.)
#6 23.08 debconf: falling back to frontend: Teletype
#6 23.68 Updating certificates in /etc/ssl/certs...
#6 24.51 150 added, 0 removed; done.
#6 24.54 Setting up libgprofng0:amd64 (2.40-2) ...
#6 24.55 Setting up libgcc-12-dev:amd64 (12.2.0-14+deb12u1) ...
#6 24.55 Setting up libgssapi-krb5-2:amd64 (1.20.1-2+deb12u5) ...
#6 24.56 Setting up libgdbm-compat4:amd64 (1.23-3) ...
#6 24.57 Setting up cpp (4:12.2.0-3) ...
#6 24.59 Setting up libcurl4:amd64 (7.88.1-10+deb12u15) ...
#6 24.59 Setting up curl (7.88.1-10+deb12u15) ...
#6 24.60 Setting up libperl5.36:amd64 (5.36.0-7+deb12u3) ...
#6 24.61 Setting up binutils-x86-64-linux-gnu (2.40-2) ...
#6 24.62 Setting up libtirpc3:amd64 (1.3.3+ds-1) ...
#6 24.63 Setting up binutils (2.40-2) ...
#6 24.64 Setting up perl (5.36.0-7+deb12u3) ...
#6 24.66 Setting up libtirpc-dev:amd64 (1.3.3+ds-1) ...
#6 24.67 Setting up gcc-12 (12.2.0-14+deb12u1) ...
#6 24.67 Setting up libdpkg-perl (1.21.23) ...
#6 24.68 Setting up libnsl2:amd64 (1.3.0-2) ...
#6 24.69 Setting up libpython3.11-stdlib:amd64 (3.11.2-6+deb12u8) ...
#6 24.70 Setting up gcc (4:12.2.0-3) ...
#6 24.72 Setting up dpkg-dev (1.21.23) ...
#6 24.74 Setting up libnsl-dev:amd64 (1.3.0-2) ...
#6 24.75 Setting up libc6-dev:amd64 (2.36-9+deb12u14) ...
#6 24.75 Setting up libpython3-stdlib:amd64 (3.11.2-1+b1) ...
#6 24.76 Setting up python3.11 (3.11.2-6+deb12u8) ...
#6 25.71 Setting up libstdc++-12-dev:amd64 (12.2.0-14+deb12u1) ...
#6 25.72 Setting up python3 (3.11.2-1+b1) ...
#6 25.73 running python rtupdate hooks for python3.11...
#6 25.73 running python post-rtupdate hooks for python3.11...
#6 25.85 Setting up g++-12 (12.2.0-14+deb12u1) ...
#6 25.86 Setting up g++ (4:12.2.0-3) ...
#6 25.87 update-alternatives: using /usr/bin/g++ to provide /usr/bin/c++ (c++) in auto mode
#6 25.88 Setting up build-essential (12.9) ...
#6 25.89 Processing triggers for libc-bin (2.36-9+deb12u14) ...
#6 25.91 Processing triggers for ca-certificates (20250419~deb12u1) ...
#6 25.93 Updating certificates in /etc/ssl/certs...
#6 26.56 0 added, 0 removed; done.
#6 26.56 Running hooks in /etc/ca-certificates/update.d...
#6 26.57 done.
#6 DONE 27.6s

#7 [ 3/11] RUN curl --fail --silent --show-error --location       --retry 3 --retry-delay 2 --retry-all-errors       "https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-linux-x64.zip"       --output /tmp/bun-linux-x64.zip   && echo "951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cbccdf7e848f  /tmp/bun-linux-x64.zip" | sha256sum --check --strict   && unzip -j /tmp/bun-linux-x64.zip 'bun-linux-x64/bun' -d /usr/local/bin   && chmod 0755 /usr/local/bin/bun   && test "$(bun --version)" = "1.3.14"   && rm -f /tmp/bun-linux-x64.zip
#7 2.699 /tmp/bun-linux-x64.zip: OK
#7 2.701 Archive:  /tmp/bun-linux-x64.zip
#7 2.705   inflating: /usr/local/bin/bun
#7 DONE 3.9s

#8 [ 4/11] WORKDIR /workspace
#8 DONE 0.0s

#9 [ 5/11] COPY agent-node/package.json agent-node/package-lock.json ./agent-node/
#9 DONE 0.1s

#10 [ 6/11] COPY agent-network/package.json agent-network/package-lock.json ./agent-network/
#10 DONE 0.1s

#11 [ 7/11] RUN cd agent-node && npm ci --include=optional   && cd ../agent-network && npm ci
#11 24.95
#11 24.95 added 108 packages, and audited 109 packages in 25s
#11 24.95
#11 24.95 32 packages are looking for funding
#11 24.95   run `npm fund` for details
#11 24.95
#11 24.95 found 0 vulnerabilities
#11 24.95 npm notice
#11 24.95 npm notice New major version of npm available! 10.9.8 -> 12.0.2
#11 24.95 npm notice Changelog: https://github.com/npm/cli/releases/tag/v12.0.2
#11 24.95 npm notice To update run: npm install -g npm@12.0.2
#11 24.95 npm notice
#11 37.24
#11 37.24 added 307 packages, and audited 308 packages in 12s
#11 37.24
#11 37.24 62 packages are looking for funding
#11 37.24   run `npm fund` for details
#11 37.26
#11 37.26 13 vulnerabilities (1 low, 2 moderate, 10 high)
#11 37.26
#11 37.26 To address issues that do not require attention, run:
#11 37.26   npm audit fix
#11 37.26
#11 37.26 To address all issues (including breaking changes), run:
#11 37.26   npm audit fix --force
#11 37.26
#11 37.26 Run `npm audit` for details.
#11 DONE 39.5s

#12 [ 8/11] COPY agent-node ./agent-node
#12 DONE 0.3s

#13 [ 9/11] COPY agent-network ./agent-network
#13 DONE 0.1s

#14 [10/11] COPY tests/test725-agent-node-unit-ci/run.sh ./tests/test725-agent-node-unit-ci/run.sh
#14 DONE 0.0s

#15 [11/11] RUN chmod 0755 ./tests/test725-agent-node-unit-ci/run.sh   && install -d -o node -g node -m 0700 "/run/user/$(id -u node)"   && chown -R node:node /workspace
#15 DONE 46.8s

#16 exporting to image
#16 exporting layers
#16 exporting layers 76.0s done
#16 exporting manifest sha256:d168d8cc3e365888449aa890cd0eb9335ba62f675d3326206a291e05c417cca7 0.0s done
#16 exporting config sha256:819c3cd1c2848a1ab700c79c31e09ef5e64a24225aa5790ba805c800764aca4f 0.0s done
#16 exporting attestation manifest sha256:a1f59a50d86a8e5b037b4ff23f4a075b4b45c32a05fac56d895fd0f3e3e5eabe 0.0s done
#16 exporting manifest list sha256:1a579eff7d843db7f24ee4aebedb62b057835330e2d950efb7745ea3f6616154 0.0s done
#16 naming to docker.io/library/anet-release46-test725:latest done
#16 unpacking to docker.io/library/anet-release46-test725:latest
#16 unpacking to docker.io/library/anet-release46-test725:latest 24.5s done
#16 DONE 100.6s
# test725 — complete agent-node unit domain
source_commit=aa7402d8148e62c00a087a4f107bd7d8bf9cd748
bun=1.3.14 node=v22.23.2 uid=1000
test_files=108
[L0] full agent-node/src unit suite as non-root
bun test v1.3.14 (0d9b296a)

src/inbox-message-policy.test.ts:
(pass) atomic peer reply inbox policy > ordinary work still expects a response [0.23ms]
(pass) atomic peer reply inbox policy > a peer reply is actionable but cannot start reply ping-pong [0.06ms]
(pass) atomic peer reply inbox policy > plain informational messages retain ack-only behavior [0.05ms]

src/external-schedules.test.ts:
(pass) external schedule manifest > reports an exact bounded shape and strips host paths to basename [1.02ms]
(pass) external schedule manifest > missing manifest is an explicit empty observation; config-less legacy stays omitted [1.14ms]
(pass) external schedule manifest > unknown keys, duplicate ids, invalid timestamps, and oversized lists fail closed [0.82ms]
(pass) external schedule manifest > symlink manifest never follows the target [0.67ms]
(pass) external schedule manifest > editable/revision are derived only from a verified managed crontab under the process gate [2.54ms]

src/inbox-skip-log.test.ts:
(pass) formatInboxSkipLog > self-message diagnostics identify the routing layer and full task [0.10ms]
(pass) formatInboxSkipLog > all inbound filter reasons produce an actionable INFO-safe line [0.10ms]
(pass) formatInboxSkipLog > the formatter has no message-content input [0.10ms]

src/owner-schedule-consumer.test.ts:
(pass) process-gated owner schedule consumer > disabled process registers no poll and makes zero network/host calls [1.00ms]
(pass) process-gated owner schedule consumer > exact node intent applies once, ACKs, and deletes journal only after ACK [8.53ms]
(pass) process-gated owner schedule consumer > foreign-node intent and invalid authority shape never reach crontab [0.85ms]
(pass) process-gated owner schedule consumer > lost ACK keeps journal; same delivered intent recovers without a second install [6.90ms]

src/codex-model-default.test.ts:
(pass) agent-node Codex model resolution > missing model uses the verified supported default [0.05ms]
(pass) agent-node Codex model resolution > explicit model remains authoritative [0.02ms]

src/codex-tui-alignment.test.ts:
(pass) Codex co-presence TUI alignment > points a manual TUI at the bridge-written thread and node-local home [0.47ms]
(pass) Codex co-presence TUI alignment > does not suggest a command without the shared remote [0.04ms]
(pass) Codex co-presence TUI alignment > quotes every operator-controlled value instead of emitting a second command [0.07ms]
(pass) Codex co-presence TUI alignment > does not print terminal control characters from config [0.11ms]
(pass) Codex co-presence TUI alignment > fails closed without returning a command for unsafe remote ws://user:review-userinfo-secret@127.0.0.1:24712/rpc [0.05ms]
(pass) Codex co-presence TUI alignment > fails closed without returning a command for unsafe remote ws://127.0.0.1:24712/rpc?token=review-query-secret [0.02ms]
(pass) Codex co-presence TUI alignment > fails closed without returning a command for unsafe remote ws://127.0.0.1:24712/rpc#review-fragment-secret [0.01ms]
(pass) Codex co-presence TUI alignment > fails closed without returning a command for unsafe remote ws://example.com:24712/rpc
(pass) Codex co-presence TUI alignment > fails closed without returning a command for unsafe remote https://127.0.0.1:24712/rpc
(pass) Codex co-presence TUI alignment > allows a credential-free loopback ws/wss origin and path [0.06ms]

src/claude-tool-aliases.test.ts:
(pass) Claude CommHub tool aliases > pins the exact registered in-process CommHub tool set [0.05ms]
(pass) Claude CommHub tool aliases > does not advertise aliases when the in-process server failed [0.05ms]

src/claude-code-cli-help-text.test.ts:
(pass) #909 agent-node --help does not present claude-code-cli as a directly-passable runtime > the `--runtime <type>` value list omits claude-code-cli (agent-node does not accept it) [126.55ms]
(pass) #909 agent-node --help does not present claude-code-cli as a directly-passable runtime > it stays documented, marked anet-provided — and is NOT called unimplemented (it is implemented) [165.60ms]
(pass) #909 rejecting claude-code-cli says where it actually lives > it does not call claude-code-cli unsupported, and names `anet node start` [194.97ms]
(pass) #909 rejecting claude-code-cli says where it actually lives > 负对照 —— 真正不存在的 runtime 仍然走原来那句 [179.86ms]

src/reply-reliability.test.ts:
(pass) classifyCommHubResponse > returns ok with parsed application payload (the happy path) [0.39ms]
(pass) classifyCommHubResponse > JSON-RPC error envelope → retryable CommHubError [0.23ms]
(pass) classifyCommHubResponse > MCP result.isError → retryable CommHubError [0.44ms]
(pass) classifyCommHubResponse > real legacy Hub unknown-tool result preserves the MCP code [0.15ms]
(pass) classifyCommHubResponse > application-level ok:false → appLevel CommHubError (NON-retryable) [0.17ms]
(pass) classifyCommHubResponse > non-JSON tool text is passed through verbatim [0.30ms]
(pass) classifyCommHubResponse > data with neither error nor result returns ok with the raw data [0.09ms]
(pass) CommHubError > instances are distinguishable from generic Error via instanceof [0.18ms]
(pass) CommHubError > appLevel flag survives the throw/catch round trip [0.14ms]
(pass) PendingReplyQueue > load() returns empty array when file does not exist [0.81ms]
(pass) PendingReplyQueue > persist + load round-trips an entry with attempts=0 [4.58ms]
(pass) PendingReplyQueue > final persistence boundary scrubs known, shaped, assignment and error credentials [4.09ms]
(pass) PendingReplyQueue > direct save cannot bypass scrub and leaves no sibling temp artifact [4.34ms]
(pass) PendingReplyQueue > load migrates an old broad-mode queue without leaving raw credential bytes [3.22ms]
(pass) PendingReplyQueue > load repairs a broad mode even when content needs no rewrite [0.66ms]
(pass) PendingReplyQueue > accepts the same process-wide redactor used by ordinary log call sites [2.52ms]
(pass) PendingReplyQueue > invalid legacy content is securely replaced with an empty 0600 queue [2.52ms]
(pass) PendingReplyQueue > persist is idempotent on (to, taskId) — attempts counter preserved [7.24ms]
(pass) PendingReplyQueue > clear removes only the matching (to, taskId) [13.39ms]
(pass) PendingReplyQueue.drain > delivers every entry on success and persists an empty queue [8.16ms]
(pass) PendingReplyQueue.drain > transient failure requeues with attempts++ and lastError [5.63ms]
(pass) PendingReplyQueue.drain > transient error text is scrubbed before it reaches disk [5.25ms]
(pass) PendingReplyQueue.drain > app-level CommHubError is dropped loud — not retried, not requeued [7.44ms]
(pass) PendingReplyQueue.drain > drain on empty queue is a no-op and does not write the file [0.60ms]
(pass) PendingReplyQueue.drain > file format is stable JSON — readable by an operator after a crash [3.27ms]
(pass) quickHash > is deterministic [0.29ms]
(pass) quickHash > differs across inputs [0.07ms]
(pass) quickHash > returns 32-char hex [0.12ms]

src/controlled-upload.test.ts:
(pass) normalizeUploadName > strips directories and control chars [0.84ms]
(pass) resolveControlledUploadPath — NUL live guard > rejects embedded NUL before any fs access [1.87ms]
(pass) resolveControlledUploadPath — NUL live guard > rejects NUL-only / leading NUL [0.42ms]
(pass) resolveControlledUploadPath > accepts regular file under root [0.81ms]
(pass) resolveControlledUploadPath > rejects path outside roots [0.56ms]
(pass) resolveControlledUploadPath > rejects absolute foreign path /etc/passwd [0.40ms]
(pass) resolveControlledUploadPath > rejects traversal that escapes root [0.61ms]
(pass) resolveControlledUploadPath > rejects missing path [0.46ms]
(pass) openFstatBoundedReadControlledFile — same fd + bound > reads small PNG via same-fd path [1.37ms]
(pass) openFstatBoundedReadControlledFile — same fd + bound > rejects oversize without allocating full max+1 into a single slurp beyond cap [20.54ms]
(pass) openFstatBoundedReadControlledFile — same fd + bound > rejects symlink leaf at open (O_NOFOLLOW) [1.55ms]
(pass) openFstatBoundedReadControlledFile — same fd + bound > fstat is on the same opened fd (structural pin) [0.74ms]
(pass) uploadControlledLocalFile > uploads PNG fixture via mock fetch and returns file_id [2.90ms]
(pass) uploadControlledLocalFile > refuses oversize before network [18.20ms]
(pass) uploadControlledLocalFile > never falls back to path when file_id missing [1.66ms]
(pass) uploadControlledLocalFile > rejects untrusted path without calling hub [0.81ms]
(pass) uploadControlledLocalFile > rejects NUL path without calling hub [0.62ms]
(pass) defaultControlledUploadRoots > includes grok sessions and attachment cache [1.02ms]
(pass) source contracts (adversarial pins) > same-fd pin: fstatSync(fd) + openSync; no path re-stat/readFileSync in reader [0.40ms]
(pass) source contracts (adversarial pins) > NUL guard pin: rawPath.includes NUL marker present [0.40ms]
(pass) source contracts (adversarial pins) > bounded-read pin: extra-byte probe after maxBytes [0.41ms]

src/commhub-mcp.test.ts:
(pass) injectAgentFromSession > adds current alias to outbound task calls [0.21ms]
(pass) injectAgentFromSession > adds current alias to outbound message calls [0.07ms]
(pass) injectAgentFromSession > overrides stale or model-supplied from_session on ntok outbound calls [0.05ms]
(pass) injectAgentFromSession > does not add from_session to read-only calls [0.03ms]

src/inbox-dispatch.test.ts:
(pass) isInteractiveDashboardTask > accepts a Hub-authenticated dashboard chat task [0.35ms]
(pass) isInteractiveDashboardTask > pre-stamp admin rows stay FIFO because aliases are not auth facts [0.15ms]
(pass) isInteractiveDashboardTask > rejects node-authenticated spoofing, malformed ids, and plain messages [0.12ms]
(pass) dispatchInboxBatch > awaited batches preserve legacy runtime serialization [3.77ms]
(pass) dispatchInboxBatch > a later SSE snapshot enters while the first detached turn is still running [4.00ms]
(pass) dispatchInboxBatch > the real serialized drain lane can fetch a later SSE snapshot before the active turn ends [1.19ms]
(pass) dispatchInboxBatch > detached completion failures remain observable [2.13ms]
(pass) dispatchInboxBatch > settling detached work emits a wake for the next Hub inbox window [11.72ms]
(pass) dispatchInboxBatch > a throwing settle callback cannot strand queued N+1 work [1.68ms]
(pass) dispatchInboxBatch > same-tick duplicate kicks claim one row exactly once [0.38ms]
(pass) dispatchInboxBatch > bounded admission waits N+1 and starts it after a slot settles [2.02ms]
(pass) dispatchInboxBatch > durable reply drain waits until detached Codex rows finish [0.07ms]
(pass) dispatchInboxBatch > active Codex direct delivery and durable drain send one reply, not two [6.43ms]

src/reply-routing-source.test.ts:
(pass) #698 peer reply runtime wiring > peer replies negotiate the atomic tool and retain only a terminal legacy fallback [1.53ms]
(pass) #698 peer reply runtime wiring > every actionable inbox turn crosses the behavior-tested reply-policy seam [0.68ms]
(pass) #698 peer reply runtime wiring > new_reply SSE events wake the actionable work inbox [0.61ms]

src/task-runtime-evidence.test.ts:
(pass) logicalTaskIdFromInbox > retry/reassign task rows use stable task_id, not fresh inbox.id [0.12ms]
(pass) logicalTaskIdFromInbox > legacy task rows and non-task rows retain transport identity [0.05ms]
(pass) createTaskRuntimeEvidenceReporter > construction and process admission report no evidence [0.18ms]
(pass) createTaskRuntimeEvidenceReporter > submission and many runtime events produce one exact report per level [0.26ms]
(pass) createTaskRuntimeEvidenceReporter > a consumed-only runtime remains honest and lets the Hub imply submission [0.25ms]
(pass) createTaskRuntimeEvidenceReporter > missing logical task identity is a fail-closed no-op [0.22ms]
(pass) createTaskRuntimeEvidenceReporter > an old-Hub failure is visible but never breaks the model turn [0.78ms]
(pass) agent-node inbox wiring > keeps transport ACK separate from stable task evidence and replies [2.89ms]
(pass) agent-node inbox wiring > all runtime dispatch families receive the same task-lifetime reporter [1.09ms]
(pass) agent-node inbox wiring > SDK and direct-stdio boundaries preserve their distinct evidence semantics [1.16ms]

src/grok-isolated-cwd.test.ts:
(pass) prepareGrokIsolatedCwd (#204 preview.7) > creates per-node grok-cwd directory under home/.anet/nodes/<nodeKey>/grok-cwd [2.33ms]
(pass) prepareGrokIsolatedCwd (#204 preview.7) > falls back to alias when nodeId is absent [1.26ms]
(pass) prepareGrokIsolatedCwd (#204 preview.7) > sanitises nodeKey to avoid path traversal / weird chars [1.64ms]
(pass) prepareGrokIsolatedCwd (#204 preview.7) > skips .mcp.json (does NOT symlink it into isolated cwd) [1.68ms]
(pass) prepareGrokIsolatedCwd (#204 preview.7) > symlinks top-level files (README.md) and directories (docs/, src/) [1.62ms]
(pass) prepareGrokIsolatedCwd (#204 preview.7) > is idempotent — second run sees existing symlinks and counts 0 new [1.43ms]
(pass) prepareGrokIsolatedCwd (#204 preview.7) > picks up new entries on re-run (snapshot freshness) [1.70ms]
(pass) prepareGrokIsolatedCwd (#204 preview.7) > falls back to userCwd (isolated=false) when mkdir fails [1.60ms]
(pass) prepareGrokIsolatedCwd (#204 preview.7) > falls back to userCwd when userCwd does not exist (readdir fails) [1.60ms]
(pass) prepareGrokIsolatedCwd (#204 preview.7) > does NOT throw on per-entry symlink failure — warns and continues [1.72ms]
(pass) prepareGrokIsolatedCwd (#204 preview.7) > two different nodes get fully isolated dirs (concurrency safe by construction) [2.14ms]

src/inbox-dispatch-wiring.test.ts:
(pass) Codex app-server live inbox kick wiring > a Codex snapshot releases the serialized fetch lane after submission [0.25ms]
(pass) Codex app-server live inbox kick wiring > Codex detached admission is explicitly bounded and completion wakes the Hub window [0.67ms]
(pass) Codex app-server live inbox kick wiring > pending reply drain is fenced while detached Codex rows are active [0.20ms]

src/owner-schedule-control.test.ts:
(pass) owner schedule managed-cron control > parses only exact managed markers and publishes bounded inventory [1.49ms]
(pass) owner schedule managed-cron control > changes timing/enabled while preserving command and unmanaged bytes [7.20ms]
(pass) owner schedule managed-cron control > command replacement, wrong node, wrong revision, and unknown patch fail before install [2.96ms]
(pass) owner schedule managed-cron control > install/readback failure restores and verifies the exact old crontab [3.22ms]
(pass) owner schedule managed-cron control > unsafe node directory and symlink journal fail closed with zero host write [1.14ms]
(pass) owner schedule managed-cron control > local audit is minimal, private and idempotent [2.57ms]

src/owner-schedule-wiring.test.ts:
(pass) owner schedule process wiring > capability is pinned from config once and never exposed as a model tool [1.65ms]
(pass) owner schedule process wiring > SSE is only a doorbell and snapshots are editable only under the same gate [1.09ms]
(pass) owner schedule process wiring > new token mint paths bind the immutable node id and opt-in is explicit [3.98ms]

src/runtime-effective-label.test.ts:
(pass) #491 startup banner reports the EFFECTIVE runtime > alias input 'codex-tui' → banner names the effective runtime (codex-app-server), not just the raw input [7193.61ms]
(pass) #491 startup banner reports the EFFECTIVE runtime > canonical input stays readable (no regression for the common case) [7142.61ms]
(pass) #491 regression lock — unknown runtime fails closed > unknown runtime → non-zero exit, error names the value AND the supported list [118.44ms]
(pass) #553 Grok startup banner reports model ownership truthfully > unset model on Grok ACP names the Grok CLI as owner, not the runtime alias as a model id [7138.28ms]
(pass) #553 Grok startup banner reports model ownership truthfully > unset model on Grok CLI uses the same non-versioned ownership statement [7148.29ms]
(pass) #553 Grok startup banner reports model ownership truthfully > an explicit Grok model is still reported exactly [7142.24ms]

src/peer-reply-send.test.ts:
(pass) peer reply capability fallback > capable Hub uses only the atomic terminal route [0.52ms]
(pass) peer reply capability fallback > old Hub wire error terminalizes through send_reply, never send_task [0.62ms]
(pass) peer reply capability fallback > every explicit capability downgrade preserves terminal reply semantics [0.63ms]
(pass) peer reply capability fallback > transport ambiguity and unrelated hard errors never choose a second route [0.52ms]
(pass) peer reply capability fallback > negative capability is rechecked instead of cached [0.42ms]
(pass) peer reply capability fallback > legacy terminalization failure stays visible to the pending queue [0.30ms]
(pass) peer reply capability fallback > classifier accepts only explicit capability signals [0.11ms]

src/private-log.test.ts:
(pass) Grok preview private ordinary logs > scrubs and repairs legacy logs before appending through a 0600 file [5.34ms]
(pass) Grok preview private ordinary logs > rejects a symlinked directory or final log file [1.61ms]
(pass) Grok preview private ordinary logs > rejects a multiply-linked log instead of rewriting another pathname [0.68ms]
(pass) Grok preview private ordinary logs > does not follow a log-directory symlink introduced after preparation [0.74ms]

src/owner-schedule-system-crontab.test.ts:
(pass) owner schedule real crontab adapter > round-trips an exact managed marker through the container crontab [22.82ms]

src/package-version-consistency.test.ts:
(pass) agent-node package version consistency > package-lock top-level version matches package.json [0.05ms]
(pass) agent-node package version consistency > package-lock root package version matches package.json [0.02ms]

src/credential-redaction.test.ts:
(pass) credential persistence redactor > removes exact caller-known values regardless of punctuation or context [0.24ms]
(pass) credential persistence redactor > redacts network, GitHub, AWS and provider token shapes in free text [0.20ms]
(pass) credential persistence redactor > redacts credential assignments while preserving keys and valid JSON [0.32ms]
(pass) credential persistence redactor > redacts shell/error assignment forms including quoted values [0.14ms]
(pass) credential persistence redactor > redacts an unlabelled connection URI with embedded userinfo [0.06ms]
(pass) credential persistence redactor > does not over-delete normal prose and non-credential settings [0.12ms]
(pass) credential persistence redactor > deep-redacts JSON-like values without mutating the input [0.46ms]
(pass) credential value collection > collects exact sensitive values and shaped values under unknown keys [2.36ms]
(pass) credential value collection > key classifier is exact enough not to treat ordinary AWS settings as credentials [0.11ms]

src/inbox-skip-log-wiring.test.ts:
(pass) processInbox logs skipped messages at INFO before acknowledging [1.69ms]

src/peer-reply-inbox.test.ts:
(pass) inbox turn reply-policy enforcement > delivers once, ACKs once, and exposes no outbound reply dependency [0.40ms]
(pass) inbox turn reply-policy enforcement > ordinary request returns its outcome without ACKing in this seam [0.26ms]
(pass) inbox turn reply-policy enforcement > runtime failure does not ACK a result that was never consumed [0.25ms]
(pass) peer reply SSE routing > new_reply schedules exactly one drain [0.13ms]
(pass) peer reply SSE routing > unrelated events do not schedule a drain [0.06ms]

src/grok-artifact-extractor.test.ts:
(pass) listGrokVideoArtifacts (#205 Step 2 simplified) > returns empty when grokSessionDir is undefined [0.56ms]
(pass) listGrokVideoArtifacts (#205 Step 2 simplified) > returns empty when videos/ subdir is missing [0.21ms]
(pass) listGrokVideoArtifacts (#205 Step 2 simplified) > enumerates .mp4 files in videos/ as absolute paths [0.91ms]
(pass) listGrokVideoArtifacts (#205 Step 2 simplified) > matches mp4 case-insensitively [0.77ms]
(pass) listGrokVideoArtifacts (#205 Step 2 simplified) > does not throw on permission errors — returns [] [0.46ms]
(pass) formatVideoTrailer (#205 Step 2 simplified) > returns empty string for empty list [0.17ms]
(pass) formatVideoTrailer (#205 Step 2 simplified) > formats one path [0.11ms]
(pass) formatVideoTrailer (#205 Step 2 simplified) > formats multiple paths [0.06ms]
(pass) formatVideoTrailer (#205 Step 2 simplified) > skips paths already mentioned in existingReply (no duplication) [0.04ms]
(pass) formatVideoTrailer (#205 Step 2 simplified) > only appends paths NOT already mentioned, even when some are [0.08ms]

src/explicit-task-lifecycle.test.ts:
(pass) explicit delegation lifecycle trace > keeps the production delegation loop wired through the tested state machine [1.24ms]
(pass) explicit delegation lifecycle trace > emits ack, start, and reply from the production polling state machine [1.00ms]
(pass) explicit delegation lifecycle trace > emits both bounded stale warnings and expiry when delivery never advances [0.32ms]
(pass) explicit delegation lifecycle trace > pins the production poll, stale-warning, and timeout defaults [0.68ms]
(pass) explicit delegation lifecycle trace > maps failed and cancelled terminal states to a failed trace without retrying [0.36ms]

src/task-trace.test.ts:
(pass) task trace contract > renders missing parent and lifecycle scope honestly [0.28ms]
(pass) task trace contract > redacts credentials from errors [0.19ms]
(pass) task trace contract > emits parseable JSON and neutralizes human log injection [0.13ms]
(pass) task trace contract > recognizes the real MCP content envelope before cli parsing [0.67ms]
(pass) task trace contract > uses stable event names for send and observed lifecycle phases [0.15ms]

src/sse-recovery-guidance.test.ts:
(pass) sseAbandonGuidance > states that abandon leaves the current process alive [0.14ms]
(pass) sseAbandonGuidance > requires stop-and-replace instead of starting a duplicate [0.09ms]
(pass) sseAbandonGuidance > preserves the co-presence launch shape in recovery guidance [0.22ms]
(pass) sseAbandonGuidance > the production SSE abandon hook uses the honest guidance [0.95ms]

src/cli-explicit-delegation.test.ts:
(pass) extractExplicitDelegation > matches send_task alias/task call [0.82ms]
(pass) extractExplicitDelegation > matches mcp send_task positional call [0.14ms]
(pass) extractExplicitDelegation > matches 给 X 发任务 [0.10ms]
(pass) extractExplicitDelegation > matches 和 X 沟通一下 [0.23ms]
(pass) extractExplicitDelegation > matches bare 和 X 沟通一下 [0.11ms]
(pass) extractExplicitDelegation > matches 和 X send_task 一下 [0.06ms]
(pass) extractExplicitDelegation > matches 和 X send_task 一下 with no punctuation before body [0.08ms]
(pass) extractExplicitDelegation > matches bare 和 X send_task 一下 [0.05ms]
(pass) extractExplicitDelegation > matches 让 X 做 [0.15ms]
(pass) extractExplicitDelegation > matches 交给 X [0.05ms]
(pass) extractExplicitDelegation > does not match no alias [0.03ms]
(pass) extractExplicitDelegation > does not match normal Q&A [0.02ms]
(pass) extractExplicitDelegation > matches bare send_task <alias> <task> (MCP-like) [0.03ms]
(pass) extractExplicitDelegation > matches bare send_task with multi-word task body [0.04ms]
(pass) extractExplicitDelegation > matches 你去给 X 打个招呼 [0.06ms]
(pass) extractExplicitDelegation > matches 你去给 X with longer body [0.04ms]
(pass) extractExplicitDelegation > matches 给 X 发个消息 BODY (verb-suffix stripped) [0.04ms]
(pass) extractExplicitDelegation > matches 给 X 发 BODY (bare verb) [0.04ms]
(pass) extractExplicitDelegation > matches 给 X 沟通一下 BODY [0.06ms]
(pass) extractExplicitDelegation > matches 给 X 说 BODY [0.04ms]
(pass) extractExplicitDelegation > matches 给 X 发任务 (regression — specific pattern still wins) [0.04ms]

src/util/timeout.test.ts:
(pass) withTimeout — happy path (factory wins) > resolves with factory value when fn settles before deadline [0.50ms]
(pass) withTimeout — happy path (factory wins) > passes a non-aborted signal when fn finishes promptly [0.18ms]
(pass) withTimeout — happy path (factory wins) > returns objects, not just strings [0.20ms]
(pass) withTimeout — happy path (factory wins) > propagates fn's rejection unchanged (not wrapped) [0.30ms]
(pass) withTimeout — timeout path (timer wins) > rejects with TimeoutError when fn outlasts deadline [32.28ms]
(pass) withTimeout — timeout path (timer wins) > TimeoutError message includes label + ms [0.07ms]
(pass) withTimeout — timeout path (timer wins) > TimeoutError without label still works [0.11ms]
(pass) withTimeout — timeout path (timer wins) > fires AbortSignal on timeout so factory can cancel in-flight work [43.77ms]
(pass) withTimeout — zero / negative deadline sentinel > timeoutMs=0 disables the timer (CLAUDE_TIMEOUT_MS=0 sentinel) [51.69ms]
(pass) withTimeout — zero / negative deadline sentinel > timeoutMs<0 also disables (defensive) [0.38ms]
(pass) withTimeout — zero / negative deadline sentinel > untimed call still receives a non-aborted signal [0.26ms]
(pass) withTimeout — externalSignal propagation > forwards external abort into factory signal [212.01ms]
(pass) withTimeout — externalSignal propagation > already-aborted external signal aborts immediately [0.46ms]
(pass) withTimeout — cleanup > clears timer on successful return (no dangling handles) [21.75ms]
(pass) resolveTimeoutMs — precedence > env wins over flag and default [0.28ms]
(pass) resolveTimeoutMs — precedence > flag wins when env is missing [0.13ms]
(pass) resolveTimeoutMs — precedence > default wins when env and flag both missing [0.11ms]
(pass) resolveTimeoutMs — precedence > flag wins when env is empty string (treated as unset) [0.07ms]
(pass) resolveTimeoutMs — precedence > flag wins when env is non-numeric garbage [0.06ms]
(pass) resolveTimeoutMs — precedence > flag wins when env is negative [0.06ms]
(pass) resolveTimeoutMs — precedence > default wins when flag is NaN [0.07ms]
(pass) resolveTimeoutMs — precedence > zero is honoured (not treated as unset) — env=0 disables timeout [0.09ms]
(pass) resolveTimeoutMs — precedence > zero is honoured at flag level too [0.07ms]
(pass) resolveTimeoutMs — clamping > clamps below minMs and reports clamped=true [0.06ms]
(pass) resolveTimeoutMs — clamping > clamps above maxMs and reports clamped=true [0.06ms]
(pass) resolveTimeoutMs — clamping > in-bounds value is not clamped [0.05ms]
(pass) resolveTimeoutMs — clamping > default value also gets clamped (configuration sanity) [0.05ms]
(pass) resolveTimeoutMs — defensive null handling > null envValue is treated as unset [0.05ms]
(pass) resolveTimeoutMs — defensive null handling > null flagValue is treated as unset [0.04ms]

src/util/single-flight.test.ts:
(pass) single-flight resource initialization > concurrent callers share exactly one initializer [0.62ms]
(pass) single-flight resource initialization > a rejected initializer is cleared and can be retried [0.35ms]

src/util/supervise-child.test.ts:
(pass) superviseChild — shutdown gate stops the loop > shutdownGate=true from the start → runOnce never called [0.56ms]
(pass) superviseChild — shutdown gate stops the loop > shutdownGate flips true after first iteration → exactly one runOnce [0.30ms]
(pass) superviseChild — backoff growth + cap > waits double the delay each iteration, capping at maxDelayMs [2.73ms]
(pass) superviseChild — runOnce that returns WITHOUT markStable is treated as failed (regression pin) > runOnce that returns cleanly without markStable → backoff doubles [0.60ms]
(pass) superviseChild — markStable resets backoff > after iteration that calls markStable, next wait is baseDelayMs again [0.63ms]
(pass) superviseChild — markStable resets backoff > markStable called multiple times in one iteration is idempotent [0.51ms]
(pass) superviseChild — abandonAfterMs > calls onAbandon and returns after cumulative downtime exceeds threshold [0.56ms]
(pass) superviseChild — abandonAfterMs > markStable in any iteration resets downtime — abandon never fires [0.56ms]
(pass) superviseChild — runOnce error handling > runOnce throws → onError fires, loop continues [0.87ms]
(pass) superviseChild — runOnce error handling > runOnce throws AND shutdownGate goes true → loop exits, no further iteration [0.31ms]
(pass) superviseChild — jitter range > jitterRatio=0.25 + random=0 → -25% of delay (lower bound) [0.55ms]
(pass) superviseChild — jitter range > jitterRatio=0.25 + random=1 → +25% of delay (upper bound) [0.43ms]
(pass) superviseChild — jitter range > jitterRatio=0 → deterministic waits at exact delay [0.48ms]
(pass) superviseChild — jitter range > waitMs floor 100 enforces minimum wait even with tiny base + negative jitter [0.44ms]
(pass) superviseChild — defensive contract > returns (does not throw) when runOnce never resolves and shutdown flips [1.41ms]

src/util/access-resolve.test.ts:
(pass) normalizeAllowFrom — input shapes > real string[] passes through deduped (filter empty strings) [0.17ms]
(pass) normalizeAllowFrom — input shapes > undefined → empty + not malformed [0.03ms]
(pass) normalizeAllowFrom — input shapes > null → empty + not malformed [0.03ms]
(pass) normalizeAllowFrom — input shapes > non-array object → empty + malformed (corrupted access.json shape) [0.03ms]
(pass) normalizeAllowFrom — input shapes > string instead of array → malformed [0.03ms]
(pass) normalizeAllowFrom — input shapes > array with non-string elements drops them [0.06ms]
(pass) resolveTelegramAccess — fail-closed empty allowFrom (v0.11 security change) > empty array → deny with empty-fail-closed kind [0.22ms]
(pass) resolveTelegramAccess — fail-closed empty allowFrom (v0.11 security change) > undefined → deny [0.06ms]
(pass) resolveTelegramAccess — fail-closed empty allowFrom (v0.11 security change) > malformed → deny + reason mentions malformed [0.12ms]
(pass) resolveTelegramAccess — wildcard '*' opens the channel > ['*'] alone allows any sender [0.10ms]
(pass) resolveTelegramAccess — wildcard '*' opens the channel > ['*', 'specific_id'] still wildcard-allows (wins precedence) [0.10ms]
(pass) resolveTelegramAccess — explicit id / username matching > senderId in list → allow [0.10ms]
(pass) resolveTelegramAccess — explicit id / username matching > senderUsername match (no id match) → allow [0.06ms]
(pass) resolveTelegramAccess — explicit id / username matching > neither id nor username in list → deny [0.06ms]
(pass) resolveTelegramAccess — explicit id / username matching > empty senderUsername doesn't accidentally match empty list entry [0.05ms]
(pass) resolveTelegramAccess — explicit id / username matching > blank-string id with username match still allows [0.04ms]
(pass) resolveFeishuAccess — DM path mirrors telegram fail-closed > empty allowFrom → deny [0.23ms]
(pass) resolveFeishuAccess — DM path mirrors telegram fail-closed > wildcard allows [0.07ms]
(pass) resolveFeishuAccess — DM path mirrors telegram fail-closed > specific id allows [0.06ms]
(pass) resolveFeishuAccess — DM path mirrors telegram fail-closed > sender not in list → deny [0.08ms]
(pass) resolveFeishuAccess — group path (allowChats + groupPolicy) > empty allowChats → fail-closed [0.12ms]
(pass) resolveFeishuAccess — group path (allowChats + groupPolicy) > chat in allowChats + groupPolicy=all → allow [0.07ms]
(pass) resolveFeishuAccess — group path (allowChats + groupPolicy) > chat in allowChats + groupPolicy=observe → deny [0.06ms]
(pass) resolveFeishuAccess — group path (allowChats + groupPolicy) > chat NOT in allowChats → deny (even with policy=all) [0.10ms]
(pass) resolveFeishuAccess — group path (allowChats + groupPolicy) > wildcard chats opens any chat (with groupPolicy=all) [0.06ms]
(pass) resolveFeishuAccess — group path (allowChats + groupPolicy) > groupPolicy=mention allows (caller decides at message inspect time) [0.05ms]
(pass) buildEmptyAllowlistWarn — boot-time visibility > returns warn string for empty allowFrom [0.13ms]
(pass) buildEmptyAllowlistWarn — boot-time visibility > returns warn string for malformed allowFrom + mentions malformed [0.05ms]
(pass) buildEmptyAllowlistWarn — boot-time visibility > returns null when allowFrom has at least one entry [0.04ms]
(pass) buildEmptyAllowlistWarn — boot-time visibility > returns null for wildcard-allow (channel intentionally open) [0.04ms]
(pass) loadTelegramAccess + resolver — wiring regression (CHANGE_REQ on #276) > loader stores raw allowFrom verbatim — no normalization at load time [0.10ms]
(pass) loadTelegramAccess + resolver — wiring regression (CHANGE_REQ on #276) > loader emits boot-warn when allowFrom is missing [0.04ms]
(pass) loadTelegramAccess + resolver — wiring regression (CHANGE_REQ on #276) > loader emits boot-warn when allowFrom is malformed (non-array) [0.05ms]
(pass) loadTelegramAccess + resolver — wiring regression (CHANGE_REQ on #276) > loader is silent when allowFrom has at least one entry (even if numeric) [0.15ms]
(pass) loadTelegramAccess + resolver — wiring regression (CHANGE_REQ on #276) > [123] alone (numeric sender id from a misformatted access.json) → loader+resolver fail-closed [0.11ms]
(pass) loadTelegramAccess + resolver — wiring regression (CHANGE_REQ on #276) > [null] (corrupted access.json) → loader+resolver fail-closed [0.11ms]
(pass) loadTelegramAccess + resolver — wiring regression (CHANGE_REQ on #276) > [{}] (object instead of id string) → loader+resolver fail-closed [0.07ms]
(pass) loadTelegramAccess + resolver — wiring regression (CHANGE_REQ on #276) > [123, '@vansin'] (mixed) → '@vansin' still allowed, numeric '123' rejected [0.16ms]
(pass) loadTelegramAccess + resolver — wiring regression (CHANGE_REQ on #276) > [null, '*'] (mixed wildcard) → wildcard wins despite garbage entries [0.08ms]
(pass) loadTelegramAccess + resolver — wiring regression (CHANGE_REQ on #276) > missing access.json entirely (loader gets null) → fail-closed [0.08ms]
(pass) regression — pre-v0.11 fail-open MUST NOT come back > empty array NEVER allows [0.05ms]
(pass) regression — pre-v0.11 fail-open MUST NOT come back > undefined NEVER allows [0.03ms]
(pass) regression — pre-v0.11 fail-open MUST NOT come back > null NEVER allows [0.04ms]
(pass) regression — pre-v0.11 fail-open MUST NOT come back > object-shape (corrupted) NEVER allows [0.04ms]

src/runtime/fetch-attachment.test.ts:
(pass) FILE_ID_REGEX matches server contract > accepts the same shapes the hub accepts [0.14ms]
(pass) FILE_ID_REGEX matches server contract > rejects path-traversal + length-out-of-range [0.07ms]
(pass) resolveAttachmentToLocalPath — file_id path > hub 200 OK → bytes written to cache + chmod 600 + Bearer auth attached [8.70ms]
(pass) resolveAttachmentToLocalPath — file_id path > file_id_invalid before any HTTP call (path traversal attempt) [0.44ms]
(pass) resolveAttachmentToLocalPath — file_id path > hub 404 → not_found code [0.55ms]
(pass) resolveAttachmentToLocalPath — file_id path > hub 401 → auth_failed code [0.47ms]
(pass) resolveAttachmentToLocalPath — size cap (🔴 通信龙 nit: BYTE unit + mid-stream abort) > Content-Length > cap → size_exceeded with declared-and-cap surfaced + no cache file written [0.75ms]
(pass) resolveAttachmentToLocalPath — size cap (🔴 通信龙 nit: BYTE unit + mid-stream abort) > Content-Length lies (says small, sends big) → size_exceeded MID-STREAM with cleanup [1.67ms]
(pass) resolveAttachmentToLocalPath — size cap (🔴 通信龙 nit: BYTE unit + mid-stream abort) > DEFAULT_MAX_BYTES is 50 MiB unless COMMHUB_ATTACHMENT_MAX_BYTES is set (current process is unset → 50 MiB) [0.08ms]
(pass) resolveAttachmentToLocalPath — trusted local path fallback (single-host / feishu compat) > no file_id + path inside cache root → returns canonical path, no HTTP call [0.99ms]
(pass) resolveAttachmentToLocalPath — trusted local path fallback (single-host / feishu compat) > configured Feishu root remains a compatible trusted drop-zone [0.64ms]
(pass) resolveAttachmentToLocalPath — trusted local path fallback (single-host / feishu compat) > existing file outside trusted roots is rejected [0.55ms]
(pass) resolveAttachmentToLocalPath — trusted local path fallback (single-host / feishu compat) > symlink inside a trusted root cannot escape to another host file [0.59ms]
(pass) resolveAttachmentToLocalPath — trusted local path fallback (single-host / feishu compat) > no file_id + path does NOT exist → not_found error [0.51ms]
(pass) resolveAttachmentToLocalPath — trusted local path fallback (single-host / feishu compat) > no file_id AND no path → no_file_id_no_path error [0.32ms]
(pass) resolveAttachmentToLocalPath — cache hit > same file_id + same size → no HTTP call, returns cached:true [0.58ms]
(pass) resolveAttachmentToLocalPath — cache hit > same file_id + different size → cache miss, re-fetches [4.37ms]
(pass) sweepAttachmentCacheOnce > purges files older than TTL, keeps fresh [0.91ms]
(pass) sweepAttachmentCacheOnce > no-op when cache dir doesn't exist [0.26ms]

src/runtime/readable-attachment-prompt.test.ts:
(pass) readable attachment prompt > pins the exact runtime set without changing structured-image SDK lanes [0.14ms]
(pass) readable attachment prompt > pins the readable extension allowlist as an exact value set [0.33ms]
(pass) readable attachment prompt > injects absolute deduplicated paths and escapes control characters [0.27ms]
(pass) readable attachment prompt > leaves text byte-identical when no attachment resolved [0.05ms]
(pass) readable attachment prompt > path-prompt runtimes reject sender-local paths while structured lanes retain legacy behavior [0.23ms]
(pass) readable attachment prompt > the inbox choke point feeds the augmented text into processTask [2.07ms]

src/runtime/attempt-log-outcome.test.ts:
(pass) formatAttemptOutcome > passes the vendor's own label through when the vendor did not claim success [0.09ms]
(pass) formatAttemptOutcome > says success only when the node's own classifier agrees [0.03ms]
(pass) formatAttemptOutcome > does not print a bare 'success' when the node rejected the turn [0.08ms]
(pass) formatAttemptOutcome > names which kind of rejection it was [0.06ms]
(pass) the live incident this module exists for > classifies the observed turn as a rejection [0.25ms]
(pass) the live incident this module exists for > would have printed a line that does not claim success [0.08ms]
(pass) the live incident this module exists for > keeps the old behaviour reachable when the turn is genuinely fine [0.07ms]

src/runtime/create-node-daemon.test.ts:
(pass) #633 daemon private state > global config repair and replacement converge to private state [4.14ms]
(pass) #633 daemon private state > global config read refuses a symlink without touching its target [0.97ms]
(pass) §4.2.2 daemon-side flag VALUE validator (BLOCKER #2 — defense in depth) > permissionMode enum [0.35ms]
(pass) §4.2.2 daemon-side flag VALUE validator (BLOCKER #2 — defense in depth) > dangerouslySkipPermissions boolean (string 'true' must be rejected) [0.13ms]
(pass) §4.2.2 daemon-side flag VALUE validator (BLOCKER #2 — defense in depth) > maxTurns integer range — 'DROP TABLE' / float / out-of-range rejected [0.25ms]
(pass) §4.2.2 daemon-side flag VALUE validator (BLOCKER #2 — defense in depth) > budget number with decimals allowed; out-of-range rejected [0.21ms]
(pass) §4.2.2 daemon-side flag VALUE validator (BLOCKER #2 — defense in depth) > timeout integer range [0.20ms]
(pass) §4.2.2 daemon-side flag VALUE validator (BLOCKER #2 — defense in depth) > unknown key rejected [0.12ms]
(pass) buildAnetArgsDaemon now reaches flag value validation > happy path with mixed flags [0.49ms]
(pass) buildAnetArgsDaemon now reaches flag value validation > smuggled string maxTurns rejected by daemon even if hub missed [0.22ms]
(pass) buildAnetArgsDaemon now reaches flag value validation > smuggled string dangerouslySkipPermissions rejected [0.10ms]
(pass) buildAnetArgsDaemon now reaches flag value validation > name shell-metachar still rejected (existing validateName, F2) [0.13ms]
(pass) buildAnetArgsDaemon now reaches flag value validation > runtime enum still enforced [0.10ms]
(pass) buildAnetArgsDaemon now reaches flag value validation > channels non-empty rejected (P1 fail-closed) [0.10ms]
(pass) §4.2.6 B2 loadAndVerifyAnetBin — install-time pin 5-check (BLOCKER #3 hardened) > happy path with hash witness [0.97ms]
(pass) §4.2.6 B2 loadAndVerifyAnetBin — install-time pin 5-check (BLOCKER #3 hardened) > REJECT: no ANET_BIN_ABS at all [0.14ms]
(pass) §4.2.6 B2 loadAndVerifyAnetBin — install-time pin 5-check (BLOCKER #3 hardened) > REJECT: relative path [0.14ms]
(pass) §4.2.6 B2 loadAndVerifyAnetBin — install-time pin 5-check (BLOCKER #3 hardened) > REJECT: symlink (contains symlink component) [0.60ms]
(pass) §4.2.6 B2 loadAndVerifyAnetBin — install-time pin 5-check (BLOCKER #3 hardened) > REJECT: world-writable (mode 0o777) [0.41ms]
(pass) §4.2.6 B2 loadAndVerifyAnetBin — install-time pin 5-check (BLOCKER #3 hardened) > REJECT: group-writable (mode 0o775) [0.38ms]
(pass) §4.2.6 B2 loadAndVerifyAnetBin — install-time pin 5-check (BLOCKER #3 hardened) > REJECT: not executable (mode 0o644) [0.39ms]
(pass) §4.2.6 B2 loadAndVerifyAnetBin — install-time pin 5-check (BLOCKER #3 hardened) > REJECT: owner not root (no opt-out) [0.39ms]
(pass) §4.2.6 B2 loadAndVerifyAnetBin — install-time pin 5-check (BLOCKER #3 hardened) > ACCEPT: owner not root WHEN ANET_DAEMON_ALLOW_NON_ROOT_BIN=1 (explicit opt-out) [0.42ms]
(pass) §4.2.6 B2 loadAndVerifyAnetBin — install-time pin 5-check (BLOCKER #3 hardened) > REJECT: sha256 mismatch with install witness [0.45ms]
(pass) minimalEnv defensive compose (BLOCKER #1+#2 lineage — kept stable) > happy path: no extra → PATH includes daemon's own node bin dir + SAFE_PATH (issue #301 nvm fix) [0.40ms]
(pass) minimalEnv defensive compose (BLOCKER #1+#2 lineage — kept stable) > legitimate extra key passes + fixed PATH keeps execPath prepend (issue #301) [0.15ms]
(pass) minimalEnv defensive compose (BLOCKER #1+#2 lineage — kept stable) > THROWS on reserved key in extra (LD_PRELOAD smuggled by attacker) [0.21ms]
(pass) minimalEnv defensive compose (BLOCKER #1+#2 lineage — kept stable) > THROWS on fixed key in extra (PATH smuggled — caller cannot override the trust-root execPath prepend) [0.13ms]
(pass) minimalEnv defensive compose (BLOCKER #1+#2 lineage — kept stable) > C1 invariant — issue #301 fix does NOT widen attacker surface: PATH source is process.execPath (daemon's already-resolved node), NOT env.PATH (attacker C1 surface) [0.34ms]
(pass) FAIL_FAST_MS primitive — real subprocess kill-0 lifecycle > child that exits within window → process.kill(pid, 0) raises ESRCH after wait [503.51ms]
(pass) FAIL_FAST_MS primitive — real subprocess kill-0 lifecycle > child that survives window → process.kill(pid, 0) succeeds [201.96ms]
(pass) RFC-027 BLOCKER-1 — childrenMap key shape matches hub canonical node_id > derive key from request_id, not alias [0.18ms]
(pass) RFC-027 BLOCKER-1 — childrenMap key shape matches hub canonical node_id > recordSpawnedChild end-to-end with the canonical key — stop-daemon can find it [9.44ms]

src/runtime/claude-native-binary.test.ts:
(pass) Claude native binary version pin > uses a directly exported package manifest when available [0.38ms]
(pass) Claude native binary version pin > walks from the resolved entrypoint when package exports hide package.json [0.37ms]
(pass) Claude native binary version pin > fails closed instead of installing latest when the SDK cannot be attested [0.18ms]
(pass) Claude native binary version pin > missing-binary fallback invokes npm with the installed SDK exact version [0.31ms]

src/runtime/stop-daemon.test.ts:
(pass) recordSpawnedChild + map shape > records + snapshot returns entry [0.38ms]
(pass) recordSpawnedChild + map shape > re-record overwrites pid [0.20ms]
(pass) handleStopDoorbell — noop_not_my_child > unknown child_node_id → degraded ack (not error) [1.52ms]
/bin/sh: 1: pgrep: not found
(pass) handleStopDoorbell — happy stop (SIGTERM-reaped quickly) > child reaped after SIGTERM → ack stopped + SIGTERM signal recorded [5.75ms]
/bin/sh: 1: pgrep: not found
(pass) handleStopDoorbell — SIGKILL escalation > child ignores SIGTERM → grace exceeded → SIGKILL → ack stopped w/ SIGKILL [37.25ms]
/bin/sh: 1: pgrep: not found
(pass) handleStopDoorbell — delete action with delete_config > mv child workdir to ~/.anet/deleted/<ts>-<alias>/ + chmod 700 + ack backup_path [2.96ms]
/bin/sh: 1: pgrep: not found
(pass) handleStopDoorbell — delete action with delete_config > delete_config=false → no backup dir, no source move [2.28ms]
(pass) handleStopDoorbell — real subprocess primitive (no mocks) > real subprocess: SIGTERM kills + kill-0 ESRCH after [303.22ms]
(pass) rebuildChildrenMapOnBoot (RFC-027 PR1.1) > happy: hub returns 2 children + each has unique matching pid → both recovered [2.75ms]
(pass) rebuildChildrenMapOnBoot (RFC-027 PR1.1) > alias substring collision: pgrep finds 'bot2' for alias 'bot' but cmdline argv exact-match rejects [1.37ms]
(pass) rebuildChildrenMapOnBoot (RFC-027 PR1.1) > zombie pid skipped (state=Z) [0.62ms]
(pass) rebuildChildrenMapOnBoot (RFC-027 PR1.1) > ambiguous: multiple verified pids → skipped (operator intervention) [0.68ms]
(pass) rebuildChildrenMapOnBoot (RFC-027 PR1.1) > hub-active but pgrep finds nothing → missing (warn, don't auto-nudge) [0.71ms]
(pass) rebuildChildrenMapOnBoot (RFC-027 PR1.1) > daemon's own pid is excluded from candidates [0.48ms]
(pass) rebuildChildrenMapOnBoot (RFC-027 PR1.1) > list_my_children failure → safe empty result (no throw, no map mutation) [0.52ms]
(pass) rebuildChildrenMapOnBoot — real subprocess primitive (no pgrep mocks, no proc mocks) > matcher accepts a real subprocess whose argv contains --alias <token> [203.24ms]

src/runtime/claude-error-classify.test.ts:
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > HTTP 429 standalone [0.23ms]
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > HTTP 529 overloaded (Anthropic spec) [0.09ms]
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > rate_limit_exceeded (Anthropic / OpenAI shape) [0.05ms]
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > rate-limit hyphen variant [0.04ms]
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > rate limit space variant [0.04ms]
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > quota exceeded phrase [0.03ms]
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > quota exhausted phrase [0.03ms]
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > Anthropic spec overloaded_error [0.03ms]
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > plain overloaded mention [0.04ms]
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > too_many_requests OpenAI-compat [0.04ms]
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > too many requests space form [0.05ms]
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > insufficient_quota OpenAI shape [0.03ms]
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > usage_limit hit [0.03ms]
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > MiniMax Chinese Token Plan 上限 [0.14ms]
(pass) isRateLimitOrQuotaError — POSITIVE (must classify as quota/rate-limit) > capacity exceeded vendor message [0.05ms]
(pass) isRateLimitOrQuotaError — NEGATIVE (regression gate, must NOT match) > 401 unauthorized (auth, not quota) [0.03ms]
(pass) isRateLimitOrQuotaError — NEGATIVE (regression gate, must NOT match) > 403 forbidden (auth, not quota) [0.03ms]
(pass) isRateLimitOrQuotaError — NEGATIVE (regression gate, must NOT match) > plain timeout (not quota) [0.03ms]
(pass) isRateLimitOrQuotaError — NEGATIVE (regression gate, must NOT match) > 400 bad request (not quota) [0.03ms]
(pass) isRateLimitOrQuotaError — NEGATIVE (regression gate, must NOT match) > 499 client closed (not quota) [0.02ms]
(pass) isRateLimitOrQuotaError — NEGATIVE (regression gate, must NOT match) > ETIMEDOUT network error (not quota) [0.03ms]
(pass) isRateLimitOrQuotaError — NEGATIVE (regression gate, must NOT match) > HTTP 4290 not a real status (avoid false positive on substring) [0.04ms]
(pass) isRateLimitOrQuotaError — NEGATIVE (regression gate, must NOT match) > empty string [0.04ms]
(pass) isRateLimitOrQuotaError — NEGATIVE (regression gate, must NOT match) > null / undefined [0.03ms]
(pass) isEmptyResultSoftFailure — POSITIVE (must flag as empty-vendor-reply) > result null + output_tokens 0 [0.12ms]
(pass) isEmptyResultSoftFailure — POSITIVE (must flag as empty-vendor-reply) > result undefined (M3 incident shape) [0.04ms]
(pass) isEmptyResultSoftFailure — POSITIVE (must flag as empty-vendor-reply) > result empty string but usage non-zero [0.04ms]
(pass) isEmptyResultSoftFailure — POSITIVE (must flag as empty-vendor-reply) > result has text but output_tokens 0 (suspicious) [0.03ms]
(pass) isEmptyResultSoftFailure — POSITIVE (must flag as empty-vendor-reply) > usage missing entirely (defaulting to 1 = non-zero) but result empty [0.03ms]
(pass) isEmptyResultSoftFailure — NEGATIVE (regression gate, normal success) > normal success — result + non-zero tokens [0.04ms]
(pass) isEmptyResultSoftFailure — NEGATIVE (regression gate, normal success) > short single-char reply still counts as success [0.03ms]
(pass) isEmptyResultSoftFailure — NEGATIVE (regression gate, normal success) > usage entirely missing but result non-empty [0.03ms]
(pass) quotaRemediationHint — vendor URL routing > intern-ai routing [0.08ms]
(pass) quotaRemediationHint — vendor URL routing > minimax routing [0.14ms]
(pass) quotaRemediationHint — vendor URL routing > deepseek routing [0.06ms]
(pass) quotaRemediationHint — vendor URL routing > anthropic-native routing [0.05ms]
(pass) quotaRemediationHint — vendor URL routing > unknown vendor falls back to generic hint [0.11ms]
(pass) quotaRemediationHint — vendor URL routing > empty / undefined → generic [0.06ms]

src/runtime/grok-build-cli.test.ts:
(pass) buildGrokCliArgs > rejects an older Grok CLI before it can ignore required safety flags [0.46ms]
(pass) buildGrokCliArgs > uses streaming headless mode and resumes an existing session [0.34ms]
(pass) buildGrokCliArgs > fails closed instead of auto-approving when permission bypass is disabled [0.11ms]
(pass) buildGrokCliArgs > maps an explicit node tool allowlist and keeps MCP unavailable [0.20ms]
(pass) buildGrokCliArgs > intersects explicit tools with the read-only set when auto-approval is off [0.14ms]
(pass) buildGrokCliArgs > rejects unknown node tool names instead of silently widening access [0.09ms]
(pass) buildGrokCliArgs > rejects an explicit empty tool allowlist instead of widening to all tools [0.08ms]
(pass) buildGrokCliArgs > denies model reads of runtime credential and node-state paths [0.13ms]
(pass) runGrokCliTurn > reports spawn submission before first exact JSONL event consumption [70.45ms]
(pass) runGrokCliTurn > reduces streaming JSON text and persists the end-event session [43.26ms]
(pass) runGrokCliTurn > spawns with exactly the projected environment and no ambient credentials [47.22ms]
(pass) runGrokCliTurn > keeps the production-shaped setpriv/sh launcher on the exact PWD-bound env [55.37ms]
(pass) runGrokCliTurn > refuses a shell launcher when PWD is missing from the reviewed env [0.94ms]
(pass) runGrokCliTurn > removes the prompt when spawn rejects a malformed allowed env value [1.27ms]
(pass) runGrokCliTurn > surfaces non-zero exits and stderr [44.68ms]
(pass) runGrokCliTurn > fails fast when headless Grok asks for an interactive login [47.49ms]
(pass) runGrokCliTurn > rejects cancelled turns [44.19ms]
(pass) runGrokCliTurn > rejects a formal error event even if the process exits zero [47.71ms]
(pass) runGrokCliTurn > rejects max-turn truncation instead of reporting a partial reply as success [46.20ms]
(pass) runGrokCliTurn > terminates the process group when the caller aborts [35.50ms]
(pass) runGrokCliTurn > kills a silent child after the idle timeout [37.46ms]
(pass) assertUnprivilegedUserNsUsable (#grok userns preflight) > passes when the probe succeeds [0.34ms]
(pass) assertUnprivilegedUserNsUsable (#grok userns preflight) > throws with the real stderr and an actionable next step when uid_map is refused [0.20ms]
(pass) assertUnprivilegedUserNsUsable (#grok userns preflight) > still throws when the probe fails with no stderr at all [0.28ms]
(pass) assertUnprivilegedUserNsUsable (#grok userns preflight) > honours a custom unshare binary path [0.12ms]

src/runtime/grok-child-env.test.ts:
(pass) Grok child environment boundary > builds the exact reviewed key set and drops every unreviewed credential [0.40ms]
(pass) Grok child environment boundary > re-projects a beforeSpawn result instead of trusting arbitrary keys [0.09ms]
(pass) Grok child environment boundary > rejects a beforeSpawn callback that changes a controlled value [1.27ms]
(pass) Grok child environment boundary > keeps the inherited list exact and reviewable [0.05ms]
(pass) Grok child environment boundary > keeps PTY PWD equal and adds only reviewed terminal/sandbox controls [0.51ms]
(pass) Grok child environment boundary > builds the narrower helper environment from an empty object [0.21ms]
(pass) Windows home isolation > redirects every Windows home variable at the isolated home [0.28ms]
(pass) Windows home isolation > leaves Linux untouched — no Windows-only keys leak into a POSIX child [0.12ms]

src/runtime/node-id-source.test.ts:
(pass) resolveNodeIdSource > configured identity wins over a polluted supervisor env [0.29ms]
(pass) resolveNodeIdSource > matching launcher env is accepted without a warning [0.05ms]
(pass) resolveNodeIdSource > legacy config without node_id keeps the env fallback [0.03ms]
(pass) resolveNodeIdSource > missing identity remains empty [0.02ms]
(pass) resolveNodeIdSource > warning escapes control characters from inherited env [0.12ms]

src/runtime/inbox-drain-lane.test.ts:
(pass) inbox drain lanes > an informational lane drains while the work lane is busy [0.67ms]
(pass) inbox drain lanes > each lane remains serial [0.39ms]
(pass) inbox drain lanes > repeated wakeups for the same drain coalesce into one dirty rerun [0.45ms]
(pass) inbox drain lanes > a failed drain is reported and does not poison later retries [0.43ms]
(pass) inbox drain lanes > retry mode backs off and eventually completes the same drain [3.35ms]
(pass) inbox drain lanes > one failed inbox item does not starve later items in the same snapshot [0.45ms]
(pass) inbox drain lanes > ack-only retry does not duplicate the first notification or delay the second [3.31ms]

src/runtime/commhub-poll-compensator.test.ts:
(pass) CommHub durable poll compensation > bounds configured intervals [0.20ms]
(pass) CommHub durable poll compensation > normal SSE delivery and a later poll share task/client-request dedup [7.20ms]
(pass) CommHub durable poll compensation > node-supplied or malformed client_request_id cannot poison Dashboard dedup [4.07ms]
(pass) CommHub durable poll compensation > lost SSE is admitted by an idle poll exactly through the existing drain [2.25ms]
(pass) CommHub durable poll compensation > cursor is private, durable across restart, and prevents replay [4.22ms]
(pass) CommHub durable poll compensation > inbound lifecycle is monotonic and a completed task never reinjects [11.66ms]
(pass) CommHub durable poll compensation > terminal outbound status missed by SSE is surfaced once across restart [12.91ms]
(pass) CommHub durable poll compensation > monotonic terminal watermark garbage-collects more than 2000 delivered rows without replay [7809.55ms]
(pass) CommHub durable poll compensation > terminal sequence handles out-of-order completion independent of task creation order [10.39ms]
(pass) CommHub durable poll compensation > expired cross-process lease retries the same stable key after simulated crash [9.05ms]
(pass) CommHub durable poll compensation > callback failure returns durable delivery to pending and retries the same idempotency key [12.10ms]
(pass) CommHub durable poll compensation > two poller processes share a delivery lease and invoke one callback [20.63ms]
(pass) CommHub durable poll compensation > concurrent triggers coalesce and backoff remains bounded [1.03ms]
(pass) CommHub durable poll compensation > old Hub visibly degrades to realtime-only instead of claiming polling [0.54ms]
(pass) CommHub durable poll compensation > non-terminal outbound states are not surfaced [2.41ms]
(pass) CommHub durable poll compensation > production wiring keeps SSE primary and routes poll wakes through the existing drain [1.77ms]
(pass) CommHub durable poll compensation > production dedup imports the authenticated Dashboard provenance gate [0.21ms]
(pass) CommHub durable poll compensation > production records the durable cursor only after Hub ACK succeeds [1.05ms]

src/runtime/codex-app-server-client.test.ts:
(pass) CodexAppServerClient — dispatch correctness (RFC-030 §7 + bug fix) > reverse request (method + id) routes to `reverse_request`, NOT orphan_response [14.09ms]
(pass) CodexAppServerClient — dispatch correctness (RFC-030 §7 + bug fix) > reverse request also fires `reverse:<method>` targeted event [10.25ms]
(pass) CodexAppServerClient — dispatch correctness (RFC-030 §7 + bug fix) > notification (method + no id) routes to method-keyed event [8.65ms]
(pass) CodexAppServerClient — dispatch correctness (RFC-030 §7 + bug fix) > response (id + result) resolves the matching pending request [11.01ms]
(pass) CodexAppServerClient — dispatch correctness (RFC-030 §7 + bug fix) > response (id + error) rejects with codex-formatted Error [9.13ms]
(pass) CodexAppServerClient — dispatch correctness (RFC-030 §7 + bug fix) > orphan response (id present, no matching pending) fires `orphan_response` [10.49ms]
(pass) CodexAppServerClient — dispatch correctness (RFC-030 §7 + bug fix) > malformed messages fire `malformed` [8.94ms]
(pass) CodexAppServerClient — dispatch correctness (RFC-030 §7 + bug fix) > parse errors on non-JSON payload fire `parse_error` [10.96ms]
(pass) CodexAppServerClient — dispatch correctness (RFC-030 §7 + bug fix) > request timeout rejects the pending promise and cleans up the entry [45.50ms]
(pass) CodexAppServerClient — dispatch correctness (RFC-030 §7 + bug fix) > close rejects any in-flight request cleanly (no unhandled rejection) [4.09ms]
(pass) CodexAppServerClient — dispatch correctness (RFC-030 §7 + bug fix) > respondToReverseRequest emits a well-formed response envelope [13.08ms]
(pass) CodexAppServerClient — dispatch correctness (RFC-030 §7 + bug fix) > errorReverseRequest emits a JSON-RPC error envelope [10.89ms]
(pass) CodexAppServerClient — dead shared endpoint diagnostics (#455) > wraps an empty TypeError with endpoint and remediation [0.67ms]
(pass) CodexAppServerClient — dead shared endpoint diagnostics (#455) > scrubs nested causes and bearer credentials independently of runtime shape [0.27ms]
(pass) CodexAppServerClient — dead shared endpoint diagnostics (#455) > synchronous WebSocket constructor failure uses the same safe boundary [0.54ms]
(pass) CodexAppServerClient — dead shared endpoint diagnostics (#455) > real dead loopback with query credential rejects/emits without leaking it [1.28ms]

src/runtime/delegation-precheck.test.ts:
(pass) delegationTargetExists > imperative happy path — real other session is found [0.18ms]
(pass) delegationTargetExists > #230 — descriptive-text false positive no longer self-reflects [0.08ms]
(pass) delegationTargetExists > self-only match — only the calling node has this alias [0.05ms]
(pass) delegationTargetExists > typo alias — caller meant a real agent but mistyped [0.05ms]
(pass) delegationTargetExists > empty sessions array → empty_sessions [0.09ms]
(pass) delegationTargetExists > missing sessions field (caller did not destructure correctly) → no_sessions_field [0.07ms]
(pass) delegationTargetExists > empty target alias is defensively reported as not_in_sessions [0.05ms]
(pass) delegationTargetExists > whitespace padding is trimmed before comparison [0.06ms]
(pass) delegationTargetExists > sessions with missing / non-string alias fields are skipped without throwing [0.06ms]

src/runtime/classify-result.test.ts:
(pass) classifyRuntimeResult — error precedence > quota error msg → soft-fail-quota (highest precedence) [0.09ms]
(pass) classifyRuntimeResult — error precedence > non-quota error → hard error [0.12ms]
(pass) classifyRuntimeResult — error precedence > auth error msg (401) → hard error (NOT quota — auth has its own path) [0.05ms]
(pass) classifyRuntimeResult — error precedence > error msg outranks empty result (don't double-classify) [0.04ms]
(pass) classifyRuntimeResult — in=0 & out=0 & cost=0 silent reject > all three zero → soft-fail-empty (even when result text present) [0.08ms]
(pass) classifyRuntimeResult — in=0 & out=0 & cost=0 silent reject > in=0 & out=0 but cost field MISSING + non-empty result → success (codex usage unreliable) [0.08ms]
(pass) classifyRuntimeResult — in=0 & out=0 & cost=0 silent reject > in=0 & cost=0 but out>0 → NOT silent reject (vendor returned something) [0.05ms]
(pass) classifyRuntimeResult — in=0 & out=0 & cost=0 silent reject > normal turn (all signals positive) → success [0.04ms]
(pass) classifyRuntimeResult — in=0 & out=0 & cost=0 silent reject > non-empty result + output_tokens=0 + cost missing → success (codex false-positive guard) [0.04ms]
(pass) classifyRuntimeResult — empty-result rule (strict) > empty string result + non-zero tokens → soft-fail-empty [0.05ms]
(pass) classifyRuntimeResult — empty-result rule (strict) > null result + non-zero tokens → soft-fail-empty [0.06ms]
(pass) classifyRuntimeResult — empty-result rule (strict) > undefined result, missing usage → soft-fail-empty (empty result alone is enough) [0.04ms]
(pass) classifyRuntimeResult — empty-result rule (strict) > single-char '0' result + tokens → success (not empty) [0.05ms]
(pass) classifyRuntimeResult — empty-result rule (strict) > result text present + missing usage → success (don't penalise unreported usage) [0.04ms]
(pass) classifyRuntimeResult — empty-result rule (strict) > empty string result + cost present + tokens → soft-fail-empty (text emptiness is the signal) [0.05ms]
(pass) classifyRuntimeResult — vendor hint routing via baseUrl > quota error with deepseek baseUrl → deepseek dashboard hint [0.06ms]
(pass) classifyRuntimeResult — vendor hint routing via baseUrl > quota error with intern baseUrl → intern hint [0.07ms]
(pass) classifyRuntimeResult — vendor hint routing via baseUrl > empty result with anthropic baseUrl → anthropic hint [0.08ms]
(pass) classifyRuntimeResult — vendor hint routing via baseUrl > missing baseUrl → generic hint [0.05ms]
(pass) formatClassificationError — message shape (parsed by IM bridge) > soft-fail-quota → 执行出错: [额度用尽][<code>] <runtime>: <body> — <hint> [0.62ms]
(pass) formatClassificationError — message shape (parsed by IM bridge) > soft-fail-empty → 执行出错: <runtime> 返回空响应 with in/out [0.11ms]
(pass) formatClassificationError — message shape (parsed by IM bridge) > error kind → 执行出错: <runtime> — <reason> [0.08ms]
(pass) formatClassificationError — message shape (parsed by IM bridge) > success kind → empty string (caller should not call this; defensive) [0.04ms]
(pass) formatClassificationError — message shape (parsed by IM bridge) > missing usage in context → in=0 out=0 fallback [0.05ms]
(pass) formatClassificationError — message shape (parsed by IM bridge) > missing hint on quota → no trailing dash artifact [0.08ms]
(pass) formatClassificationError — message shape (parsed by IM bridge) > reason longer than 80 chars is truncated on quota path [0.07ms]

src/runtime/codex-app-server-bridge.test.ts:
(pass) CodexAppServerBridge — bootstrap + task mapping > bootstrap sends initialize + initialized + thread/resume in order [6.84ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > empty threadId → bootstrap creates a thread (thread/start) and adopts its id [6.94ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > stale threadId with no rollout → resume fails, bootstrap falls back to thread/start [6.01ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > startTaskTurn returns the server-assigned turnId and marks bridge working [5.06ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > turn/completed for OUR turn fires task_reply mapped back to the task_id [16.06ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > only exact owned-turn item events emit task_activity [16.01ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > authenticated Dashboard native /goal text reaches the shared thread unchanged and replies [17.20ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > clientUserMessageId rebinds a task when a goal successor replaces the turn/start response id [54.34ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > client-id ownership observed before the RPC response wins without reversing task event order [26.88ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > real bridge + runtime bounds a deferred terminal when exact client identity never arrives [34.70ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > real bridge + runtime bounds an unresolved turn/start through the left-FIFO fallback [61.81ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > agentMessage/delta accumulates when server omits finalText [15.11ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > turn/completed for a HUMAN-TUI-initiated turn is dropped (§7.5) [13.90ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > events for a DIFFERENT thread are dropped (defense in depth) [16.60ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > startTaskTurn refuses a second task while one is active [7.86ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > turn/completed with an error field fires task_error, NOT task_reply [17.70ms]
(pass) CodexAppServerBridge — bootstrap + task mapping > turn/completed with interrupted status cannot become a successful reply [16.22ms]
(pass) CodexAppServerBridge — approvals (waiting_human) §7.6 > reverse-request approval records waiting_human and sends NO response [17.30ms]
(pass) CodexAppServerBridge — approvals (waiting_human) §7.6 > serverRequest/resolved clears waiting_human and status recovers [27.86ms]
(pass) CodexAppServerBridge — approvals (waiting_human) §7.6 > multiple concurrent approvals: bridge stays waiting_human until all resolve [37.92ms]
(pass) CodexAppServerBridge — two-client race for idle > only one bridge wins turn/start; the other observes and does not reply [22.67ms]
(pass) CodexAppServerBridge — authenticated Dashboard steering > reconnect recovers an active human turn and keeps it steerable [6.71ms]
(pass) CodexAppServerBridge — authenticated Dashboard steering > reconnect provenance keeps an orphaned network turn FIFO-only [26.55ms]
(pass) CodexAppServerBridge — authenticated Dashboard steering > reconnect provenance ignores leading whitespace before the network prefix [5.84ms]
(pass) CodexAppServerBridge — authenticated Dashboard steering > reconnect stays FIFO-only when real-wire active history omits userMessage [4.07ms]
(pass) CodexAppServerBridge — authenticated Dashboard steering > uses exact turn/steer contract and maps the human turn final answer [28.64ms]
(pass) CodexAppServerBridge — authenticated Dashboard steering > multiple Dashboard rows steer one human turn while ordinary agent work stays queued [39.36ms]
(pass) CodexAppServerBridge — authenticated Dashboard steering > steer mismatch fails closed and preserves the task in the normal FIFO [38.70ms]
(pass) CodexAppServerBridge — authenticated Dashboard steering > turn completion cannot attribute a task before turn/steer acceptance [40.98ms]
(pass) CodexAppServerBridge — authenticated Dashboard steering > reconciliation recovers a missed human turn completion and exact steered reply [18.14ms]
(pass) CodexAppServerBridge — sync claim + FIFO queue (通信龙) > concurrent startTaskTurn: exactly ONE turn/start reaches the server even with a slow response [56.67ms]
(pass) CodexAppServerBridge — sync claim + FIFO queue (通信龙) > submitTask queues the second task and drains it after turn/completed (order preserved) [117.90ms]
(pass) CodexAppServerBridge — sync claim + FIFO queue (通信龙) > cancelQueuedTask removes only the named FIFO row before it can execute [57.20ms]
(pass) CodexAppServerBridge — sync claim + FIFO queue (通信龙) > thread/read recovers a completed owned turn while a successor keeps the thread active [108.01ms]
(pass) CodexAppServerBridge — sync claim + FIFO queue (通信龙) > thread/read uses clientUserMessageId to recover a replacement turn when all live item events were lost [5.50ms]
(pass) CodexAppServerBridge — sync claim + FIFO queue (通信龙) > slow full-history fallback recovers when both terminal and successor notifications are lost [4.74ms]
(pass) CodexAppServerBridge — sync claim + FIFO queue (通信龙) > full history never attributes a different completed turn to the owned task [4.73ms]
(pass) CodexAppServerBridge — sync claim + FIFO queue (通信龙) > thread/read never recovers an interrupted turn as success [5.04ms]
(pass) CodexAppServerBridge — sync claim + FIFO queue (通信龙) > drain losing the idle race requeues at the FRONT and retries on next idle [169.01ms]

src/runtime/probe-daemon.test.ts:
(pass) createPinnedLookup — Node/Bun lookup callback contract > single-address callback honors requested family [0.54ms]
(pass) createPinnedLookup — Node/Bun lookup callback contract > all-address callback returns only pinned copies [0.25ms]
(pass) createPinnedLookup — Node/Bun lookup callback contract > wrong hostname and unavailable family fail closed without fallback [0.36ms]
(pass) assertSecureTlsEnv (boot guard) > clean env passes [0.10ms]
(pass) assertSecureTlsEnv (boot guard) > NODE_TLS_REJECT_UNAUTHORIZED=0 throws [0.15ms]
(pass) classifyProbeResponse — status enum mapping > 200 → ok [0.18ms]
(pass) classifyProbeResponse — status enum mapping > 401 → auth_fail [0.05ms]
(pass) classifyProbeResponse — status enum mapping > 403 → auth_fail [0.03ms]
(pass) classifyProbeResponse — status enum mapping > 429 → quota [0.05ms]
(pass) classifyProbeResponse — status enum mapping > 500 → vendor_5xx [0.03ms]
(pass) classifyProbeResponse — status enum mapping > 404 → other_4xx [0.03ms]
(pass) classifyProbeResponse — status enum mapping > errorKind=redirect_forbidden surfaces directly [0.04ms]
(pass) classifyProbeResponse — status enum mapping > errorKind=timeout surfaces [0.03ms]
(pass) classifyProbeResponse — status enum mapping > errorKind=probe_resolve_unsafe_ip → returned status string passes through [0.05ms]
(pass) classifyProbeResponse — status enum mapping > ack has NO error_message / response_body / url fields (zod whitelist on hub side will reject; we just don't include) [0.09ms]
(pass) safelyFetchProbe — SSRF guards (per 通信龙 spot-check c) > base_url with private IP literal (169.254.169.254) → probe_resolve_unsafe_ip [1.48ms]
(pass) safelyFetchProbe — SSRF guards (per 通信龙 spot-check c) > base_url with private IP literal (10.0.0.1) → probe_resolve_unsafe_ip [0.19ms]
(pass) safelyFetchProbe — SSRF guards (per 通信龙 spot-check c) > base_url with localhost without ALLOW_LOOPBACK env → probe_resolve_unsafe_ip [0.14ms]
(pass) safelyFetchProbe — SSRF guards (per 通信龙 spot-check c) > base_url with localhost WITH ALLOW_LOOPBACK env → permitted to proceed (will fail on real network but not on IP guard) [5.27ms]
(pass) safelyFetchProbe — SSRF guards (per 通信龙 spot-check c) > NODE_TLS_REJECT_UNAUTHORIZED=0 → tls_error before any fetch [0.13ms]
(pass) handleProbeDoorbell — daemon validateBaseUrl re-check (compromised-hub defense) > non-allowlist host for anthropic → daemon-level reject + ack probe_target_forbidden, no fetch [1.33ms]
(pass) handleProbeDoorbell — daemon validateBaseUrl re-check (compromised-hub defense) > unknown vendor → daemon rejects, ack probe_target_forbidden [0.30ms]
(pass) handleProbeDoorbell — daemon validateBaseUrl re-check (compromised-hub defense) > bad URL (not parseable) → daemon rejects, ack probe_target_forbidden [0.32ms]
(pass) handleProbeDoorbell — daemon validateBaseUrl re-check (compromised-hub defense) > plain HTTP scheme on non-loopback host → daemon rejects, ack probe_target_forbidden [0.29ms]
(pass) handleProbeDoorbell — daemon validateBaseUrl re-check (compromised-hub defense) > get_probe_request returns ok:false → no ack pushed (hub sweeper handles) [0.27ms]

src/runtime/current-alias.test.ts:
(pass) CurrentAliasResolver — startup snapshot > current() returns the initial alias before any refresh() [0.24ms]
(pass) CurrentAliasResolver — startup snapshot > ageMs() reports Infinity before first fetch (cache is cold) [0.14ms]
(pass) CurrentAliasResolver — refresh() cache behaviour > warm cache short-circuits — no fetch fired within TTL [0.53ms]
(pass) CurrentAliasResolver — refresh() cache behaviour > expired cache hits the server and updates the alias + fires onDrift [0.42ms]
(pass) CurrentAliasResolver — refresh() cache behaviour > concurrent refresh() calls dedupe onto one fetch [10.65ms]
(pass) CurrentAliasResolver — graceful fetch failure > fetch throwing keeps the cached value and emits a warn [0.56ms]
(pass) CurrentAliasResolver — graceful fetch failure > fetch returning null is treated as 'server does not know yet' [0.23ms]
(pass) CurrentAliasResolver — graceful fetch failure > fetch returning empty string is also treated as 'server does not know' [0.27ms]
(pass) CurrentAliasResolver — graceful fetch failure > after a failed fetch the cache timestamp still bumps — no hammering [0.35ms]
(pass) CurrentAliasResolver — set() force install > set() updates the alias and fires onDrift with source 'snapshot' [0.25ms]
(pass) CurrentAliasResolver — set() force install > set() with the same value is a no-op (no drift event, but cache timestamp bumps) [0.09ms]
(pass) CurrentAliasResolver — set() force install > set('') is ignored (defends against caller forgetting to validate) [0.06ms]
(pass) CurrentAliasResolver — edge cases > nodeId = null short-circuits refresh() and never calls the fetch hook [0.23ms]
(pass) CurrentAliasResolver — edge cases > cacheTtlMs = 0 disables caching — every refresh() fetches [0.22ms]
(pass) CurrentAliasResolver — edge cases > ageMs() reflects elapsed time after a refresh [0.19ms]

src/runtime/feishu-outbound-dir.test.ts:
(pass) Feishu legacy outbound directory > prefers the canonical worker value verbatim [0.13ms]
(pass) Feishu legacy outbound directory > reconstructs a legacy envelope from the explicit channel binding [0.09ms]
(pass) Feishu legacy outbound directory > does not consult a stale ambient node alias [0.11ms]
(pass) Feishu legacy outbound directory > passes the same explicit binding name to the worker [0.09ms]

src/runtime/deleted-sweeper.test.ts:
(pass) RFC-027 §5.2 K — sweeper purges 30d+ backups (physical delete, no soft state) > backup older than RETENTION_MS → physically removed [1.32ms]
(pass) RFC-027 §5.2 K — sweeper purges 30d+ backups (physical delete, no soft state) > backup younger than 30d → KEPT [0.63ms]
(pass) RFC-027 §5.2 K — sweeper purges 30d+ backups (physical delete, no soft state) > mixed: 2 old + 1 recent → only the 2 olds purged [0.84ms]
(pass) sweeper safety invariants (D7 nit) > skips dir names that don't match <ts>-<alias> pattern (no accidental purge) [0.49ms]
(pass) sweeper safety invariants (D7 nit) > log function receives ONLY the dir name — never any inner file path [0.57ms]
(pass) sweeper safety invariants (D7 nit) > dir-listing error (deletedRoot missing) → returns clean empty result, no throw [0.46ms]
[deleted-sweeper] failed to purge 1785146210199-bad: simulated EACCES
(pass) sweeper safety invariants (D7 nit) > rmDir throw → counted as error, sweep continues for siblings [0.97ms]

src/runtime/config-apply.test.ts:
(pass) RESTART_SENTINEL — exact value pin > equals 75 (BSD EX_TEMPFAIL semantics, parent supervisor checks this exact code) [0.39ms]
(pass) #633 private text writer > replaces a leaf symlink without following it [2.68ms]
(pass) validateLocalPatch — defense-in-depth > undefined model + empty flags passes (no-op patch) [0.57ms]
(pass) validateLocalPatch — defense-in-depth > valid full patch passes [0.24ms]
(pass) validateLocalPatch — defense-in-depth > unknown flag rejected (even if hub validator drifts loose) [0.22ms]
(pass) validateLocalPatch — defense-in-depth > permissionMode invalid enum rejected [0.22ms]
(pass) validateLocalPatch — defense-in-depth > dangerouslySkipPermissions non-boolean rejected [0.25ms]
(pass) validateLocalPatch — defense-in-depth > maxTurns out of range rejected [0.21ms]
(pass) validateLocalPatch — defense-in-depth > timeout invalid rejected [0.20ms]
(pass) validateLocalPatch — defense-in-depth > empty-string model rejected [0.18ms]
(pass) computeApplyMode — tier classifier > empty patch → restart_only (restart_node) [0.31ms]
(pass) computeApplyMode — tier classifier > model only → restart [0.18ms]
(pass) computeApplyMode — tier classifier > permissionMode → restart [0.19ms]
(pass) computeApplyMode — tier classifier > dangerouslySkipPermissions → restart [0.18ms]
(pass) computeApplyMode — tier classifier > teammateMode no longer in allowlist → ignored by classifier (returns hot since no restart-required flag matches) [0.18ms]
(pass) computeApplyMode — tier classifier > timeout → restart [0.22ms]
(pass) computeApplyMode — tier classifier > maxTurns only → hot [0.19ms]
(pass) computeApplyMode — tier classifier > budget only → hot [0.17ms]
(pass) computeApplyMode — tier classifier > mixed (model + maxTurns) → restart (strictest wins) [0.19ms]
(pass) atomicWriteJson — temp + rename > creates file with JSON content + trailing newline [2.13ms]
(pass) atomicWriteJson — temp + rename > overwrites existing file atomically (no .tmp left behind) [2.31ms]
(pass) #472 private config permissions > atomic write is 0600 under umask 0 [2.39ms]
(pass) #472 private config permissions > atomic write is 0600 under umask 2 [2.10ms]
(pass) #472 private config permissions > atomic write is 0600 under umask 22 [2.17ms]
(pass) #472 private config permissions > atomic write is 0600 under umask 77 [2.14ms]
(pass) #472 private config permissions > repairs existing primary, backup, and parent before token read [0.75ms]
(pass) #472 private config permissions > custom --config parent is never chmodded [0.45ms]
(pass) #472 private config permissions > atomic custom --config write preserves parent mode [2.41ms]
(pass) #472 private config permissions > backup atomically replaces a legacy broad .prev [2.34ms]
(pass) backupConfigPrev — pre-write snapshot > copies existing config to .prev [2.66ms]
(pass) backupConfigPrev — pre-write snapshot > returns backedUp=false when no config exists yet (first-write case) [0.30ms]
(pass) backupConfigPrev — pre-write snapshot > overwrites previous .prev (single-generation rotation) [3.84ms]
(pass) loadConfigWithSelfHeal — boot recovery > primary parses → returns primary [0.53ms]
(pass) loadConfigWithSelfHeal — boot recovery > primary corrupted + .prev valid → restores .prev + reports source=prev [2.58ms]
(pass) loadConfigWithSelfHeal — boot recovery > primary corrupted + no .prev → throws (truly bricked, caller surfaces) [0.47ms]
(pass) loadConfigWithSelfHeal — boot recovery > primary AND .prev corrupted → throws with both errors [0.57ms]
(pass) loadConfigWithSelfHeal — boot recovery > primary missing entirely → throws (caller will skip / first-boot path) [0.30ms]
(pass) mergePatch — patch + existing → new config (no mutation) > model replace [0.42ms]
(pass) mergePatch — patch + existing → new config (no mutation) > flags merge (does not replace whole flags obj) [0.24ms]
(pass) mergePatch — patch + existing → new config (no mutation) > empty existing + patch → patch only [0.21ms]
(pass) mergePatch — patch + existing → new config (no mutation) > empty patch → existing unchanged (deep clone) [0.21ms]
(pass) buildConfigSnapshot — pure helper contract (#290 final, drain-omit guard) > buildConfigSnapshot returns a valid snapshot regardless of caller drain state (pure) [0.58ms]
(pass) validateLocalPatch — teammateMode dropped (#290 review) > teammateMode rejected (was: allowed boolean; now: not-in-allowlist) [0.25ms]
(pass) computeApplyMode — teammateMode is no longer restart-required (#290 review) > teammateMode-only patch → hot (no longer in RESTART_REQUIRED_FLAGS) [0.20ms]
(pass) buildConfigSnapshot — masked report (no secrets) > includes model + ALLOWED_FLAGS only [0.35ms]
(pass) buildConfigSnapshot — masked report (no secrets) > missing model → null (not undefined, dashboard renders explicitly) [0.22ms]
(pass) buildConfigSnapshot — masked report (no secrets) > config_update_capable=false signals bare node (no supervisor wrapper) [0.20ms]
(pass) buildConfigSnapshot — role (PR1 #338) > role: host_supervisor passes through (string) [0.21ms]
(pass) buildConfigSnapshot — role (PR1 #338) > role: member passes through [0.18ms]
(pass) buildConfigSnapshot — role (PR1 #338) > role: missing → null (not undefined; dashboard distinguishes) [0.20ms]
(pass) buildConfigSnapshot — role (PR1 #338) > role: non-string narrowed to null (typeof guard) [0.43ms]
(pass) buildConfigSnapshot — daemon_capabilities (PR3 #338 nit ①) > nests runtimes_supported + allowed_secret_keys + max_concurrent_children [0.28ms]
(pass) buildConfigSnapshot — daemon_capabilities (PR3 #338 nit ①) > matches hub canonical path snap.daemon_capabilities.* — NOT at top level [0.44ms]
(pass) buildConfigSnapshot — daemon_capabilities (PR3 #338 nit ①) > partial declare: only runtimes_supported emits, others omitted [0.21ms]
(pass) buildConfigSnapshot — daemon_capabilities (PR3 #338 nit ①) > missing → daemon_capabilities undefined (regular non-daemon node) [0.18ms]
(pass) buildConfigSnapshot — daemon_capabilities (PR3 #338 nit ①) > typeof narrow: non-array runtimes_supported dropped silently [0.26ms]
(pass) buildConfigSnapshot — daemon_capabilities (PR3 #338 nit ①) > typeof narrow: array with non-string element dropped silently [0.23ms]
(pass) buildConfigSnapshot — daemon_capabilities (PR3 #338 nit ①) > typeof narrow: max_concurrent_children non-finite or non-positive dropped [0.26ms]
(pass) buildConfigSnapshot — daemon_capabilities (PR3 #338 nit ①) > partial valid + partial invalid: only valid fields included [0.19ms]
(pass) channels — validateLocalPatch > valid keys pass [0.25ms]
(pass) channels — validateLocalPatch > commhub rejected — not a fork target (cli.ts:673 UNSUPPORTED_CHANNEL guard) [0.20ms]
(pass) channels — validateLocalPatch > unknown channel key rejected (defense-in-depth vs hub drift) [0.26ms]
(pass) channels — validateLocalPatch > non-array rejected [0.25ms]
(pass) channels — validateLocalPatch > non-string element rejected [0.31ms]
(pass) channels — validateLocalPatch > more than 16 entries rejected [0.29ms]
(pass) channels — computeApplyMode > channels-present patch is restart-tier [0.19ms]
(pass) channels — computeApplyMode > channels: [] still a state change → restart [0.17ms]
(pass) channels — computeApplyMode > channels + hot flag upgrades to restart [0.20ms]
(pass) channels — computeApplyMode > model + channels → restart [0.19ms]
(pass) channels — computeApplyMode > empty patch → restart_only [0.16ms]
(pass) channels — mergePatch replaces, does not merge > channels absent in patch: existing.channels preserved [0.24ms]
(pass) channels — mergePatch replaces, does not merge > channels present: existing.channels REPLACED wholesale [0.38ms]
(pass) channels — mergePatch replaces, does not merge > channels: [] disables all editable channels [0.21ms]
(pass) channels — mergePatch replaces, does not merge > first-write case (existing has no channels key) [0.22ms]
(pass) channels — mergePatch replaces, does not merge > defensive clone — patch mutation does not leak into merged [0.23ms]
(pass) mergePatch — path-qualified specs preserved > bare-type patch preserves existing telegram:/abs/path [0.27ms]
(pass) mergePatch — path-qualified specs preserved > bare-type patch keeps both when both were path-qualified [0.45ms]
(pass) mergePatch — path-qualified specs preserved > bare-type patch adds new bare key when existing had no matching spec [0.24ms]
(pass) mergePatch — path-qualified specs preserved > disable-all still works — empty patch wipes even path-qualified specs [0.26ms]
(pass) mergePatch — path-qualified specs preserved > first-write no existing channels: bare types stay bare [0.20ms]
(pass) buildConfigSnapshot — always emits channels for content-match finalize > empty config emits channels=[] [0.24ms]
(pass) buildConfigSnapshot — always emits channels for content-match finalize > bare-type list emitted verbatim + sorted [0.30ms]
(pass) buildConfigSnapshot — always emits channels for content-match finalize > path-qualified specs collapse to bare type [0.26ms]
(pass) buildConfigSnapshot — always emits channels for content-match finalize > dupes deduped, unparseable dropped [0.22ms]
(pass) buildConfigSnapshot — always emits channels for content-match finalize > non-array channels field yields [] [0.20ms]

src/runtime/codex-dep-loader.test.ts:
(pass) loadCodexSdk > returns the imported module without installing when already present [0.47ms]
(pass) loadCodexSdk > auto-installs and retries when the first import fails [0.52ms]
(pass) loadCodexSdk > throws a friendly multi-line error when install fails — includes pasteable npm command + module path + both root causes [0.71ms]
(pass) loadCodexSdk > install succeeds but post-install import still fails → terminal error names the install-then-resolve mismatch [0.39ms]
(pass) loadCodexSdk > module dir with shell metacharacters is single-quoted in the recovery hint [0.46ms]

src/runtime/create-node-daemon-private-wiring.test.ts:
(pass) #633 daemon secret writers all use the private atomic choke point [0.23ms]

src/runtime/grok-cli-deny-paths.test.ts:
(pass) grokCliDenyPaths > hides the two .anet directories, the node config, and project .mcp.json [0.16ms]
(pass) grokCliDenyPaths > keeps a placeholder when the node has no config file [0.07ms]
(pass) grokCliDenyPaths > 🔴 issue #885: the isolated GROK_HOME is NOT denied — this is the open gap [0.09ms]
(pass) cli.ts call sites > every denyPaths argument comes from grokCliDenyPaths [0.83ms]

src/runtime/grok-build-cli-home.test.ts:
(pass) prepareGrokCliHome > resolves the CommHub MCP command to one canonical executable [1.69ms]
(pass) prepareGrokCliHome > requires a real CommHub MCP doctor handshake and all three tools [0.69ms]
(pass) prepareGrokCliHome > derives an opaque path segment and rejects dot identities [0.33ms]
(pass) prepareGrokCliHome > accepts only the pinned Grok regular-file copy of source agent_id [6.34ms]
(pass) prepareGrokCliHome > isolates config/trust, preserves a shared auth path, and creates stable sandbox profiles [2.75ms]
(pass) prepareGrokCliHome > refuses broad-mode or symlinked source auth without repairing it [1.24ms]
(pass) prepareGrokCliHome > repairs an existing Grok session store to owner-only modes [2.37ms]
(pass) prepareGrokCliHome > does not follow a symlink while repairing an existing session store [1.39ms]
(pass) prepareGrokCliHome > keeps the post-stop cleanup policy exact and reviewable [0.17ms]
(pass) prepareGrokCliHome > removes exact empty read-only project placeholders before resume without admitting executable sources [4.66ms]
(pass) prepareGrokCliHome > validates every exact project placeholder before unlinking any sibling [1.42ms]
(pass) prepareGrokCliHome > does not let a fatal project counterexample starve independent state containment [2.30ms]
(pass) prepareGrokCliHome > preserves nonempty, linked, wrong-mode, and wrong-type project counterexamples [4.25ms]
(pass) prepareGrokCliHome > preserves real project extension directories and still rejects executable contents on resume [1.58ms]
(pass) prepareGrokCliHome > removes only exact transient state and hardens retained post-stop state [5.93ms]
(pass) prepareGrokCliHome > hardens only the native lock derived from the exact leader socket [1.30ms]
(pass) prepareGrokCliHome > retains a non-empty leader log and rejects post-stop link attacks [2.31ms]
(pass) prepareGrokCliHome > refuses a non-empty exact sandbox placeholder [1.23ms]
(pass) prepareGrokCliHome > reclaims an empty mode-000 sandbox marker under a foreign pid without aborting [1.26ms]
(pass) prepareGrokCliHome > keeps a non-empty foreign sandbox marker unreadable so it fails closed [1.92ms]
(pass) prepareGrokCliHome > validates exact TUI process ids before mutation and refuses a placeholder symlink [1.51ms]
(pass) prepareGrokCliHome > enables the single TUI leader only for explicit copresence mode [13.12ms]
(pass) prepareGrokCliHome > admits only canonical owner-held commhub MCP artifacts [3.70ms]
(pass) prepareGrokCliHome > rejects a shared auth path covered by a required sandbox deny before state mutation [0.66ms]
(pass) prepareGrokCliHome > refuses to claim sandbox isolation when no deny target exists [0.88ms]
(pass) prepareGrokCliHome > rejects a source GROK_HOME reached through an ancestor symlink before state mutation [0.85ms]
(pass) prepareGrokCliHome > removes runtime-owned native hooks before every turn [1.53ms]
(pass) prepareGrokCliHome > unlinks a runtime-owned hook symlink without touching its external target [1.42ms]
(pass) prepareGrokCliHome > fails closed when a project native hook path exists [0.72ms]
(pass) prepareGrokCliHome > trusts only the exact canonical nested cwd and atomically replaces stale grants [2.89ms]
(pass) prepareGrokCliHome > rejects broad or symlinked folder-trust targets before writing trust state [1.30ms]
(pass) prepareGrokCliHome > refuses a planted trust-store symlink and leaves its target untouched [1.70ms]
(pass) prepareGrokCliHome > rejects every project executable source before granting folder trust [10.83ms]
(pass) prepareGrokCliHome > does not impose the shared-folder strict policy on legacy headless mode [2.03ms]
(pass) prepareGrokCliHome > rejects repo-root hooks from a nested cwd and dangling hook links [0.89ms]
(pass) prepareGrokCliHome > rejects a symlinked project .grok directory [0.71ms]
(pass) prepareGrokCliHome > rejects symlinked isolated homes and generated state without changing targets [1.61ms]
(pass) prepareGrokCliHome > rejects a state-home path escape before chmod, removal, or writes [0.90ms]
(pass) prepareGrokCliHome > requires a valid zero-hook inspect response [0.53ms]
(pass) prepareGrokCliHome > flocks the canonical project inode across symlink aliases and releases cleanly [119.18ms]
(pass) prepareGrokCliHome > gives the real flock holder only the exact helper environment [60.53ms]
(pass) grok folder-trust breadth predicate > names $HOME and the filesystem root as over-broad, and nothing else [0.17ms]
(pass) grok folder-trust breadth predicate > refuses $HOME as a project cwd but accepts a real project directory [0.91ms]

src/goals/format.test.ts:
(pass) formatSelfLoopsBlock — empty / omit semantics > no goals + omitWhenEmpty=true (default) → empty string [0.22ms]
(pass) formatSelfLoopsBlock — empty / omit semantics > no goals + omitWhenEmpty=false → explicit '无活跃循环' block [0.09ms]
(pass) formatSelfLoopsBlock — empty / omit semantics > only terminal goals (cancelled/complete/failed) → empty (same as no goals) [0.20ms]
(pass) formatSelfLoopsBlock — content shape > single active goal: header + id8 + cadence + text [0.46ms]
(pass) formatSelfLoopsBlock — content shape > paused goals shown with status='paused' [0.16ms]
(pass) formatSelfLoopsBlock — content shape > mix active + paused + terminal → only active+paused appear [0.16ms]
(pass) formatSelfLoopsBlock — cron-lite cadence rendering > time_of_day cadence: '每天 09:00' [0.11ms]
(pass) formatSelfLoopsBlock — cron-lite cadence rendering > weekday cadence: 'mon/wed/fri 18:30' [0.11ms]
(pass) formatSelfLoopsBlock — cron-lite cadence rendering > new-format interval cadence renders same as legacy interval_ms [0.09ms]
(pass) formatSelfLoopsBlock — cap + truncation > more than maxGoals → truncates with '...' summary [0.38ms]
(pass) formatSelfLoopsBlock — cap + truncation > text is one-line truncated at 100 chars [0.14ms]
(pass) formatSelfLoopsBlock — cap + truncation > multi-line text is rendered as single line [0.15ms]
(pass) formatSelfLoopsBlock — relative time rendering > next_wake_at far in the future → ISO-shortened [0.13ms]
(pass) formatSelfLoopsBlock — relative time rendering > next_wake_at in past → '已到期' [0.10ms]
(pass) formatSelfLoopsBlock — relative time rendering > malformed ISO doesn't crash, falls back to raw [0.10ms]

src/goals/routing.test.ts:
(pass) shouldCreateScheduledGoal — Dashboard native slash pass-through > authenticated Dashboard /goal and /loop pass through for every agent-node runtime [0.19ms]
(pass) shouldCreateScheduledGoal — Dashboard native slash pass-through > authenticated Dashboard /agoal and /aloop always select the ANet scheduler [0.10ms]
(pass) shouldCreateScheduledGoal — Dashboard native slash pass-through > non-Dashboard traffic retains /goal and /loop during the compatibility window [0.29ms]
(pass) shouldCreateScheduledGoal — Dashboard native slash pass-through > Codex TUI /goal passes through even when Dashboard provenance is absent [0.15ms]
(pass) shouldCreateScheduledGoal — Dashboard native slash pass-through > Codex TUI keeps explicit ANet scheduling and legacy /loop compatibility [0.08ms]
(pass) shouldCreateScheduledGoal — Dashboard native slash pass-through > near matches and slash text away from the start never select the scheduler [0.11ms]
(pass) appendLegacyScheduledGoalNotice > non-Dashboard /goal and /loop replies carry a deterministic migration notice [0.12ms]
(pass) appendLegacyScheduledGoalNotice > new namespaced commands, Dashboard pass-through, and near matches are not warned [0.07ms]
(pass) appendLegacyScheduledGoalNotice > the migration notice is first so the outer reply cap cannot truncate it [0.11ms]
(pass) Dashboard native slash migration notice > interval-shaped /goal and /loop replies explain that ANet scheduling moved to /aloop [0.95ms]
(pass) Dashboard native slash migration notice > ordinary native commands, namespaced commands, and non-Dashboard paths are untouched [0.14ms]
(pass) Dashboard native slash migration notice > the notice survives low-value filtering and the outer reply cap [0.23ms]
(pass) Dashboard native slash migration notice > low-value filtering judges the notice-prefixed text, not the raw model reply [0.12ms]
(pass) Dashboard native slash migration notice > failed native replies still surface the migration notice and the failure [0.09ms]
(pass) reply filtering uses authenticated message provenance > a short presence reply to an authenticated Dashboard human task is delivered [0.10ms]
(pass) reply filtering uses authenticated message provenance > the same low-value class remains filtered for agent-to-agent tasks [0.19ms]
(pass) reply filtering uses authenticated message provenance > a provenance flag cannot bypass filtering for a non-task message type [0.09ms]

src/goals/loops-http-server.test.ts:
(pass) localhost binding (通信龙 hard constraint #1+#2) > server bound to 127.0.0.1, not 0.0.0.0 [7.98ms]
(pass) localhost binding (通信龙 hard constraint #1+#2) > port is reachable [9.61ms]
(pass) localhost binding (通信龙 hard constraint #1+#2) > random port (different runs get different ports) [4.93ms]
(pass) bearer auth no-bypass (通信龙 hard constraint #4) > missing Authorization header → 401 [5.08ms]
(pass) bearer auth no-bypass (通信龙 hard constraint #4) > wrong token → 401 [6.96ms]
(pass) bearer auth no-bypass (通信龙 hard constraint #4) > non-Bearer scheme → 401 [5.30ms]
(pass) bearer auth no-bypass (通信龙 hard constraint #4) > correct Bearer → 200 [5.02ms]
(pass) bearer auth no-bypass (通信龙 hard constraint #4) > path other than /mcp → 404 [7.69ms]
(pass) MCP protocol — initialize / tools/list / tools/call > initialize returns serverInfo + tools capability [7.01ms]
(pass) MCP protocol — initialize / tools/list / tools/call > tools/list returns all 6 self-loop tools [6.00ms]
(pass) MCP protocol — initialize / tools/list / tools/call > tools/list each tool has description + inputSchema [8.48ms]
(pass) MCP protocol — initialize / tools/list / tools/call > unknown method → JSON-RPC -32601 [6.78ms]
(pass) MCP protocol — initialize / tools/list / tools/call > malformed JSON → -32700 [5.37ms]
(pass) tools/call — handler dispatch into parent ctx > list_my_loops on empty store [8.75ms]
(pass) tools/call — handler dispatch into parent ctx > create_my_loop with interval string writes to parent goalStore [8.49ms]
(pass) tools/call — handler dispatch into parent ctx > unknown tool name → JSON-RPC -32601 [7.37ms]
(pass) safety防线 cross-HTTP boundary (M2 verification line) > batch-cancel via HTTP triggers confirm-back on 4th call [11.48ms]
(pass) safety防线 cross-HTTP boundary (M2 verification line) > cooldown via HTTP — edit within 30s of upsert rejected [6.91ms]
(pass) safety防线 cross-HTTP boundary (M2 verification line) > max-active-goals cap honored across HTTP [11.47ms]
(pass) safety防线 cross-HTTP boundary (M2 verification line) > preflight invalid timezone rejected via HTTP (M1 #302 round-2 still works) [10.58ms]
(pass) custom token override (for tests) > explicit token honored [12.13ms]
(pass) path routing — exact pathname (通信牛 hardening nit) > /mcp (exact) accepted → 200 [6.55ms]
(pass) path routing — exact pathname (通信牛 hardening nit) > /mcp?foo=bar (with query string) accepted → 200 [9.74ms]
(pass) path routing — exact pathname (通信牛 hardening nit) > /mcpXYZ (suffix) rejected → 404 (not auth-checked) [6.22ms]
(pass) path routing — exact pathname (通信牛 hardening nit) > /mcp/ (trailing slash) rejected → 404 [4.90ms]
(pass) path routing — exact pathname (通信牛 hardening nit) > /mcp-leak (dash suffix) rejected → 404 [7.63ms]
(pass) path routing — exact pathname (通信牛 hardening nit) > / (root) rejected → 404 [12.60ms]

src/goals/failure-counter.test.ts:
(pass) resolveMaxConsecutiveFailures > default 5 when env unset [0.12ms]
(pass) resolveMaxConsecutiveFailures > env override honored [0.06ms]
(pass) resolveMaxConsecutiveFailures > invalid env falls back to default [0.05ms]
(pass) getFailureCount > legacy undefined → 0 [0.15ms]
(pass) getFailureCount > explicit 0 → 0 [0.06ms]
(pass) getFailureCount > explicit N → N [0.04ms]
(pass) bumpFailure > first failure: undefined → 1, shouldPause=false at default threshold [0.13ms]
(pass) bumpFailure > 4 → 5 at default threshold: shouldPause=true [0.06ms]
(pass) bumpFailure > 3 → 4 at threshold 5: shouldPause=false (below threshold) [0.05ms]
(pass) bumpFailure > custom threshold — 2 → 3 at threshold 3: shouldPause=true [0.04ms]
(pass) bumpFailure > beyond threshold: count continues to increment but shouldPause stays true [0.10ms]
(pass) resetFailure > legacy undefined stays undefined (no unnecessary write) [0.07ms]
(pass) resetFailure > 0 stays 0 (no unnecessary write) [0.04ms]
(pass) resetFailure > N > 0 → 0 [0.05ms]
(pass) resetFailure > threshold value → 0 [0.03ms]
(pass) applyAutoPause > status flipped to paused + counter preserved for observability [0.14ms]
(pass) applyAutoPause > progress_log entry recorded with count + reason [0.09ms]
(pass) applyAutoPause > long reason truncated to 300 chars in summary [0.11ms]
(pass) integration: full cycle > 5 bumps → pause → unpause reset → 5 more bumps → pause again [0.17ms]

src/goals/parser.test.ts:
(pass) parseGoalCommand — English intervals > `5 min` form [0.20ms]
(pass) parseGoalCommand — English intervals > `5min` joined form [0.06ms]
(pass) parseGoalCommand — English intervals > `5 minutes` long form (plural wins over `min`) [0.05ms]
(pass) parseGoalCommand — English intervals > `1 hour` [0.07ms]
(pass) parseGoalCommand — English intervals > `hourly` keyword [0.07ms]
(pass) parseGoalCommand — English intervals > `daily` [0.08ms]
(pass) parseGoalCommand — English intervals > `1 day` [0.10ms]
(pass) parseGoalCommand — English intervals > `/goal` prefix is optional [0.04ms]
(pass) parseGoalCommand — English intervals > `/loop` alias [0.07ms]
(pass) parseGoalCommand — English intervals > `/aloop` strips the namespaced canonical prefix [0.12ms]
(pass) parseGoalCommand — English intervals > `/agoal` strips the namespaced compatibility prefix [0.09ms]
(pass) parseGoalCommand — Chinese intervals > `每5分钟` [0.25ms]
(pass) parseGoalCommand — Chinese intervals > `每 5 分钟` with spaces [0.06ms]
(pass) parseGoalCommand — Chinese intervals > `5分钟` bare (no 每) [0.13ms]
(pass) parseGoalCommand — Chinese intervals > `每小时` [0.04ms]
(pass) parseGoalCommand — Chinese intervals > `每天` [0.05ms]
(pass) parseGoalCommand — Chinese intervals > `每2小时` [0.05ms]
(pass) parseGoalCommand — rejection paths > no interval — reject [0.13ms]
(pass) parseGoalCommand — rejection paths > empty input — reject [0.03ms]
(pass) parseGoalCommand — rejection paths > seconds rejected with informative error [0.07ms]
(pass) parseGoalCommand — rejection paths > Chinese 秒 rejected [0.05ms]
(pass) parseGoalCommand — rejection paths > text becomes empty after stripping interval — reject [0.09ms]
(pass) parseGoalCommand — rejection paths > `/goal hourly` alone — reject (no text) [0.04ms]
(pass) parseGoalCommand — rejection paths > MIN_INTERVAL_MS is 60s [0.03ms]
(pass) parseGoalCommand — defence-in-depth > `1 min` exact minimum is accepted [0.05ms]
(pass) parseGoalCommand — #144 round-6 single-letter units (CLI parity) > `5m` parses to 5 × 60_000 ms (the canonical CLI emission) [0.05ms]
(pass) parseGoalCommand — #144 round-6 single-letter units (CLI parity) > `30m` / `90m` arbitrary minutes parse correctly [0.07ms]
(pass) parseGoalCommand — #144 round-6 single-letter units (CLI parity) > `2h` parses to 2 hours [0.07ms]
(pass) parseGoalCommand — #144 round-6 single-letter units (CLI parity) > `1d` parses to 24 hours [0.06ms]
(pass) parseGoalCommand — #144 round-6 single-letter units (CLI parity) > single-letter and word-form yield the same interval (no semantic drift) [0.09ms]
(pass) parseGoalCommand — #144 round-6 single-letter units (CLI parity) > `5min` still wins over `5m` (longest-prefix declaration order) [0.07ms]
(pass) parseGoalCommand — #144 round-6 single-letter units (CLI parity) > single-letter inside a larger word is NOT swallowed (lookahead guard) [0.06ms]
(pass) parseGoalCommand — #144 round-6 single-letter units (CLI parity) > `30s` is rejected with sub-minute error (parser + CLI aligned) [0.08ms]

src/goals/loops-grok-wire.test.ts:
(pass) grok ACP MCP injection — RFC-025 M3 wire > when LOOPS env unset, only commhub server (back-compat) [0.21ms]
(pass) grok ACP MCP injection — RFC-025 M3 wire > when LOOPS env set, commhub + loops servers both present [0.11ms]
(pass) grok ACP MCP injection — RFC-025 M3 wire > loops server entry: ACP http schema (type+url+headers array) [0.08ms]
(pass) grok ACP MCP injection — RFC-025 M3 wire > loops headers: Authorization Bearer <token> + transport tag + alias hint [0.15ms]
(pass) grok ACP MCP injection — RFC-025 M3 wire > loops entry localhost URL only (per security constraint) [0.10ms]
(pass) grok ACP MCP injection — RFC-025 M3 wire > loops + commhub independent: commhub headers don't leak token, loops headers don't leak ntok [0.14ms]
(pass) grok ACP MCP injection — #693 upload stdio > adds stdio commhub_upload when uploadMcpCommand provided [0.20ms]

src/goals/completion-detect.test.ts:
(pass) isGoalCompleteSentinel — POSITIVE (must detect) > Chinese sentinel on its own line [0.12ms]
(pass) isGoalCompleteSentinel — POSITIVE (must detect) > Chinese sentinel at end of text without trailing newline [0.03ms]
(pass) isGoalCompleteSentinel — POSITIVE (must detect) > Chinese sentinel at start of text [0.02ms]
(pass) isGoalCompleteSentinel — POSITIVE (must detect) > English GOAL_COMPLETE underscore on its own line [0.06ms]
(pass) isGoalCompleteSentinel — POSITIVE (must detect) > English GOAL COMPLETE (space) on its own line [0.02ms]
(pass) isGoalCompleteSentinel — POSITIVE (must detect) > sentinel with leading/trailing whitespace on the line [0.02ms]
(pass) isGoalCompleteSentinel — NEGATIVE (regression gate, must NOT detect) > bare 'completed' in progress report [0.03ms]
(pass) isGoalCompleteSentinel — NEGATIVE (regression gate, must NOT detect) > 'X completed' phrase mid-sentence [0.03ms]
(pass) isGoalCompleteSentinel — NEGATIVE (regression gate, must NOT detect) > Chinese '已完成' as section header (not the goal-complete sentinel) [0.03ms]
(pass) isGoalCompleteSentinel — NEGATIVE (regression gate, must NOT detect) > Chinese '已完成 X 项' enumeration in body [0.05ms]
(pass) isGoalCompleteSentinel — NEGATIVE (regression gate, must NOT detect) > 'goal completed' as a phrase inside prose (was caught by old regex) [0.03ms]
(pass) isGoalCompleteSentinel — NEGATIVE (regression gate, must NOT detect) > '目标已完成' substring without standalone line (old regex would match) [0.03ms]
(pass) isGoalCompleteSentinel — NEGATIVE (regression gate, must NOT detect) > lowercased 'goal_complete' (sentinel is case-sensitive on English) [0.04ms]
(pass) isGoalCompleteSentinel — NEGATIVE (regression gate, must NOT detect) > empty / null / undefined input [0.07ms]

src/goals/schedule.test.ts:
(pass) computeNextWakeAt — interval mode > interval 5min from a baseline returns baseline + 5min [0.06ms]
(pass) computeNextWakeAt — interval mode > interval 24h returns +24h [0.03ms]
(pass) computeNextWakeAt — interval mode > interval is timezone-independent (UTC anchor same result regardless of node TZ) [0.08ms]
(pass) computeNextWakeAt — time_of_day mode (per-TZ wall clock) > 09:00 Asia/Shanghai, called at 10:00 Asia/Shanghai → tomorrow 09:00 (already past today) [2.35ms]
(pass) computeNextWakeAt — time_of_day mode (per-TZ wall clock) > 09:00 Asia/Shanghai, called at 08:00 Asia/Shanghai → today 09:00 (still upcoming) [0.41ms]
(pass) computeNextWakeAt — time_of_day mode (per-TZ wall clock) > 09:00 Asia/Shanghai, called AT 09:00 exactly → today (boundary include) [0.86ms]
(pass) computeNextWakeAt — time_of_day mode (per-TZ wall clock) > falls back to node default TZ if schedule has no timezone [0.86ms]
(pass) computeNextWakeAt — weekday mode > Monday 09:00 Asia/Shanghai, called Sun 10:00 → tomorrow (Mon) 09:00 [0.71ms]
(pass) computeNextWakeAt — weekday mode > Mon/Wed/Fri 18:30 Asia/Shanghai, called Sun 10:00 → Monday 18:30 (next eligible) [0.57ms]
(pass) computeNextWakeAt — weekday mode > Mon/Wed/Fri 18:30, called Mon 18:00 → today 18:30 (today eligible AND time still upcoming) [0.40ms]
(pass) computeNextWakeAt — weekday mode > Mon/Wed/Fri 18:30, called Mon 19:00 → today is Mon but past 18:30 → Wed 18:30 [0.71ms]
(pass) computeNextWakeAt — weekday mode > Friday 09:00, called Saturday → next Friday (full week wrap-around) [0.84ms]
(pass) computeNextWakeAt — weekday mode > workdays ['mon','tue','wed','thu','fri'] for daily standup is supported [0.47ms]
(pass) computeNextWakeAt — DST edge cases (US Eastern) > 09:00 America/New_York in summer (EDT) → 13:00 UTC [0.63ms]
(pass) computeNextWakeAt — DST edge cases (US Eastern) > 09:00 America/New_York in winter (EST) → 14:00 UTC [0.68ms]
(pass) computeNextWakeAt — DST edge cases (US Eastern) > daily 02:30 wake DOES NOT skip on DST spring-forward day (just shifts that day) [0.70ms]
(pass) computeNextWakeAt — DST edge cases (US Eastern) > daily 03:30 exists on spring-forward day (post-jump, unambiguous EDT) [0.75ms]
(pass) computeNextWakeAt — DST fall-back (autumn) — RFC-025 P1.3 > daily 01:30, called Sat noon → fires at FIRST 01:30 EDT (before fall-back) [0.63ms]
(pass) computeNextWakeAt — DST fall-back (autumn) — RFC-025 P1.3 > daily 01:30, called AT first 01:30 EDT boundary → NEXT DAY (not second 01:30 EST same day) [0.65ms]
(pass) computeNextWakeAt — DST fall-back (autumn) — RFC-025 P1.3 > daily 01:30, called between the two occurrences (05:45 UTC) → next day [0.59ms]
(pass) computeNextWakeAt — DST fall-back (autumn) — RFC-025 P1.3 > daily 01:30, called AT fall-back moment (06:00 UTC) → next day (skip 2nd occurrence) [0.51ms]
(pass) computeNextWakeAt — DST fall-back (autumn) — RFC-025 P1.3 > daily 01:30, called AFTER second occurrence (06:30 UTC) → next day [0.61ms]
(pass) computeNextWakeAt — DST fall-back (autumn) — RFC-025 P1.3 > daily 02:30 (post-fallback UNAMBIGUOUS) still fires on fall-back day — was buggy before P1.3 [0.65ms]
(pass) computeNextWakeAt — DST fall-back (autumn) — RFC-025 P1.3 > daily 03:00 (fully post-fallback) on fall-back day — regression for iterated offset [0.55ms]
(pass) computeNextWakeAt — DST fall-back (autumn) — RFC-025 P1.3 > weekday Sun 01:30 on fall-back Sunday → first occurrence EDT [0.42ms]
(pass) computeNextWakeAt — DST fall-back (autumn) — RFC-025 P1.3 > weekday Sun 02:30 on fall-back Sunday → same day (was CRASH before P1.3) [0.61ms]
(pass) computeNextWakeAt — DST fall-back (autumn) — RFC-025 P1.3 > weekday Sun 01:30 called AT first fire → NEXT Sunday (not same-day 2nd occurrence) [1.06ms]
(pass) computeNextWakeAt — DST fall-back (autumn) — RFC-025 P1.3 > time_of_day 09:00 on fall-back day (outside ambiguous window) unchanged [0.35ms]
(pass) computeNextWakeAt — legacy interval-only (back-compat regression) > undefined schedule → uses interval_ms from goal context, returns now + interval [0.11ms]
(pass) computeNextWakeAt — legacy interval-only (back-compat regression) > undefined schedule + zero fallback interval → still returns now (no negative offset) [0.09ms]
(pass) computeNextWakeAt — legacy interval-only (back-compat regression) > undefined schedule + missing fallback interval throws (programmer error) [0.13ms]
(pass) computeNextWakeAt — parser-rejected edge cases (defensive) > invalid time format '25:99' throws [0.19ms]
(pass) computeNextWakeAt — parser-rejected edge cases (defensive) > empty weekday list throws (caught by parser too, defense in depth) [0.13ms]
(pass) computeNextWakeAt — parser-rejected edge cases (defensive) > unknown weekday name throws [0.16ms]

src/goals/self-loop-tools.test.ts:
(pass) list_my_loops > empty store → {goals: [], total: 0} [0.73ms]
(pass) list_my_loops > includes goal_id_short + cadence schedule shape [0.84ms]
(pass) create_my_loop > interval string '5m' creates goal [0.76ms]
(pass) create_my_loop > cron-lite time_of_day creates goal with schedule field [1.94ms]
(pass) create_my_loop > missing task → invalid_args [0.31ms]
(pass) create_my_loop > missing both schedule and interval → invalid_schedule [0.41ms]
(pass) create_my_loop > sub-minute interval rejected (parser 60s floor) [0.46ms]
(pass) create_my_loop > max active goals cap (3 cap → 4th rejected) [1.69ms]
(pass) edit_my_loop > change interval + report new value [1.57ms]
(pass) edit_my_loop > paused=true → status=paused [1.21ms]
(pass) edit_my_loop > cooldown — edit within 30s of last update rejected [0.57ms]
(pass) edit_my_loop > unknown goal_id → goal_not_found [0.30ms]
(pass) edit_my_loop > P0.3 unpause resets consecutive_failures (fresh 5-strike window) [1.31ms]
(pass) edit_my_loop > P0.3 paused=false when already active does NOT wipe mid-failure counter [1.22ms]
(pass) edit_my_loop > P0.3 paused=true does NOT reset consecutive_failures [1.51ms]
(pass) reschedule_my_loop (★ ScheduleWakeup 范式) > pushes next_wake_at forward, interval_ms unchanged [1.90ms]
(pass) reschedule_my_loop (★ ScheduleWakeup 范式) > invalid next_wake_in → invalid_interval [0.76ms]
(pass) reschedule_my_loop (★ ScheduleWakeup 范式) > cooldown applies [0.68ms]
(pass) complete_my_loop (★ 达标归档) > status → 'complete' [1.51ms]
(pass) complete_my_loop (★ 达标归档) > unknown goal_id → goal_not_found [0.41ms]
(pass) cancel_my_loop > status → 'cancelled' [1.36ms]
(pass) cancel_my_loop > batch cancel (3 in 30s) triggers confirm-back on 4th [4.77ms]
(pass) #302 round-2 — preflight computeNextWakeAt (self-lock prevention) > create_my_loop: bad timezone in schedule → invalid_schedule, NOT written [0.86ms]
(pass) #302 round-2 — preflight computeNextWakeAt (self-lock prevention) > create_my_loop: bad weekday → invalid_schedule, NOT written [1.47ms]
(pass) #302 round-2 — preflight computeNextWakeAt (self-lock prevention) > create_my_loop: bad time format → invalid_schedule, NOT written [0.54ms]
(pass) #302 round-2 — preflight computeNextWakeAt (self-lock prevention) > edit_my_loop: bad timezone on edit → invalid_schedule, EXISTING goal untouched [1.10ms]
(pass) #302 round-2 — preflight computeNextWakeAt (self-lock prevention) > create_my_loop: VALID structured schedule still works (regression) [1.68ms]
(pass) SELF_LOOP_TOOL_SPECS — registration table > exports 6 tools with stable names [0.27ms]
(pass) SELF_LOOP_TOOL_SPECS — registration table > every spec has non-empty description (LLM-discoverable) [0.23ms]
(pass) SELF_LOOP_TOOL_SPECS — registration table > description guides per RFC-025 §3.2 (intent-parse + report-back + safety) [0.52ms]

src/goals/codex-wake.test.ts:
(pass) runCodexWakeForGoal — first wake (no codex_thread_id) > startThread path → captures threadId, returns text + failed=false [1.83ms]
(pass) runCodexWakeForGoal — first wake (no codex_thread_id) > startThread with thread.id still null → threadId undefined (SDK didn't expose id yet) [0.25ms]
(pass) runCodexWakeForGoal — first wake (no codex_thread_id) > empty agent_message stream → returns '(无回复)' fallback [0.26ms]
(pass) runCodexWakeForGoal — subsequent wake (has codex_thread_id) > resumeThread succeeds → captures (possibly updated) threadId [0.38ms]
(pass) runCodexWakeForGoal — subsequent wake (has codex_thread_id) > resume returns thread whose .id was updated by SDK → reflects new id [0.23ms]
(pass) runCodexWakeForGoal — resume-fail fallback (the critical path) > resumeThread throws → startThread fallback, threadRebuilt=true, rebuildReason populated [0.68ms]
(pass) runCodexWakeForGoal — resume-fail fallback (the critical path) > startThread fallback also throws → failed=true with both errors surfaced [0.32ms]
(pass) runCodexWakeForGoal — resume-fail fallback (the critical path) > first wake + startThread throws → failed=true, threadRebuilt=false [0.31ms]
(pass) runCodexWakeForGoal — run-time error after thread obtained > runStreamed throws on first wake → failed=true, threadId still captured if SDK set it [0.31ms]
(pass) runCodexWakeForGoal — run-time error after thread obtained > runStreamed throws on resume → failed=true, threadRebuilt=false (resume itself worked) [0.36ms]
(pass) runCodexWakeForGoal — DI plumbing > newCodex called per wake (not cached across wakes — fresh client each time) [0.41ms]
(pass) runCodexWakeForGoal — DI plumbing > buildOpts passed verbatim to start/resume Thread [0.40ms]
(pass) runCodexWakeForGoal — DI plumbing > warn callback fires on resume-fail; log callback fires on success [0.46ms]
(pass) runCodexWakeForGoal — DI plumbing > missing log/warn deps → no throw (defaults are noops) [0.22ms]

src/goals/scheduler.test.ts:
(pass) decideTickWork — basic selection > empty list → empty buckets [0.25ms]
(pass) decideTickWork — basic selection > single active goal due now → due [0.36ms]
(pass) decideTickWork — basic selection > single active goal due 1ms ago → due [0.10ms]
(pass) decideTickWork — basic selection > single active goal due 1ms in future → pending, not due [0.10ms]
(pass) decideTickWork — basic selection > multiple active goals: only the overdue ones wake; pending stay [0.20ms]
(pass) decideTickWork — status filtering > each non-active status is skipped (never appears in due) [0.19ms]
(pass) decideTickWork — status filtering > mixed batch: only active+due appear in due bucket [0.25ms]
(pass) decideTickWork — status filtering > wake order preserves input order — deterministic, no shuffling [0.20ms]
(pass) decideTickWork — invalid timestamp recovery > missing next_wake_at → treated as overdue (surface to wake handler) [0.08ms]
(pass) decideTickWork — invalid timestamp recovery > empty string next_wake_at → treated as overdue [0.07ms]
(pass) decideTickWork — invalid timestamp recovery > garbage next_wake_at (Date.parse → NaN) → treated as overdue [0.05ms]
(pass) decideTickWork — invalid timestamp recovery > non-string next_wake_at (number 0 from corrupt JSON) → treated as overdue [0.07ms]
(pass) decideTickWork — invalid timestamp recovery > inactive + invalid timestamp → still skipped (status wins over wake check) [0.07ms]
(pass) decideTickWork — counter sanity > active + skipped sums to total goals; pending + due sums to active [0.18ms]

src/goals/store.test.ts:
(pass) GoalStore — basic lifecycle > fresh store: load with no file → ok, empty list [0.67ms]
(pass) GoalStore — basic lifecycle > upsert → get → list roundtrip [0.77ms]
(pass) GoalStore — basic lifecycle > delete → flushes to disk [1.48ms]
(pass) GoalStore — basic lifecycle > setStatus → in-memory + persisted [1.31ms]
(pass) GoalStore — basic lifecycle > setStatus on unknown id → undefined, no throw [0.36ms]
(pass) GoalStore — basic lifecycle > mutate applies in-place + bumps updated_at [6.68ms]
(pass) GoalStore — basic lifecycle > mutate on unknown id → undefined, mutator NOT invoked [0.49ms]
(pass) GoalStore — restart persistence > two instances see the same goals (= restart simulation) [1.03ms]
(pass) GoalStore — restart persistence > status change survives reload [1.08ms]
(pass) GoalStore — corruption recovery (#2) > invalid JSON → ok=false, .corrupt backup, empty store [1.84ms]
(pass) GoalStore — corruption recovery (#2) > unknown schema version → recovery [0.75ms]
(pass) GoalStore — corruption recovery (#2) > malformed shape (goals not array) → recovery [0.57ms]
(pass) GoalStore — Grok preview persistence boundary > recursively migrates task/progress/error, final writes, and archives at 0600 [3.66ms]
(pass) GoalStore — Grok preview persistence boundary > scrubs a broad-mode corrupt backup and replaces the live file with an empty safe store [1.67ms]
(pass) GoalStore — Grok preview persistence boundary > recursively scrubs a parseable unsupported-schema backup [1.30ms]
(pass) P0 runtime gate — name resolution > isClaudeRuntime accepts every claude alias [0.17ms]
(pass) P0 runtime gate — name resolution > isClaudeRuntime rejects codex / grok / unknown / empty [0.10ms]
(pass) P0 runtime gate — name resolution > runtimeBucket maps to canonical buckets [0.15ms]
(pass) #144 round-6 — claude runtime gate REMOVED, scheduler is universal > newGoal({runtime: 'claude-agent-sdk'}) succeeds (was the load-bearing bug) [0.12ms]
(pass) #144 round-6 — claude runtime gate REMOVED, scheduler is universal > newGoal succeeds for every recognized runtime alias (no per-bucket carve-out) [0.22ms]
(pass) #144 round-6 — claude runtime gate REMOVED, scheduler is universal > GoalStore.upsert accepts a claude-runtime goal end-to-end [0.72ms]
(pass) #144 round-6 — claude runtime gate REMOVED, scheduler is universal > isClaudeRuntime still classifies (kept for cross-bucket detection, not gating) [0.10ms]
(pass) P0 runtime gate — archiveAndClear > with live goals: backup file created, store emptied, reload sees empty [1.71ms]
(pass) P0 runtime gate — archiveAndClear > with no live file: returns undefined, no throw, store still flushes empty [0.56ms]
(pass) P0 runtime gate — archiveAndClear > backup filenames are unique across rapid calls [14.72ms]
(pass) #144 round-6 — decideStartupAction (refined-B matrix) > claude + empty → ok (scheduler runs; was 'skip' pre-#144) [0.24ms]
(pass) #144 round-6 — decideStartupAction (refined-B matrix) > claude + only claude-active goals → ok (scheduler runs) [0.28ms]
(pass) #144 round-6 — decideStartupAction (refined-B matrix) > codex + empty → ok [0.05ms]
(pass) #144 round-6 — decideStartupAction (refined-B matrix) > codex + only codex goals → ok [0.11ms]
(pass) #144 round-6 — decideStartupAction (refined-B matrix) > grok + only grok goals → ok [0.10ms]
(pass) #144 round-6 — decideStartupAction (refined-B matrix) > claude + active codex/grok goals → archive + runScheduler=true (recover after archive) [0.37ms]
(pass) #144 round-6 — decideStartupAction (refined-B matrix) > codex + grok-active leftover → archive (NOT fatal exit anymore) [0.17ms]
(pass) #144 round-6 — decideStartupAction (refined-B matrix) > grok + codex-active leftover → archive [0.09ms]
(pass) #144 round-6 — decideStartupAction (refined-B matrix) > inactive foreign-bucket goals do NOT trigger archive (only `active` counts) [0.15ms]
(pass) #144 round-6 — decideStartupAction (refined-B matrix) > claude with only inactive foreign leftover → ok (just cleanup pending) [0.09ms]
(pass) #144 round-6 — decideStartupAction (refined-B matrix) > unknown bucket → skip (no scheduler, no auto-archive) [0.18ms]
(pass) GoalStore — mutex serialisation (#1+#3) > 50 concurrent upserts → all 50 persist (no torn writes) [19.53ms]
(pass) GoalStore — mutex serialisation (#1+#3) > interleaved upsert + setStatus + delete stays consistent [12.91ms]

src/runtime/grok-copresence/runtime-retirement.test.ts:
(pass) Grok co-presence terminal-runtime retirement > retains live and recovering runtimes [0.50ms]
(pass) Grok co-presence terminal-runtime retirement > closes and retires a terminal runtime even when teardown reports an error [0.61ms]
(pass) Grok co-presence terminal-runtime retirement > wires retirement before returning the cached product runtime [0.94ms]

src/runtime/grok-copresence/profile-process.test.ts:
(pass) Grok co-presence profile is pinned for the whole process > same input yields three exact, non-overlapping process capabilities [185.73ms]

src/runtime/grok-copresence/jsonl.test.ts:
(pass) Grok copresence envelope and user parsing > parses only an exact, query-anchored Agent Network envelope [0.42ms]
(pass) Grok copresence envelope and user parsing > extracts the first authoritative user_query from string or Grok text-array content [0.40ms]
(pass) Grok copresence envelope and user parsing > does not trust a syntactically valid prefix unless the bridge registered it [1.62ms]
(pass) Grok copresence envelope and user parsing > nested user_query text cannot turn an owned network task into human delegation [0.43ms]
(pass) Grok copresence turn reducer > waits for completion and replies with the last non-empty assistant record [0.58ms]
(pass) Grok copresence turn reducer > keeps the last no-tool assistant when later tool-bearing chatter exists [0.29ms]
(pass) Grok copresence turn reducer > handles completion/chat-history polling order without returning an empty reply [0.38ms]
(pass) Grok copresence turn reducer > does not finalize an intermediate assistant visible before the completion event [0.27ms]
(pass) Grok copresence turn reducer > retains a completion observed before even the network user line [0.41ms]
(pass) Grok copresence turn reducer > retains an event-first human completion only for a trusted PTY submission [0.30ms]
(pass) Grok copresence turn reducer > never carries an unowned idle completion into a later network task [0.35ms]
(pass) Grok copresence turn reducer > binds an event-first completion to the exact registered network task [0.46ms]
(pass) Grok copresence turn reducer > consumes sanitized sample A block content and turn_number boundary [0.32ms]
(pass) Grok copresence turn reducer > consumes sanitized sample B and selects only the 14th no-tool assistant [0.68ms]
(pass) Grok copresence turn reducer > ignores standalone system-reminder user records without abandoning a network turn [0.19ms]
(pass) Grok copresence turn reducer > fails a terminal record without turn_started and never binds it to the next user [0.26ms]
(pass) Grok copresence turn reducer > never maps a human turn or failed network turn to a network reply [0.63ms]
(pass) Grok copresence turn reducer > abandons an unfinished network turn rather than attaching its answer to a human turn [0.49ms]
(pass) Grok copresence turn reducer > pairs events correctly when chat_history leads by two unnumbered turns [0.63ms]
(pass) Grok copresence turn reducer > does not let a new start overtake an abandoned numbered terminal [0.36ms]
(pass) Grok completion compatibility and defensive parsing > recognizes only top-level turn_ended with an exact successful outcome [0.34ms]
(pass) Grok completion compatibility and defensive parsing > binds turn_started turn_number while permission lifecycle remains inert [0.27ms]
(pass) Grok completion compatibility and defensive parsing > fails a started turn when turn_ended has no outcome [0.24ms]
(pass) Grok completion compatibility and defensive parsing > fails closed on an overlapping turn_started epoch [0.25ms]
(pass) Grok completion compatibility and defensive parsing > retains only a bounded tail of raw completion candidates [0.33ms]
(pass) Grok completion compatibility and defensive parsing > contains malformed and overlong lines instead of parsing or retaining them [1.31ms]
(pass) Grok completion compatibility and defensive parsing > incrementally joins split lines and drops a fragmented oversized line once [1.47ms]
(pass) persistent JSONL tail cursor > starts fresh at end by default, with an explicit start override [0.36ms]
(pass) persistent JSONL tail cursor > continues and fails closed on truncate or inode rotation [0.23ms]
(pass) persistent JSONL tail cursor > treats corrupt persisted state as non-replayable and advances JSON-safely [0.21ms]

src/runtime/grok-copresence/stuck-phase-alarm.test.ts:
(pass) describeStuckPhase > says nothing while idle, no matter how long [0.12ms]
(pass) describeStuckPhase > says nothing for an ordinary long turn [0.05ms]
(pass) describeStuckPhase > fires at the threshold and names the phase, the wait, and the issue [0.09ms]
(pass) describeStuckPhase > fires before the first task's own timeout, not with it [0.05ms]
(pass) describeStuckPhase > counts the tasks already waiting [0.09ms]
(pass) describeStuckPhase > refuses to guess on a non-finite age [0.05ms]
(pass) describeStuckPhase > does not claim it will recover [0.06ms]

src/runtime/grok-copresence/attach.test.ts:
(pass) Grok co-presence local attach server > serves one owner-only client and cleans its socket on close [15.93ms]
(pass) Grok co-presence local attach server > rejects a second client without disturbing the attached human [4.76ms]
(pass) Grok co-presence local attach server > routes input and resize frames only through serialized arbiter callbacks [3.38ms]
(pass) Grok co-presence local attach server > fails closed when an inbound frame exceeds the configured bound [20.12ms]
(pass) Grok co-presence local attach server > refuses symlinks and regular files at the socket path [1.10ms]

src/runtime/grok-copresence/platform.test.ts:
(pass) grok copresence platform capabilities > linux keeps every guarantee and the existing Unix socket path verbatim [0.18ms]
(pass) grok copresence platform capabilities > linux without /proc is refused, and the error names what is missing [0.16ms]
(pass) grok copresence platform capabilities > windows is supported over a named pipe, and says exactly what it loses [0.22ms]
(pass) grok copresence platform capabilities > named pipe names are namespaced by the full path, not by the basename [0.28ms]
(pass) grok copresence platform capabilities > darwin is supported over a Unix socket, and says exactly what it loses [0.16ms]
(pass) grok copresence platform capabilities > an unverified platform is still refused rather than silently downgraded [0.11ms]
(pass) POSIX file-mode predicates > mode assertions still判事 on POSIX and go silent only where modes do not exist [0.09ms]
(pass) POSIX file-mode predicates > chmod is a no-op exactly where mode bits do not exist, and runs everywhere else [0.14ms]

src/runtime/grok-copresence/state.test.ts:
(pass) Grok co-presence arbitration > lets the first human byte win a simultaneous human/network race [1.31ms]
(pass) Grok co-presence arbitration > gives a newly active human composer priority over an existing FIFO [0.36ms]
(pass) Grok co-presence arbitration > dequeues network tasks FIFO and never preempts an active turn [0.78ms]
(pass) Grok co-presence arbitration > cancels only queued timeouts and rejects duplicate task ids [0.37ms]
(pass) Grok co-presence arbitration > retains the active network task and FIFO across disconnect/reconnect [0.86ms]
(pass) Grok co-presence arbitration > marks approvals waiting for the human without emitting a response [0.30ms]
(pass) Grok co-presence arbitration > clears an already-waiting preview todo resolution in either active turn without completing it [0.36ms]

src/runtime/grok-copresence/profile-wiring.test.ts:
(pass) Grok co-presence profile wiring > pins validated config before dynamically loading the runtime [2.01ms]
(pass) Grok co-presence profile wiring > cannot mutate the capability according to a logical turn owner [0.13ms]

src/runtime/grok-copresence/leader-lifecycle.test.ts:
(pass) Grok auto-Leader lifecycle identity > rejects a different kernel executable hidden behind a pinned argv0 [0.91ms]
(pass) Grok auto-Leader lifecycle identity > rejects a live native listener whose argv0 forges the pinned executable [215.94ms]
(pass) Grok auto-Leader lifecycle identity > terminates one exact generation and removes only its stale socket [75.84ms]
(pass) Grok auto-Leader lifecycle identity > does not adopt a listener whose generation marker differs [163.17ms]
(pass) Grok auto-Leader lifecycle identity > does not signal or unlink after the socket pathname is replaced [56.12ms]
(pass) Grok auto-Leader lifecycle identity > revalidates the exact identity before escalating a TERM-resistant Leader [586.90ms]
(pass) Grok auto-Leader lifecycle identity > does not escalate when a TERM-resistant Leader replaces its listener [356.33ms]
(pass) Grok auto-Leader lifecycle identity > does not signal after the configured binary inode is replaced [52.35ms]
(pass) Grok auto-Leader lifecycle identity > retains the stale socket when another process from the generation remains [299.89ms]

src/runtime/grok-copresence/allowlist-near-miss.test.ts:
(pass) grok copresence preview tool profile is an exact value set > a profile tool with an otherwise valid tuple is accepted [0.51ms]
(pass) grok copresence preview tool profile is an exact value set > refuses "todo_write2" [0.05ms]
(pass) grok copresence preview tool profile is an exact value set > refuses "search_tool2"
(pass) grok copresence preview tool profile is an exact value set > refuses "use_tool2"
(pass) grok copresence preview tool profile is an exact value set > refuses "use_tool_v2"
(pass) grok copresence preview tool profile is an exact value set > refuses "use_tool-admin" [0.02ms]
(pass) grok copresence preview tool profile is an exact value set > refuses "Use_Tool"
(pass) grok copresence preview tool profile is an exact value set > refuses "USE_TOOL"
(pass) grok copresence preview tool profile is an exact value set > refuses "Todo_Write"
(pass) grok copresence preview tool profile is an exact value set > refuses " use_tool"
(pass) grok copresence preview tool profile is an exact value set > refuses "use_tool "
(pass) grok copresence preview tool profile is an exact value set > refuses "use_tool\n"
(pass) grok copresence preview tool profile is an exact value set > refuses "use_too"
(pass) grok copresence preview tool profile is an exact value set > refuses "tool"
(pass) grok copresence preview tool profile is an exact value set > refuses "not_use_tool"
(pass) grok copresence preview tool profile is an exact value set > refuses "xuse_toolx"
(pass) grok copresence preview tool profile is an exact value set > refuses "ｕｓｅ＿ｔｏｏｌ"
(pass) grok copresence preview tool profile is an exact value set > refuses "use​tool"
(pass) grok copresence preview tool profile is an exact value set > refuses "use_to​ol"
(pass) grok copresence preview tool profile is an exact value set > refuses ""
(pass) grok copresence preview tool profile is an exact value set > refuses " "
(pass) grok copresence preview tool profile is an exact value set > refuses "Search_Tool"
(pass) grok copresence preview tool profile is an exact value set > refuses "TODO_WRITE"
(pass) grok copresence preview tool profile is an exact value set > refuses "use_tool\r"
(pass) grok copresence preview tool profile is an exact value set > refuses "use_tool\u0000"
(pass) grok copresence preview tool profile is an exact value set > refuses "x_todo_write"
(pass) grok copresence preview tool profile is an exact value set > refuses "use-tool"
(pass) grok copresence preview tool profile is an exact value set > refuses "todo-write"
(pass) grok copresence preview tool profile is an exact value set > the profile is exactly the three pinned tools [0.12ms]

src/runtime/grok-copresence/blocked-key-name.test.ts:
(pass) describeBlockedKey > names the legacy control byte for Ctrl+P and says what Grok uses it for [0.41ms]
(pass) describeBlockedKey > names Ctrl+P when it arrives CSI-u encoded [0.06ms]
(pass) describeBlockedKey > names CSI-u Ctrl+M as the model picker [0.06ms]
(pass) describeBlockedKey > does not call a plain Tab 'Ctrl+I' [0.08ms]
(pass) describeBlockedKey > says Enter and Ctrl+M share one byte [0.05ms]
(pass) describeBlockedKey > reads the CSI-u modifier as a bitmask plus one, not as a raw mask [0.08ms]
(pass) describeBlockedKey > returns null rather than guessing [0.11ms]
(pass) describeBlockedKey > names an undocumented control key without inventing a purpose [0.04ms]

src/runtime/grok-copresence/profile-selection.test.ts:
(pass) Grok co-presence process capability profile > accepts only the exact startup profiles [0.26ms]
(pass) Grok co-presence process capability profile > defaults closed and rejects an invalid process profile [0.13ms]
(pass) Grok co-presence process capability profile > uses the strict sandbox only for repo-read [0.10ms]

src/runtime/grok-copresence/runtime.test.ts:
(pass) Grok copresence launch and injection policy > keeps the fixed-tool auto-resolution exception exact and limited to active turns [0.49ms]
(pass) Grok copresence launch and injection policy > admits exact automatic lifecycles only for the fixed preview tool boundary [0.30ms]
(pass) Grok copresence launch and injection policy > exposes only reviewed value-free task failure codes and exact JSONL subcodes [0.60ms]
(pass) Grok copresence launch and injection policy > keeps the JSONL subcode allowlist direct, frozen, and actual-path-only [0.33ms]
(pass) Grok copresence launch and injection policy > admits only black-box verified Grok builds [0.55ms]
(pass) Grok copresence launch and injection policy > fail-closes on the discovery surfaces grok 1.0.5 added [1.30ms]
(pass) Grok copresence launch and injection policy > keeps the hidden toggle flags in argv on every verified build [2.32ms]
(pass) Grok copresence launch and injection policy > records per-build Leader behaviour instead of assuming every build has one [0.11ms]
(pass) Grok copresence launch and injection policy > pins one TUI-effective commhub-only agent profile and hard-denies fallback routes [0.94ms]
(pass) Grok copresence launch and injection policy > rejects terminal escape injection and reserved origin markup [0.45ms]
(pass) Grok copresence launch and injection policy > recognizes the pinned TUI composer footer across ANSI fragments [0.23ms]
(pass) Grok copresence launch and injection policy > rejects external permission sources and noninteractive modes [2.11ms]
(pass) Grok copresence runtime integration > terminates the independently persistent auto-Leader and its unchanged stale socket [545.44ms]
(pass) Grok copresence runtime integration > cleans and hardens the exact pinned footprint only after confirmed close [547.03ms]
(pass) Grok copresence runtime integration > cleans each exact sandbox placeholder at its confirmed recovery boundary [856.09ms]
(pass) Grok copresence runtime integration > removes an old placeholder before a recovery generation reuses its PID [1147.88ms]
(pass) Grok copresence runtime integration > queues network input until the pinned TUI composer is ready [1184.16ms]
(pass) Grok copresence runtime integration > start reports attach=, injects a mapped reply, and a dead TUI is not idle [1111.24ms]
(pass) Grok copresence runtime integration > a TUI child mid-recovery is not reported idle [905.42ms]
(pass) Grok copresence runtime integration > maps keyless fake-writer file mutations to exact value-free tail subcodes [3809.22ms]
(pass) Grok copresence runtime integration > continues exactly once across prefix-preserving atomic chat rewrites [2247.17ms]
(pass) Grok copresence runtime integration > rejects an atomic replacement that preserves only the consumed prefix [653.71ms]
(pass) Grok copresence runtime integration > rejects a same-inode shrink below the highest observed size even when offset remains valid [554.11ms]
(pass) Grok copresence runtime integration > does not expose an intermediate atomic generation before its successor preserves it [1069.65ms]
(pass) Grok copresence runtime integration > does not expose a pinned generation unlinked between path check and read [1077.49ms]
(pass) Grok copresence runtime integration > maps chat and events reset callback failures and stops polling after fatal [1486.50ms]
(pass) Grok copresence runtime integration > maps keyless reducer, lifecycle, and combined flush invariants at their boundaries [2453.79ms]
(pass) Grok copresence runtime integration > close waits for and tears down a Leader spawned by in-flight recovery [883.23ms]
(pass) Grok copresence runtime integration > retains containment and lifetime locks when a closing recovery PTY will not stop [2892.37ms]
(pass) Grok copresence runtime integration > excludes a different runtime from the same canonical project for the full TUI lifetime [1090.17ms]
(pass) Grok copresence runtime integration > contains an exited recovery generation before reusing its PID [1732.52ms]
(pass) Grok copresence runtime integration > retains final-cleanup ownership after every failed recovery PID is consumed [867.09ms]
(pass) Grok copresence runtime integration > reports exact submission and trusted consumption, never queued admission [1760.32ms]
(pass) Grok copresence runtime integration > arbitrates a live PTY, settles final JSONL, attaches once, and resumes [4631.21ms]
(pass) Grok copresence runtime integration > fails closed on automatic permission resolution without a human action [550.90ms]
(pass) Grok copresence runtime integration > accepts only the pinned preview todo_write automatic resolution tuple [1869.74ms]
(pass) Grok copresence runtime integration > keeps the shared TUI alive when the pinned preview auto-resolves todo_write in a human turn [1739.60ms]
(pass) Grok copresence runtime integration > keeps the shared TUI alive across exact search_tool then use_tool in a human turn [1658.96ms]
(pass) Grok copresence runtime integration > rejects every mutated preview todo_write automatic resolution tuple [3937.83ms]
(pass) Grok copresence runtime integration > preserves exact permission lifecycle order across coalesced and split event reads [2292.35ms]
(pass) Grok copresence runtime integration > fails closed on malformed or oversized permission lifecycle JSONL [1146.23ms]
(pass) Grok copresence runtime integration > rejects terminal reordering around automatic permission lifecycles [1687.40ms]
(pass) Grok copresence runtime integration > allows repeated fixed-tool automatic permission lifecycles in one network turn [1077.10ms]
(pass) Grok copresence runtime integration > allows a pinned tool batch whose automatic resolutions are not request ordered [1082.23ms]
(pass) Grok copresence runtime integration > never replies with a tool-bearing assistant when the final log is delayed past settling [1868.18ms]
(pass) Grok copresence runtime integration > rejects a completed turn that never resolved its approval [554.27ms]
(pass) Grok copresence runtime integration > does not resume a TUI that crashed at an approval prompt [572.62ms]
(pass) Grok copresence runtime integration > rejects a permission record that landed just before the crash poll [884.86ms]
(pass) Grok copresence runtime integration > refuses process-level resume with a persisted unresolved approval [190.18ms]
(pass) Grok copresence runtime integration > permits process-level resume after a persisted approval was resolved [535.97ms]
(pass) Grok copresence runtime integration > arms both resume tails before spawn-time permission records can be skipped [270.73ms]
(pass) Grok copresence runtime integration > discards spawn-time orphan completions before accepting the first new network task [1096.95ms]
(pass) Grok copresence runtime integration > drains more than one tail chunk before attach and fully cleans a startup rejection [868.05ms]
(pass) Grok copresence runtime integration > accepts the pinned startup auto-approval transition [553.60ms]
(pass) Grok copresence runtime integration > reruns the spawn audit and refuses recovery when it fails [782.15ms]
(pass) Grok copresence runtime integration > keeps auto-approval across recovery before scheduling [1714.84ms]
(pass) Grok copresence runtime integration > jointly drains chat and events until both recovery cursors are stable [1830.03ms]
(pass) Grok copresence runtime integration > rejects a beforeSpawn callback that widens a controlled child setting [198.02ms]
(pass) Grok copresence runtime integration > gives every real lifetime-lock holder only the exact helper environment [554.99ms]

src/runtime/grok-copresence/verified-builds.test.ts:
(pass) grok co-presence verified builds > the macOS 1.0.5 build is registered — measured on an Apple M4 [0.11ms]
(pass) grok co-presence verified builds > darwin 1.0.5 keeps autoLeader=false, like the linux build of the same commit [0.03ms]
(pass) grok co-presence verified builds > an unregistered build is still refused, and the message names what it saw [0.25ms]
(pass) grok co-presence verified builds > 🔴 the darwin registration and the darwin capability row tell the SAME story [0.07ms]

src/runtime/grok-copresence/liveness.test.ts:
(pass) Grok copresence liveness and hub status > a missing session is never idle or working [0.48ms]
(pass) Grok copresence liveness and hub status > named attach.sock and leader.sock plus a live composer are the only idle path [5.11ms]
(pass) Grok copresence liveness and hub status > a leftover non-socket file at the attach path is not present [3.92ms]

src/runtime/opencode-acp/events.test.ts:
(pass) reduceOpencodeAcpNotification — session/update dispatch > agent_message_chunk with text content → replyText += content.text [2.28ms]
(pass) reduceOpencodeAcpNotification — session/update dispatch > agent_thought_chunk with text → thoughtText, NOT replyText (grok discipline) [0.09ms]
(pass) reduceOpencodeAcpNotification — session/update dispatch > tool_call and tool_call_update both bump toolCalls [0.05ms]
(pass) reduceOpencodeAcpNotification — session/update dispatch > usage_update snaps totalTokens into state.usage [0.10ms]
(pass) reduceOpencodeAcpNotification — session/update dispatch > available_commands_update consumed silently (session-init only) [0.10ms]
(pass) reduceOpencodeAcpNotification — session/update dispatch > agent_message_chunk without text content adds a warning [0.11ms]
(pass) reduceOpencodeAcpNotification — session/update dispatch > unknown method returns ignored without mutating state [0.11ms]
(pass) reduceOpencodeAcpNotification — session/update dispatch > unknown sessionUpdate subtype returns ignored (forward-compat) [0.06ms]
(pass) reduceOpencodeAcpResponse — session/prompt terminal response > captures stopReason + usage from result [0.24ms]
(pass) reduceOpencodeAcpResponse — session/prompt terminal response > missing stopReason still marks turn complete [0.08ms]
(pass) reduceOpencodeAcpFrames — replay the Phase 0b captured turn > full one-word turn: 10 thought chunks + 1 message chunk + usage + response [0.46ms]
(pass) reduceOpencodeAcpFrames — replay the Phase 0b captured turn > thinking-only terminal turn (no agent_message_chunk) — replyText stays empty [0.17ms]

src/runtime/opencode-acp/child-env.test.ts:
(pass) buildOpencodeChildEnv — deny-by-default boundary > locks the exact hardened ancestor candidate set [0.14ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > rejects sticky world-writable /tmp instead of silently degrading [4.77ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > passes only runtime/network allowlist and controls all state roots [19.35ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > safe inline policy disables every local tool without replacing provider/model [12.40ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > unsafe opt-in explicitly overrides the wizard's persisted safe policy [7.46ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > detects exact managed config sources across Linux, Windows, and macOS [1.03ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > safe runtime renders ordinary same-uid config through a strict allowlist [12.05ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > copies only blessed API auth fields into fresh data and keeps persistent state outside the child [13.68ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > never exposes planted persistent DB/log/cache/state/tmp descendants in safe or unsafe mode [19.89ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > removes a partially built launch tree when env construction fails [10.84ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > pre-spawn revalidation hard-fails when an ancestor discovery candidate appears [15.48ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > keeps active roots but reclaims a dead-owner crash root without following symlinks [35.27ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > reclaims dead-owner roots after the node workDir is deleted or recreated [47.32ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > a transient cleanup pathname swap is retried after child exit [23.92ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > a dead owner marker is retained while an orphan child still references the root [39.52ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > an exact exited-process identity exemption never hides a live descendant or PID mismatch [54.95ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > rejects symlinks at workDir and every security-sensitive state layer [15.17ms]
(pass) buildOpencodeChildEnv — deny-by-default boundary > rejects permissive modes and foreign ownership without repairing them [1.36ms]

src/runtime/opencode-acp/profile-state.test.ts:
(pass) OpenCode private profile state > loads, atomically updates, backs up, and writes a session [14.03ms]
(pass) OpenCode private profile state > a post-load config symlink cannot redirect session writeback [0.98ms]
(pass) OpenCode private profile state > boot refuses a config symlink before self-heal can write its target [0.96ms]
(pass) OpenCode private profile state > backup refuses a pre-planted .prev symlink [0.65ms]
(pass) OpenCode private profile state > runtime hint rejects suspicious config leaves for every runtime [0.80ms]

src/runtime/opencode-acp/client.test.ts:
(pass) OpencodeAcpClient — request/response correlation > request() resolves with the matching response's result [57.64ms]
(pass) OpencodeAcpClient — request/response correlation > error response rejects the promise with a shaped message [54.05ms]
(pass) OpencodeAcpClient — streaming notifications > emits 'notification' for every session/update frame [55.34ms]
(pass) OpencodeAcpClient — streaming notifications > id-carrying reverse requests get an explicit method-not-found response [55.25ms]
(pass) OpencodeAcpClient — process lifecycle > child exit rejects all pending requests [56.22ms]
(pass) OpencodeAcpClient — process lifecycle > isRunning flips false after stop() [2.10ms]
(pass) OpencodeAcpClient — process lifecycle > explicit child env is not merged with the client's process.env [54.65ms]

src/runtime/opencode-acp/runtime.test.ts:
[opencode-acp] session/new — ses_test...
(pass) openOpencodeRuntime — cwd and tool policy > safe default keeps spawn + ACP session in one external launch workspace [123.90ms]
[opencode-acp] session/new — ses_probe_au...
(pass) openOpencodeRuntime — cwd and tool policy > version probe root is credential-free and gone before runtime auth is materialized [122.84ms]
[opencode-acp] session/load ok — resumed ses_existing...
(pass) openOpencodeRuntime — cwd and tool policy > safe session/load reuses the exact spawn PWD as its ACP cwd [120.87ms]
[opencode-acp] session/new — ses_test...
(pass) openOpencodeRuntime — cwd and tool policy > explicit unsafe flag restores project cwd and emits a trusted-task warning [113.56ms]
[opencode-acp] session/new — ses_evidence...
(pass) openOpencodeRuntime — cwd and tool policy > reports submission before exact prompt-response consumption [126.15ms]
[opencode-acp] session/new — ses_test...
(pass) openOpencodeRuntime — opening lifecycle > normal stop removes the launch root and copied vendor auth [125.18ms]
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
[opencode-acp] session/new — ses_test...
(pass) openOpencodeRuntime — opening lifecycle > repeated open/stop cycles do not accumulate launch roots [3026.72ms]
(pass) openOpencodeRuntime — opening lifecycle > an ancestor candidate planted by the version probe hard-fails before ACP spawn [62.77ms]
(pass) openOpencodeRuntime — opening lifecycle > package replacement after credential-free probe is rejected and runtime auth root is discarded [63.23ms]
(pass) openOpencodeRuntime — opening lifecycle > in-place binary self-modification after probe is rejected before credential spawn [70.39ms]
(pass) openOpencodeRuntime — opening lifecycle > production rejects canonical same-version packages below project cwd or node workDir [24.10ms]
(pass) openOpencodeRuntime — opening lifecycle > initialize failure force-kills the child before rejecting [122.16ms]
(pass) openOpencodeRuntime — opening lifecycle > onClient exposes a stalled-handshake child synchronously for shutdown [55.48ms]
[opencode-acp] session/new — ses_idle...
(pass) opencodeThink — failed-turn lifecycle > prompt idle timeout force-kills the child before rejecting [182.71ms]
[opencode-acp] session/new — ses_rescue_i...
[opencode-acp] #383 thinking-only terminal turn (chunks=0 thoughtChunks=1) — re-prompting for plain-text final
(pass) opencodeThink — failed-turn lifecycle > a failed thinking-only rescue discards the child before returning [161.23ms]

src/runtime/opencode-acp/binary.test.ts:
(pass) resolvePinnedOpencodeBinary > locks the non-root uid=gid umask-0002 compatibility policy [0.19ms]
(pass) resolvePinnedOpencodeBinary > accepts the canonical package entrypoint and probes it from the external cwd [40.56ms]
(pass) resolvePinnedOpencodeBinary > accepts an npm-style PATH shim but returns the canonical package binary [25.65ms]
(pass) resolvePinnedOpencodeBinary > rejects a same-version fake package inside the project before executing it [1.45ms]
(pass) resolvePinnedOpencodeBinary > rejects forged package metadata and noncanonical entrypoints [3.14ms]
(pass) resolvePinnedOpencodeBinary > rejects unsafe file, package-directory, ancestor, and owner modes [3.03ms]
(pass) resolvePinnedOpencodeBinary > still enforces exact --version output after package identity succeeds [26.99ms]
(pass) resolvePinnedOpencodeBinary > refuses a caller-selected version other than the vetted release pin [0.82ms]
(pass) resolvePinnedOpencodeBinary > rejects a same-version package in a monorepo ancestor before probing it [1.57ms]
(pass) resolvePinnedOpencodeBinary > discovers a workspace ancestor when the configured project leaf is absent [0.86ms]
(pass) resolvePinnedOpencodeBinary > launcher absolute path wins over a hostile search PATH [24.67ms]
(pass) resolvePinnedOpencodeBinary > rejects non-absolute overrides [0.22ms]

src/runtime/grok-build-acp/events.test.ts:
(pass) Grok ACP event reducer — fixture replay > T6 prompt fixture accumulates final reply chunks [7.50ms]
(pass) Grok ACP event reducer — fixture replay > T8 session/load skips replay chunks from the previous turn [0.84ms]
(pass) Grok ACP event reducer — fixture replay > T9 abort + resume accumulates only the resumed turn reply [0.83ms]

src/runtime/grok-build-acp/resume-hint.test.ts:
(pass) fetchUnresolvedOutbound > returns empty array when the hub has no outbound rows for this sender [0.42ms]
(pass) fetchUnresolvedOutbound > filters to only delivered/started status [0.34ms]
(pass) fetchUnresolvedOutbound > caps results at topN (preserves server-side recency order) [0.48ms]
(pass) fetchUnresolvedOutbound > forwards the sender alias and a sane limit to the listTasks hook (no node_id fallback path) [0.24ms]
(pass) fetchUnresolvedOutbound > #146 PR-4 二审 — sends from_node_id ONLY when probe confirmed server supports it [0.24ms]
(pass) fetchUnresolvedOutbound > #146 PR-4 二审 — without probe confirmation, never sends from_node_id (old-server safety) [0.19ms]
(pass) fetchUnresolvedOutbound > #146 PR-4 二审 — when probe explicitly returned false, falls back even with node_id available [0.23ms]
(pass) fetchUnresolvedOutbound > #146 PR-4 — empty / null nodeId falls back to from_name path [0.29ms]
(pass) fetchUnresolvedOutbound > graceful fallback when list_tasks throws — returns empty, does not propagate [0.35ms]
(pass) fetchUnresolvedOutbound > graceful fallback for malformed payloads — non-array tasks [0.35ms]
(pass) fetchUnresolvedOutbound > clamps absurd opts: topN > 50 is capped, limit > 100 is capped [0.19ms]
(pass) fetchUnresolvedOutbound > 二审 — drops rows whose from_node_id does not match ours (server bug defence) [0.29ms]
(pass) fetchUnresolvedOutbound > 二审 — when row has no from_node_id, falls back to from_name match [0.48ms]
(pass) fetchUnresolvedOutbound > 二审 — drops rows with NEITHER from_node_id nor from_name (conservative) [0.38ms]
(pass) fetchUnresolvedOutbound > 二审 — prefers from_node_id over from_name when both present (handles rename correctly) [0.29ms]
(pass) fetchUnresolvedOutbound > 二审 — when WE have no nodeId, identity check uses from_name only [0.28ms]
(pass) buildResumeHint > returns null for an empty list — caller skips the prepend with no noise [0.11ms]
(pass) buildResumeHint > single task is listed with target alias + task id (8-char) + content preview [0.33ms]
(pass) buildResumeHint > hint wording: explicit do-NOT-redispatch instruction in both Chinese phrasing and English keyword [0.16ms]
(pass) buildResumeHint > hint promotes send_message as the legitimate alternative for status check-ins [0.12ms]
(pass) buildResumeHint > hint mentions server-side dedup as a safety net but tells the LLM not to rely on it [0.13ms]
(pass) buildResumeHint > hint avoids to-do framing — would push the LLM into reprocessing [0.15ms]
(pass) buildResumeHint > long content is truncated to 120 chars including ellipsis [0.29ms]
(pass) buildResumeHint > content with triple-backticks is defanged (prevents code-fence injection from resumed task body) [0.08ms]
(pass) buildResumeHint > missing fields fall back gracefully without throwing [0.08ms]
(pass) buildResumeHint > multi-task list preserves order from the input (server-side recency) [0.12ms]

src/runtime/grok-build-acp/client.test.ts:
(pass) GrokAcpClient > starts the ACP server as `grok agent stdio` without inventing a model flag [68.38ms]
(pass) GrokAcpClient > handles ACP server-to-client fs and permission requests [64.73ms]
(pass) GrokAcpClient > coerces non-integer fs error codes to numeric JSON-RPC codes [72.22ms]
(pass) GrokAcpClient > requestWithIdleTimeout does not fire while agent is streaming notifications [791.12ms]
(pass) GrokAcpClient > requestWithIdleTimeout fires when agent goes silent past threshold [1205.90ms]
(pass) GrokAcpClient > preserves valid integer error codes [60.34ms]

src/runtime/grok-build-acp/timeout-resolve.test.ts:
(pass) resolveGrokAcpTimeout > env wins over flags and default (mirrors cli.ts precedence) [2.04ms]
(pass) resolveGrokAcpTimeout > flag wins over default when env is unset [0.08ms]
(pass) resolveGrokAcpTimeout > flag string is parsed (config.json values arrive as strings or numbers) [0.06ms]
(pass) resolveGrokAcpTimeout > default fires when neither env nor flag is set [0.09ms]
(pass) resolveGrokAcpTimeout > empty string env is ignored (operator unset the var) [0.06ms]
(pass) resolveGrokAcpTimeout > null and empty flag are ignored — falls through to default [0.10ms]
(pass) resolveGrokAcpTimeout > non-numeric / negative / NaN inputs fall through (the silent-default trap) [0.08ms]

src/runtime/grok-build-acp/runtime.test.ts:
(pass) runGrokAcpTurn runtime evidence > separates prompt submission from exact prompt-response consumption [83.34ms]

src/runtime/opencode-copresence/inbox-wiring.test.ts:
(pass) OpenCode copresence CommHub message wiring > work and informational drains are independent lanes [0.53ms]
(pass) OpenCode copresence CommHub message wiring > new_message SSE uses a non-blocking informational lane [0.23ms]
(pass) OpenCode copresence CommHub message wiring > message is displayed as a non-replying TUI notification in the fast drain [0.21ms]
(pass) OpenCode copresence CommHub message wiring > the task drain does not claim OpenCode copresence messages [0.19ms]
(pass) OpenCode copresence CommHub message wiring > network tasks pass their authenticated sender into the shared TUI turn [0.17ms]
(pass) OpenCode copresence CommHub message wiring > startup and SSE reconnect both recover pending informational messages [0.38ms]
(pass) OpenCode copresence CommHub message wiring > runtime startup is single-flight and shutdown waits for an in-flight open [0.16ms]
(pass) OpenCode copresence CommHub message wiring > tmux SIGHUP enters the same cleanup path as SIGTERM [0.44ms]

src/runtime/opencode-copresence/runtime.test.ts:
(pass) OpenCode native serve+attach copresence > requires an explicit provider/model for production copresence [0.30ms]
(pass) OpenCode native serve+attach copresence > requires an explicit provider/model at the vetted launch seam too [1.61ms]
(pass) OpenCode native serve+attach copresence > wires one token-bound CommHub MCP without reopening local tools [1.88ms]
(pass) OpenCode native serve+attach copresence > uses one authenticated loopback session for FIFO network turns and emits an owner-only attach launcher [182.48ms]
(pass) OpenCode native serve+attach copresence > shows the network sender in both the toast title and message body [173.70ms]
(pass) OpenCode native serve+attach copresence > shows the normalized network-task sender in the shared TUI turn [146.90ms]
(pass) OpenCode native serve+attach copresence > waits for an already-busy human session before injecting a network turn [611.51ms]
(pass) OpenCode native serve+attach copresence > refuses a reply owned by a human turn that won the idle-to-submit race [205.32ms]
(pass) OpenCode native serve+attach copresence > uses OpenCode's ascending message ID shape across sequential network turns [231.09ms]
(pass) OpenCode native serve+attach copresence > does not treat a missing session status and missing session record as idle [487.07ms]
(pass) OpenCode native serve+attach copresence > binds teardown authority to a detached pid, pgrp, and process start ticks [2.04ms]

src/runtime/side-thread/fork-process-race.test.ts:
(pass) cross-process stable fork operation has exactly one RPC executor [154.30ms]

src/runtime/side-thread/operation-ledger.test.ts:
(pass) PrivateFileOperationLedger > atomically persists 0600 and recovers across instances [9.35ms]
(pass) PrivateFileOperationLedger > rejects traversal, bearer, URL and unhashed targets [0.83ms]
(pass) PrivateFileOperationLedger > operation ids are stable and identity/state cannot be rewritten [6.19ms]

src/runtime/side-thread/fork-lease.test.ts:
(pass) PrivateFileForkLeaseStore > persists a private per-source lease and the same operation resumes across instances [11.42ms]
(pass) PrivateFileForkLeaseStore > a different operation cannot steal an unresolved source lease [2.65ms]
(pass) PrivateFileForkLeaseStore > kernel executor claim is process-exclusive and explicitly gated off unproved platforms [16.96ms]
(pass) PrivateFileForkLeaseStore > reopen repairs lease mode and rejects hard-linked state [2.83ms]
(pass) PrivateFileForkLeaseStore > executor lock refuses symlink and hardlink substitution [5.06ms]

src/runtime/side-thread/command-transport.test.ts:
(pass) SideThread dedicated node command boundary > durable receipt makes an ACK-loss replay mutation-free across executor restart [13.02ms]
(pass) SideThread dedicated node command boundary > same command identity with changed payload fails closed [11.20ms]
(pass) SideThread dedicated node command boundary > all attachments materialize and verify before start; no text-only downgrade [15.96ms]
(pass) SideThread dedicated node command boundary > bring-back is native+journal injected or unsupported, never a task fallback [15.94ms]
(pass) SideThread dedicated node command boundary > only identity-bound four-tuple terminal events leave the node [4.62ms]
(pass) SideThread dedicated node command boundary > bring-back write-ahead journal fails closed after response loss [10.29ms]
(pass) SideThread dedicated node command boundary > attachment grant is bound to node token, exact size and digest [1.43ms]
(pass) SideThread dedicated node command boundary > consumer replays a durable receipt after ACK response loss without native replay [13.47ms]
(pass) SideThread dedicated node command boundary > two executors cannot concurrently cross receipt/native/receipt boundary [61.65ms]
(pass) SideThread dedicated node command boundary > terminal POST response loss survives consumer restart and drains before commands [6.01ms]

src/runtime/side-thread/codex-app-server-adapter.test.ts:
(pass) CodexAppServerSideThreadAdapter > capability matrix fails closed [3.40ms]
(pass) CodexAppServerSideThreadAdapter > fork sends one exact boundary and no permission override [59.83ms]
(pass) CodexAppServerSideThreadAdapter > adapter itself fails before RPC for unsupported boundary [25.83ms]
(pass) CodexAppServerSideThreadAdapter > binds execution by echoed client id, not response turn id [47.11ms]
(pass) CodexAppServerSideThreadAdapter > does not duplicate when response is lost after identity echo [39.45ms]
(pass) CodexAppServerSideThreadAdapter > exact cancel refuses source, sibling, and unknown turns [79.88ms]
(pass) CodexAppServerSideThreadAdapter > out-of-order terminals remain isolated by thread and turn [87.03ms]
(pass) CodexAppServerSideThreadAdapter > duplicate derived identity and delete during starting fail closed [55.12ms]
(pass) CodexAppServerSideThreadAdapter > terminal before identity echo is buffered and unowned events are reported [58.65ms]
(pass) CodexAppServerSideThreadAdapter > identity timeout is ambiguous and close settles a pending start [48.08ms]
(pass) CodexAppServerSideThreadAdapter > snapshots thread/list before fork and uniquely reconciles a lost response without another RPC [41.50ms]
(pass) CodexAppServerSideThreadAdapter > multiple post-snapshot fork candidates stay ambiguous and retries never fork again [43.05ms]
(pass) CodexAppServerSideThreadAdapter > an ambiguous start reconciles the unique persisted client identity without another turn/start [54.16ms]
(pass) CodexAppServerSideThreadAdapter > accepted and ambiguous start/interrupt/archive/delete operations never repeat their RPC [101.22ms]
(pass) CodexAppServerSideThreadAdapter > recovers a lease-first snapshot tear without adopting a pre-snapshot fork [35.37ms]
(pass) CodexAppServerSideThreadAdapter > restart reconciliation restores exact terminal and cancel ownership [70.09ms]
(pass) CodexAppServerSideThreadAdapter > discard compensation is durable and response-loss replay never deletes twice [45.56ms]

src/runtime/side-thread/domain.test.ts:
(pass) SideThreadService > fails closed before fork for unsupported capability [1.65ms]
(pass) SideThreadService > concurrent create and attempt request keys are idempotent [2.31ms]
(pass) SideThreadService > boundary-specific capability rejects before without blocking through [0.34ms]
(pass) SideThreadService > cancel uses exact derived thread and active turn [0.99ms]
(pass) SideThreadService > drops mismatched and stale terminal events without settling current attempt [0.98ms]
(pass) SideThreadService > domain rejects unbound terminal racing start return [0.42ms]
(pass) SideThreadService > archive is idempotent, purge is owned and refuses running turns [1.20ms]
(pass) SideThreadService > audit is field-minimized and never contains prompt [0.47ms]
(pass) SideThreadService > hostile dropped-event details are reduced to a fixed audit reason [0.40ms]
(pass) SideThreadService > close removes subscription and refuses new mutations [0.41ms]
(pass) SideThreadService > rejects duplicate fork ownership, capability drift, and unsafe identities [0.73ms]
(pass) SideThreadService > audit sink failures cannot orphan or duplicate a fork [0.31ms]
(pass) SideThreadService > capability flip after fork fails create and compensates derived thread [0.53ms]
(pass) SideThreadService > ambiguous create and start retries reuse stable side/attempt operation identities [0.83ms]

src/runtime/codex-app-server/session-manager.test.ts:
(pass) createCodexSessionManager > the production Codex inbox path is wired through the shared holder [1.25ms]
(pass) createCodexSessionManager > shared co-presence attaches eagerly before SSE and the human TUI [1.17ms]
(pass) createCodexSessionManager > concurrent Dashboard handlers share one complete open attempt [1.06ms]
(pass) createCodexSessionManager > a rejected open is cleared and the next row can retry [0.40ms]
(pass) createCodexSessionManager > stopped and explicitly invalidated sessions are never reused [0.30ms]
(pass) createCodexSessionManager > a session that dies during bootstrap is not published [0.21ms]

src/runtime/codex-app-server/runtime.test.ts:
(pass) buildOwnedAppServerArgs > no opts → bare app-server (codex defaults apply) [0.13ms]
(pass) buildOwnedAppServerArgs > approval_policy only → single -c override before --listen [0.08ms]
(pass) buildOwnedAppServerArgs > sandbox_mode only → single -c override [0.05ms]
(pass) buildOwnedAppServerArgs > auto-approve posture (never + danger-full-access) → both overrides, policy first [0.07ms]
(pass) buildOwnedAppServerArgs > commhubMcpUrl → adds url + bearer-token-env-var -c overrides [0.08ms]
(pass) buildOwnedAppServerArgs > the CommHub bearer TOKEN never appears in argv (only the env-var NAME) [0.14ms]
(pass) buildOwnedAppServerArgs > full production posture (yolo + commhub MCP) → stable order, --listen last [0.15ms]
(pass) recoverSharedTurnOnAttach > invokes persisted active-turn recovery before shared runtime is returned [0.51ms]
(pass) recoverSharedTurnOnAttach > history read failure is visible and never reported as steerable [0.27ms]
(pass) codexAppServerThink — terminal-event reconciliation watchdog > FIFO admission reports neither submission nor consumption [22.02ms]
(pass) codexAppServerThink — terminal-event reconciliation watchdog > exact runtime submission and task_started report each level once [0.71ms]
(pass) codexAppServerThink — terminal-event reconciliation watchdog > exact task activity resets the response idle deadline for a long-running turn [70.63ms]
(pass) codexAppServerThink — terminal-event reconciliation watchdog > activity from another task cannot keep a silent owned task alive [61.04ms]
(pass) codexAppServerThink — terminal-event reconciliation watchdog > a started task whose client identity never confirms has a bounded, distinct response timeout [26.30ms]
(pass) codexAppServerThink — terminal-event reconciliation watchdog > a never-started FIFO task has its own finite, distinct queue deadline [80.68ms]
(pass) codexAppServerThink — terminal-event reconciliation watchdog > lost task_started after FIFO removal remains finite [80.75ms]
(pass) codexAppServerThink — terminal-event reconciliation watchdog > a failed start or steer requeued after the queue deadline cannot leave a ghost row [115.48ms]
(pass) codexAppServerThink — terminal-event reconciliation watchdog > queued wait does not consume the model-response timeout budget [88.62ms]
(pass) codexAppServerThink — terminal-event reconciliation watchdog > another task starting cannot arm this task's timeout [111.25ms]
(pass) codexAppServerThink — terminal-event reconciliation watchdog > resolves from authoritative reconciliation when turn/completed is missed [7.36ms]
(pass) codexAppServerThink — terminal-event reconciliation watchdog > forwards the authenticated Dashboard steering decision to the bridge [5.43ms]
(pass) codexAppServerReplyOrThrow > failed bridge outcomes enter processTask's thrown failure path [0.28ms]
(pass) codexAppServerReplyOrThrow > successful empty replies preserve the existing fallback [0.06ms]

 1420 pass
 0 fail
 5102 expect() calls
Ran 1420 tests across 108 files. [126.67s]
executed_files=108 discovered_files=108
[L0b] every agent-node/tests file, dispatched by kind
tests_dir_executed=6 tests_dir_discovered=6 tests_dir_failed=0
[L1] witnessed-red: disconnect readable attachment content from runtime
MUTATION_RED readable-attachment-runtime-disconnected rc=1
RESULT: PASS
