@junghanacs/entwurf 0.19.0 → 0.20.1

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 (74) hide show
  1. package/AGENTS.md +1 -1
  2. package/BASELINE.md +23 -5
  3. package/CHANGELOG.md +261 -0
  4. package/DELIVERY.md +59 -6
  5. package/README.md +41 -9
  6. package/VERIFY.md +9 -1
  7. package/docs/acp-backend-rail.md +41 -16
  8. package/docs/external-mcp-host.md +10 -5
  9. package/docs/fresh-cut-policy.md +3 -2
  10. package/docs/setup-clean-host.md +93 -7
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +2 -2
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +3 -3
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +6 -2
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/tool-surface.js +6 -0
  15. package/package.json +3 -3
  16. package/pi-extensions/acp-provider.ts +1 -1
  17. package/pi-extensions/lib/acp/acp-client.ts +3 -3
  18. package/pi-extensions/lib/acp/backend-adapter.ts +3 -3
  19. package/pi-extensions/lib/acp/backend.ts +3 -3
  20. package/pi-extensions/lib/acp/event-mapper.ts +4 -4
  21. package/pi-extensions/lib/acp/models.ts +3 -3
  22. package/pi-extensions/lib/acp/overlay.ts +6 -2
  23. package/pi-extensions/lib/acp/tool-surface.ts +6 -0
  24. package/pi-extensions/lib/meta-session.ts +25 -0
  25. package/run.sh +104 -33
  26. package/scripts/agy-bridge.sh +1 -1
  27. package/scripts/agy-imprint.sh +10 -7
  28. package/scripts/check-acp-carrier-augment.ts +6 -5
  29. package/scripts/check-acp-cortex.ts +41 -0
  30. package/scripts/check-acp-provider-surface.ts +9 -6
  31. package/scripts/check-acp-usage-accounting.ts +9 -9
  32. package/scripts/check-copilot-birth-hook.ts +3 -1
  33. package/scripts/check-copilot-receive-arm.ts +169 -21
  34. package/scripts/check-copilot-statusline.ts +3 -1
  35. package/scripts/check-gate-qualification.ts +11 -10
  36. package/scripts/check-hook-launch-topology.ts +6 -5
  37. package/scripts/check-install-surface.ts +25 -8
  38. package/scripts/check-meta-facts.ts +6 -4
  39. package/scripts/check-meta-hook-session-switch.ts +4 -3
  40. package/scripts/check-meta-identity-consumers.ts +8 -7
  41. package/scripts/check-meta-receiver-marker.ts +2 -1
  42. package/scripts/check-omp-birth-hook.ts +3 -2
  43. package/scripts/check-probe-bridge-command.ts +3 -1
  44. package/scripts/check-setup-qualification.sh +21 -0
  45. package/scripts/copilot-bridge-doctor.sh +15 -5
  46. package/scripts/copilot-bridge-install.sh +6 -2
  47. package/scripts/copilot-launch.sh +16 -2
  48. package/scripts/copilot-receive-bridge.sh +80 -13
  49. package/scripts/lib/reclaim-on-exit.ts +86 -0
  50. package/scripts/meta-bridge-doctor.sh +56 -15
  51. package/scripts/meta-bridge-install.sh +13 -7
  52. package/scripts/meta-bridge-uninstall.sh +6 -4
  53. package/scripts/mutants/acp-cortex.json +26 -2
  54. package/scripts/mutants/copilot-receive.json +26 -0
  55. package/scripts/mutants/omp-birth.json +23 -6
  56. package/scripts/mutants/pi-package-ownership.json +26 -0
  57. package/scripts/mutants/setup-verdict.json +13 -0
  58. package/scripts/omp-bridge-doctor.sh +110 -41
  59. package/scripts/omp-bridge-install.sh +6 -2
  60. package/scripts/omp-receive-install.sh +7 -2
  61. package/scripts/pi_settings_io.py +3 -1
  62. package/scripts/raw-async-delivery/README.md +10 -1
  63. package/scripts/raw-codex-measure/README.md +689 -0
  64. package/scripts/raw-codex-measure/source-audit.md +243 -0
  65. package/scripts/raw-macos-measure/README.md +148 -0
  66. package/scripts/raw-macos-measure/probe.sh +389 -0
  67. package/scripts/register-pi-package.py +38 -30
  68. package/scripts/register-pi-provider.py +3 -2
  69. package/scripts/smoke-acp-raw-turn-live.ts +1 -1
  70. package/scripts/smoke-meta-async-drift.sh +7 -5
  71. package/scripts/smoke-meta-install-state.sh +70 -19
  72. package/scripts/smoke-omp-bridge-state.sh +38 -0
  73. package/scripts/smoke-setup-verdict.sh +100 -0
  74. package/scripts/smoke-user-scope-citizen.sh +199 -71
