@junghanacs/entwurf 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/BASELINE.md +23 -5
- package/CHANGELOG.md +236 -0
- package/DELIVERY.md +59 -6
- package/README.md +40 -9
- package/VERIFY.md +9 -1
- package/docs/acp-backend-rail.md +9 -1
- package/docs/external-mcp-host.md +6 -3
- package/docs/setup-clean-host.md +93 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +3 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +6 -2
- package/package.json +2 -2
- package/pi-extensions/acp-provider.ts +1 -1
- package/pi-extensions/lib/acp/models.ts +3 -3
- package/pi-extensions/lib/acp/overlay.ts +6 -2
- package/pi-extensions/lib/meta-session.ts +25 -0
- package/run.sh +71 -26
- package/scripts/agy-bridge.sh +1 -1
- package/scripts/agy-imprint.sh +10 -7
- package/scripts/check-acp-carrier-augment.ts +6 -5
- package/scripts/check-acp-cortex.ts +41 -0
- package/scripts/check-acp-provider-surface.ts +9 -6
- package/scripts/check-copilot-birth-hook.ts +3 -1
- package/scripts/check-copilot-receive-arm.ts +169 -21
- package/scripts/check-copilot-statusline.ts +3 -1
- package/scripts/check-gate-qualification.ts +10 -9
- package/scripts/check-hook-launch-topology.ts +6 -5
- package/scripts/check-install-surface.ts +2 -1
- package/scripts/check-meta-facts.ts +6 -4
- package/scripts/check-meta-hook-session-switch.ts +4 -3
- package/scripts/check-meta-identity-consumers.ts +8 -7
- package/scripts/check-meta-receiver-marker.ts +2 -1
- package/scripts/check-omp-birth-hook.ts +3 -2
- package/scripts/check-probe-bridge-command.ts +3 -1
- package/scripts/check-setup-qualification.sh +21 -0
- package/scripts/copilot-bridge-doctor.sh +15 -5
- package/scripts/copilot-bridge-install.sh +6 -2
- package/scripts/copilot-launch.sh +16 -2
- package/scripts/copilot-receive-bridge.sh +80 -13
- package/scripts/lib/reclaim-on-exit.ts +86 -0
- package/scripts/meta-bridge-doctor.sh +56 -15
- package/scripts/meta-bridge-install.sh +13 -7
- package/scripts/meta-bridge-uninstall.sh +6 -4
- package/scripts/mutants/acp-cortex.json +26 -2
- package/scripts/mutants/copilot-receive.json +26 -0
- package/scripts/mutants/omp-birth.json +23 -6
- package/scripts/mutants/setup-verdict.json +13 -0
- package/scripts/omp-bridge-doctor.sh +110 -41
- package/scripts/omp-bridge-install.sh +6 -2
- package/scripts/omp-receive-install.sh +7 -2
- package/scripts/raw-async-delivery/README.md +10 -1
- package/scripts/raw-codex-measure/README.md +689 -0
- package/scripts/raw-codex-measure/source-audit.md +243 -0
- package/scripts/raw-macos-measure/README.md +148 -0
- package/scripts/raw-macos-measure/probe.sh +389 -0
- package/scripts/smoke-meta-async-drift.sh +7 -5
- package/scripts/smoke-meta-install-state.sh +70 -19
- package/scripts/smoke-omp-bridge-state.sh +38 -0
- package/scripts/smoke-setup-verdict.sh +100 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# raw-macos-measure/probe.sh — Darwin host measurement for the macOS parity lane (#78).
|
|
3
|
+
#
|
|
4
|
+
# MEASUREMENT ONLY. This script writes nothing outside its own temp dir, installs
|
|
5
|
+
# nothing, needs no entwurf installation, and touches no operator config. It is
|
|
6
|
+
# meant to be run ONCE on a borrowed Mac and its whole stdout pasted into
|
|
7
|
+
# scripts/raw-macos-measure/README.md.
|
|
8
|
+
#
|
|
9
|
+
# It is /bin/sh (not bash) on purpose: macOS ships bash 3.2 and one of the things
|
|
10
|
+
# under measurement is what a shell can assume here at all.
|
|
11
|
+
#
|
|
12
|
+
# ./probe.sh # human-readable ledger on stdout
|
|
13
|
+
#
|
|
14
|
+
# Every cell prints its own verdict token so a reader never has to interpret raw
|
|
15
|
+
# tool output: PRESENT / ABSENT / OK / DIFFERS / FAIL / UNKNOWN.
|
|
16
|
+
|
|
17
|
+
set -u
|
|
18
|
+
|
|
19
|
+
TMP=$(mktemp -d "${TMPDIR:-/tmp}/entwurf-macos-probe.XXXXXX") || exit 1
|
|
20
|
+
trap 'rm -rf "$TMP"' EXIT INT TERM
|
|
21
|
+
|
|
22
|
+
hdr() {
|
|
23
|
+
printf '\n== %s ==\n' "$1"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# `have <cmd>` -> PRESENT/ABSENT plus the resolved path.
|
|
27
|
+
have() {
|
|
28
|
+
if p=$(command -v "$1" 2>/dev/null); then
|
|
29
|
+
printf ' %-18s PRESENT %s\n' "$1" "$p"
|
|
30
|
+
return 0
|
|
31
|
+
fi
|
|
32
|
+
printf ' %-18s ABSENT\n' "$1"
|
|
33
|
+
return 1
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
printf 'entwurf raw-macos-measure probe\n'
|
|
37
|
+
printf 'run at: %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ') UTC"
|
|
38
|
+
|
|
39
|
+
hdr 'M1. host identity'
|
|
40
|
+
if command -v sw_vers >/dev/null 2>&1; then
|
|
41
|
+
sw_vers | sed 's/^/ /'
|
|
42
|
+
else
|
|
43
|
+
printf ' sw_vers ABSENT — this is not a Darwin host; the ledger cell is void.\n'
|
|
44
|
+
fi
|
|
45
|
+
printf ' uname -srm: %s\n' "$(uname -srm)"
|
|
46
|
+
printf ' hw.model: %s\n' "$(sysctl -n hw.model 2>/dev/null || echo UNKNOWN)"
|
|
47
|
+
printf ' cpu: %s\n' "$(sysctl -n machdep.cpu.brand_string 2>/dev/null || echo UNKNOWN)"
|
|
48
|
+
|
|
49
|
+
hdr 'M2. shell — what a script may assume'
|
|
50
|
+
printf ' /bin/sh -> %s\n' "$(/bin/sh -c 'echo ${BASH_VERSION:-not-bash}' 2>/dev/null)"
|
|
51
|
+
printf ' /bin/bash -> %s\n' "$(/bin/bash -c 'echo ${BASH_VERSION:-unknown}' 2>/dev/null || echo ABSENT)"
|
|
52
|
+
printf ' env bash -> %s (%s)\n' \
|
|
53
|
+
"$(env bash -c 'echo ${BASH_VERSION:-unknown}' 2>/dev/null || echo ABSENT)" \
|
|
54
|
+
"$(command -v bash 2>/dev/null || echo no-bash-on-PATH)"
|
|
55
|
+
# bash 4 features the repo's gates use: `declare -A`, `mapfile`.
|
|
56
|
+
if env bash -c 'declare -A _x' >/dev/null 2>&1; then
|
|
57
|
+
printf ' declare -A (bash4) OK\n'
|
|
58
|
+
else
|
|
59
|
+
printf ' declare -A (bash4) FAIL — associative arrays unavailable to `env bash`\n'
|
|
60
|
+
fi
|
|
61
|
+
if env bash -c 'mapfile -t _y < /dev/null' >/dev/null 2>&1; then
|
|
62
|
+
printf ' mapfile (bash4) OK\n'
|
|
63
|
+
else
|
|
64
|
+
printf ' mapfile (bash4) FAIL\n'
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
hdr 'M3. runtime prerequisites'
|
|
68
|
+
have node && printf ' %-18s %s\n' 'node --version' "$(node --version 2>/dev/null)"
|
|
69
|
+
have npm && printf ' %-18s %s\n' 'npm --version' "$(npm --version 2>/dev/null)"
|
|
70
|
+
have pnpm && printf ' %-18s %s\n' 'pnpm --version' "$(pnpm --version 2>/dev/null)"
|
|
71
|
+
# python3 on macOS may be the CommandLineTools STUB at /usr/bin/python3, which
|
|
72
|
+
# prints nothing useful and pops a GUI installer instead. The shipped operator
|
|
73
|
+
# surface calls python3 in hundreds of places, so a stub is a total install
|
|
74
|
+
# failure, not a degraded cell.
|
|
75
|
+
if have python3; then
|
|
76
|
+
printf ' %-18s %s\n' 'python3 -V' "$(python3 -V 2>&1)"
|
|
77
|
+
if python3 -c 'print("live")' 2>/dev/null | grep -q live; then
|
|
78
|
+
printf ' %-18s REAL (executes code, no install prompt)\n' 'python3 kind'
|
|
79
|
+
else
|
|
80
|
+
printf ' %-18s STUB/BROKEN — the whole install+doctor surface dies here\n' 'python3 kind'
|
|
81
|
+
fi
|
|
82
|
+
fi
|
|
83
|
+
have git
|
|
84
|
+
have tmux && printf ' %-18s %s\n' 'tmux -V' "$(tmux -V 2>/dev/null)"
|
|
85
|
+
|
|
86
|
+
hdr 'M4. GNU-vs-BSD tool matrix (the P1 substitution surface)'
|
|
87
|
+
have sha256sum || true
|
|
88
|
+
have shasum || true
|
|
89
|
+
have openssl || true
|
|
90
|
+
have realpath || true
|
|
91
|
+
have timeout || true
|
|
92
|
+
have gtimeout || true
|
|
93
|
+
have gsed || true
|
|
94
|
+
have gstat || true
|
|
95
|
+
printf '\n -- behavioural probes (presence is not compatibility) --\n'
|
|
96
|
+
printf 'abc' >"$TMP/f"
|
|
97
|
+
# stat: GNU `-c %s` vs BSD `-f %z`
|
|
98
|
+
if stat -c %s "$TMP/f" >/dev/null 2>&1; then
|
|
99
|
+
printf ' stat -c %%s OK (GNU form works)\n'
|
|
100
|
+
else
|
|
101
|
+
printf ' stat -c %%s FAIL (GNU form rejected) — BSD `stat -f %%z` = %s\n' \
|
|
102
|
+
"$(stat -f %z "$TMP/f" 2>/dev/null || echo FAIL)"
|
|
103
|
+
fi
|
|
104
|
+
# readlink -f
|
|
105
|
+
ln -s "$TMP/f" "$TMP/link"
|
|
106
|
+
if readlink -f "$TMP/link" >/dev/null 2>&1; then
|
|
107
|
+
printf ' readlink -f OK\n'
|
|
108
|
+
else
|
|
109
|
+
printf ' readlink -f FAIL (no GNU -f)\n'
|
|
110
|
+
fi
|
|
111
|
+
# stat: both fields the repo reads (size AND mtime), because a working `-f %z`
|
|
112
|
+
# does not promise `-f %m`.
|
|
113
|
+
printf ' stat -f %%z (size) %s\n' "$(stat -f %z "$TMP/f" 2>/dev/null || echo FAIL)"
|
|
114
|
+
printf ' stat -f %%m (mtime) %s\n' "$(stat -f %m "$TMP/f" 2>/dev/null || echo FAIL)"
|
|
115
|
+
printf ' stat -c %%Y (mtime) %s\n' "$(stat -c %Y "$TMP/f" 2>/dev/null || echo FAIL)"
|
|
116
|
+
# sha256: which producer, and does the digest text match across producers?
|
|
117
|
+
S_SUM=$(sha256sum "$TMP/f" 2>/dev/null | awk '{print $1}')
|
|
118
|
+
S_SHA=$(shasum -a 256 "$TMP/f" 2>/dev/null | awk '{print $1}')
|
|
119
|
+
S_SSL=$(openssl dgst -sha256 "$TMP/f" 2>/dev/null | awk '{print $NF}')
|
|
120
|
+
printf ' sha256sum %s\n' "${S_SUM:-ABSENT}"
|
|
121
|
+
printf ' shasum -a 256 %s\n' "${S_SHA:-ABSENT}"
|
|
122
|
+
printf ' openssl dgst %s\n' "${S_SSL:-ABSENT}"
|
|
123
|
+
for v in "$S_SUM" "$S_SHA" "$S_SSL"; do
|
|
124
|
+
[ -n "$v" ] && [ "$v" != "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" ] &&
|
|
125
|
+
printf ' DIGEST MISMATCH a producer disagrees with the known sha256 of "abc"\n'
|
|
126
|
+
done
|
|
127
|
+
# NUL-delimited pipelines
|
|
128
|
+
if printf 'a\0b\0' | sort -z >/dev/null 2>&1; then
|
|
129
|
+
printf ' sort -z OK\n'
|
|
130
|
+
else
|
|
131
|
+
printf ' sort -z FAIL (no BSD equivalent flag)\n'
|
|
132
|
+
fi
|
|
133
|
+
if printf 'a\0' | xargs -0 true >/dev/null 2>&1; then
|
|
134
|
+
printf ' xargs -0 OK\n'
|
|
135
|
+
else
|
|
136
|
+
printf ' xargs -0 FAIL\n'
|
|
137
|
+
fi
|
|
138
|
+
if printf 'a\0' | xargs -0r true >/dev/null 2>&1; then
|
|
139
|
+
printf ' xargs -0r OK\n'
|
|
140
|
+
else
|
|
141
|
+
printf ' xargs -0r FAIL (GNU-only -r; BSD xargs already skips empty input)\n'
|
|
142
|
+
fi
|
|
143
|
+
# grep -P
|
|
144
|
+
if printf 'a\n' | grep -P 'a' >/dev/null 2>&1; then
|
|
145
|
+
printf ' grep -P OK\n'
|
|
146
|
+
else
|
|
147
|
+
printf ' grep -P FAIL (no PCRE); grep -E = %s\n' \
|
|
148
|
+
"$(printf 'a\n' | grep -E 'a' >/dev/null 2>&1 && echo OK || echo FAIL)"
|
|
149
|
+
fi
|
|
150
|
+
# date -d
|
|
151
|
+
if date -d '@0' >/dev/null 2>&1; then
|
|
152
|
+
printf ' date -d OK\n'
|
|
153
|
+
else
|
|
154
|
+
printf ' date -d FAIL (BSD date uses -r/-j -f)\n'
|
|
155
|
+
fi
|
|
156
|
+
# mktemp with a template (both accept it, but confirm)
|
|
157
|
+
printf ' mktemp -d %s\n' "$(mktemp -d "${TMPDIR:-/tmp}/probe.XXXXXX" >/dev/null 2>&1 && echo OK || echo FAIL)"
|
|
158
|
+
|
|
159
|
+
hdr 'M5. start-key sources — the identity rail (meta-session.ts:1554)'
|
|
160
|
+
printf ' /proc present? %s\n' "$([ -d /proc ] && echo YES || echo NO)"
|
|
161
|
+
SELF=$$
|
|
162
|
+
printf ' ps -o lstart= self: %s\n' "$(ps -o lstart= -p "$SELF" 2>/dev/null | sed 's/^ *//;s/ *$//')"
|
|
163
|
+
printf ' ps -o command= self: %s\n' "$(ps -o command= -p "$SELF" 2>/dev/null | sed 's/^ *//' | cut -c1-100)"
|
|
164
|
+
# RESOLUTION TEST: two children started back to back. If their lstart strings are
|
|
165
|
+
# equal, the `ps:` scheme's pid-reuse defense is 1-second granular.
|
|
166
|
+
sleep 4 &
|
|
167
|
+
C1=$!
|
|
168
|
+
sleep 4 &
|
|
169
|
+
C2=$!
|
|
170
|
+
L1=$(ps -o lstart= -p "$C1" 2>/dev/null | sed 's/^ *//;s/ *$//')
|
|
171
|
+
L2=$(ps -o lstart= -p "$C2" 2>/dev/null | sed 's/^ *//;s/ *$//')
|
|
172
|
+
printf ' child A (%s): %s\n' "$C1" "$L1"
|
|
173
|
+
printf ' child B (%s): %s\n' "$C2" "$L2"
|
|
174
|
+
if [ "$L1" = "$L2" ]; then
|
|
175
|
+
printf ' RESOLUTION 1-SECOND (two back-to-back starts share one key string)\n'
|
|
176
|
+
else
|
|
177
|
+
printf ' RESOLUTION SUB-SECOND (back-to-back starts differ) — re-run to confirm\n'
|
|
178
|
+
fi
|
|
179
|
+
# WIDENING candidate: would including argv in the key have separated them? Both
|
|
180
|
+
# children run the SAME argv on purpose — that is the WORST case for widening, and
|
|
181
|
+
# the worst case is the one a fail-closed identity rail has to survive.
|
|
182
|
+
W1=$(ps -o lstart=,command= -p "$C1" 2>/dev/null | sed 's/^ *//;s/ *$//')
|
|
183
|
+
W2=$(ps -o lstart=,command= -p "$C2" 2>/dev/null | sed 's/^ *//;s/ *$//')
|
|
184
|
+
printf ' widened key A %s\n' "$W1"
|
|
185
|
+
printf ' widened key B %s\n' "$W2"
|
|
186
|
+
if [ "$W1" = "$W2" ]; then
|
|
187
|
+
printf ' WIDENING INSUFFICIENT ALONE (identical argv collides even widened)\n'
|
|
188
|
+
else
|
|
189
|
+
printf ' WIDENING SEPARATES (argv distinguished two same-second starts)\n'
|
|
190
|
+
fi
|
|
191
|
+
kill "$C1" "$C2" 2>/dev/null
|
|
192
|
+
wait "$C1" 2>/dev/null
|
|
193
|
+
wait "$C2" 2>/dev/null
|
|
194
|
+
# MICROSECOND candidate: libproc proc_pidinfo(PROC_PIDTBSDINFO) via python3 ctypes.
|
|
195
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
196
|
+
python3 - "$SELF" <<'PY' 2>&1 | sed 's/^/ /'
|
|
197
|
+
import ctypes, ctypes.util, sys
|
|
198
|
+
pid = int(sys.argv[1])
|
|
199
|
+
lib = ctypes.util.find_library("proc") or "/usr/lib/libproc.dylib"
|
|
200
|
+
try:
|
|
201
|
+
libproc = ctypes.CDLL(lib)
|
|
202
|
+
except OSError as e:
|
|
203
|
+
print(f"libproc UNAVAILABLE ({e})")
|
|
204
|
+
raise SystemExit(0)
|
|
205
|
+
|
|
206
|
+
PROC_PIDTBSDINFO = 3
|
|
207
|
+
class ProcBsdInfo(ctypes.Structure):
|
|
208
|
+
_fields_ = [
|
|
209
|
+
("pbi_flags", ctypes.c_uint32), ("pbi_status", ctypes.c_uint32),
|
|
210
|
+
("pbi_xstatus", ctypes.c_uint32), ("pbi_pid", ctypes.c_uint32),
|
|
211
|
+
("pbi_ppid", ctypes.c_uint32), ("pbi_uid", ctypes.c_uint32),
|
|
212
|
+
("pbi_gid", ctypes.c_uint32), ("pbi_ruid", ctypes.c_uint32),
|
|
213
|
+
("pbi_rgid", ctypes.c_uint32), ("pbi_svuid", ctypes.c_uint32),
|
|
214
|
+
("pbi_svgid", ctypes.c_uint32), ("rfu_1", ctypes.c_uint32),
|
|
215
|
+
("pbi_comm", ctypes.c_char * 16), ("pbi_name", ctypes.c_char * 32),
|
|
216
|
+
("pbi_nfiles", ctypes.c_uint32), ("pbi_pgid", ctypes.c_uint32),
|
|
217
|
+
("pbi_pjobc", ctypes.c_uint32), ("e_tdev", ctypes.c_uint32),
|
|
218
|
+
("e_tpgid", ctypes.c_uint32), ("pbi_nice", ctypes.c_int32),
|
|
219
|
+
("pbi_start_tvsec", ctypes.c_uint64), ("pbi_start_tvusec", ctypes.c_uint64),
|
|
220
|
+
]
|
|
221
|
+
|
|
222
|
+
info = ProcBsdInfo()
|
|
223
|
+
n = libproc.proc_pidinfo(pid, PROC_PIDTBSDINFO, ctypes.c_uint64(0),
|
|
224
|
+
ctypes.byref(info), ctypes.sizeof(info))
|
|
225
|
+
if n != ctypes.sizeof(info):
|
|
226
|
+
print(f"proc_pidinfo FAIL (returned {n}, expected {ctypes.sizeof(info)})")
|
|
227
|
+
else:
|
|
228
|
+
print(f"proc_pidinfo OK pid={info.pbi_pid} "
|
|
229
|
+
f"start={info.pbi_start_tvsec}.{info.pbi_start_tvusec:06d} "
|
|
230
|
+
f"comm={info.pbi_comm.decode(errors='replace')}")
|
|
231
|
+
print("RESOLUTION MICROSECOND (a sub-second start key IS reachable here)")
|
|
232
|
+
PY
|
|
233
|
+
else
|
|
234
|
+
printf ' proc_pidinfo SKIPPED (no python3)\n'
|
|
235
|
+
fi
|
|
236
|
+
|
|
237
|
+
hdr 'M6. process discovery — can a reader see another process at all?'
|
|
238
|
+
# The bridge/receiver doctors narrow candidates through /proc/<pid>/{environ,cmdline}
|
|
239
|
+
# (scripts/omp-bridge-doctor.sh:258-267, scripts/copilot-receive-bridge.sh:264-289).
|
|
240
|
+
# Darwin has neither, so `ps -E` is the only candidate — and WHICH PROCESS IS ASKED
|
|
241
|
+
# decides the answer. Apple-signed, SIP-protected binaries refuse environ reads by
|
|
242
|
+
# construction, so probing `/bin/sleep` would report a false REJECTED.
|
|
243
|
+
#
|
|
244
|
+
# SCOPE, STATED EXACTLY: the node group below is a PROXY for entwurf's own MCP child,
|
|
245
|
+
# which is a node process this probe can start. It is NOT a measurement of the Copilot
|
|
246
|
+
# CLI or of omp: those are different binaries with their own signing and hardened-
|
|
247
|
+
# runtime state, and a proxy result does not transfer to them. The optional group 3
|
|
248
|
+
# probes a REAL copilot/omp process only if the operator already has one running; when
|
|
249
|
+
# it does not, that is reported as NOT MEASURED, never as coverage.
|
|
250
|
+
probe_environ() {
|
|
251
|
+
# $1 = label, $2 = pid, $3 = marker expected in the environment (or "")
|
|
252
|
+
_lbl=$1
|
|
253
|
+
_pid=$2
|
|
254
|
+
_marker=$3
|
|
255
|
+
if ps -E -p "$_pid" >/dev/null 2>&1; then
|
|
256
|
+
_out=$(ps -Eww -p "$_pid" 2>/dev/null | tail -1)
|
|
257
|
+
if [ -n "$_marker" ]; then
|
|
258
|
+
if printf '%s' "$_out" | grep -q "$_marker"; then
|
|
259
|
+
printf ' %-22s VISIBLE — marker found in `ps -Eww` output\n' "$_lbl"
|
|
260
|
+
else
|
|
261
|
+
printf ' %-22s ACCEPTED-BUT-EMPTY — ps -E returned, marker ABSENT\n' "$_lbl"
|
|
262
|
+
fi
|
|
263
|
+
else
|
|
264
|
+
printf ' %-22s ACCEPTED (width %s chars)\n' "$_lbl" \
|
|
265
|
+
"$(printf '%s' "$_out" | wc -c | tr -d ' ')"
|
|
266
|
+
fi
|
|
267
|
+
else
|
|
268
|
+
printf ' %-22s REJECTED by ps -E\n' "$_lbl"
|
|
269
|
+
fi
|
|
270
|
+
}
|
|
271
|
+
# Group 1 — UNRESTRICTED target: a node process we start ourselves, carrying a marker.
|
|
272
|
+
# This is the group that decides whether the doctors' discovery path survives.
|
|
273
|
+
if command -v node >/dev/null 2>&1; then
|
|
274
|
+
ENTWURF_PROBE_MARKER=hello-entwurf \
|
|
275
|
+
node -e 'setTimeout(function(){}, 5000)' >/dev/null 2>&1 &
|
|
276
|
+
N1=$!
|
|
277
|
+
sleep 1
|
|
278
|
+
printf ' node target pid %s\n' "$N1"
|
|
279
|
+
printf ' node argv %s\n' \
|
|
280
|
+
"$(ps -o command= -p "$N1" 2>/dev/null | sed 's/^ *//' | cut -c1-120)"
|
|
281
|
+
probe_environ 'node environ' "$N1" 'ENTWURF_PROBE_MARKER=hello-entwurf'
|
|
282
|
+
printf ' node ppid %s (expect this shell, %s)\n' \
|
|
283
|
+
"$(ps -o ppid= -p "$N1" 2>/dev/null | tr -d ' ')" "$SELF"
|
|
284
|
+
kill "$N1" 2>/dev/null
|
|
285
|
+
wait "$N1" 2>/dev/null
|
|
286
|
+
else
|
|
287
|
+
printf ' node target SKIPPED (no node on PATH) — THIS CELL IS THE IMPORTANT ONE\n'
|
|
288
|
+
fi
|
|
289
|
+
# Group 2 — RESTRICTED control: an Apple-signed system binary. A REJECTED here beside
|
|
290
|
+
# a VISIBLE above is the proof that the refusal is SIP, not a missing capability.
|
|
291
|
+
sleep 5 &
|
|
292
|
+
D1=$!
|
|
293
|
+
printf ' sleep argv %s\n' \
|
|
294
|
+
"$(ps -o command= -p "$D1" 2>/dev/null | sed 's/^ *//' | cut -c1-100)"
|
|
295
|
+
probe_environ '/bin/sleep environ' "$D1" ''
|
|
296
|
+
kill "$D1" 2>/dev/null
|
|
297
|
+
wait "$D1" 2>/dev/null
|
|
298
|
+
# Group 3 — THE REAL TARGETS, when the operator already has one running. Group 1 is a
|
|
299
|
+
# proxy; these are the binaries the doctors actually interrogate. A different signing
|
|
300
|
+
# or hardened-runtime state here than on our own node child is exactly the result that
|
|
301
|
+
# would invalidate the proxy, so an absent process is NOT MEASURED, never coverage.
|
|
302
|
+
for real in copilot omp claude; do
|
|
303
|
+
_rp=$(pgrep -x "$real" 2>/dev/null | head -1)
|
|
304
|
+
if [ -n "${_rp:-}" ]; then
|
|
305
|
+
printf ' %-22s live pid %s\n' "$real (real target)" "$_rp"
|
|
306
|
+
probe_environ "$real environ" "$_rp" ''
|
|
307
|
+
else
|
|
308
|
+
printf ' %-22s NOT MEASURED — no live `%s` process on this host\n' \
|
|
309
|
+
"$real (real target)" "$real"
|
|
310
|
+
fi
|
|
311
|
+
done
|
|
312
|
+
# Full-table scan: the fallback if environ is unreadable is argv-only matching over
|
|
313
|
+
# every process. Measure that it works AND what it costs.
|
|
314
|
+
SCAN_START=$(date +%s)
|
|
315
|
+
SCAN_N=$(ps -A -o pid=,ppid=,command= 2>/dev/null | wc -l | tr -d ' ')
|
|
316
|
+
SCAN_END=$(date +%s)
|
|
317
|
+
printf ' ps -A scan %s rows in ~%ss\n' "$SCAN_N" "$((SCAN_END - SCAN_START))"
|
|
318
|
+
printf ' pgrep present? %s\n' "$(command -v pgrep >/dev/null 2>&1 && echo YES || echo NO)"
|
|
319
|
+
printf ' lsof present? %s\n' "$(command -v lsof >/dev/null 2>&1 && echo YES || echo NO)"
|
|
320
|
+
|
|
321
|
+
hdr 'M7. pid space — how reachable is a same-second pid reuse?'
|
|
322
|
+
printf ' kern.maxproc: %s\n' "$(sysctl -n kern.maxproc 2>/dev/null || echo UNKNOWN)"
|
|
323
|
+
printf ' kern.maxprocperuid: %s\n' "$(sysctl -n kern.maxprocperuid 2>/dev/null || echo UNKNOWN)"
|
|
324
|
+
printf ' current pid: %s\n' "$SELF"
|
|
325
|
+
printf ' (PID_MAX on Darwin is a compile-time 99999; a wrap needs that many spawns)\n'
|
|
326
|
+
|
|
327
|
+
hdr 'M8. filesystem semantics that installers depend on'
|
|
328
|
+
printf ' case-sensitive? '
|
|
329
|
+
touch "$TMP/CaseFile"
|
|
330
|
+
if [ -e "$TMP/casefile" ]; then printf 'NO (case-INSENSITIVE volume)\n'; else printf 'YES\n'; fi
|
|
331
|
+
printf ' HOME: %s\n' "${HOME:-UNSET}"
|
|
332
|
+
printf ' XDG_DATA_HOME: %s\n' "${XDG_DATA_HOME:-unset (entwurf defaults apply)}"
|
|
333
|
+
printf ' symlink support: %s\n' "$([ -L "$TMP/link" ] && echo OK || echo FAIL)"
|
|
334
|
+
printf ' ~/.local/bin on PATH? %s\n' \
|
|
335
|
+
"$(printf '%s' "${PATH:-}" | tr ':' '\n' | grep -qx "$HOME/.local/bin" && echo YES || echo NO)"
|
|
336
|
+
|
|
337
|
+
hdr 'M9. fs.watch rename semantics — the mailbox doorbell'
|
|
338
|
+
# The receiver arms a watch and a sender delivers by writing then renaming into
|
|
339
|
+
# place. Darwin's fs.watch is FSEvents-backed, not inotify: confirm a rename-over
|
|
340
|
+
# actually raises an event for the WATCHED path.
|
|
341
|
+
if command -v node >/dev/null 2>&1; then
|
|
342
|
+
mkdir -p "$TMP/watch"
|
|
343
|
+
printf 'v1\n' >"$TMP/watch/target"
|
|
344
|
+
node -e '
|
|
345
|
+
const fs = require("fs");
|
|
346
|
+
const dir = process.argv[1];
|
|
347
|
+
let fired = [];
|
|
348
|
+
let watchErr = null;
|
|
349
|
+
let w = null;
|
|
350
|
+
try {
|
|
351
|
+
w = fs.watch(dir + "/target", (ev) => fired.push(ev));
|
|
352
|
+
w.on("error", (e) => { watchErr = e; });
|
|
353
|
+
} catch (e) {
|
|
354
|
+
watchErr = e;
|
|
355
|
+
}
|
|
356
|
+
setTimeout(() => {
|
|
357
|
+
try {
|
|
358
|
+
fs.writeFileSync(dir + "/staged", "v2\n");
|
|
359
|
+
fs.renameSync(dir + "/staged", dir + "/target");
|
|
360
|
+
} catch (e) {
|
|
361
|
+
watchErr = watchErr || e;
|
|
362
|
+
}
|
|
363
|
+
}, 200);
|
|
364
|
+
setTimeout(() => {
|
|
365
|
+
try { if (w) w.close(); } catch (e) { /* closing a dead watcher is not the measurement */ }
|
|
366
|
+
// EVERY path prints exactly one verdict token. An error is an honest UNKNOWN, not a
|
|
367
|
+
// missing line: a borrowed host must never hand back a cell that simply is not there.
|
|
368
|
+
if (watchErr) {
|
|
369
|
+
console.log(" fs.watch rename UNKNOWN — watcher errored: " + (watchErr.code || watchErr.message));
|
|
370
|
+
} else if (fired.length) {
|
|
371
|
+
console.log(" fs.watch rename FIRED [" + fired.join(",") + "]");
|
|
372
|
+
} else {
|
|
373
|
+
console.log(" fs.watch rename SILENT — doorbell would not ring");
|
|
374
|
+
}
|
|
375
|
+
try {
|
|
376
|
+
const dw = fs.watch(dir, () => {});
|
|
377
|
+
dw.close();
|
|
378
|
+
console.log(" fs.watch on dir SUPPORTED");
|
|
379
|
+
} catch (e) {
|
|
380
|
+
console.log(" fs.watch on dir UNSUPPORTED — " + (e.code || e.message));
|
|
381
|
+
}
|
|
382
|
+
}, 1200);
|
|
383
|
+
' "$TMP/watch" 2>&1 | sed 's/^/ /;s/^ \( *fs\.watch\)/\1/'
|
|
384
|
+
else
|
|
385
|
+
printf ' fs.watch SKIPPED (no node on PATH)\n'
|
|
386
|
+
fi
|
|
387
|
+
|
|
388
|
+
printf '\n== probe complete ==\n'
|
|
389
|
+
printf 'Paste this whole output into scripts/raw-macos-measure/README.md under the matching cell.\n'
|
|
@@ -62,11 +62,13 @@ RAW_DIR="$HERE/raw-async-delivery"
|
|
|
62
62
|
# 1.0 -> 1.1) is the real "re-verify the markers + Gotchas + raw/LIVE probes"
|
|
63
63
|
# trigger and DOES scream.
|
|
64
64
|
PIN_CLAUDE_MINOR="2.1"
|
|
65
|
-
# codex 0.
|
|
66
|
-
#
|
|
67
|
-
# 0.
|
|
68
|
-
#
|
|
69
|
-
|
|
65
|
+
# codex 0.153 (2026-09-08): RE-VERIFIED, not merely observed. The archived 0.136.0 raw probe
|
|
66
|
+
# (codex-local-appserver.sh + raw-codex-ws-turn-start.py) was re-run AS SHIPPED on codex-cli
|
|
67
|
+
# 0.153.4 and went green — idle plain `codex` auto-attached to a bare `codex app-server
|
|
68
|
+
# --listen` woke with zero typing and the model replied in the same visible session. Receipts
|
|
69
|
+
# and the six step-1 vendor measurements: scripts/raw-codex-measure/README.md (see raw-codex-
|
|
70
|
+
# measure); coordinates restated in DELIVERY.md §Codex. Codex is still NOT a citizen backend.
|
|
71
|
+
PIN_CODEX_MINOR="0.153"
|
|
70
72
|
# agy 1.1 (2026-07-14): re-verified live — entwurf_self called without a permission prompt,
|
|
71
73
|
# bidirectional native-push reply on the same gid, LIVE=1 smoke-agy-native-push-live 13/13
|
|
72
74
|
# at agy 1.1.0 (evidence recorded in DELIVERY.md §Antigravity).
|
|
@@ -962,31 +962,82 @@ else
|
|
|
962
962
|
bad "doctor did not surface enabled-but-cache-miss as a hard load failure:"$'\n'"$DOC_CACHE_OUT"
|
|
963
963
|
fi
|
|
964
964
|
|
|
965
|
-
#
|
|
966
|
-
#
|
|
967
|
-
#
|
|
968
|
-
#
|
|
969
|
-
#
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
965
|
+
# 0.20.0 D4: the platform fence moved from a bare `uname -s` refusal to the
|
|
966
|
+
# installer's own REAL dependency (python3; see meta-bridge-install.sh's platform
|
|
967
|
+
# gate comment). This gate must therefore pin the NEW contract, not the retired one:
|
|
968
|
+
# (a) Darwin install no longer refuses on platform name — it reaches PAST the
|
|
969
|
+
# platform line to its own toolchain gate, and dies there ONLY when a real
|
|
970
|
+
# dependency is actually missing;
|
|
971
|
+
# (b) with the real dependency present, Darwin clears the platform gate entirely
|
|
972
|
+
# and reaches the external claude-CLI toolchain step (never "unsupported
|
|
973
|
+
# platform", never the retired "not yet verified/certified" wording);
|
|
974
|
+
# (c) meta-bridge-doctor.sh's Darwin RAIL verdict is a SEPARATE, unmoved evidence
|
|
975
|
+
# axis (Hard Rule 17) — it still refuses (nonzero), on a narrowed reason (Q2:
|
|
976
|
+
# start-key no longer needs /proc; per-process environ discovery still does);
|
|
977
|
+
# (d) uninstall was ALREADY open to Darwin (precedent) and is untouched here.
|
|
978
|
+
FAKE_UNAME_BIN="$TMP/fake-uname-bin"; mkdir -p "$FAKE_UNAME_BIN"
|
|
979
|
+
# Bake the ABSOLUTE bash path into the shebang: the two cells below deliberately
|
|
980
|
+
# narrow PATH (no bash on it), and `#!/usr/bin/env bash` would need `env` to find
|
|
981
|
+
# `bash` on THAT narrowed PATH — this fixture's own launcher must not depend on it.
|
|
982
|
+
cat > "$FAKE_UNAME_BIN/uname" <<SH
|
|
983
|
+
#!$(command -v bash)
|
|
973
984
|
printf '%s\n' Darwin
|
|
974
985
|
SH
|
|
975
|
-
chmod +x "$
|
|
986
|
+
chmod +x "$FAKE_UNAME_BIN/uname"
|
|
987
|
+
|
|
988
|
+
# (a) A minimal PATH carrying ONLY `dirname` (the sole external command
|
|
989
|
+
# meta-bridge-install.sh calls before its own python3 check) plus the fake Darwin
|
|
990
|
+
# `uname`. No real python3/node/claude can leak in from the host — the death point
|
|
991
|
+
# is fully controlled by this fixture, not by what happens to be installed here.
|
|
992
|
+
NOPY_BIN="$TMP/nopy-bin"; mkdir -p "$NOPY_BIN"
|
|
993
|
+
ln -sf "$(command -v dirname)" "$NOPY_BIN/dirname"
|
|
994
|
+
set +e
|
|
995
|
+
DARWIN_NOPY_OUT="$(env HOME="$TMP/darwin-nopy-home" XDG_DATA_HOME="$TMP/darwin-nopy-xdg" PATH="$FAKE_UNAME_BIN:$NOPY_BIN" "$BASH" "$REPO/scripts/meta-bridge-install.sh" 2>&1)"
|
|
996
|
+
DARWIN_NOPY_CODE=$?
|
|
997
|
+
set -e
|
|
998
|
+
if [ "$DARWIN_NOPY_CODE" -ne 0 ] \
|
|
999
|
+
&& printf '%s\n' "$DARWIN_NOPY_OUT" | grep -q "python3' not on PATH" \
|
|
1000
|
+
&& ! printf '%s\n' "$DARWIN_NOPY_OUT" | grep -qi 'unsupported platform'; then
|
|
1001
|
+
ok "Darwin install clears the platform gate and refuses on the REAL missing dependency (python3), never on platform name"
|
|
1002
|
+
else bad "Darwin install did not reach the python3 dependency gate as the new fence contract requires:"$'\n'"$DARWIN_NOPY_OUT"; fi
|
|
1003
|
+
|
|
1004
|
+
# (b) The mirror proof: Darwin WITH python3+node present must clear the platform
|
|
1005
|
+
# gate AND the toolchain gate, refusing only because `claude` is absent from this
|
|
1006
|
+
# fixture's deliberately narrow PATH (never on platform name, never on the retired
|
|
1007
|
+
# "not yet verified/certified" wording).
|
|
1008
|
+
OK_BIN="$TMP/darwin-ok-bin"; mkdir -p "$OK_BIN"
|
|
1009
|
+
ln -sf "$(command -v dirname)" "$OK_BIN/dirname"
|
|
1010
|
+
ln -sf "$(command -v node)" "$OK_BIN/node"
|
|
1011
|
+
ln -sf "$(command -v python3)" "$OK_BIN/python3"
|
|
1012
|
+
set +e
|
|
1013
|
+
DARWIN_OK_OUT="$(env HOME="$TMP/darwin-ok-home" XDG_DATA_HOME="$TMP/darwin-ok-xdg" PI_CODING_AGENT_DIR="$TMP/darwin-ok-agent" PATH="$FAKE_UNAME_BIN:$OK_BIN" "$BASH" "$REPO/scripts/meta-bridge-install.sh" 2>&1)"
|
|
1014
|
+
DARWIN_OK_CODE=$?
|
|
1015
|
+
set -e
|
|
1016
|
+
if [ "$DARWIN_OK_CODE" -ne 0 ] \
|
|
1017
|
+
&& printf '%s\n' "$DARWIN_OK_OUT" | grep -q "'claude' CLI not on PATH" \
|
|
1018
|
+
&& ! printf '%s\n' "$DARWIN_OK_OUT" | grep -qi 'unsupported platform' \
|
|
1019
|
+
&& ! printf '%s\n' "$DARWIN_OK_OUT" | grep -qi 'not yet verified'; then
|
|
1020
|
+
ok "Darwin install with real python3+node clears BOTH the platform and toolchain-part-1 gates, reaching the external claude-CLI step"
|
|
1021
|
+
else bad "Darwin install with real python3+node did not clear the platform gate as the new contract requires:"$'\n'"$DARWIN_OK_OUT"; fi
|
|
1022
|
+
|
|
1023
|
+
# (c) The doctor's RAIL verdict is untouched by the fence change: still nonzero,
|
|
1024
|
+
# still reaches its final verdict line. Wording is narrowed under Q2/D1 (start-key
|
|
1025
|
+
# no longer blamed; only per-process environ discovery is), so pin the substring
|
|
1026
|
+
# that survives that rename, not the retired sentence.
|
|
976
1027
|
set +e
|
|
977
|
-
|
|
978
|
-
DARWIN_INSTALL_CODE=$?
|
|
979
|
-
DARWIN_DOCTOR_OUT="$(env HOME="$DOC_HOME" CLAUDE_CONFIG_DIR="$DOC_CFG" PI_CODING_AGENT_DIR="$DOC_AGENT" ENTWURF_META_SESSIONS_DIR="$DOC_STORE" PATH="$PLATFORM_BIN:$DOC_BIN:$PATH" bash "$REPO/scripts/meta-bridge-doctor.sh" 2>&1)"
|
|
1028
|
+
DARWIN_DOCTOR_OUT="$(env HOME="$DOC_HOME" CLAUDE_CONFIG_DIR="$DOC_CFG" PI_CODING_AGENT_DIR="$DOC_AGENT" ENTWURF_META_SESSIONS_DIR="$DOC_STORE" PATH="$FAKE_UNAME_BIN:$DOC_BIN:$PATH" bash "$REPO/scripts/meta-bridge-doctor.sh" 2>&1)"
|
|
980
1029
|
DARWIN_DOCTOR_CODE=$?
|
|
981
|
-
|
|
1030
|
+
set -e
|
|
1031
|
+
if [ "$DARWIN_DOCTOR_CODE" -ne 0 ] && printf '%s\n' "$DARWIN_DOCTOR_OUT" | grep -q 'NOT CERTIFIED' && printf '%s\n' "$DARWIN_DOCTOR_OUT" | grep -q 'meta-bridge doctor: FAIL'; then
|
|
1032
|
+
ok "Darwin doctor stays nonzero and reaches its final NOT-CERTIFIED verdict (rail certification is a separate, unmoved axis)"
|
|
1033
|
+
else bad "Darwin doctor did not hold the rail-certification evidence boundary:"$'\n'"$DARWIN_DOCTOR_OUT"; fi
|
|
1034
|
+
|
|
1035
|
+
# (d) Uninstall precedent, unchanged by this lane: it was ALREADY open to Darwin
|
|
1036
|
+
# before 0.20.0 (legacy-cleanup capability, never install certification).
|
|
1037
|
+
set +e
|
|
1038
|
+
DARWIN_UNINSTALL_OUT="$(env HOME="$TMP/darwin-clean-home" XDG_DATA_HOME="$TMP/darwin-clean-xdg" PATH="$FAKE_UNAME_BIN:$PATH" bash "$REPO/scripts/meta-bridge-uninstall.sh" 2>&1)"
|
|
982
1039
|
DARWIN_UNINSTALL_CODE=$?
|
|
983
1040
|
set -e
|
|
984
|
-
if [ "$DARWIN_INSTALL_CODE" -ne 0 ] && printf '%s\n' "$DARWIN_INSTALL_OUT" | grep -q 'not yet verified/certified for this repair cut'; then
|
|
985
|
-
ok "Darwin install is refused fail-loud as not-yet-certified (future validation may reopen)"
|
|
986
|
-
else bad "Darwin install did not enforce the repair-cut evidence boundary:"$'\n'"$DARWIN_INSTALL_OUT"; fi
|
|
987
|
-
if [ "$DARWIN_DOCTOR_CODE" -ne 0 ] && printf '%s\n' "$DARWIN_DOCTOR_OUT" | grep -q 'NOT YET VERIFIED/CERTIFIED for this repair cut' && printf '%s\n' "$DARWIN_DOCTOR_OUT" | grep -q 'meta-bridge doctor: FAIL'; then
|
|
988
|
-
ok "Darwin doctor stays nonzero and reaches its final NOT-YET-CERTIFIED verdict"
|
|
989
|
-
else bad "Darwin doctor did not hold the repair-cut evidence boundary:"$'\n'"$DARWIN_DOCTOR_OUT"; fi
|
|
990
1041
|
if [ "$DARWIN_UNINSTALL_CODE" -ne 0 ] && printf '%s\n' "$DARWIN_UNINSTALL_OUT" | grep -q 'install state missing' && ! printf '%s\n' "$DARWIN_UNINSTALL_OUT" | grep -q 'unsupported platform'; then
|
|
991
1042
|
ok "Darwin uninstall passes the platform gate and reaches honest state preflight (legacy inverse retained)"
|
|
992
1043
|
else bad "Darwin uninstall was blocked by the support hard-cut instead of reaching honest inverse preflight:"$'\n'"$DARWIN_UNINSTALL_OUT"; fi
|
|
@@ -114,6 +114,44 @@ kill "$CARRIER_PID"
|
|
|
114
114
|
wait "$CARRIER_PID" 2>/dev/null || true
|
|
115
115
|
CARRIER_PID=""
|
|
116
116
|
|
|
117
|
+
# THE CANDIDATE SET ITSELF CAN BE UNKNOWN, AND UNKNOWN IS NOT EMPTY (#78 B1). `pgrep`
|
|
118
|
+
# answers three ways and only two of them are facts about omp: 0 = it enumerated and
|
|
119
|
+
# matched, 1 = it enumerated and NOTHING matched (a real, positive absence), anything
|
|
120
|
+
# else = it never enumerated. The doctor used to `|| true` that third answer into the
|
|
121
|
+
# second, so a broken enumeration produced an empty candidate set, the clean carrier
|
|
122
|
+
# line and a PASS — with a contaminated session possibly live on the host.
|
|
123
|
+
#
|
|
124
|
+
# BOTH DIRECTIONS ARE PINNED, because a repair that also reddened the honest "nothing
|
|
125
|
+
# matched" would be a different defect. `ENTWURF_OMP_CARRIER_PIDS` must be UNSET for
|
|
126
|
+
# these two: that seam short-circuits the very enumeration under test, which is why it
|
|
127
|
+
# is a narrowing seam and never production proof.
|
|
128
|
+
PGREP_SHIM="$SB/pgrep-shim"
|
|
129
|
+
mkdir -p "$PGREP_SHIM"
|
|
130
|
+
printf '#!/usr/bin/env bash\nexit 1\n' > "$PGREP_SHIM/pgrep"
|
|
131
|
+
chmod +x "$PGREP_SHIM/pgrep"
|
|
132
|
+
if OUT="$(env -u ENTWURF_OMP_CARRIER_PIDS PATH="$PGREP_SHIM:$PATH" "$RUN" doctor-omp-bridge 2>&1)"; then
|
|
133
|
+
printf '%s\n' "$OUT" | grep -q "no live omp process carries" || die "an enumerated-and-empty candidate set did not print the clean carrier verdict"
|
|
134
|
+
ok "a \`pgrep\` that enumerated and matched NOTHING is a real absence and stays green"
|
|
135
|
+
else
|
|
136
|
+
printf '%s\n' "$OUT" >&2
|
|
137
|
+
die "a \`pgrep\` exit 1 (nothing matched) turned the carrier axis red"
|
|
138
|
+
fi
|
|
139
|
+
printf '#!/usr/bin/env bash\nexit 2\n' > "$PGREP_SHIM/pgrep"
|
|
140
|
+
if OUT="$(env -u ENTWURF_OMP_CARRIER_PIDS PATH="$PGREP_SHIM:$PATH" "$RUN" doctor-omp-bridge 2>&1)"; then
|
|
141
|
+
printf '%s\n' "$OUT" >&2
|
|
142
|
+
die "[QK:OMP-DOCTOR-UNENUMERATED-IS-UNVERIFIABLE] a FAILED process enumeration left the doctor green — it printed a carrier verdict with no candidate set, so a live omp session carrying a foreign pi garden id would read as clean"
|
|
143
|
+
fi
|
|
144
|
+
if ! printf '%s\n' "$OUT" | grep -q "UNVERIFIABLE — 'pgrep -x omp' FAILED (exit 2)"; then
|
|
145
|
+
printf '%s\n' "$OUT" >&2
|
|
146
|
+
die "the doctor went red without naming the failed enumeration as UNVERIFIABLE"
|
|
147
|
+
fi
|
|
148
|
+
if printf '%s\n' "$OUT" | grep -q "no live omp process carries"; then
|
|
149
|
+
printf '%s\n' "$OUT" >&2
|
|
150
|
+
die "the doctor claimed a clean carrier axis while the candidate set was unknown"
|
|
151
|
+
fi
|
|
152
|
+
ok "a FAILED enumeration is UNVERIFIABLE and red, and it claims neither contamination nor absence"
|
|
153
|
+
rm -rf "$PGREP_SHIM"
|
|
154
|
+
|
|
117
155
|
# ── 2. reinstall is idempotent ───────────────────────────────────────────────
|
|
118
156
|
"$RUN" install-omp-bridge >/dev/null || die "reinstall over our own state failed"
|
|
119
157
|
"$RUN" doctor-omp-bridge >/dev/null || die "doctor red after a reinstall"
|