@junghanacs/entwurf 0.15.0 → 0.16.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.
Files changed (90) hide show
  1. package/AGENTS.md +1 -0
  2. package/CHANGELOG.md +299 -0
  3. package/DELIVERY.md +4 -3
  4. package/README.md +99 -67
  5. package/VERIFY.md +13 -7
  6. package/docs/acp-backend-rail.md +1 -1
  7. package/docs/external-mcp-host.md +147 -9
  8. package/docs/setup-clean-host.md +221 -16
  9. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +65 -20
  10. package/mcp/entwurf-bridge/dist/pi-extensions/entwurf-capabilities.json +1 -0
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +17 -6
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +1 -1
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +172 -5
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +152 -17
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/omp-fresh-preflight.js +271 -0
  16. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-omp.js +988 -0
  17. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-receive-omp.js +574 -0
  18. package/mcp/entwurf-bridge/dist/scripts/omp-receive-facts.js +84 -0
  19. package/mcp/entwurf-bridge/src/index.ts +65 -19
  20. package/mcp/entwurf-bridge/tsconfig.build.json +19 -3
  21. package/mcp/tsconfig.json +10 -0
  22. package/package.json +14 -4
  23. package/pi/entwurf-capabilities.json +1 -0
  24. package/pi/meta-bridge-omp/entwurf-meta-omp/package.json +7 -0
  25. package/pi/omp-receive/entwurf-receive-omp/package.json +7 -0
  26. package/pi-extensions/entwurf-control.ts +12 -9
  27. package/pi-extensions/lib/entwurf-self-address.ts +18 -7
  28. package/pi-extensions/lib/meta-sender-identity.ts +1 -1
  29. package/pi-extensions/lib/meta-session.ts +219 -5
  30. package/pi-extensions/lib/mux-fresh-call.ts +171 -17
  31. package/pi-extensions/lib/omp-fresh-preflight.ts +275 -0
  32. package/pi-extensions/meta-bridge-omp.ts +1244 -0
  33. package/pi-extensions/meta-bridge-receive-omp.ts +666 -0
  34. package/run.sh +1041 -174
  35. package/scripts/agy-bridge.sh +4 -2
  36. package/scripts/check-copilot-birth-hook.ts +700 -23
  37. package/scripts/check-entwurf-self-address.ts +31 -0
  38. package/scripts/check-fresh-cut-gate.sh +12 -4
  39. package/scripts/check-gate-qualification.ts +8 -2
  40. package/scripts/check-harness-admission-parity.ts +143 -0
  41. package/scripts/check-meta-doctor-oracle.sh +20 -0
  42. package/scripts/check-omp-birth-hook.ts +1049 -0
  43. package/scripts/check-omp-fresh-preflight.ts +181 -0
  44. package/scripts/check-omp-receive-arm.ts +516 -0
  45. package/scripts/check-setup-qualification.sh +126 -0
  46. package/scripts/copilot-bridge-doctor.sh +104 -71
  47. package/scripts/copilot-bridge-install.sh +180 -20
  48. package/scripts/copilot-bridge-oracle.sh +223 -0
  49. package/scripts/copilot-bridge-uninstall.sh +137 -0
  50. package/scripts/dev-bin.sh +50 -9
  51. package/scripts/fake-copilot-vendor.sh +67 -0
  52. package/scripts/inventory-verification-surface.ts +1 -1
  53. package/scripts/meta-bridge-hook-log.sh +9 -1
  54. package/scripts/mutants/copilot-birth.json +96 -5
  55. package/scripts/mutants/mux-fresh-call.json +22 -22
  56. package/scripts/mutants/omp-birth.json +173 -0
  57. package/scripts/mutants/omp-fresh.json +300 -0
  58. package/scripts/mutants/omp-receive.json +135 -0
  59. package/scripts/mutants/pi-package-ownership.json +92 -0
  60. package/scripts/mutants/self-address.json +34 -0
  61. package/scripts/mutants/setup-verdict.json +148 -0
  62. package/scripts/mutants/source-install.json +32 -0
  63. package/scripts/omp-bridge-doctor.sh +315 -0
  64. package/scripts/omp-bridge-install.sh +221 -0
  65. package/scripts/omp-bridge-oracle.sh +154 -0
  66. package/scripts/omp-bridge-uninstall.sh +57 -0
  67. package/scripts/omp-mcp-bridge.sh +320 -0
  68. package/scripts/omp-mcp-config.py +392 -0
  69. package/scripts/omp-receive-doctor.sh +246 -0
  70. package/scripts/omp-receive-facts.ts +106 -0
  71. package/scripts/omp-receive-install.sh +228 -0
  72. package/scripts/omp-receive-uninstall.sh +60 -0
  73. package/scripts/omp-tool-surface.py +349 -0
  74. package/scripts/pi_settings_io.py +22 -0
  75. package/scripts/raw-omp-measure/README.md +420 -0
  76. package/scripts/raw-omp-measure/probe-extension.ts +76 -0
  77. package/scripts/raw-omp-measure/probe-receive-surface.ts +250 -0
  78. package/scripts/raw-omp-measure/source-audit.md +414 -0
  79. package/scripts/register-pi-package.py +525 -7
  80. package/scripts/register-pi-provider.py +162 -12
  81. package/scripts/smoke-agy-install-state.sh +86 -30
  82. package/scripts/smoke-agy-statusline-state.sh +9 -6
  83. package/scripts/smoke-omp-bridge-state.sh +221 -0
  84. package/scripts/smoke-omp-fresh-live.ts +497 -0
  85. package/scripts/smoke-omp-mcp-state.sh +327 -0
  86. package/scripts/smoke-omp-receive-live.ts +340 -0
  87. package/scripts/smoke-omp-receive-state.sh +196 -0
  88. package/scripts/smoke-setup-verdict.sh +291 -0
  89. package/scripts/smoke-user-scope-citizen.sh +388 -1
  90. package/scripts/tsconfig.json +2 -0