@@ -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
- # #51 repair support boundary. Fake only `uname -s`: no macOS implementation is
966
- # emulated. New Darwin install must refuse as not-yet-certified, doctor must stay
967
- # nonzero with the same evidence wording, while uninstall MUST get past the platform
968
- # gate so an older managed install is not stranded (it then honestly fails on our
969
- # fixture's intentionally absent state file).
970
- PLATFORM_BIN="$TMP/platform-bin"; mkdir -p "$PLATFORM_BIN"
971
- cat > "$PLATFORM_BIN/uname" <<'SH'
972
- #!/usr/bin/env bash
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 "$PLATFORM_BIN/uname"
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
- DARWIN_INSTALL_OUT="$(env HOME="$DOC_HOME" XDG_DATA_HOME="$TMP/darwin-xdg" PI_CODING_AGENT_DIR="$DOC_AGENT" PATH="$PLATFORM_BIN:$DOC_BIN:$PATH" bash "$REPO/scripts/meta-bridge-install.sh" 2>&1)"
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
- DARWIN_UNINSTALL_OUT="$(env HOME="$TMP/darwin-clean-home" XDG_DATA_HOME="$TMP/darwin-clean-xdg" PATH="$PLATFORM_BIN:$PATH" bash "$REPO/scripts/meta-bridge-uninstall.sh" 2>&1)"
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"
@@ -287,6 +287,106 @@ rm -rf "$HOME/.omp" "$XDG_DATA_HOME/entwurf/omp-bridge" "$XDG_DATA_HOME/entwurf/
287
287
  "$XDG_DATA_HOME/entwurf/omp-config" "$XDG_DATA_HOME/entwurf/omp-receive" \
288
288
  "$XDG_DATA_HOME/entwurf/meta-bridge-omp" "$XDG_DATA_HOME/entwurf/omp-receive"
289
289
 
