@junghanacs/entwurf 0.18.2 → 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.
Files changed (77) hide show
  1. package/AGENTS.md +2 -2
  2. package/BASELINE.md +23 -5
  3. package/CHANGELOG.md +415 -0
  4. package/DELIVERY.md +59 -6
  5. package/README.md +43 -12
  6. package/VERIFY.md +10 -2
  7. package/docs/acp-backend-rail.md +9 -1
  8. package/docs/external-mcp-host.md +8 -5
  9. package/docs/setup-clean-host.md +93 -7
  10. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +18 -7
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +3 -3
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +6 -2
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +76 -9
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-placement.js +54 -6
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/resolve-tmux-session.js +114 -0
  16. package/mcp/entwurf-bridge/src/index.ts +22 -7
  17. package/package.json +2 -2
  18. package/pi-extensions/acp-provider.ts +1 -1
  19. package/pi-extensions/entwurf-control.ts +27 -3
  20. package/pi-extensions/lib/acp/models.ts +3 -3
  21. package/pi-extensions/lib/acp/overlay.ts +6 -2
  22. package/pi-extensions/lib/meta-session.ts +25 -0
  23. package/pi-extensions/lib/mux-fresh-call.ts +98 -11
  24. package/pi-extensions/lib/mux-placement.ts +65 -10
  25. package/pi-extensions/lib/resolve-tmux-session.ts +137 -0
  26. package/run.sh +71 -26
  27. package/scripts/agy-bridge.sh +1 -1
  28. package/scripts/agy-imprint.sh +10 -7
  29. package/scripts/check-acp-carrier-augment.ts +6 -5
  30. package/scripts/check-acp-cortex.ts +41 -0
  31. package/scripts/check-acp-provider-surface.ts +9 -6
  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-fresh-cut-gate.sh +54 -2
  36. package/scripts/check-gate-qualification.ts +13 -12
  37. package/scripts/check-hook-launch-topology.ts +6 -5
  38. package/scripts/check-install-surface.ts +2 -1
  39. package/scripts/check-meta-facts.ts +6 -4
  40. package/scripts/check-meta-hook-session-switch.ts +4 -3
  41. package/scripts/check-meta-identity-consumers.ts +8 -7
  42. package/scripts/check-meta-receiver-marker.ts +2 -1
  43. package/scripts/check-mux-launch-tmux.ts +77 -2
  44. package/scripts/check-mux-launch.ts +17 -0
  45. package/scripts/check-mux-placement-tmux.ts +61 -1
  46. package/scripts/check-mux-placement.ts +33 -0
  47. package/scripts/check-omp-birth-hook.ts +3 -2
  48. package/scripts/check-probe-bridge-command.ts +3 -1
  49. package/scripts/check-setup-qualification.sh +21 -0
  50. package/scripts/copilot-bridge-doctor.sh +15 -5
  51. package/scripts/copilot-bridge-install.sh +6 -2
  52. package/scripts/copilot-launch.sh +16 -2
  53. package/scripts/copilot-receive-bridge.sh +80 -13
  54. package/scripts/lib/reclaim-on-exit.ts +86 -0
  55. package/scripts/meta-bridge-doctor.sh +56 -15
  56. package/scripts/meta-bridge-install.sh +13 -7
  57. package/scripts/meta-bridge-uninstall.sh +6 -4
  58. package/scripts/mutants/acp-cortex.json +26 -2
  59. package/scripts/mutants/copilot-receive.json +26 -0
  60. package/scripts/mutants/fresh-cut.json +26 -0
  61. package/scripts/mutants/mux-boundary.json +24 -0
  62. package/scripts/mutants/mux-fresh-call.json +81 -0
  63. package/scripts/mutants/omp-birth.json +33 -3
  64. package/scripts/mutants/setup-verdict.json +13 -0
  65. package/scripts/omp-bridge-doctor.sh +110 -31
  66. package/scripts/omp-bridge-install.sh +6 -2
  67. package/scripts/omp-receive-install.sh +7 -2
  68. package/scripts/raw-async-delivery/README.md +10 -1
  69. package/scripts/raw-codex-measure/README.md +689 -0
  70. package/scripts/raw-codex-measure/source-audit.md +243 -0
  71. package/scripts/raw-macos-measure/README.md +148 -0
  72. package/scripts/raw-macos-measure/probe.sh +389 -0
  73. package/scripts/smoke-meta-async-drift.sh +7 -5
  74. package/scripts/smoke-meta-install-state.sh +70 -19
  75. package/scripts/smoke-mux-fresh-call-live.ts +175 -3
  76. package/scripts/smoke-omp-bridge-state.sh +43 -2
  77. package/scripts/smoke-setup-verdict.sh +100 -0