@@ -0,0 +1,291 @@
1
+ #!/usr/bin/env bash
2
+ # smoke-setup-verdict.sh — the smallest aggregate `setup` verdict fixture (#86 C1).
3
+ #
4
+ # The aggregate composition had ZERO automated consumers before this file: no
5
+ # living layer executed `entwurf setup` at all, so the false-green shape (WARN
6
+ # swallowing + unconditional "DONE ... green") had only a human operator as its
7
+ # gate. This fixture drives the REAL `run.sh setup` end to end in a sandbox and
8
+ # pins exactly the #86 C1 acceptance cells:
9
+ #
10
+ # S-1 all-harness-absent → core PASS, pi/claude/agy SKIP, computed green,
11
+ # zero harness writes, credential store untouched
12
+ # S-2 pi below floor → detected FAIL (never SKIP), nonzero, no Pi wiring
13
+ # S-3 pi at floor → presence completes project+user wiring, green,
14
+ # credential store still byte-identical
15
+ # S-4 agy detected+corrupt→ named component FAIL + NON-GREEN + nonzero exit,
16
+ # core and later components still attempted
17
+ # S-5 installed mode → the installed-vs-source branch is a NAMED verdict
18
+ # printed before anything else, and never reaches
19
+ # the source pnpm bootstrap
20
+ #
21
+ # Mutation attribution does NOT live here (round 3): the setup-verdict lane's
22
+ # QK signatures and kill cells moved to the snapshot-safe oracle
23
+ # scripts/check-setup-qualification.sh, so this file carries no [QK] tokens.
24
+ # This fixture is the BEHAVIOR authority only — S-2/S-4 still exercise the same
25
+ # below-floor and false-green shapes as living end-to-end evidence.
26
+ #
27
+ # Deterministic: no model, no network, no cost. Presence probes are pinned via
28
+ # PI_BIN / CLAUDE_BIN / AGY_BIN (the same hermetic seam smoke-agy-install-state
29
+ # uses), and every write root is sandboxed: HOME, XDG roots, the pi agent dir,
30
+ # and the dev-bin dir. The source bootstrap (`pnpm install --frozen-lockfile`)
31
+ # runs against the ALREADY-INSTALLED checkout, which is a verified no-op under a
32
+ # sandbox HOME (measured 2026-08-26).
33
+ set -euo pipefail
34
+
35
+ HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
36
+ REPO_DIR="$(cd "$HERE/.." && pwd)"
37
+
38
+ case "$REPO_DIR" in
39
+ */node_modules/*)
40
+ echo "entwurf: 'smoke-setup-verdict' is a dev-clone-only surface — run it from a checkout." >&2
41
+ exit 1
42
+ ;;
43
+ esac
44
+
45
+ # Same snapshot-purity rule as the sibling install smokes: run.sh paths import
46
+ # scripts/*.py and CPython would mint scripts/__pycache__/*.pyc inside the
47
+ # gate-qualification snapshot, ending the run IMPURE.
48
+ export PYTHONDONTWRITEBYTECODE=1
49
+
50
+ SB="$(mktemp -d -t entwurf-setup-verdict.XXXXXX)"
51
+ cleanup() { rm -rf "$SB"; }
52
+ trap cleanup EXIT
53
+
54
+ export HOME="$SB/home"
55
+ export XDG_DATA_HOME="$SB/home/.local/share"
56
+ export XDG_STATE_HOME="$SB/home/.local/state"
57
+ export XDG_CACHE_HOME="$SB/home/.cache"
58
+ export XDG_CONFIG_HOME="$SB/home/.config"
59
+ export PI_CODING_AGENT_DIR="$SB/home/.pi/agent"
60
+ export ENTWURF_DEV_BIN_DIR="$SB/bin"
61
+ export PATH="$SB/bin:$PATH"
62
+ mkdir -p "$HOME" "$PI_CODING_AGENT_DIR" "$SB/bin" "$SB/harness"
63
+
64
+ # Presence pins: default every harness to a definitely-absent path; each cell
65
+ # re-pins what it needs. Production leaves these unset.
66
+ ABSENT="$SB/harness/definitely-absent"
67
+ export PI_BIN="$ABSENT" CLAUDE_BIN="$ABSENT" AGY_BIN="$ABSENT" COPILOT_BIN="$ABSENT"
68
+
69
+ PASS=0
70
+ ok() { PASS=$((PASS + 1)); printf ' ok %s\n' "$*"; }
71
+ die() { printf 'FAIL: %s\n' "$*" >&2; exit 1; }
72
+ want() { # $1 = label, $2 = shell condition
73
+ if eval "$2"; then ok "$1"; else die "$1"; fi
74
+ }
75
+
76
+ AUTH="$PI_CODING_AGENT_DIR/auth.json"
77
+ seed_auth() {
78
+ printf '{\n "anthropic": {\n "type": "oauth",\n "access": "sandbox-oauth-token"\n }\n}\n' > "$AUTH"
79
+ AUTH_BEFORE="$(sha256sum "$AUTH" | cut -d' ' -f1)"
80
+ }
81
+ want_auth_untouched() { # $1 = cell label prefix
82
+ want "$1: credential store is byte-identical (no read-modify-write)" \
83
+ "[ \"\$(sha256sum '$AUTH' | cut -d' ' -f1)\" = '$AUTH_BEFORE' ]"
84
+ want "$1: no auth.json.bak was written" "[ ! -e '$AUTH.bak' ]"
85
+ want "$1: no 'entwurf' credential alias appeared" \
86
+ "! grep -q '\"entwurf\"' '$AUTH'"
87
+ }
88
+
89
+ # ── S-1: all harnesses absent → core PASS, three SKIPs, computed green, zero writes ──
90
+ echo "[smoke-setup-verdict] S-1 all-harness-absent setup"
91
+ PROJ1="$SB/proj1"; mkdir -p "$PROJ1"
92
+ seed_auth
93
+ set +e; OUT="$(bash "$REPO_DIR/run.sh" setup "$PROJ1" 2>&1)"; RC=$?; set -e
94
+ want "S-1: all-absent setup exits 0 (core green is still green)" "[ '$RC' -eq 0 ]"
95
+ want "S-1: mode is a named source-checkout branch, printed first" \
96
+ "printf '%s' \"\$OUT\" | head -n 1 | grep -q 'mode: source checkout'"
97
+ want "S-1: pi absent is an explicit zero-state SKIP" "printf '%s' \"\$OUT\" | grep -q 'pi: SKIP'"
98
+ want "S-1: claude absent is an explicit zero-state SKIP" "printf '%s' \"\$OUT\" | grep -q 'claude: SKIP'"
99
+ want "S-1: agy absent is an explicit zero-state SKIP" "printf '%s' \"\$OUT\" | grep -q 'agy: SKIP'"
100
+ want "S-1: copilot absent is an explicit zero-state SKIP" "printf '%s' \"\$OUT\" | grep -q 'copilot: SKIP'"
101
+ want "S-1: core bridge boundary validated (PASS)" "printf '%s' \"\$OUT\" | grep -q 'core: PASS'"
102
+ want "S-1: final verdict is computed, not unconditional" \
103
+ "printf '%s' \"\$OUT\" | grep -q 'result: green (computed from the component outcomes above)'"
104
+ want "S-1: the retired unconditional green line is gone" \
105
+ "! printf '%s' \"\$OUT\" | grep -q 'pi adapter + detected native bridges + v2 install smoke) green'"
106
+ want "S-1: zero Pi wiring written for an absent pi" "[ ! -e '$PROJ1/.pi' ]"
107
+ want "S-1: no user-scope pi settings were created" "[ ! -e '$PI_CODING_AGENT_DIR/settings.json' ]"
108
+ want "S-1: no agy config was created" "[ ! -e '$HOME/.gemini' ]"
109
+ want "S-1: no Copilot config/units were created" "[ ! -e '$HOME/.copilot' ]"
110
+ want_auth_untouched "S-1"
111
+
112
+ # ── S-2: pi resolvable but BELOW floor → detected FAIL, never SKIP, no writes ──
113
+ echo "[smoke-setup-verdict] S-2 pi below floor"
114
+ PROJ2="$SB/proj2"; mkdir -p "$PROJ2"
115
+ printf '#!/usr/bin/env bash\necho 0.1.0\n' > "$SB/harness/pi-stale"; chmod +x "$SB/harness/pi-stale"
116
+ seed_auth
117
+ set +e; OUT="$(PI_BIN="$SB/harness/pi-stale" bash "$REPO_DIR/run.sh" setup "$PROJ2" 2>&1)"; RC=$?; set -e
118
+ # Assertion ORDER is part of the kill contract: the verdict-label check runs
119
+ # FIRST so the PI-FLOOR-SKIP mutant dies on its own token, and the exit-code
120
+ # check runs SECOND so the FALSE-GREEN mutant (labels intact, exit flipped)
121
+ # dies on its token instead of a mislabeled line.
122
+ want "S-2: below-floor pi is a detected FAIL naming the supported range" \
123
+ "printf '%s' \"\$OUT\" | grep -q 'pi: FAIL' && printf '%s' \"\$OUT\" | grep -q 'outside the supported range'"
124
+ want "S-2: a detected component FAIL owns a nonzero setup exit" "[ '$RC' -ne 0 ]"
125
+ want "S-2: a stale pi is never relabeled SKIP" "! printf '%s' \"\$OUT\" | grep -q 'pi: SKIP'"
126
+ want "S-2: summary is NON-GREEN and names the failed component" \
127
+ "printf '%s' \"\$OUT\" | grep -q 'NON-GREEN (FAIL: pi)'"
128
+ want "S-2: no Pi wiring was written for the refused pi" "[ ! -e '$PROJ2/.pi' ]"
129
+ want_auth_untouched "S-2"
130
+
131
+ # ── S-2b: pi resolvable but --version CRASHES → computed FAIL, never a set -e abort ──
132
+ # Review defect (2026-08-26): an unreadable detected pi must reach the verdict
133
+ # engine and the summary, not kill setup before them.
134
+ echo "[smoke-setup-verdict] S-2b pi present but version unreadable"
135
+ PROJ2B="$SB/proj2b"; mkdir -p "$PROJ2B"
136
+ printf '#!/usr/bin/env bash\necho "pi exploded" >&2\nexit 1\n' > "$SB/harness/pi-broken"; chmod +x "$SB/harness/pi-broken"
137
+ seed_auth
138
+ set +e; OUT="$(PI_BIN="$SB/harness/pi-broken" bash "$REPO_DIR/run.sh" setup "$PROJ2B" 2>&1)"; RC=$?; set -e
139
+ want "S-2b: unreadable pi version makes setup exit nonzero via the computed verdict" "[ '$RC' -ne 0 ]"
140
+ want "S-2b: unreadable pi is a detected FAIL naming the unreadable version" \
141
+ "printf '%s' \"\$OUT\" | grep -q 'pi: FAIL' && printf '%s' \"\$OUT\" | grep -q 'unreadable version'"
142
+ want "S-2b: later components were still attempted (core bridge smoke ran)" \
143
+ "printf '%s' \"\$OUT\" | grep -q 'core: PASS'"
144
+ want "S-2b: summary is NON-GREEN (no set -e abort before the summary)" \
145
+ "printf '%s' \"\$OUT\" | grep -q 'NON-GREEN (FAIL: pi)'"
146
+ want "S-2b: no Pi wiring was written for the unreadable pi" "[ ! -e '$PROJ2B/.pi' ]"
147
+ want_auth_untouched "S-2b"
148
+
149
+ # ── S-3: pi at the pinned floor → presence completes project + user wiring ──
150
+ echo "[smoke-setup-verdict] S-3 pi present at floor"
151
+ PROJ3="$SB/proj3"; mkdir -p "$PROJ3"
152
+ PI_PIN="$(node -e 'console.log(require(process.argv[1]).devDependencies["@earendil-works/pi-coding-agent"])' "$REPO_DIR/package.json")"
153
+ printf '#!/usr/bin/env bash\necho %s\n' "$PI_PIN" > "$SB/harness/pi-ok"; chmod +x "$SB/harness/pi-ok"
154
+ seed_auth
155
+ set +e; OUT="$(PI_BIN="$SB/harness/pi-ok" bash "$REPO_DIR/run.sh" setup "$PROJ3" 2>&1)"; RC=$?; set -e
156
+ want "S-3: pi-present setup exits 0" "[ '$RC' -eq 0 ]"
157
+ want "S-3: pi wiring completed as PASS at pin $PI_PIN" "printf '%s' \"\$OUT\" | grep -q 'pi: PASS'"
158
+ want "S-3: project .pi/settings.json written (Pi-owned wiring gated on presence)" \
159
+ "[ -f '$PROJ3/.pi/settings.json' ] && grep -q 'entwurf' '$PROJ3/.pi/settings.json'"
160
+ want "S-3: user-scope citizen registered" \
161
+ "[ -f '$PI_CODING_AGENT_DIR/settings.json' ] && grep -q 'entwurf' '$PI_CODING_AGENT_DIR/settings.json'"
162
+ want_auth_untouched "S-3"
163
+
164
+ # ── S-4: agy detected + corrupt config → named component FAIL, NON-GREEN, later components attempted ──
165
+ echo "[smoke-setup-verdict] S-4 agy detected but corrupt"
166
+ PROJ4="$SB/proj4"; mkdir -p "$PROJ4"
167
+ printf '#!/usr/bin/env bash\necho fake-agy\n' > "$SB/harness/agy"; chmod +x "$SB/harness/agy"
168
+ mkdir -p "$HOME/.gemini/config"
169
+ printf 'this is not json{{{' > "$HOME/.gemini/config/mcp_config.json"
170
+ seed_auth
171
+ set +e; OUT="$(AGY_BIN="$SB/harness/agy" bash "$REPO_DIR/run.sh" setup "$PROJ4" 2>&1)"; RC=$?; set -e
172
+ want "S-4: detected agy failure owns a nonzero setup exit" "[ '$RC' -ne 0 ]"
173
+ want "S-4: the corrupt agy bridge is a NAMED component FAIL" \
174
+ "printf '%s' \"\$OUT\" | grep -q 'agy-bridge: FAIL'"
175
+ want "S-4: the reason is corrupt-specific (invalid JSON), not a silent skip" \
176
+ "printf '%s' \"\$OUT\" | grep -qi 'invalid JSON'"
177
+ want "S-4: later components were still attempted (core bridge smoke ran)" \
178
+ "printf '%s' \"\$OUT\" | grep -q 'core: PASS'"
179
+ want "S-4: summary is NON-GREEN and computed from the outcomes" \
180
+ "printf '%s' \"\$OUT\" | grep -q 'NON-GREEN' && ! printf '%s' \"\$OUT\" | grep -q 'result: green'"
181
+ want "S-4: the corrupt config was preserved, not clobbered" \
182
+ "[ \"\$(cat '$HOME/.gemini/config/mcp_config.json')\" = 'this is not json{{{' ]"
183
+ want_auth_untouched "S-4"
184
+ rm -rf "$HOME/.gemini" "$SB/harness/agy"
185
+
186
+ # ── S-6: copilot PRESENT → all FOUR units compose independently as PASS (#86 C3b) ──
187
+ # The fake vendor is the shared factory (scripts/fake-copilot-vendor.sh, the
188
+ # same measured answer shapes check-copilot-birth-hook.ts bakes), so the birth
189
+ # installer's real preflight/list/add/install sequence runs end to end against
190
+ # it. The three writer units (MCP/receiver/footer) never touch the vendor; they
191
+ # land in the sandbox HOME/XDG.
192
+ echo "[smoke-setup-verdict] S-6 copilot present — four-unit composition"
193
+ PROJ6="$SB/proj6"; mkdir -p "$PROJ6"
194
+ FAKE_COP="$SB/harness/copilot-fake"
195
+ bash "$REPO_DIR/scripts/fake-copilot-vendor.sh" "$FAKE_COP" "$REPO_DIR/pi/meta-bridge-copilot/entwurf-meta-receive-copilot/.claude-plugin/plugin.json"
196
+ seed_auth
197
+ set +e; OUT="$(COPILOT_BIN="$FAKE_COP/copilot" PATH="$FAKE_COP:$PATH" bash "$REPO_DIR/run.sh" setup "$PROJ6" 2>&1)"; RC=$?; set -e
198
+ want "S-6: copilot-present setup exits 0 (four units + core all green)" "[ '$RC' -eq 0 ]"
199
+ want "S-6: birth unit composed as PASS" "printf '%s' \"\$OUT\" | grep -q 'copilot-birth: PASS'"
200
+ want "S-6: MCP unit composed as PASS" "printf '%s' \"\$OUT\" | grep -q 'copilot-mcp: PASS'"
201
+ want "S-6: receiver unit composed as PASS" "printf '%s' \"\$OUT\" | grep -q 'copilot-receive: PASS'"
202
+ want "S-6: visible-footer unit composed as PASS" "printf '%s' \"\$OUT\" | grep -q 'copilot-statusline: PASS'"
203
+ want "S-6: computed summary is green" \
204
+ "printf '%s' \"\$OUT\" | grep -q 'result: green (computed from the component outcomes above)'"
205
+ want "S-6: the birth install drove the real vendor sequence (marketplace add before plugin install)" \
206
+ "grep -q '^plugin marketplace add ' '$FAKE_COP/calls.log' && grep -q '^plugin install entwurf-meta-receive-copilot@meta-bridge-copilot-local$' '$FAKE_COP/calls.log'"
207
+ want "S-6: all four package-owned install-states exist (each unit keeps its inverse authority)" \
208
+ "[ -f '$XDG_DATA_HOME/entwurf/copilot-bridge/install-state.json' ] && [ -f '$XDG_DATA_HOME/entwurf/copilot-mcp/install-state.json' ] && [ -f '$XDG_DATA_HOME/entwurf/copilot-receive/install-state.json' ] && [ -f '$XDG_DATA_HOME/entwurf/copilot-statusline/install-state.json' ]"
209
+ want "S-6: the receiver unit was deployed from the compiled dist closure" \
210
+ "[ -f '$HOME/.copilot/extensions/entwurf-receive/extension.mjs' ] && [ -f '$HOME/.copilot/extensions/entwurf-receive/lib/meta-session.js' ]"
211
+ want "S-6: MCP config and footer settings landed in the sandbox HOME" \
212
+ "grep -q 'entwurf-bridge' '$HOME/.copilot/mcp-config.json' && grep -q 'entwurf-copilot-statusline' '$HOME/.copilot/settings.json'"
213
+ want_auth_untouched "S-6"
214
+ # Reset the composed Copilot state so the next cell decides on a clean host.
215
+ rm -rf "$HOME/.copilot" "$XDG_DATA_HOME/entwurf/copilot-bridge" "$XDG_DATA_HOME/entwurf/copilot-mcp" \
216
+ "$XDG_DATA_HOME/entwurf/copilot-receive" "$XDG_DATA_HOME/entwurf/copilot-statusline" \
217
+ "$XDG_DATA_HOME/entwurf/meta-bridge-copilot"
218
+
219
+ # ── S-7: copilot present but vendor lists FAIL → birth is a NAMED FAIL, the other ──
220
+ # three units are still attempted (independent outcomes), and the aggregate is
221
+ # NON-GREEN + nonzero. A failing `plugin list` is UNKNOWN, never absence (#86
222
+ # C3a), so the composition must not relabel it SKIP or cosmetic PASS.
223
+ echo "[smoke-setup-verdict] S-7 copilot present, vendor list failing"
224
+ PROJ7="$SB/proj7"; mkdir -p "$PROJ7"
225
+ BROKEN_COP="$SB/harness/copilot-broken"; mkdir -p "$BROKEN_COP"
226
+ printf '#!/usr/bin/env bash\necho "not authenticated" >&2\nexit 1\n' > "$BROKEN_COP/copilot"
227
+ chmod +x "$BROKEN_COP/copilot"
228
+ seed_auth
229
+ set +e; OUT="$(COPILOT_BIN="$BROKEN_COP/copilot" PATH="$BROKEN_COP:$PATH" bash "$REPO_DIR/run.sh" setup "$PROJ7" 2>&1)"; RC=$?; set -e
230
+ want "S-7: the failing-vendor birth is a NAMED component FAIL, never SKIP or PASS" \
231
+ "printf '%s' \"\$OUT\" | grep -q 'copilot-birth: FAIL' && ! printf '%s' \"\$OUT\" | grep -q 'copilot: SKIP'"
232
+ want "S-7: the other three units were still attempted independently" \
233
+ "printf '%s' \"\$OUT\" | grep -q 'copilot-mcp: PASS' && printf '%s' \"\$OUT\" | grep -q 'copilot-receive: PASS' && printf '%s' \"\$OUT\" | grep -q 'copilot-statusline: PASS'"
234
+ want "S-7: the detected birth failure owns a nonzero setup exit" "[ '$RC' -ne 0 ]"
235
+ want "S-7: summary is NON-GREEN naming copilot-birth" \
236
+ "printf '%s' \"\$OUT\" | grep -q 'NON-GREEN (FAIL: copilot-birth)'"
237
+ want "S-7: later components were still attempted (core bridge smoke ran)" \
238
+ "printf '%s' \"\$OUT\" | grep -q 'core: PASS'"
239
+ want "S-7: the refused birth wrote no vendor ownership state" \
240
+ "[ ! -e '$XDG_DATA_HOME/entwurf/copilot-bridge/install-state.json' ]"
241
+ want_auth_untouched "S-7"
242
+ rm -rf "$HOME/.copilot" "$XDG_DATA_HOME/entwurf/copilot-mcp" "$XDG_DATA_HOME/entwurf/copilot-receive" \
243
+ "$XDG_DATA_HOME/entwurf/copilot-statusline"
244
+
245
+ # ── S-5: installed mode is a NAMED first verdict, never the source bootstrap ──
246
+ # A bare copy of run.sh under a fake node_modules root pins the mode seam
247
+ # cheaply: the copy is NOT a runnable installed package (no dist), so this cell
248
+ # asserts only that the installed-vs-source branch is decided and printed before
249
+ # any prerequisite check and the source-only pnpm bootstrap is never reached.
250
+ # The REAL packed installed-package `setup` consumer (all-absent SKIP, computed
251
+ # green, zero writes) lives in check-pack-install's installed all-absent setup
252
+ # row; the no-bootstrap KILL attribution lives in the oracle
253
+ # scripts/check-setup-qualification.sh (round 3).
254
+ echo "[smoke-setup-verdict] S-5 installed-mode named branch (pnpm-scrubbed)"
255
+ FAKE_PKG="$SB/node_modules/@junghanacs/entwurf"
256
+ mkdir -p "$FAKE_PKG" "$SB/proj5"
257
+ cp "$REPO_DIR/run.sh" "$FAKE_PKG/run.sh"; chmod +x "$FAKE_PKG/run.sh"
258
+ cp "$REPO_DIR/package.json" "$FAKE_PKG/package.json"
259
+ # The Missing-pnpm assertion was vacuous while the fixture inherited a PATH that
260
+ # still resolved pnpm (review round 2, 2026-08-26). Build a GENUINELY scrubbed
261
+ # PATH: shim the tools the pre-death setup path needs (resolved BEFORE the
262
+ # scrub, so a host that co-locates pnpm with node — e.g. corepack — still keeps
263
+ # node), then keep only the PATH directories that do NOT carry an executable
264
+ # pnpm, and PROVE the scrub before running the cell.
265
+ SCRUB_SHIMS="$SB/pnpm-scrub-shims"; mkdir -p "$SCRUB_SHIMS"
266
+ for _tool in bash node python3 head tr cut sed grep dirname readlink cat mkdir cp chmod rm env sha256sum; do
267
+ _src="$(command -v "$_tool" 2>/dev/null || true)"
268
+ [ -n "$_src" ] && ln -s "$_src" "$SCRUB_SHIMS/$_tool"
269
+ done
270
+ SCRUBBED_PATH="$SCRUB_SHIMS"
271
+ IFS=':' read -r -a _path_dirs <<<"$PATH"
272
+ for _d in "${_path_dirs[@]}"; do
273
+ [ -n "$_d" ] || continue
274
+ [ -x "$_d/pnpm" ] && continue
275
+ SCRUBBED_PATH="$SCRUBBED_PATH:$_d"
276
+ done
277
+ unset _path_dirs _d _tool _src
278
+ want "S-5: the scrub itself holds — pnpm does NOT resolve on the scrubbed PATH" \
279
+ "! PATH=\"$SCRUBBED_PATH\" command -v pnpm >/dev/null 2>&1"
280
+ want "S-5: the scrub preserved the tools the cell needs (bash/node/python3)" \
281
+ "PATH=\"$SCRUBBED_PATH\" command -v bash >/dev/null && PATH=\"$SCRUBBED_PATH\" command -v node >/dev/null && PATH=\"$SCRUBBED_PATH\" command -v python3 >/dev/null"
282
+ set +e; OUT="$(PATH="$SCRUBBED_PATH" bash "$FAKE_PKG/run.sh" setup "$SB/proj5" 2>&1)"; RC=$?; set -e
283
+ want "S-5: installed mode is the FIRST named line, before any prerequisite check" \
284
+ "printf '%s' \"\$OUT\" | head -n 1 | grep -q 'mode: installed package'"
285
+ want "S-5: installed mode never runs the source pnpm bootstrap" \
286
+ "! printf '%s' \"\$OUT\" | grep -qi 'pnpm install\|Lockfile is up to date\|Progress: resolved'"
287
+ want "S-5: installed setup never requires pnpm merely to decide/compose" \
288
+ "! printf '%s' \"\$OUT\" | grep -q 'Missing command: pnpm'"
289
+
290
+ echo ""
291
+ echo "smoke-setup-verdict: $PASS checks passed"