290
+ # ── S-9: rail certification is a SEPARATE axis from install success (#78 D1) ──
291
+ # The 0.20.0 macOS lane opened the installers to Darwin (meta-bridge-install.sh's
292
+ # platform gate became its own python3/node dependency instead of the platform
293
+ # name), and that removed the only thing which used to keep a detected Mac host
294
+ # non-green: the installer's refusal. A detected harness on Darwin now INSTALLS,
295
+ # every harness doctor still refuses there (NOT CERTIFIED — pending physical
296
+ # host), and `setup` runs no doctor. Hard Rule 17 names that shape non-green, so
297
+ # setup_harness_result does — and these cells are its ONLY executing consumer,
298
+ # because nothing else in this repo ever takes the Darwin branch.
299
+ #
300
+ # `uname` is faked on PATH exactly the way smoke-meta-install-state.sh already
301
+ # fakes it for the installer's own platform gate. Both directions are pinned so
302
+ # the fixture cannot pass for the wrong reason: the Linux twin below is the SAME
303
+ # sandbox, the SAME stub harnesses and the SAME fixture with one byte different,
304
+ # and S-3/S-8 above are the unfaked real-host Linux evidence.
305
+ FAKE_UNAME="$SB/fake-uname-darwin"; mkdir -p "$FAKE_UNAME"
306
+ # Absolute bash in the shebang, same reason as the sibling fixture: a cell may
307
+ # hand this script a PATH that does not carry `env`/`bash` itself.
308
+ cat > "$FAKE_UNAME/uname" <<SH
309
+ #!$(command -v bash)
310
+ printf '%s\n' Darwin
311
+ SH
312
+ chmod +x "$FAKE_UNAME/uname"
313
+ FAKE_UNAME_LINUX="$SB/fake-uname-linux"; mkdir -p "$FAKE_UNAME_LINUX"
314
+ cat > "$FAKE_UNAME_LINUX/uname" <<SH
315
+ #!$(command -v bash)
316
+ printf '%s\n' Linux
317
+ SH
318
+ chmod +x "$FAKE_UNAME_LINUX/uname"
319
+
320
+ omp_reset() {
321
+ rm -rf "$HOME/.omp" "$XDG_DATA_HOME/entwurf/omp-bridge" "$XDG_DATA_HOME/entwurf/omp-mcp" \
322
+ "$XDG_DATA_HOME/entwurf/omp-config" "$XDG_DATA_HOME/entwurf/omp-receive" \
323
+ "$XDG_DATA_HOME/entwurf/meta-bridge-omp"
324
+ }
325
+
326
+ # ── S-9a: fake Darwin + DETECTED harnesses → named non-green, install intact ──
327
+ # Two harness FAMILIES on purpose (the pi adapter rail and the four omp units):
328
+ # a rule applied to one backend and not the next is a new defect, not half a fix.
329
+ echo "[smoke-setup-verdict] S-9a detected harnesses on an uncertified platform"
330
+ PROJ9="$SB/proj9"; mkdir -p "$PROJ9"
331
+ seed_auth
332
+ set +e; OUT="$(PI_BIN="$SB/harness/pi-ok" OMP_BIN="$FAKE_OMP/omp" ENTWURF_OMP_AGENT_DIR="$HOME/.omp/agent" PATH="$FAKE_UNAME:$FAKE_OMP:$PATH" bash "$REPO_DIR/run.sh" setup "$PROJ9" 2>&1)"; RC=$?; set -e
333
+ want "S-9a: a detected harness on an uncertified platform owns a nonzero setup exit" "[ '$RC' -ne 0 ]"
334
+ want "S-9a: the pi adapter rail is named non-green, never a cosmetic PASS" \
335
+ "printf '%s' \"\$OUT\" | grep -q 'pi: FAIL' && ! printf '%s' \"\$OUT\" | grep -q 'pi: PASS'"
336
+ want "S-9a: all four omp units are named non-green, none cosmetically PASS" \
337
+ "printf '%s' \"\$OUT\" | grep -q 'omp-birth: FAIL' && printf '%s' \"\$OUT\" | grep -q 'omp-mcp: FAIL' && printf '%s' \"\$OUT\" | grep -q 'omp-config: FAIL' && printf '%s' \"\$OUT\" | grep -q 'omp-receive: FAIL' && ! printf '%s' \"\$OUT\" | grep -q 'omp-[a-z]*: PASS'"
338
+ want "S-9a: the reason says the wiring WAS written (this is not an install failure)" \
339
+ "printf '%s' \"\$OUT\" | grep -q 'the wiring WAS written and nothing failed to install'"
340
+ want "S-9a: the reason names the RAIL evidence state and the platform" \
341
+ "printf '%s' \"\$OUT\" | grep -q 'NOT CERTIFIED — pending physical host on Darwin'"
342
+ want "S-9a: the reason names the doctor that owns the rail axis, per component" \
343
+ "printf '%s' \"\$OUT\" | grep -qF \"owned by './run.sh doctor-omp-bridge'\" && printf '%s' \"\$OUT\" | grep -qF \"owned by './run.sh doctor-pi-provider'\""
344
+ want "S-9a: the reason points at the tracking issue" "printf '%s' \"\$OUT\" | grep -q 'Tracking: #78'"
345
+ want "S-9a: it never reads as an install refusal (no unsupported-platform / did-not-complete vocabulary)" \
346
+ "! printf '%s' \"\$OUT\" | grep -qi 'unsupported platform' && ! printf '%s' \"\$OUT\" | grep -q 'did not complete'"
347
+ want "S-9a: the summary is NON-GREEN and names the uncertified components" \
348
+ "printf '%s' \"\$OUT\" | grep -q 'NON-GREEN (FAIL:' && ! printf '%s' \"\$OUT\" | grep -q 'result: green'"
349
+ # The load-bearing half: the installs genuinely SUCCEEDED. Without this the cell
350
+ # would also pass if the platform had merely broken the installers.
351
+ want "S-9a: the wiring really landed — pi project settings plus both omp extensions and the MCP hand" \
352
+ "[ -f '$PROJ9/.pi/settings.json' ] && [ -d '$HOME/.omp/agent/extensions/entwurf-meta-omp' ] && [ -d '$HOME/.omp/agent/extensions/entwurf-receive-omp' ] && [ -f '$HOME/.omp/agent/mcp.json' ]"
353
+ want_auth_untouched "S-9a"
354
+ omp_reset
355
+
356
+ # ── S-9b: the Linux twin — same fixture, one byte different → still PASS/green ──
357
+ # This is the regression axis that matters most: the certified platform's behavior
358
+ # must not have moved at all.
359
+ echo "[smoke-setup-verdict] S-9b the same detected harnesses on the certified platform"
360
+ PROJ9B="$SB/proj9b"; mkdir -p "$PROJ9B"
361
+ seed_auth
362
+ set +e; OUT="$(PI_BIN="$SB/harness/pi-ok" OMP_BIN="$FAKE_OMP/omp" ENTWURF_OMP_AGENT_DIR="$HOME/.omp/agent" PATH="$FAKE_UNAME_LINUX:$FAKE_OMP:$PATH" bash "$REPO_DIR/run.sh" setup "$PROJ9B" 2>&1)"; RC=$?; set -e
363
+ want "S-9b: the certified platform still exits 0" "[ '$RC' -eq 0 ]"
364
+ want "S-9b: pi and all four omp units still compose as PASS" \
365
+ "printf '%s' \"\$OUT\" | grep -q 'pi: PASS' && printf '%s' \"\$OUT\" | grep -q 'omp-birth: PASS' && printf '%s' \"\$OUT\" | grep -q 'omp-mcp: PASS' && printf '%s' \"\$OUT\" | grep -q 'omp-config: PASS' && printf '%s' \"\$OUT\" | grep -q 'omp-receive: PASS'"
366
+ want "S-9b: a PASS row is byte-identical to the pre-#78 wording (the operator surface did not move)" \
367
+ "printf '%s' \"\$OUT\" | grep -q 'omp-birth: PASS — birth extension installed — verify: ./run.sh doctor-omp-bridge'"
368
+ want "S-9b: the computed summary is green and carries no rail-certification wording" \
369
+ "printf '%s' \"\$OUT\" | grep -q 'result: green (computed from the component outcomes above)' && ! printf '%s' \"\$OUT\" | grep -q 'NOT CERTIFIED'"
370
+ want_auth_untouched "S-9b"
371
+ omp_reset
372
+
373
+ # ── S-9c: fake Darwin + NO harness → still green (the macOS CI job's contract) ──
374
+ # The macos-install-surface job asserts exactly this shape on a real Darwin runner:
375
+ # five zero-state SKIPs, core PASS, computed green. The rule above must not reach
376
+ # an absent harness — SKIP is not a completed integration.
377
+ echo "[smoke-setup-verdict] S-9c harness-free host on an uncertified platform"
378
+ PROJ9C="$SB/proj9c"; mkdir -p "$PROJ9C"
379
+ seed_auth
380
+ set +e; OUT="$(PATH="$FAKE_UNAME:$PATH" bash "$REPO_DIR/run.sh" setup "$PROJ9C" 2>&1)"; RC=$?; set -e
381
+ want "S-9c: a harness-free uncertified host still exits 0" "[ '$RC' -eq 0 ]"
382
+ want "S-9c: all five harness probes are still zero-state SKIPs" \
383
+ "printf '%s' \"\$OUT\" | grep -q 'pi: SKIP' && printf '%s' \"\$OUT\" | grep -q 'claude: SKIP' && printf '%s' \"\$OUT\" | grep -q 'agy: SKIP' && printf '%s' \"\$OUT\" | grep -q 'copilot: SKIP' && printf '%s' \"\$OUT\" | grep -q 'omp: SKIP'"
384
+ want "S-9c: core still PASSes and the computed summary is still green" \
385
+ "printf '%s' \"\$OUT\" | grep -q 'core: PASS' && printf '%s' \"\$OUT\" | grep -q 'result: green (computed from the component outcomes above)'"
386
+ want "S-9c: an absent harness is never given a rail verdict it did not earn" \
387
+ "! printf '%s' \"\$OUT\" | grep -q 'NOT CERTIFIED'"
388
+ want_auth_untouched "S-9c"
389
+
290
390
  # ── S-5: installed mode is a NAMED first verdict, never the source bootstrap ──