@@ -0,0 +1,86 @@
1
+ // Reclaim a gate's OWN process resources when that gate exits — however it exits.
2
+ //
3
+ // WHY THIS EXISTS (test-infra, not a product capability):
4
+ // A gate ends red by THROWING (`ok()` is `assert.ok`), and ^C or a runner's SIGTERM
5
+ // ends it with no statement running at all. Teardown written as the last line of the
6
+ // file is therefore skipped on every path except the green one, and the mutant runner
7
+ // makes that the COMMON path: qualification runs each committed mutant expecting the
8
+ // gate to go red. Measured on `oracle` 2026-09-08, before this leaf existed: ~9,200
9
+ // stale temp roots and 3.8G under `/tmp`, plus 360 reparented fixture Node processes
10
+ // from `check-copilot-receive-arm` alone. `pnpm check` was still minting a fresh one
11
+ // per run at that point.
12
+ //
13
+ // WHAT IT IS NOT. It is not error handling and it does not soften a failure: the exit
14
+ // code is untouched (a red gate stays red, a signal still ends as 128+n), nothing is
15
+ // logged, and no failure is converted into a warning (Hard Rule 15). It reclaims
16
+ // process resources only — never a record, transcript or operator artifact (Hard Rule
17
+ // 8). A SIGKILL of the gate still runs nothing here, by construction; that residue is
18
+ // the release protocol's `P9. Reclaim the host` step, and a fixture child that must
19
+ // outlive nothing needs its own parent-death watchdog.
20
+
21
+ import type { ChildProcess } from "node:child_process";
22
+ import { rmSync } from "node:fs";
23
+
24
+ const roots: string[] = [];
25
+ const children: ChildProcess[] = [];
26
+ let wired = false;
27
+ let done = false;
28
+
29
+ /** Sync-only, idempotent: an `exit` handler may not await anything. */
30
+ function reclaim(): void {
31
+ if (done) return;
32
+ done = true;
33
+ for (const c of children) {
34
+ try {
35
+ c.kill("SIGKILL");
36
+ } catch {
37
+ // kill() throws ESRCH on an already-reaped pid — gone either way
38
+ }
39
+ }
40
+ for (const dir of roots) {
41
+ try {
42
+ rmSync(dir, { recursive: true, force: true });
43
+ } catch {
44
+ // Best-effort teardown must never become the reason a GREEN gate exits
45
+ // non-zero: a throw inside an `exit` handler would flip the verdict of a
46
+ // run that had already passed every assertion it makes.
47
+ }
48
+ }
49
+ }
50
+
51
+ function wire(): void {
52
+ if (wired) return;
53
+ wired = true;
54
+ process.on("exit", reclaim);
55
+ // A signal is not an exit: without these, `exit` never fires. Re-raising as
56
+ // 128+n keeps the shell's own convention rather than inventing a code.
57
+ for (const [signal, n] of [
58
+ ["SIGINT", 2],
59
+ ["SIGTERM", 15],
60
+ ["SIGHUP", 1],
61
+ ] as const) {
62
+ process.on(signal, () => {
63
+ reclaim();
64
+ process.exit(128 + n);
65
+ });
66
+ }
67
+ }
68
+
69
+ /** Register a temp root to remove on exit. Returns it, so it wraps `mkdtempSync`. */
70
+ export function reclaimOnExit(dir: string): string {
71
+ wire();
72
+ roots.push(dir);
73
+ return dir;
74
+ }
75
+
76
+ /** Register a spawned child to SIGKILL on exit. Returns it, so it wraps `spawn`. */
77
+ export function killOnExit<T extends ChildProcess>(child: T): T {
78
+ wire();
79
+ children.push(child);
80
+ return child;
81
+ }
82
+
83
+ /** Run the registered teardown now (the green tail); later exits become no-ops. */
84
+ export function reclaimNow(): void {
85
+ reclaim();
86
+ }
@@ -66,13 +66,18 @@ echo "meta-bridge doctor"
66
66
  echo "config=$CLAUDE_CFG agent-dir=$AGENT"
67
67
 
68
68
  echo "[platform]"
69
- # The #51 repair contract is Linux-only because certification requires discovery of
70
- # each live bridge process's environment through /proc. Darwin is not an install lane
71
- # for this cut and must stay nonzero here too never downgrade unsupported to a
72
- # static/synthetic PASS.
69
+ # WHAT THIS FENCE IS ABOUT, NARROWLY. It is not "GNU tools" and it is not the
70
+ # start-key: the python join below now mints the SAME `ps:` string the TS core mints
71
+ # (audit Q2), so start-key and ppid are portable in this doctor too and that half of
72
+ # the old reason is retired. What is left is bridge DISCOVERY — finding the live
73
+ # entwurf MCP children by their per-process ENVIRONMENT — which has no measured
74
+ # portable equivalent, so the live-owner tier is unreachable rather than merely
75
+ # unobserved (the rc=3 branch below is the same verdict, stated where it fires).
76
+ # Darwin therefore stays nonzero here: a doctor that cannot measure its central axis
77
+ # must never downgrade "unsupported" to a static/synthetic PASS.
73
78
  case "$(uname -s)" in
74
79
  Linux) ok "Linux supported — the certified live axis (live owner join is instrumentable)" ;;
75
- Darwin) bad "macOS is NOT YET VERIFIED/CERTIFIED for this repair cut: strict live-owner certification currently requires /proc. The installer refuses Darwin; this doctor remains nonzero for diagnosis/legacy cleanup. Future validation may reopen the lane." ;;
80
+ Darwin) bad "macOS is NOT CERTIFIED for this cut: the live-owner join needs per-process ENVIRONMENT discovery of the live bridge children, and no portable Darwin equivalent has been MEASURED yet (start-key/ppid are portable here now — that half of the old reason is retired). This doctor stays nonzero on Darwin for diagnosis and legacy cleanup until a physical Darwin receipt exists." ;;
76
81
  *) bad "$(uname -s) unsupported (Claude meta-bridge repair cut is Linux-only)" ;;
77
82
  esac
78
83
 
@@ -982,7 +987,7 @@ fi
982
987
  echo "[live Claude MCP owner join]"
983
988
  if command -v python3 >/dev/null; then
984
989
  if JOIN_OUT="$(python3 - "$AGENT" "$META_SESSIONS" <<'PY' 2>&1
985
- import json, os, sys
990
+ import json, re, subprocess, sys
986
991
  from pathlib import Path
987
992
 
988
993
  agent = Path(sys.argv[1]).expanduser().resolve()
@@ -990,23 +995,52 @@ store = Path(sys.argv[2]).expanduser().resolve()
990
995
  proc = Path("/proc")
991
996
  if not proc.is_dir():
992
997
  # rc=3 is a PLATFORM verdict, distinct from rc=2 ("no session open right now").
993
- # The runtime this doctor verifies has a `ps` fallback for start-key/ppid, but
994
- # bridge DISCOVERY needs per-process environ, which has no portable equivalent
995
- # here so the live tier is unreachable, not merely unobserved.
996
- print("live owner join is NOT INSTRUMENTABLE on this platform: /proc is unavailable, so entwurf MCP children cannot be discovered")
998
+ # NARROWLY: start-key and ppid are NOT the reason — `parent()`/`start_key()` below
999
+ # carry the same two-tier `/proc`-then-`ps` fallback the runtime writer has, so they
1000
+ # answer on any platform with a `ps`. Bridge DISCOVERY is the reason: it needs each
1001
+ # candidate's per-process ENVIRONMENT, which has no measured portable equivalent, so
1002
+ # the live tier is unreachable here rather than merely unobserved.
1003
+ print("live owner join is NOT INSTRUMENTABLE on this platform: what holds the lane closed is per-process environment DISCOVERY alone — start-key and ppid are portable there (`ps` fallback, same string the TS core mints), but no measured Darwin equivalent exists for reading each live bridge child's environment")
997
1004
  raise SystemExit(3)
998
1005
 
999
1006
  def stat_fields(pid):
1000
1007
  text = Path(f"/proc/{pid}/stat").read_text()
1001
1008
  return text[text.rfind(")") + 2:].split()
1002
1009
 
1010
+ def ps_field(pid, fmt):
1011
+ # The SAME argv vector the writer uses (meta-session.ts parentPid/processStartKey),
1012
+ # so the two writers cannot disagree by construction.
1013
+ try:
1014
+ out = subprocess.run(["ps", "-o", fmt, "-p", str(pid)], capture_output=True, text=True).stdout
1015
+ except Exception:
1016
+ return ""
1017
+ return out.strip()
1018
+
1003
1019
  def parent(pid):
1020
+ if not isinstance(pid, int) or pid <= 0: return None
1004
1021
  try: return int(stat_fields(pid)[1])
1005
- except Exception: return None
1022
+ except Exception: pass
1023
+ # `ps -o ppid=` — literally the fallback parentPid() already ships.
1024
+ ppid = ps_field(pid, "ppid=")
1025
+ return int(ppid) if ppid.isdigit() and int(ppid) > 0 else None
1006
1026
 
1007
1027
  def start_key(pid):
1008
- try: return "linux:" + stat_fields(pid)[19]
1009
- except Exception: return ""
1028
+ # TWO WRITERS, ONE STRING. The runtime mints this key (meta-session.ts
1029
+ # processStartKey) and this doctor RE-mints it to compare against the marker; if the
1030
+ # two ever mint different strings for the same live pid the join fails for a reason
1031
+ # that has nothing to do with the install. So this is not "a portable start key" —
1032
+ # it is the same two tiers in the same order with the same prefixes: `/proc/<pid>/stat`
1033
+ # field 22 as `linux:<ticks>`, else `ps -o lstart= -p <pid>` trimmed as `ps:<lstart>`.
1034
+ # python `.strip()` and JS `.trim()` both strip ASCII whitespace from this single-line
1035
+ # output, and the argv vector is identical, so the bytes are identical (audit Q2).
1036
+ # "" stays the UNKNOWN answer and never matches a marker — fail-closed, unchanged.
1037
+ if not isinstance(pid, int) or pid <= 0: return ""
1038
+ try:
1039
+ starttime = stat_fields(pid)[19]
1040
+ if re.fullmatch(r"\d+", starttime): return "linux:" + starttime
1041
+ except Exception: pass
1042
+ lstart = ps_field(pid, "lstart=")
1043
+ return "ps:" + lstart if lstart else ""
1010
1044
 
1011
1045
  def process_agent(env):
1012
1046
  raw = env.get("PI_CODING_AGENT_DIR")
@@ -1088,7 +1122,7 @@ PY
1088
1122
  # send an operator to completely different places.
1089
1123
  case "$JOIN_RC" in
1090
1124
  2) bad "NOT CERTIFIED — $JOIN_OUT. Nothing here says the install is broken: the evidence simply does not exist yet. Open a Claude Code session (or restart the affected one) and run this doctor again." ;;
1091
- 3) bad "NOT CERTIFIED on this platform — $JOIN_OUT. This repair cut currently certifies the Claude meta-bridge on Linux only; static/synthetic evidence cannot certify $(uname -s), and future native validation may reopen that lane." ;;
1125
+ 3) bad "NOT CERTIFIED on this platform — $JOIN_OUT. This repair cut certifies the Claude meta-bridge on Linux only; static/synthetic evidence cannot certify $(uname -s), and only a physical native run can reopen that lane." ;;
1092
1126
  *) bad "$JOIN_OUT. Re-run install-meta-bridge, restart the affected Claude session(s), then run doctor again." ;;
1093
1127
  esac
1094
1128
  fi
@@ -1121,7 +1155,14 @@ livewrite_schema() { # $1=meta-session.<ext> → v3|v2|v1|absent
1121
1155
  elif grep -q "serializeMetaIdentity" "$1"; then echo "v2"
1122
1156
  else echo "v1"; fi
1123
1157
  }