291
391
  # A bare copy of run.sh under a fake node_modules root pins the mode seam
292
392
  # cheaply: the copy is NOT a runnable installed package (no dist), so this cell
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env bash
2
2
  # smoke-user-scope-citizen — deterministic gate for pi packages[] citizen
3
- # registration/removal (register-pi-package.py). Offline/hermetic: a fake
4
- # settings file + a fake REPO_DIR under $TMP, no pi, no network, no ~/.pi touched.
3
+ # registration/removal (register-pi-package.py). Offline/hermetic: fake settings
4
+ # files and fake REPO_DIRs under $TMP, sandboxed HOME/PI_CODING_AGENT_DIR/XDG,
5
+ # no network, nothing of the operator's ~/.pi read or written.
5
6
  #
6
7
  # Guards the wiring that dropped when `pi install` was removed from setup
7
8
  # (2026-07-03: `--entwurf-control` / `--emacs-agent-socket` unknown in a foreign
@@ -10,10 +11,14 @@
10
11
  # in another repo. This gate is that missing tripwire: if the registration ever
11
12
  # regresses, `pnpm run check:full` goes red.
12
13
  #
13
- # Cells 11–13 close the second omission (#53 B): every case here drove a fake
14
- # settings file with ABSOLUTE entries, so the portable, settings-relative form this
15
- # repo actually commits was never registered against — and `setup` duplicated and
16
- # restyled the tracked file for four cuts without a single gate seeing it.
14
+ # Cells 11–13 close the second omission (#53 B): every case before them drove a fake
15
+ # settings file with ABSOLUTE entries, so the portable, settings-relative form was
16
+ # never registered against — and `setup` duplicated and restyled a tracked file for
17
+ # four cuts without a single gate seeing it.
18
+ #
19
+ # Cell 15 closes the third (#110), and it is the one cell here that SPAWNS pi: the
20
+ # defect is not a byte, it is which of two checkouts wins `--entwurf-control`, and
21
+ # only the real loader can say. It uses the pinned devDep pi, never PATH.
17
22
  set -euo pipefail
18
23
  export PYTHONDONTWRITEBYTECODE=1 # snapshot purity: no ignored scripts/__pycache__ writes under qualification
19
24
 
@@ -193,69 +198,64 @@ assert d['defaultProvider']=='openai-codex', 'run.sh remove-user-scope dropped a
193
198
  # idempotent: a second remove-user-scope is a clean no-op (no crash on absent entry)
194
199
  if XDG_DATA_HOME="$TMP/xdg" PI_CODING_AGENT_DIR="$AGENT_DIR" bash "$RUN" remove-user-scope >/dev/null 2>&1; then ok "run.sh remove-user-scope is idempotent (no-op second run)"; else bad "run.sh remove-user-scope second run crashed"; fi
195
200
 
196
- # ── 11–13. #53 B: install must not dirty a tracked, formatter-governed settings file
201
+ # ── 11–13. #53 B: a settings-relative self entry is source, never install state
197
202
  # The cell whose ABSENCE let this ship. Every case above drove a fake settings file
198
- # with absolute entries, so the one shape this repo actually commits — the portable,
199
- # settings-relative `".."` that check-install-surface S7c pins was never registered
200
- # against. `setup` therefore appended the absolute path BESIDE it and rewrote the
201
- # tracked, biome-owned bytes at indent=2, and `pnpm check` died at step 1 reading
202
- # "format error" instead of "install wrote this".
203
+ # with ABSOLUTE entries, so the portable, settings-relative form — the one shape
204
+ # register never WRITES, and must therefore never duplicate, absolutize or restyle —
205
+ # was never registered against. `setup` appended the absolute path BESIDE it and
206
+ # rewrote the file at indent=2, and `pnpm check` died at step 1 reading "format
207
+ # error" instead of "install wrote this".
203
208
  #
204
- # The seed is the repo's OWN committed settings, copied into a stand-in checkout so
205
- # `".."` resolves to that clone rather than to the real repo (nothing here touches
206
- # $REPO). Setup landing is PROVEN before any product verdict: if the seed is not the
207
- # portable form, this says SETUP MISS in its own name instead of blaming the code.
209
+ # The seed is a FIXTURE. It used to be this repo's OWN committed `.pi/settings.json`,
210
+ # because the repo shipped `packages: [".."]`; #110 retired that entry (entwurf's own
211
+ # checkout self-registers through user scope alone, so a second checkout can no
212
+ # longer register a rival copy of pi-extensions). A witness that depends on us still
213
+ # SHIPPING the shape it tests dies with the shape — and the shape it tests did not
214
+ # die. An operator may hand-write a settings-relative entry, and
215
+ # `is_settings_relative_self` is also what stops an unrelated relative package
216
+ # (`../../repos/gh/andenken`) from being read as ours. Dropping the fixture to a
217
+ # literal here makes the reason honest: the predicate is the subject, not our bytes.
208
218
  CLONE="$TMP/selfclone"; mkdir -p "$CLONE/.pi"
209
219
  CS="$CLONE/.pi/settings.json"
210
- seed_src=""
211
- if (cd "$REPO" && git show :.pi/settings.json) > "$CS" 2>/dev/null && [ -s "$CS" ]; then
212
- seed_src="candidate index"
213
- elif cp "$REPO/.pi/settings.json" "$CS" 2>/dev/null; then
214
- seed_src="worktree"
220
+ # Tab-indented with a compact array on purpose: cell 13 pins that a genuine rewrite
221
+ # preserves the file's own indent unit, and 11b below pins that this file is not
222
+ # rewritten at all. A seed written in the writer's default style could not tell the
223
+ # two apart.
224
+ printf '{\n\t"skills": ["../.claude/skills"],\n\t"packages": [".."]\n}\n' > "$CS"
225
+ BEFORE="$(sha256sum "$CS" | cut -d' ' -f1)"; MT_B="$(stat -c %Y "$CS")"; sleep 1
226
+ OUT_SELF="$(python3 "$REG" "$CS" "$CLONE")"
227
+ AFTER="$(sha256sum "$CS" | cut -d' ' -f1)"; MT_A="$(stat -c %Y "$CS")"
228
+ if printf '%s' "$OUT_SELF" | grep -q 'no-op'; then
229
+ ok "11 register against a settings-relative self entry is a no-op"
230
+ else
231
+ bad "11 register duplicated/absolutized the portable '..' entry" "$OUT_SELF"
215
232
  fi
216
- if [ ! -s "$CS" ]; then
217
- bad "11 SETUP MISS: could not seed this repo's own .pi/settings.json (no git object, no worktree file)"
218
- elif ! python3 -c "
219
- import json,sys
220
- p=json.load(open(sys.argv[1])).get('packages')
221
- sys.exit(0 if p==['..'] else 1)" "$CS"; then
222
- bad "11 SETUP MISS: the seed ($seed_src) is not the committed portable form (packages != ['..']) — product verdict withheld"
233
+ if [ "$BEFORE" = "$AFTER" ] && [ "$MT_B" = "$MT_A" ]; then
234
+ ok "11b the formatter-governed bytes are UNCHANGED (sha256 + mtime)"
223
235
  else