1124
- hash12() { [ -f "$1" ] && sha256sum "$1" | cut -c1-12 || echo "------------"; }
1158
+ # 12-hex digest, portable. NOT `sha256sum` (coreutils, absent on macOS) and NOT
1159
+ # `shasum -a 256` — that would be a second digest convention, while python3 is already
1160
+ # a hard prerequisite of this whole doctor (line 31 reads install-state through it). So
1161
+ # this reuses the python3 hashlib form omp-receive-doctor.sh:99 already ships. An absent
1162
+ # file still yields `------------`, and a hashing failure now falls into that same
1163
+ # placeholder instead of an empty string — either way the parity rows below read it as
1164
+ # drift and go red, which is the fail-closed side.
1165
+ hash12() { [ -f "$1" ] && python3 -c 'import hashlib,sys;print(hashlib.sha256(open(sys.argv[1],"rb").read()).hexdigest()[:12])' "$1" 2>/dev/null || echo "------------"; }
1125
1166
  registry_for_ms() { # $1=bundle meta-session.ts → sibling plugin-root registry path
1126
1167
  [ -f "$1" ] || { echo ""; return; }
1127
1168
  dirname "$(dirname "$1")"
@@ -25,9 +25,13 @@
25
25
  # Idempotent: re-running removes the prior marketplace/plugin first, so a
26
26
  # `nix rebuild` that moved node just re-bakes and re-installs cleanly.
27
27
  #
28
- # Platform: Linux only for the #51 repair cut. macOS cannot reach the strict
29
- # live-owner certification tier, so accepting an install there would advertise a
30
- # surface this release can never certify. Windows and every other platform fail fast.
28
+ # Platform: Linux and Darwin. This installer's own platform dependency is python3 +
29
+ # node + the claude CLI (all checked below); it touches no /proc, no systemd, no
30
+ # GNU-only tool. Windows and every other platform fail fast. Live-owner rail
31
+ # certification is a SEPARATE evidence axis owned by doctor-meta-bridge (Hard Rule 17:
32
+ # installation portability and rail/runtime support are separate evidence axes) — a
33
+ # green install here does not certify the Darwin rail; run ./run.sh doctor-meta-bridge
34
+ # for that verdict.
31
35
  set -euo pipefail
32
36
 
33
37
  HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -64,11 +68,13 @@ esac
64
68
 
65
69
  die() { echo "meta-bridge-install: $*" >&2; exit 1; }
66
70
 
67
- # --- platform gate (Linux-only repair contract) -----------------------------
71
+ # --- platform gate (installer's own dependency, not rail certification) -----
72
+ # Darwin is open on the same precedent as meta-bridge-uninstall.sh:20-23: this
73
+ # installer touches no /proc and no GNU-only tool, so its own mechanism is portable
74
+ # even while the live-owner rail (doctor-meta-bridge) stays a separate, unproven axis.
68
75
  case "$(uname -s)" in
69
- Linux) ;;
70
- Darwin) die "macOS is not yet verified/certified for this repair cut. Strict live-owner certification currently requires /proc, so Darwin install is refused rather than left NOT CERTIFIED; future validation may reopen this lane." ;;
71
- *) die "unsupported platform '$(uname -s)'. The Claude meta-bridge repair cut supports Linux only (no unverified fallback)." ;;
76
+ Linux | Darwin) ;;
77
+ *) die "unsupported platform '$(uname -s)'. This installer requires Linux or Darwin." ;;
72
78
  esac
73
79
 
74
80
  # --- toolchain gate, part 1: this machine's own runtime ---------------------
@@ -14,12 +14,14 @@ PLUGIN="entwurf-meta-receive"
14
14
 
15
15
  die() { echo "meta-bridge-uninstall: $*" >&2; exit 1; }
16
16
 
17
- # Darwin stays here intentionally even though NEW installs are Linux-only in the #51
18
- # repair cut. Removing the inverse would strand an older macOS install precisely when
19
- # support narrows; uninstall is a legacy-cleanup capability, not install certification.
17
+ # Darwin is accepted on both halves as of 0.20.0. It was accepted HERE first, while new
18
+ # installs were still refused, because removing the inverse would strand an older macOS
19
+ # install precisely when support narrows. That asymmetry is now gone the installer
20
+ # refuses on its real dependency instead of the platform name — so the two halves agree
21
+ # and this fence only turns away platforms neither half has ever run on.
20
22
  case "$(uname -s)" in
21
23
  Linux | Darwin) ;;
22
- *) die "unsupported platform '$(uname -s)'. This repair cut certifies new Claude meta-bridge installs on Linux only; uninstall additionally permits Darwin so legacy state can be removed honestly." ;;
24
+ *) die "unsupported platform '$(uname -s)'. Both halves of the Claude meta-bridge repair cut run on Linux and Darwin only. Rail certification is a separate axis owned by doctor-meta-bridge." ;;
23
25
  esac
24
26
 
25
27
  command -v python3 >/dev/null || die "'python3' not on PATH. It is required for stateful uninstall."
@@ -26,6 +26,19 @@
26
26
  "signature": "[QK:CORTEX-CURATED-FOUR-ROWS]",
27
27
  "signatureSource": "scripts/check-acp-cortex.ts"
28
28
  },
29
+ {
30
+ "claim": "CLAUDE-CURATED-THREE-ROWS",
31
+ "title": "dropping a curated CLAUDE row shrinks the operator's model list while the exact-set comparison stays green — expected derives from the same constant, so only the independent count catches it",
32
+ "subject": "pi-extensions/lib/acp/models.ts",
33
+ "find": [
34
+ "export const SUPPORTED_ANTHROPIC_MODEL_IDS = [\"claude-sonnet-5\", \"claude-opus-5\", \"claude-fable-5-1\"] as const;"
35
+ ],
36
+ "replace": ["export const SUPPORTED_ANTHROPIC_MODEL_IDS = [\"claude-sonnet-5\", \"claude-opus-5\"] as const;"],
37
+ "gate": ["bash", "run.sh", "check-acp-provider-surface"],
38
+ "timeoutSeconds": 300,
39
+ "signature": "[QK:CLAUDE-CURATED-THREE-ROWS]",
40
+ "signatureSource": "scripts/check-acp-provider-surface.ts"
41
+ },
29
42
  {
30
43
  "claim": "CORTEX-AUTH-NARROW-CREDENTIAL-CACHE",
31
44
  "title": "widening the auth passthrough to the whole cortex/cache leaks operator tool_outputs/tip_history into the child",
@@ -56,6 +69,17 @@
56
69
  "signature": "[QK:CORTEX-AUTOUPDATE-OFF]",
57
70
  "signatureSource": "scripts/check-acp-cortex.ts"
58
71
  },
72
+ {
73
+ "claim": "CORTEX-REALHOME-PLATFORM-NEUTRAL",
74
+ "title": "re-deriving realHome absoluteness from the POSIX flavor alone makes a drive/UNC HOME read as relative — the guard would state the host it runs on instead of the contract (PR #77, @yizixu)",
75
+ "subject": "pi-extensions/lib/acp/overlay.ts",
76
+ "find": ["\tif (!params.realHome || !(isAbsolute(params.realHome) || win32.isAbsolute(params.realHome))) {"],
77
+ "replace": ["\tif (!params.realHome || !params.realHome.startsWith(\"/\")) {"],
78
+ "gate": ["bash", "run.sh", "check-acp-cortex"],
79
+ "timeoutSeconds": 300,
80
+ "signature": "[QK:CORTEX-REALHOME-PLATFORM-NEUTRAL]",
81
+ "signatureSource": "scripts/check-acp-cortex.ts"
82
+ },
59
83
  {
60
84
  "claim": "CORTEX-BRIDGE-DUAL-HOME",
61
85
  "title": "dropping the bridge-only real-HOME restore leaves the garden store cut off — tools reach the model but see an empty garden (D10)",
@@ -182,14 +206,14 @@
182
206
  "signatureSource": "scripts/check-acp-session-reuse.ts"
183
207
  },
184
208
  {
185
- "claim": "CORTEX-PROVIDER-SIX-ROW-SURFACE",
209
+ "claim": "CORTEX-PROVIDER-EXACT-ROW-SURFACE",
186
210
  "title": "filtering the cortex rows out of the REAL provider entry drops the whole backend from the operator's model list while models.ts and check-acp-cortex stay green",
187
211
  "subject": "pi-extensions/acp-provider.ts",
188
212
  "find": ["\t\tmodels: allCuratedModels(),"],
189
213
  "replace": ["\t\tmodels: allCuratedModels().filter((m) => !m.id.startsWith(\"cortex-\")),"],
190
214
  "gate": ["bash", "run.sh", "check-acp-provider-surface"],
191
215
  "timeoutSeconds": 300,
192
- "signature": "[QK:CORTEX-PROVIDER-SIX-ROW-SURFACE]",
216
+ "signature": "[QK:CORTEX-PROVIDER-EXACT-ROW-SURFACE]",
193
217
  "signatureSource": "scripts/check-acp-provider-surface.ts"
194
218
  }
195
219
  ]
@@ -233,6 +233,17 @@
233
233
  "signature": "[QK:COPILOT-RECEIVE-DOCTOR-UNREADABLE-ENVIRON-IS-RED]",
234
234
  "signatureSource": "scripts/check-copilot-receive-arm.ts"
235
235
  },
236
+ {
237
+ "claim": "COPILOT-RECEIVE-DOCTOR-UNREADABLE-ARGV-IS-UNVERIFIABLE",
238
+ "title": "collapsing every OSError on `/proc/<pid>/cmdline` back to None makes a REFUSED identity read indistinguishable from a process that left: the candidate is skipped before identity is decided, all counters stay zero, and the doctor prints the benign `no live GitHub Copilot CLI process` note — claiming ABSENCE while a live CLI it was never allowed to identify may be sitting there inert. The environ claim above cannot cover this one: that branch is reachable only AFTER a successful argv match",
239
+ "subject": "scripts/copilot-receive-bridge.sh",
240
+ "find": ["\t\tif exc.errno in (errno.ENOENT, errno.ESRCH):", "\t\t\treturn None", "\t\treturn UNREADABLE"],
241
+ "replace": ["\t\treturn None"],
242
+ "gate": ["bash", "run.sh", "check-copilot-receive-arm"],
243
+ "timeoutSeconds": 300,
244
+ "signature": "[QK:COPILOT-RECEIVE-DOCTOR-UNREADABLE-ARGV-IS-UNVERIFIABLE]",
245
+ "signatureSource": "scripts/check-copilot-receive-arm.ts"
246
+ },
236
247
  {
237
248
  "claim": "COPILOT-RECEIVE-DOCTOR-OWNS-SCANNER-FAILURE",
238
249
  "title": "letting the scanner's exit status reach the assignment under `set -e` kills the doctor mid-section: no verdict line is printed at all, so the operator cannot tell a healthy host from a broken doctor — the same silent-death shape this lane already fixed once in the log grep",
@@ -258,6 +269,21 @@
258
269
  "timeoutSeconds": 300,
259
270
  "signature": "[QK:COPILOT-RECEIVE-DOCTOR-PI-CARRIER-IS-RED]",
260
271
  "signatureSource": "scripts/check-copilot-receive-arm.ts"
272
+ },
273
+ {
274
+ "claim": "COPILOT-RECEIVE-STUB-CHILD-DIES-WITH-PARENT",
275
+ "title": "a stub child with no parent-death watchdog outlives the gate forever — measured on `oracle` as 360 reparented Node receivers, because a red gate exits by THROWING and never reaches any teardown written below it",
276
+ "subject": "scripts/check-copilot-receive-arm.ts",
277
+ "find": [
278
+ "if (parentAtStart === 1) process.exit(0);",
279
+ "setInterval(() => {",
280
+ "\tif (process.ppid !== parentAtStart) process.exit(0);"
281
+ ],
282
+ "replace": ["void parentAtStart;", "setInterval(() => {", "\t/* the vendor bootstrap's parent check, removed */"],
283
+ "gate": ["bash", "run.sh", "check-copilot-receive-arm"],
284
+ "timeoutSeconds": 300,
285
+ "signature": "[QK:COPILOT-RECEIVE-STUB-CHILD-DIES-WITH-PARENT]",
286
+ "signatureSource": "scripts/check-copilot-receive-arm.ts"
261
287
  }
262
288
  ]
263
289
  }
@@ -12,6 +12,32 @@
12
12
  "timeoutSeconds": 180,
13
13
  "signature": "[QK:FRESH-CUT-COLLISION-NO-MOVE]",
14
14
  "signatureSource": "scripts/check-fresh-cut-gate.sh"