224
- BEFORE="$(sha256sum "$CS" | cut -d' ' -f1)"; MT_B="$(stat -c %Y "$CS")"; sleep 1
225
- OUT_SELF="$(python3 "$REG" "$CS" "$CLONE")"
226
- AFTER="$(sha256sum "$CS" | cut -d' ' -f1)"; MT_A="$(stat -c %Y "$CS")"
227
- if printf '%s' "$OUT_SELF" | grep -q 'no-op'; then
228
- ok "11 register against this repo's OWN committed settings is a no-op (seed: $seed_src)"
229
- else
230
- bad "11 register duplicated/absolutized the portable '..' entry" "$OUT_SELF"
231
- fi
232
- if [ "$BEFORE" = "$AFTER" ] && [ "$MT_B" = "$MT_A" ]; then
233
- ok "11b the tracked, formatter-governed bytes are UNCHANGED (sha256 + mtime)"
234
- else
235
- bad "11b install rewrote the tracked settings file (sha $BEFORE -> $AFTER, mtime $MT_B -> $MT_A)"
236
- fi
237
- # The inverse direction of the same asymmetry: the shared matcher now RECOGNIZES
238
- # `".."`, so an uninstall that deleted it would edit committed source — the same
239
- # defect pointed the other way. remove leaves it and says so; dry-run agrees,
240
- # because both ask one predicate.
241
- BEFORE_R="$(sha256sum "$CS" | cut -d' ' -f1)"
242
- OUT_RM="$(python3 "$REG" "$CS" "$CLONE" --remove)"
243
- OUT_DRY="$(python3 "$REG" "$CS" "$CLONE" --remove --dry-run)"
244
- if [ "$BEFORE_R" = "$(sha256sum "$CS" | cut -d' ' -f1)" ]; then
245
- ok "11c --remove does NOT delete the committed portable entry (bytes unchanged)"
246
- else
247
- bad "11c --remove edited the repo's committed settings source" "$OUT_RM"
248
- fi
249
- if printf '%s' "$OUT_RM" | grep -q 'kept 1 settings-relative'; then
250
- ok "11d the inverse REPORTS what it deliberately left behind (never a silent partial uninstall)"
251
- else
252
- bad "11d --remove left the entry without saying so" "$OUT_RM"
253
- fi
254
- if printf '%s' "$OUT_DRY" | grep -q 'no entwurf packages\[\] entry to remove'; then
255
- ok "11e --dry-run agrees with remove (one predicate, no over-report)"
256
- else
257
- bad "11e --dry-run disagreed with what remove actually does" "$OUT_DRY"
258
- fi
236
+ bad "11b register rewrote a settings file it only recognizes (sha $BEFORE -> $AFTER, mtime $MT_B -> $MT_A)"
237
+ fi
238
+ # The inverse direction of the same asymmetry: the shared matcher RECOGNIZES `".."`,
239
+ # so an uninstall that deleted it would edit source it never wrote — the same defect
240
+ # pointed the other way. remove leaves it and says so; dry-run agrees, because both
241
+ # ask one predicate.
242
+ BEFORE_R="$(sha256sum "$CS" | cut -d' ' -f1)"
243
+ OUT_RM="$(python3 "$REG" "$CS" "$CLONE" --remove)"
244
+ OUT_DRY="$(python3 "$REG" "$CS" "$CLONE" --remove --dry-run)"
245
+ if [ "$BEFORE_R" = "$(sha256sum "$CS" | cut -d' ' -f1)" ]; then
246
+ ok "11c --remove does NOT delete a settings-relative self entry (bytes unchanged)"
247
+ else
248
+ bad "11c --remove edited settings source it never authored" "$OUT_RM"
249
+ fi
250
+ if printf '%s' "$OUT_RM" | grep -q 'kept 1 settings-relative'; then
251
+ ok "11d the inverse REPORTS what it deliberately left behind (never a silent partial uninstall)"
252
+ else
253
+ bad "11d --remove left the entry without saying so" "$OUT_RM"
254
+ fi
255
+ if printf '%s' "$OUT_DRY" | grep -q 'no entwurf packages\[\] entry to remove'; then
256
+ ok "11e --dry-run agrees with remove (one predicate, no over-report)"
257
+ else
258
+ bad "11e --dry-run disagreed with what remove actually does" "$OUT_DRY"
259
259
  fi
260
260
 
261
261
  # 12. the state a pre-fix `setup` already left on real hosts: the portable entry AND
@@ -291,12 +291,20 @@ if grep -q $'^\t"packages"' "$S"; then ok "13 a rewrite preserves the file's tab
291
291
  # indent=2 — semantically a no-op, byte-wise a RED `pnpm check` diagnosed as "formatting".
292
292
  # A per-writer cell can never see that; only the real drive can. So this one runs
293
293
  # `run.sh install <checkout>` for real and demands sha256 + mtime invariance.
294
- #
295
294
  # The checkout is a stand-in: run.sh resolves its OWN symlinks to find REPO_DIR, so
296
295
  # run.sh is COPIED (a link would point the drive back at the operator's real repo) while
297
296
  # the trees it only reads are linked. That makes REPO_DIR == the stand-in, which is the
298
- # shape that matters — `".."` in <checkout>/.pi/settings.json resolves to the very repo
299
- # being registered, exactly as it does in a dev clone.
297
+ # shape that matters — the drive installs entwurf INTO entwurf's own checkout, exactly
298
+ # as `./run.sh setup` does from a dev clone (PROJECT_DIR_DEFAULT=$(pwd)).
299
+ #
300
+ # #110 raised what this cell demands. "install is a no-op here" used to hold because
301
+ # the committed `packages: [".."]` already satisfied the writer. That entry is gone,
302
+ # so the writer must instead RECOGNIZE that the project it is installing into IS this
303
+ # root and skip project scope entirely — user scope already registers it, and a second
304
+ # entry naming a different checkout is what made pi load two rival copies of
305
+ # pi-extensions/entwurf-control.ts. The invariant, tested end to end below: entwurf's
306
+ # own checkout carries no project-scope self-registration, in tracked bytes OR in
307
+ # bytes a writer produced.
300
308
  CK="$TMP/checkout"
301
309
  mkdir -p "$CK/.pi"
302
310
  cp "$REPO/run.sh" "$CK/run.sh"
@@ -317,8 +325,8 @@ if [ ! -s "$CKS" ]; then
317
325
  elif ! python3 -c "
318
326
  import json,sys
319
327
  d=json.load(open(sys.argv[1]))
320
- sys.exit(0 if d.get('packages')==['..'] and isinstance(d.get('entwurfProvider'),dict) else 1)" "$CKS"; then
321
- bad "14 SETUP MISS: the seed ($ck_seed) is not the committed portable form (packages ['..'] + entwurfProvider)"
328
+ sys.exit(0 if d.get('packages') is None and isinstance(d.get('entwurfProvider'),dict) else 1)" "$CKS"; then
329
+ bad "14 SETUP MISS: the seed ($ck_seed) is not the committed form (no packages key + entwurfProvider)"
322
330
  else
323
331
  CK_BEFORE="$(sha256sum "$CKS" | cut -d' ' -f1)"; CK_MT="$(stat -c %Y "$CKS")"
324
332
  sleep 1
@@ -359,6 +367,124 @@ else
359
367
  else
360
368
  bad "14d the user-scope citizen was not written under the sandboxed PI_CODING_AGENT_DIR" "$ck_out"
361
369
  fi
370
+ # The invariant, read off the file the drive just wrote through: no writer put a
371
+ # project-scope self-registration back. 14b already pins the bytes, but a writer
372
+ # that ADDED `packages` to a file with no `packages` key would fail 14b for a
373
+ # reason a reader could mistake for formatting; this says the thing #110 is about,
374
+ # in its own words.
375
+ L14E="14e install into entwurf's OWN checkout wrote no project-scope packages[] self-registration [QK:SELF-CHECKOUT-PROJECT-REGISTRATION]"
376
+ if python3 -c "
377
+ import json,sys
378
+ sys.exit(0 if json.load(open(sys.argv[1])).get('packages') is None else 1)" "$CKS"; then
379
+ ok "$L14E"
380
+ else
381
+ bad "$L14E — violated: install self-registered this checkout, so a second checkout will load a rival copy of pi-extensions" "$(cat "$CKS")"
382
+ fi
383
+ case "$ck_out" in
384
+ *"project-scope packages[] skipped"*) ok "14f the drive REPORTS the skip (a silent skip and a silent write read alike)" ;;
385
+ *) bad "14f install skipped project scope without saying so — 14e cannot tell that apart from a writer that never ran" "$ck_out" ;;
386
+ esac
387
+ fi
388
+ fi
389
+
390
+ # ── 15. #110: the operator-observable this whole contract exists for ───────────
391
+ # Cells 11–14 read settings bytes. Bytes are the mechanism; the SYMPTOM is what pi
392
+ # does with them, and that is what nobody could see: a second checkout booted pi,
393
+ # printed all seven `entwurf` model rows, and looked fine, while `--entwurf-control`
394
+ # — the flag that makes a pi session a garden citizen — was being served by the
395
+ # branch copy, and the INSTALLED extension failed to load with an error naming the
396
+ # installed path as the loser. Not silent. Designed to be misread.
397
+ #
398
+ # pi's package identity is `local:<resolved path>` and dedupePackages collapses only
399
+ # EQUAL identities (package-manager.js getPackageIdentity/dedupePackages), so two
400
+ # real checkouts can never merge — no realpath rule, ours or pi's, would fix this.
401
+ # The only lever is not registering the second one.
402
+ #
403
+ # The cell is control-then-assert on purpose. A sandbox where pi loads no project
404
+ # settings at all (untrusted cwd, missing extension deps, a probe that dies early)
405
+ # would report "no conflicts" for reasons that have nothing to do with the contract,
406
+ # and that green would be a lie. So it first PLANTS the retired entry and demands the
407
+ # conflict APPEAR; only a cell that has just watched the defect happen is allowed to
408
+ # assert its absence.
409
+ # Two different absences, and only one of them is allowed to be quiet. A tree with no
410
+ # `node_modules` at all is a genuinely reduced checkout and the property is untestable
411
+ # there — a named skip. A tree that HAS dependencies but no pinned pi is a broken dev
412
+ # checkout, and skipping it would hide the breakage behind an exit-0 gate, so that one
413
+ # fails loud. (The qualification snapshot is the first case only in principle: it
414
+ # symlinks the origin's node_modules in after its baseline commit — mutation-qualify.ts
415
+ # createRepoSnapshot — so cell 15 really runs there, which is what lets the two mutants
416
+ # below cover this skip. A skip nobody can reach with a planted defect would be exactly
417
+ # the quiet green this cell is built to refuse.)
418
+ PI_BIN_PINNED="$REPO/node_modules/.bin/pi"
419
+ if [ ! -d "$REPO/node_modules" ]; then
420
+ echo " skip 15 second-checkout probe skipped: this tree has no node_modules (reduced checkout); the property is untestable here, not violated"
421
+ elif [ ! -x "$PI_BIN_PINNED" ]; then
422
+ bad "15 the pinned pi is missing from a checkout that HAS dependencies ($PI_BIN_PINNED) — a broken dev checkout, not a reduced one; re-run pnpm install"
423
+ else
424
+ A15="$TMP/dual/installed"; B15="$TMP/dual/second"
425
+ AG15="$TMP/agent15"
426
+ mkdir -p "$A15/.pi" "$B15/.pi" "$AG15"
427
+ # pi-extensions is COPIED into each root, not linked: the defect is two DISTINCT
428
+ # real paths declaring the same flag, and a shared symlink target would be one path
429
+ # wearing two names — a fixture that cannot reproduce what two checkouts do.
430
+ for root in "$A15" "$B15"; do
431
+ cp -R "$REPO/pi-extensions" "$root/pi-extensions"
432
+ for entry in node_modules package.json protocol.js; do
433
+ [ -e "$REPO/$entry" ] && ln -s "$REPO/$entry" "$root/$entry"
434
+ done
435
+ done
436
+ # user scope registers the INSTALLED root, absolutely — what `register_user_scope_citizen`
437
+ # writes on a real host. Trust is seeded for the second checkout because `.pi/` is a
438
+ # trust-gated input: an untrusted cwd loads no project settings, which would silence
439
+ # the control below and make the assertion vacuous.
440
+ printf '{"packages": ["%s"]}\n' "$A15" > "$AG15/settings.json"
441
+ printf '{"%s": true}\n' "$B15" > "$AG15/trust.json"
442
+ # Two fences on the probe child, and BOTH are load-bearing.
443
+ #
444
+ # `< /dev/null`: `pi --print` reads a non-tty stdin as piped prompt input, so it
445
+ # inherits whatever the CALLER handed this gate. Under an interactive shell or a
446
+ # /dev/null stdin that ends immediately and the probe returns in ~2s; under a
447
+ # supervised runner — which hands the process an open socket — it blocks forever.
448
+ # Measured 2026-09-10: a release-gate run sat 1h56m on this line with `pi` alive
449
+ # and no output, and the gate has no timeout of its own to catch it. A gate must
450
+ # read the loader, never the stdin of whoever started it.
451
+ #
452
+ # `timeout 60`: even so, a probe that cannot finish must go RED rather than hang.
453
+ # 124 lands in the captured output, the conflict grep misses, and the cell fails
454
+ # with its own name — the honest outcome for "the loader never answered".
455
+ #
456
+ # Ambient identity carriers are stripped for the same reason: a live pi/ACP session
457
+ # exports PI_SESSION_ID/PI_AGENT_ID and CLAUDE_CONFIG_DIR into children.
458
+ probe15() {
459
+ (cd "$B15" && env -u PI_SESSION_ID -u PI_AGENT_ID -u CLAUDE_CONFIG_DIR \
460
+ HOME="$TMP/home" PI_CODING_AGENT_DIR="$AG15" \
461
+ XDG_DATA_HOME="$TMP/xdg" XDG_STATE_HOME="$TMP/state" XDG_CACHE_HOME="$TMP/cache" \
462
+ timeout 60 "$PI_BIN_PINNED" --model zzz-no-such-provider/zzz-no-such-model --print x \
463
+ </dev/null 2>&1 || true)
464
+ }
465
+ # CONTROL: the retired shape, re-planted. `".."` resolves against <B>/.pi, so the
466
+ # project entry names B while user scope names A — two identities, both loaded.
467
+ printf '{"packages": [".."]}\n' > "$B15/.pi/settings.json"
468
+ OUT15_CTL="$(probe15)"
469
+ if printf '%s' "$OUT15_CTL" | grep -q 'conflicts with'; then
470
+ ok "15 control: a second checkout that registers itself DOES collide on the extension flags"
471
+ else
472
+ bad "15 SETUP MISS: the planted second registration produced no conflict — this sandbox cannot observe the defect, so 15b would be vacuous" "$OUT15_CTL"
473
+ fi
474
+ # ASSERT: this repo's real `.pi/settings.json`, read from the WORKING TREE — not
475
+ # from the candidate index the way cells 11/14 read theirs. The subject here is
476
+ # what pi's loader does with the file that exists ON DISK when a session starts;
477
+ # the index is a different question and check-install-surface S7c already owns it.
478
+ # Reading the index here also made this cell blind to its own replant: a mutation
479
+ # writes the file, git show reads the staged bytes, and the gate stayed green over
480
+ # a planted defect (measured — qualification reported SURVIVED, 2026-09-10).
481
+ cp "$REPO/.pi/settings.json" "$B15/.pi/settings.json"
482
+ OUT15="$(probe15)"
483
+ L15B="15b a second checkout of this repo boots pi with zero extension conflicts [QK:SECOND-CHECKOUT-EXTENSION-COLLISION]"
484
+ if printf '%s' "$OUT15" | grep -q 'conflicts with'; then
485
+ bad "$L15B — violated: the branch copy wins --entwurf-control and the INSTALLED extension fails, printing the installed path as the loser" "$OUT15"
486
+ else
487
+ ok "$L15B"
362
488
  fi