15
+ },
16
+ {
17
+ "claim": "FRESHCUT-SYNCAUTH-TRIPWIRE-FIRES",
18
+ "title": "the retired-credential tripwire goes blind again. This replants the ACTUAL defect rather than a stand-in: under pipefail a `-q` grep exits at the first match and SIGPIPEs the awk still writing ~200KB of a 433KB run.sh, so the pipeline reports 141 and the `if` takes the CLEAN branch — the cell reported no sync_auth surface EXACTLY when one existed. It was deterministic here (100/100 measured) because the producer dwarfs the pipe buffer, which is why the self-test plants its surface near the TOP of the real run.sh: a small synthetic fixture would pass under this mutant and prove nothing",
19
+ "subject": "scripts/check-fresh-cut-gate.sh",
20
+ "find": [" awk '!/^[[:space:]]*#/' \"$1\" | grep -c 'sync_auth' || true"],
21
+ "replace": [" awk '!/^[[:space:]]*#/' \"$1\" | grep -q 'sync_auth' && echo 1 || echo 0"],
22
+ "gate": ["bash", "run.sh", "check-fresh-cut-gate"],
23
+ "timeoutSeconds": 180,
24
+ "signature": "[QK:FRESHCUT-SYNCAUTH-TRIPWIRE-FIRES]",
25
+ "signatureSource": "scripts/check-fresh-cut-gate.sh"
26
+ },
27
+ {
28
+ "claim": "FRESHCUT-PREFLIGHT-CUT-DETECTED",
29
+ "title": "the cell forbidding an install from cutting a generation by itself stops SEEING the call it forbids — the context window silently narrows to the matched line, so a fresh-cut invocation one line into preflight_v3_store() reads as absent and D7 stays green. A forbidding cell that is green on a clean tree cannot tell blindness from compliance, which is what the self-test exists to separate",
30
+ "subject": "scripts/check-fresh-cut-gate.sh",
31
+ "find": [
32
+ " grep -n 'preflight_v3_store()' -A 40 \"$1\" | grep -cE 'run_ts scripts/meta-bridge-fresh-cut\\.ts' || true"
33
+ ],
34
+ "replace": [
35
+ " grep -n 'preflight_v3_store()' -A 0 \"$1\" | grep -cE 'run_ts scripts/meta-bridge-fresh-cut\\.ts' || true"
36
+ ],
37
+ "gate": ["bash", "run.sh", "check-fresh-cut-gate"],
38
+ "timeoutSeconds": 180,
39
+ "signature": "[QK:FRESHCUT-PREFLIGHT-CUT-DETECTED]",
40
+ "signatureSource": "scripts/check-fresh-cut-gate.sh"
15
41
  }
16
42
  ]
17
43
  }
@@ -191,6 +191,30 @@
191
191
  "timeoutSeconds": 60,
192
192
  "signature": "[QK:MUX-LAUNCH-CORE-IMPORT-FREE]",
193
193
  "signatureSource": "scripts/check-mux-launch.ts"
194
+ },
195
+ {
196
+ "claim": "MUX-CLOSE-SERVER-BOUND",
197
+ "title": "the close-side predicate accepts a foreign SERVER — a restarted server hands out the same `@id`, and a close would kill whatever window now wears it",
198
+ "subject": "pi-extensions/lib/mux-placement.ts",
199
+ "find": ["\treturn origin.serverPid === now.serverPid;\n}"],
200
+ "replace": ["\treturn true;\n}"],
201
+ "gate": ["bash", "run.sh", "check-mux-placement"],
202
+ "timeoutSeconds": 120,
203
+ "signature": "[QK:MUX-CLOSE-SERVER-BOUND]",
204
+ "signatureSource": "scripts/check-mux-placement.ts"
205
+ },
206
+ {
207
+ "claim": "RESOLVE-TMUX-SESSION-IMPORT-FREE",
208
+ "title": "the session-lookup leaf reaches into the placement leaf for runTmux — the one decision leaf that must not be able to run tmux acquires exactly that power, and the injected-runner seam its whole safety argument rests on stops being the only way in",
209
+ "subject": "pi-extensions/lib/resolve-tmux-session.ts",
210
+ "find": ["export type TmuxSessionRejectReason = \"tmux-session-name-invalid\" | \"tmux-session-missing\";"],
211
+ "replace": [
212
+ "import { runTmux } from \"./mux-placement.ts\";\nvoid runTmux;\nexport type TmuxSessionRejectReason = \"tmux-session-name-invalid\" | \"tmux-session-missing\";"
213
+ ],
214
+ "gate": ["bash", "run.sh", "check-mux-launch"],
215
+ "timeoutSeconds": 120,
216
+ "signature": "[QK:RESOLVE-TMUX-SESSION-IMPORT-FREE]",
217
+ "signatureSource": "scripts/check-mux-launch.ts"
194
218
  }
195
219
  ]
196
220
  }
@@ -438,6 +438,87 @@
438
438
  "timeoutSeconds": 180,
439
439
  "signature": "[QK:FRESHCALL-BACKEND-SET-SURFACE-PARITY-PI]",
440
440
  "signatureSource": "test/fresh-call-surfaces.contract.test.ts"
441
+ },
442
+ {
443
+ "claim": "TMUXSESSION-LOOKUP-ENGINE",
444
+ "title": "the seat lookup goes back to the `-f` filter engine, which was measured to match EVERY session when the name contains a '}' — a fresh sibling then opens in whichever session tmux listed first",
445
+ "subject": "pi-extensions/lib/resolve-tmux-session.ts",
446
+ "find": ["\treturn [\"list-windows\", \"-t\", `=${name}`, \"-F\", \"#{session_id}\"];"],
447
+ "replace": ["\treturn [\"list-sessions\", \"-f\", `#{==:#{session_name},${name}}`, \"-F\", \"#{session_id}\"];"],
448
+ "gate": ["bash", "run.sh", "check-mux-fresh-call"],
449
+ "timeoutSeconds": 180,
450
+ "signature": "[QK:TMUXSESSION-LOOKUP-ENGINE]",
451
+ "signatureSource": "test/mux-fresh-call.test.ts"
452
+ },
453
+ {
454
+ "claim": "TMUXSESSION-NAME-GRAMMAR",
455
+ "title": "the seat name grammar is widened to 'anything non-empty' — tmux then stores a DIFFERENT name than the one requested (or splits it on '.'/':') and the seat can never be found, reported as 'missing' instead of as a shape this rail does not address",
456
+ "subject": "pi-extensions/lib/resolve-tmux-session.ts",
457
+ "find": ["const SESSION_NAME = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;"],
458
+ "replace": ["const SESSION_NAME = /^.+$/;"],
459
+ "gate": ["bash", "run.sh", "check-mux-fresh-call"],
460
+ "timeoutSeconds": 180,
461
+ "signature": "[QK:TMUXSESSION-NAME-GRAMMAR]",
462
+ "signatureSource": "test/mux-fresh-call.test.ts"
463
+ },
464
+ {
465
+ "claim": "FRESHCALL-PLACEMENT-MISSING-REJECTS",
466
+ "title": "an absent seat is read as success — tmux's exit code is ignored, so a missing session falls through to the caller's own session and the launch looks like the seat worked. Proof is in two halves: this mutant dies on the leaf's injected-runner assert plus the source-text ordering assert in the fast lane, and the behavioural oracle independent of that source is the real-tmux seat cell in check-mux-launch-tmux (refusal by name with a byte-identical list-windows -a before and after)",
467
+ "subject": "pi-extensions/lib/resolve-tmux-session.ts",
468
+ "find": ["\tif (result.status !== 0) return { ok: false, reason: \"tmux-session-missing\" };"],
469
+ "replace": [
470
+ "\tif (result.status !== 0 && result.stdout.length > 0) return { ok: false, reason: \"tmux-session-missing\" };"
471
+ ],
472
+ "gate": ["bash", "run.sh", "check-mux-fresh-call"],
473
+ "timeoutSeconds": 180,
474
+ "signature": "[QK:FRESHCALL-PLACEMENT-MISSING-REJECTS]",
475
+ "signatureSource": "test/mux-fresh-call.test.ts"
476
+ },
477
+ {
478
+ "claim": "FRESHCALL-PLACEMENT-TARGET-ARGV",
479
+ "title": "the launch argv targets the caller's own session again — a seated fresh call silently opens beside the caller instead of in the operator's project session, and the receipt still looks right",
480
+ "subject": "pi-extensions/lib/mux-fresh-call.ts",
481
+ "find": ["\t\t`${targetSessionId}:{end}`,"],
482
+ "replace": ["\t\t`$0:{end}`,"],
483
+ "gate": ["bash", "run.sh", "check-mux-fresh-call"],
484
+ "timeoutSeconds": 180,
485
+ "signature": "[QK:FRESHCALL-PLACEMENT-TARGET-ARGV]",
486
+ "signatureSource": "test/mux-fresh-call.test.ts"
487
+ },
488
+ {
489
+ "claim": "FRESHCALL-PLACEMENT-BACKEND-PARITY",
490
+ "title": "the project seat becomes a pi capability — the grammar refusal is gated on the backend, so claude-code, copilot and omp fall past the seat check into runtime resolution and answer with the wrong reason. Every seat assertion that existed when #105 landed was written against backend pi alone, so nothing would have noticed",
491
+ "subject": "pi-extensions/lib/mux-fresh-call.ts",
492
+ "find": ["\t\tif (badSeat) return { ok: false, reason: badSeat };"],
493
+ "replace": ["\t\tif (badSeat && params.backend === \"pi\") return { ok: false, reason: badSeat };"],
494
+ "gate": ["bash", "run.sh", "check-mux-fresh-call"],
495
+ "timeoutSeconds": 180,
496
+ "signature": "[QK:FRESHCALL-PLACEMENT-BACKEND-PARITY]",
497
+ "signatureSource": "test/mux-fresh-call.test.ts"
498
+ },
499
+ {
500
+ "claim": "FRESHCALL-PLACEMENT-RECEIPT-TARGET",
501
+ "title": "the receipt copies the CALLER's session id again — the window is in the seat, the receipt names the caller's session, and every later close/lookup built on that receipt addresses the wrong session. Proof is in two halves: this mutant dies on the source-text assembly assert in the fast lane, and the behavioural oracle independent of that source is the real-tmux seat cell in check-mux-launch-tmux (receipt.sessionId === seatId !== callerId, read from the server's own inventory)",
502
+ "subject": "pi-extensions/lib/mux-fresh-call.ts",
503
+ "find": ["\t\t\tsessionId: targetSessionId,"],
504
+ "replace": ["\t\t\tsessionId: placement.sessionId,"],
505
+ "gate": ["bash", "run.sh", "check-mux-fresh-call"],
506
+ "timeoutSeconds": 180,
507
+ "signature": "[QK:FRESHCALL-PLACEMENT-RECEIPT-TARGET]",
508
+ "signatureSource": "test/mux-fresh-call.test.ts"
509
+ },
510
+ {
511
+ "claim": "FRESHCALL-PLACEMENT-SURFACE-PARITY",
512
+ "title": "one surface drops the optional seat from its schema, so opening a sibling in the operator's project session works from pi and silently cannot exist from the MCP bridge",
513
+ "subject": "mcp/entwurf-bridge/src/index.ts",
514
+ "find": [
515
+ "\t\tplacement: z\n\t\t\t.object({\n\t\t\t\ttmuxSession: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"EXACT name of an EXISTING session on this agent's own tmux server. Nothing is created: an absent session is refused as tmux-session-missing, and a name outside [A-Za-z0-9][A-Za-z0-9_-]* as tmux-session-name-invalid.\",\n\t\t\t\t\t),\n\t\t\t})\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t\"Optional project seat: open the sibling in ONE EXISTING tmux session of this agent's own server instead of the caller's session. Nothing is ever created — an absent session is a refusal, not a new session. Independent of cwd; neither is inferred from the other. The receipt echoes the REQUESTED name and reports the resolved target session id.\",\n\t\t\t),\n"
516
+ ],
517
+ "replace": [""],
518
+ "gate": ["bash", "run.sh", "check-mux-fresh-call"],
519
+ "timeoutSeconds": 180,
520
+ "signature": "[QK:FRESHCALL-PLACEMENT-SURFACE-PARITY]",
521
+ "signatureSource": "test/fresh-call-surfaces.contract.test.ts"
441
522
  }
442
523
  ]
443
524
  }
@@ -158,16 +158,46 @@
158
158
  },