363
489
  fi
364
490
 
@@ -740,14 +866,16 @@ if [ "$RC34B" -ne 0 ] && printf '%s' "$OUT34B" | grep -q 'CORRUPT'; then
740
866
  ok "34b doctor coupling FAILs on a wrong-type provider installerRoot (named CORRUPT) $QK34"
741
867
  else bad "34b doctor stayed green/silent over a corrupt installerRoot (rc=$RC34B): $OUT34B $QK34"; fi
742
868
 
743
- # 15. WIRING: both writers of this one file must share the serializer, not copy it.
869
+ # 35. WIRING: both writers of this one file must share the serializer, not copy it.
744
870
  # A duplicated indent-detector is how the provider writer stayed open after the
745
871
  # package writer was closed; a parity check is cheaper than a third round.
872
+ # (Numbered 35, after the ownership block: it used to be a second "15", which
873
+ # stopped being merely untidy once #110 added the real cell 15 above.)
746
874
  for w in register-pi-package.py register-pi-provider.py; do
747
875
  if grep -q "from pi_settings_io import" "$REPO/scripts/$w"; then
748
- ok "15 $w routes through the shared pi_settings_io serializer"
876
+ ok "35 $w routes through the shared pi_settings_io serializer"
749
877
  else
750
- bad "15 $w serializes settings on its own again (copied rule = the #53 B shape)"
878
+ bad "35 $w serializes settings on its own again (copied rule = the #53 B shape)"
751
879
  fi
752
880
  done
753
881