159
159
  {
160
160
  "claim": "OMP-DOCTOR-CARRIER-TRIMS",
161
- "title": "treating an empty or whitespace-only PI carrier as an inherited identity makes Bundle C's deliberate tmux `-e NAME=` scrub fail the deterministic floor whenever a visible fresh omp citizen is alive",
161
+ "title": "treating an empty or whitespace-only PI carrier as an inherited identity makes Bundle C's deliberate tmux `-e NAME=` scrub fail the deterministic floor whenever a visible fresh omp citizen is alive. Re-anchored twice, and the replanted defect is unchanged both times — only the line it attaches to moved: first when the carrier scan went from an early-exiting `grep -q` to `grep -c` (the SIGPIPE/pipefail repair), then when the scan lost an indentation level because the `[ -d /proc ]` wrapper whose `else` arm was a fail-open `note` was removed (#78 D1)",
162
162
  "subject": "scripts/omp-bridge-doctor.sh",
163
163
  "find": [
164
- " if tr '\\0' '\\n' < \"$ENVIRON\" 2>/dev/null | grep -qE '^(PI_SESSION_ID|PI_AGENT_ID)=.*[^[:space:]]'; then"
164
+ " HITS=\"$(tr '\\0' '\\n' < \"$ENVIRON\" 2>/dev/null | grep -cE '^(PI_SESSION_ID|PI_AGENT_ID)=.*[^[:space:]]' || true)\""
165
+ ],
166
+ "replace": [
167
+ " HITS=\"$(tr '\\0' '\\n' < \"$ENVIRON\" 2>/dev/null | grep -cE '^(PI_SESSION_ID|PI_AGENT_ID)=' || true)\""
165
168
  ],
166
- "replace": [" if tr '\\0' '\\n' < \"$ENVIRON\" 2>/dev/null | grep -qE '^(PI_SESSION_ID|PI_AGENT_ID)='; then"],
167
169
  "gate": ["bash", "run.sh", "smoke-omp-bridge-state"],
168
170
  "timeoutSeconds": 300,
169
171
  "signature": "[QK:OMP-DOCTOR-CARRIER-TRIMS]",
170
172
  "signatureSource": "scripts/smoke-omp-bridge-state.sh"
173
+ },
174
+ {
175
+ "claim": "OMP-DOCTOR-CARRIER-NONBLANK-IS-RED",
176
+ "title": "the doctor stops flagging a live omp process that carries a NONBLANK inherited PI_SESSION_ID/PI_AGENT_ID, so a session whose MCP children would speak under the parent pi garden id reads as clean and the doctor prints PASS. The real defect was subtler than this replant, which is why the replant is written this way: `grep -q` exited at the first match, SIGPIPEd `tr` mid-environ, and pipefail turned a MATCH into a failed pipeline — a race on how far `tr` got, misreading ~15% of runs, so a `-q` replant would SURVIVE most of the time and prove nothing. This one makes the same false-clean deterministic. Re-anchored at one indentation level less when the `[ -d /proc ]` wrapper was removed (#78 D1)",
177
+ "subject": "scripts/omp-bridge-doctor.sh",
178
+ "find": [" if [ \"${HITS:-0}\" -gt 0 ]; then"],
179
+ "replace": [" if [ \"${HITS:-0}\" -gt 99 ]; then"],
180
+ "gate": ["bash", "run.sh", "smoke-omp-bridge-state"],
181
+ "timeoutSeconds": 180,
182
+ "signature": "[QK:OMP-DOCTOR-CARRIER-NONBLANK-IS-RED]",
183
+ "signatureSource": "scripts/smoke-omp-bridge-state.sh"
184
+ },
185
+ {
186
+ "claim": "OMP-DOCTOR-UNENUMERATED-IS-UNVERIFIABLE",
187
+ "title": "restoring `|| true` on the candidate-discovery `pgrep` folds a FAILED enumeration (exit 2, or a `pgrep` that is not on PATH at all) into `nothing matched` (exit 1): the loop receives an empty candidate set, the doctor prints the clean carrier line and PASSes, and a live omp session carrying a foreign pi garden id reads as CLEAN because the tool that would have found it never ran. The documented `ENTWURF_OMP_CARRIER_PIDS` seam cannot substitute for this — it narrows candidates and short-circuits the very enumeration that failed",
188
+ "subject": "scripts/omp-bridge-doctor.sh",
189
+ "find": [
190
+ " ENUM_RC=0",
191
+ " CARRIER_CANDIDATES=\"$(pgrep -x omp 2>/dev/null)\" || ENUM_RC=$?",
192
+ " if [ \"$ENUM_RC\" -gt 1 ]; then",
193
+ " ENUM_FAILED=\"$ENUM_RC\"",
194
+ " fi"
195
+ ],
196
+ "replace": [" CARRIER_CANDIDATES=\"$(pgrep -x omp 2>/dev/null || true)\""],
197
+ "gate": ["bash", "run.sh", "smoke-omp-bridge-state"],
198
+ "timeoutSeconds": 300,
199
+ "signature": "[QK:OMP-DOCTOR-UNENUMERATED-IS-UNVERIFIABLE]",
200
+ "signatureSource": "scripts/smoke-omp-bridge-state.sh"
171
201
  }
172
202
  ]
173
203
  }
@@ -178,6 +178,19 @@
178
178
  "timeoutSeconds": 180,
179
179
  "signature": "[QK:SETUP-OMP-CONFIG-NO-OVERWRITE]",
180
180
  "signatureSource": "scripts/check-setup-qualification.sh"
181
+ },
182
+ {
183
+ "claim": "SETUP-DARWIN-RAIL-COSMETIC-PASS",
184
+ "title": "the platform rail check is dropped, so a harness whose install completes on a platform with no rail receipt reads PASS and the whole setup reads green again — the 0.20.0 hole the installer's retired Darwin refusal used to cover",
185
+ "subject": "run.sh",
186
+ "find": [
187
+ " if harness_rail_certified_platform; then\n setup_result \"$1\" PASS \"$2 — verify: $3\"\n return 0\n fi"
188
+ ],
189
+ "replace": [" setup_result \"$1\" PASS \"$2 — verify: $3\"\n return 0"],
190
+ "gate": ["bash", "scripts/check-setup-qualification.sh"],
191
+ "timeoutSeconds": 180,
192
+ "signature": "[QK:SETUP-DARWIN-RAIL-COSMETIC-PASS]",
193
+ "signatureSource": "scripts/check-setup-qualification.sh"
181
194
  }
182
195
  ]
183
196
  }