@junghanacs/entwurf 0.45.0 → 0.51.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 (116) hide show
  1. package/AGENTS.md +5 -3
  2. package/BASELINE.md +110 -1
  3. package/CHANGELOG.md +249 -0
  4. package/CONTRIBUTING.md +1 -1
  5. package/ENTWURF-CLI.json +1229 -0
  6. package/ENTWURF.json +63 -15
  7. package/FAQ.md +4 -4
  8. package/README.md +132 -188
  9. package/VERIFY.md +18 -11
  10. package/demo/README.md +1 -1
  11. package/docs/acp-backend-rail.md +1 -1
  12. package/docs/external-mcp-host.md +4 -4
  13. package/docs/setup-clean-host.md +94 -22
  14. package/mcp/entwurf-bridge/dist/ENTWURF.json +63 -15
  15. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +19 -8
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +4 -4
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-visible-resume.js +483 -18
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-dispatch.js +47 -10
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +613 -33
  20. package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-resume-call.js +497 -0
  21. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +3 -1
  22. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-resume-call.js +50 -5
  23. package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-fresh-preflight.js +7 -1
  24. package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-location.js +347 -0
  25. package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-owner-fence.js +1132 -0
  26. package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-runtime.js +1 -0
  27. package/mcp/entwurf-bridge/dist/pi-extensions/lib/resume-launch-identity.js +18 -11
  28. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js +30 -15
  29. package/mcp/entwurf-bridge/dist/scripts/herdr-rails.mjs +40 -7
  30. package/mcp/entwurf-bridge/dist/scripts/meta-bridge-fresh-cut.js +1 -27
  31. package/mcp/entwurf-bridge/dist/scripts/meta-bridge-prune.js +1 -1
  32. package/mcp/entwurf-bridge/dist/scripts/meta-facts.js +1 -1
  33. package/mcp/entwurf-bridge/dist/scripts/peer-facts.js +1 -1
  34. package/mcp/entwurf-bridge/src/index.ts +28 -8
  35. package/mcp/entwurf-bridge/tsconfig.build.json +7 -1
  36. package/native/win32-x64/manifest.json +1 -1
  37. package/package.json +16 -20
  38. package/pi/pi-durable/bootstrap.mjs +179 -6
  39. package/pi/pi-durable/carrier/runtime.js +327 -57
  40. package/pi/pi-durable/carrier/session-name.js +11 -0
  41. package/pi/pi-durable/carrier/sessions.js +96 -20
  42. package/pi/pi-durable/carrier/subagent.js +5 -2
  43. package/pi/pi-durable/carrier/tui.js +60 -22
  44. package/pi/pi-durable/overlay/upstream-pin.json +26 -19
  45. package/pi-extensions/lib/entwurf-v2-contract-schema.ts +73 -69
  46. package/pi-extensions/lib/entwurf-v2-contract.ts +4 -4
  47. package/pi-extensions/lib/entwurf-v2-visible-resume.ts +710 -38
  48. package/pi-extensions/lib/fresh-call-dispatch.ts +64 -12
  49. package/pi-extensions/lib/herdr-fresh-call.ts +919 -40
  50. package/pi-extensions/lib/herdr-resume-call.ts +810 -0
  51. package/pi-extensions/lib/meta-session.ts +13 -8
  52. package/pi-extensions/lib/mux-resume-call.ts +77 -4
  53. package/pi-extensions/lib/pi-durable-fresh-preflight.ts +9 -2
  54. package/pi-extensions/lib/pi-durable-location.ts +446 -0
  55. package/pi-extensions/lib/pi-durable-owner-fence.ts +1461 -0
  56. package/pi-extensions/lib/pi-durable-runtime.ts +4 -0
  57. package/pi-extensions/lib/resume-launch-identity.ts +31 -12
  58. package/pi-extensions/meta-bridge-pi-durable.ts +30 -16
  59. package/run.sh +552 -699
  60. package/scripts/check-claude-launch.ts +341 -0
  61. package/scripts/check-entwurf-v2-contract.ts +4 -4
  62. package/scripts/check-entwurf-v2-surface.ts +2 -2
  63. package/scripts/check-fresh-call-dispatch.ts +70 -9
  64. package/scripts/check-fresh-cut-gate.sh +23 -9
  65. package/scripts/check-gate-qualification.ts +19 -14
  66. package/scripts/check-herdr-activation.ts +301 -23
  67. package/scripts/check-herdr-fresh-call.ts +161 -25
  68. package/scripts/check-herdr-plugin-build.ts +173 -1
  69. package/scripts/check-herdr-plugin.ts +28 -2
  70. package/scripts/check-herdr-runtime-bootstrap.ts +136 -0
  71. package/scripts/check-install-surface.ts +1236 -6
  72. package/scripts/check-meta-doctor-oracle.sh +1 -1
  73. package/scripts/check-meta-facts.ts +20 -1
  74. package/scripts/check-mux-resume-call.ts +28 -0
  75. package/scripts/check-peer-facts.ts +39 -2
  76. package/scripts/cli-help.mjs +222 -0
  77. package/scripts/dev-bin.sh +39 -2
  78. package/scripts/herdr-activation.mjs +28 -6
  79. package/scripts/herdr-operator-link.mjs +389 -0
  80. package/scripts/herdr-plugin-activate.mjs +5 -0
  81. package/scripts/herdr-plugin-deactivate.mjs +18 -5
  82. package/scripts/herdr-rails.mjs +43 -7
  83. package/scripts/herdr-runtime.mjs +27 -0
  84. package/scripts/meta-bridge-fresh-cut.ts +1 -27
  85. package/scripts/meta-bridge-prune.ts +1 -1
  86. package/scripts/meta-facts.ts +1 -1
  87. package/scripts/mutants/agent-guidance.json +4 -4
  88. package/scripts/mutants/claude-launch.json +142 -0
  89. package/scripts/mutants/cli-help-source.json +420 -0
  90. package/scripts/mutants/control-send-receipt.json +1 -1
  91. package/scripts/mutants/dev-gate-dispatch.json +109 -0
  92. package/scripts/mutants/fresh-call-dispatch.json +38 -2
  93. package/scripts/mutants/fresh-cut.json +15 -0
  94. package/scripts/mutants/herdr-activation.json +128 -0
  95. package/scripts/mutants/herdr-fresh-call.json +278 -5
  96. package/scripts/mutants/herdr-operator-link.json +318 -0
  97. package/scripts/mutants/herdr-plugin-build.json +55 -0
  98. package/scripts/mutants/herdr-plugin.json +17 -0
  99. package/scripts/mutants/herdr-resume-call.json +288 -0
  100. package/scripts/mutants/herdr-runtime-bootstrap.json +48 -0
  101. package/scripts/mutants/meta-facts.json +15 -0
  102. package/scripts/mutants/mux-resume-call.json +63 -2
  103. package/scripts/mutants/pack-install.json +4 -4
  104. package/scripts/mutants/peer-facts.json +15 -0
  105. package/scripts/mutants/pi-durable.json +1167 -3
  106. package/scripts/mutants/pi-floor.json +22 -5
  107. package/scripts/mutants/source-install.json +35 -0
  108. package/scripts/mutants/v2-surface.json +2 -2
  109. package/scripts/mutants/v2-visible-resume.json +255 -6
  110. package/scripts/peer-facts.ts +1 -1
  111. package/scripts/smoke-agy-install-state.sh +66 -0
  112. package/scripts/smoke-meta-prune.sh +23 -0
  113. package/scripts/smoke-omp-fresh-live.ts +12 -3
  114. package/scripts/smoke-omp-receive-live.ts +7 -1
  115. package/scripts/smoke-pi-durable-fresh-live.ts +12 -2
  116. package/team.json.example +39 -0
@@ -0,0 +1,341 @@
1
+ /**
2
+ * check-claude-launch — deterministic gate for the Claude Code launch (`entwurf claude`, #157 stage 4).
3
+ * Hermetic: no real Claude Code, no network, no model turn, no write outside its own temp root. Linux
4
+ * only: the fake vendor reads its own environment from /proc/$$/environ (it runs in the Linux check job).
5
+ *
6
+ * SAME ORACLE AS check-pi-launch and check-copilot-launch: the subject is a process REPLACEMENT, so
7
+ * the truth is a FAKE VENDOR — a real executable named `claude` on a sandbox PATH that reports the
8
+ * argv, cwd, environment and pid it was actually handed. Nothing below is asserted by reading the
9
+ * launcher's source, and the launcher is driven through its PUBLIC address (`run.sh claude`),
10
+ * because the dispatcher's own argv handling — the help preflight included — is part of the contract.
11
+ *
12
+ * WHAT THE LAUNCH PROMISES, AND WHAT IT DOES NOT. It is a spelling: the vendor's argv, cwd, exit
13
+ * status and signal are Claude Code's own, and `--help` is Claude Code's help, not an Entwurf page.
14
+ * It adds nothing to the argv. Its only environment changes are the recursion sentinel and the
15
+ * REMOVAL of an inherited PI_SESSION_ID/PI_AGENT_ID pair, which is another citizen's identity. It
16
+ * does not promise a garden citizen: that comes from the meta-bridge plugin and hooks `setup`
17
+ * installed, which this launch neither checks nor supplies, so nothing here models them.
18
+ *
19
+ * WHY TWO RECURSION FENCES WHEN PI HAS ONE. pi's single fence rests on the flag it injects: a PATH
20
+ * `pi` symlinked to run.sh re-enters as the unknown verb `--entwurf-control`. This launch injects
21
+ * nothing, so the same symlink would re-enter with the operator's argv as the VERB. The resolved-path
22
+ * fence refuses that, and the cell measuring it hands the loop an EMPTY argv on purpose: with the
23
+ * fence mutated away, the re-entry prints the root page and exits 0 instead of running any verb.
24
+ *
25
+ * TWO CELLS CARRY NO MUTANT, and the reason is measured coupling rather than a gap. run.sh is
26
+ * `set -euo pipefail`, so dropping `exec` still propagates a non-zero vendor status (set -e exits
27
+ * with it) and turns a vendor death by signal into a status of 128+n. The mutation that breaks the
28
+ * exit or signal claim is therefore the one that breaks the pid claim, and the pid cell is asserted
29
+ * first so that mutant lands on exactly one QK. The exit and signal cells stand on their assertions.
30
+ */
31
+
32
+ import assert from "node:assert/strict";
33
+ import { spawnSync } from "node:child_process";
34
+ import {
35
+ chmodSync,
36
+ existsSync,
37
+ mkdirSync,
38
+ mkdtempSync,
39
+ readFileSync,
40
+ realpathSync,
41
+ rmSync,
42
+ symlinkSync,
43
+ writeFileSync,
44
+ } from "node:fs";
45
+ import { tmpdir } from "node:os";
46
+ import * as path from "node:path";
47
+ import { fileURLToPath } from "node:url";
48
+
49
+ const REPO = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
50
+ const RUN_SH = path.join(REPO, "run.sh");
51
+ const SENTINEL = "ENTWURF_CLAUDE_LAUNCH_ACTIVE";
52
+ /** The variables bash itself maintains across a script and an exec — not the launcher's choice. */
53
+ const BASH_OWNED = new Set(["SHLVL", "_", "PWD", "OLDPWD"]);
54
+
55
+ let passed = 0;
56
+ function ok(label: string, cond: boolean, detail = ""): void {
57
+ assert.ok(cond, detail ? `${label}\n${detail}` : label);
58
+ console.log(` ok ${label}`);
59
+ passed++;
60
+ }
61
+
62
+ const root = mkdtempSync(path.join(tmpdir(), "entwurf-claude-launch."));
63
+ try {
64
+ const bin = path.join(root, "bin");
65
+ const work = path.join(root, "work");
66
+ mkdirSync(bin, { recursive: true });
67
+ mkdirSync(work, { recursive: true });
68
+ const envDump = path.join(root, "vendor.environ");
69
+
70
+ // The fake vendor, installed under the REAL name `claude`. It reports what exec handed it: its
71
+ // own initial environment is read from the kernel (/proc/$$/environ), not from its shell's view,
72
+ // so bash's own bookkeeping inside the fake is not mistaken for the launcher's.
73
+ const vendor = path.join(bin, "claude");
74
+ writeFileSync(
75
+ vendor,
76
+ `#!/usr/bin/env bash
77
+ echo "PID=$$"
78
+ echo "CWD=$(pwd -P)"
79
+ echo "SENTINEL=[\${${SENTINEL}-<unset>}]"
80
+ cat "/proc/$$/environ" >"$FAKE_CLAUDE_ENV_OUT"
81
+ for a in "$@"; do printf 'ARG<%s>\\n' "$a"; done
82
+ if [ -n "\${FAKE_CLAUDE_SIGNAL:-}" ]; then kill -s "$FAKE_CLAUDE_SIGNAL" "$$"; sleep 5; fi
83
+ exit "\${FAKE_CLAUDE_EXIT:-0}"
84
+ `,
85
+ );
86
+ chmodSync(vendor, 0o755);
87
+
88
+ // TOTAL sandbox, as the sibling launch gates: the launcher writes nothing, but it EXECS a vendor.
89
+ const sandboxEnv = {
90
+ HOME: path.join(root, "home"),
91
+ XDG_DATA_HOME: path.join(root, "xdg", "data"),
92
+ XDG_CONFIG_HOME: path.join(root, "xdg", "config"),
93
+ XDG_STATE_HOME: path.join(root, "xdg", "state"),
94
+ XDG_CACHE_HOME: path.join(root, "xdg", "cache"),
95
+ XDG_RUNTIME_DIR: path.join(root, "xdg", "runtime"),
96
+ PI_CODING_AGENT_DIR: path.join(root, "pi-agent"),
97
+ CLAUDE_CONFIG_DIR: path.join(root, "claude-config"),
98
+ };
99
+ for (const d of Object.values(sandboxEnv)) mkdirSync(d, { recursive: true });
100
+
101
+ // A PATH with no `claude` anywhere on it: every real entry that holds one is dropped, rather than
102
+ // emptying PATH (the launcher still needs bash, dirname and readlink).
103
+ const pathWithoutVendor = (process.env.PATH ?? "")
104
+ .split(":")
105
+ .filter((d) => d !== "" && !existsSync(path.join(d, "claude")))
106
+ .join(":");
107
+
108
+ /**
109
+ * Every bash this gate starts gets a NON-SOCKET stdin. Node's default stdin is a socketpair, and
110
+ * bash reads `-c` with a socket on stdin as a remote shell and sources the system bashrc — measured
111
+ * here on NixOS, where that re-runs set-environment and resets PATH, dropping the sandbox bin
112
+ * (S4CLI-F01-BASHC-REMOTE-SHELL-R1). The sibling gates never see it because they pass the
113
+ * operator's whole environment; this one builds its environment from scratch to compare it.
114
+ */
115
+ const STDIO: ["ignore", "pipe", "pipe"] = ["ignore", "pipe", "pipe"];
116
+
117
+ /** The caller's whole environment, built explicitly so the vendor's can be compared to it. */
118
+ function callerEnv(pathValue: string, extra: Record<string, string> = {}): Record<string, string> {
119
+ return { ...sandboxEnv, PATH: pathValue, LANG: "C.UTF-8", FAKE_CLAUDE_ENV_OUT: envDump, ...extra };
120
+ }
121
+
122
+ interface Run {
123
+ status: number | null;
124
+ signal: NodeJS.Signals | null;
125
+ out: string;
126
+ args: string[];
127
+ sentinel: string;
128
+ pid: string;
129
+ cwd: string;
130
+ env: Map<string, string> | null;
131
+ }
132
+ function launch(args: string[], env: Record<string, string>, cwd = work): Run {
133
+ rmSync(envDump, { force: true });
134
+ const r = spawnSync("bash", [RUN_SH, "claude", ...args], {
135
+ cwd,
136
+ encoding: "utf8",
137
+ env,
138
+ timeout: 30_000,
139
+ stdio: STDIO,
140
+ });
141
+ const out = `${r.stdout ?? ""}${r.stderr ?? ""}`;
142
+ const argv: string[] = [];
143
+ for (const line of out.split("\n")) {
144
+ const m = /^ARG<([\s\S]*)>$/.exec(line);
145
+ if (m) argv.push(m[1] as string);
146
+ }
147
+ let vendorEnv: Map<string, string> | null = null;
148
+ if (existsSync(envDump)) {
149
+ vendorEnv = new Map();
150
+ for (const entry of readFileSync(envDump, "utf8").split("\0")) {
151
+ if (entry === "") continue;
152
+ const eq = entry.indexOf("=");
153
+ vendorEnv.set(entry.slice(0, eq), entry.slice(eq + 1));
154
+ }
155
+ }
156
+ return {
157
+ status: r.status,
158
+ signal: r.signal,
159
+ out,
160
+ args: argv,
161
+ sentinel: /^SENTINEL=\[(.*)\]$/m.exec(out)?.[1] ?? "<no-launch>",
162
+ pid: /^PID=(.*)$/m.exec(out)?.[1] ?? "",
163
+ cwd: /^CWD=(.*)$/m.exec(out)?.[1] ?? "",
164
+ env: vendorEnv,
165
+ };
166
+ }
167
+ const withVendor = `${bin}:${pathWithoutVendor}`;
168
+
169
+ // ── 1. the dispatcher verb must not reach the vendor ────────────────────────
170
+ {
171
+ const r = launch(["--model", "x"], callerEnv(withVendor));
172
+ ok(
173
+ "[QK:CLAUDELAUNCH-VERB-DROPPED] the dispatcher verb never reaches the vendor — without the shift, `claude` arrives as a prompt argument",
174
+ r.status === 0 && r.pid !== "" && !r.args.includes("claude"),
175
+ `status=${r.status} argv=${JSON.stringify(r.args)}\n${r.out}`,
176
+ );
177
+ }
178
+
179
+ // ── 2. operator argv crosses byte-identical, and nothing is added to it ─────
180
+ {
181
+ const operator = ["--model", "a b", "", "-", "--", "한글 인자", " spaced ", "--help"];
182
+ const r = launch(operator, callerEnv(withVendor));
183
+ ok(
184
+ "[QK:CLAUDELAUNCH-ARGV-UNTOUCHED] the vendor's argv IS the operator's, element for element — empty strings, spaces, a bare dash, the terminator, non-ASCII and a trailing --help — with nothing injected",
185
+ r.status === 0 && JSON.stringify(r.args) === JSON.stringify(operator),
186
+ `expected: ${JSON.stringify(operator)}\nactual: ${JSON.stringify(r.args)}`,
187
+ );
188
+ }
189
+
190
+ // ── 3. the vendor's own help, never an Entwurf page in its place ───────────
191
+ {
192
+ const bad = (["--help", "-h"] as const).flatMap((flag) => {
193
+ const r = launch([flag], callerEnv(withVendor));
194
+ return r.status === 0 && r.pid !== "" && JSON.stringify(r.args) === JSON.stringify([flag])
195
+ ? []
196
+ : [`${flag}: status=${r.status} argv=${JSON.stringify(r.args)} out=${JSON.stringify(r.out.slice(0, 160))}`];
197
+ });
198
+ ok(
199
+ "[QK:CLAUDELAUNCH-VENDOR-HELP] `entwurf claude --help` and `-h` reach Claude Code itself — the help preflight lets this verb through instead of answering with the command's description",
200
+ bad.length === 0,
201
+ bad.join("\n"),
202
+ );
203
+ }
204
+
205
+ // ── 4. the caller's directory is the vendor's ───────────────────────────────
206
+ {
207
+ const r = launch([], callerEnv(withVendor));
208
+ ok(
209
+ "[QK:CLAUDELAUNCH-CWD-KEPT] the vendor starts in the caller's directory, not the package's — Claude Code keys its project and session to that directory",
210
+ r.status === 0 && r.cwd === realpathSync(work),
211
+ `expected=${realpathSync(work)} actual=${r.cwd}`,
212
+ );
213
+ }
214
+
215
+ // ── 5–7. the environment: a sentinel added, a foreign identity removed, nothing else ──
216
+ {
217
+ const caller = callerEnv(withVendor, { PI_SESSION_ID: "foreign-garden", PI_AGENT_ID: "pi-agent-fixture" });
218
+ const r = launch([], caller);
219
+ ok(
220
+ "[QK:CLAUDELAUNCH-SENTINEL-EXPORTED] the sentinel is EXPORTED, so a PATH `claude` that shells back to `entwurf claude` sees it on re-entry",
221
+ r.sentinel === "1",
222
+ `sentinel=${r.sentinel}`,
223
+ );
224
+ ok(
225
+ "[QK:CLAUDELAUNCH-CARRIERS-SCRUBBED] an inherited PI_SESSION_ID/PI_AGENT_ID pair is another citizen's identity and BOTH are gone from the vendor's environment — absent, not emptied",
226
+ r.env !== null && !r.env.has("PI_SESSION_ID") && !r.env.has("PI_AGENT_ID"),
227
+ `vendor env keys: ${JSON.stringify(r.env === null ? null : [...r.env.keys()].filter((k) => k.startsWith("PI_")))}`,
228
+ );
229
+ const expected = new Map(Object.entries(caller));
230
+ expected.delete("PI_SESSION_ID");
231
+ expected.delete("PI_AGENT_ID");
232
+ expected.set(SENTINEL, "1");
233
+ const diff: string[] = [];
234
+ const actual = r.env ?? new Map<string, string>();
235
+ for (const [k, v] of expected)
236
+ if (actual.get(k) !== v) diff.push(`expected ${k}=${JSON.stringify(v)}, got ${JSON.stringify(actual.get(k))}`);
237
+ for (const [k, v] of actual)
238
+ if (!expected.has(k) && !BASH_OWNED.has(k)) diff.push(`added ${k}=${JSON.stringify(v)}`);
239
+ ok(
240
+ `[QK:CLAUDELAUNCH-ENV-EXACT] beyond those two changes the vendor's environment IS the caller's (${expected.size} variables; ${[...BASH_OWNED].join(", ")} are bash's own) — no auth, model, permission or settings variable is decided here`,
241
+ r.env !== null && diff.length === 0,
242
+ diff.join("\n"),
243
+ );
244
+ }
245
+
246
+ // ── 8. the vendor's exit status is this command's exit status (no mutant: see header) ──
247
+ {
248
+ const r = launch([], callerEnv(withVendor, { FAKE_CLAUDE_EXIT: "7" }));
249
+ ok(
250
+ "[QK:CLAUDELAUNCH-EXIT-PASSTHROUGH] the vendor's exit status is the launch's exit status",
251
+ r.status === 7,
252
+ `status=${r.status}`,
253
+ );
254
+ }
255
+
256
+ // ── 9. exec, not fork: the pid survives ─────────────────────────────────────
257
+ {
258
+ const r = spawnSync("bash", ["-c", `echo "SHELL_PID=$$"; exec bash "${RUN_SH}" claude`], {
259
+ cwd: work,
260
+ encoding: "utf8",
261
+ env: callerEnv(withVendor),
262
+ timeout: 30_000,
263
+ stdio: STDIO,
264
+ });
265
+ const shellPid = /^SHELL_PID=(\d+)$/m.exec(r.stdout ?? "")?.[1];
266
+ const vendorPid = /^PID=(\d+)$/m.exec(r.stdout ?? "")?.[1];
267
+ ok(
268
+ "[QK:CLAUDELAUNCH-EXEC-KEEPS-PID] the vendor REPLACES this process — a fork would leave run.sh as a parent that owns nothing, between Claude Code and the terminal",
269
+ Boolean(shellPid) && shellPid === vendorPid,
270
+ `shell=${shellPid} vendor=${vendorPid}`,
271
+ );
272
+ }
273
+
274
+ // ── 10. a vendor death by signal is the caller's to see (no mutant: see header) ──
275
+ {
276
+ const r = launch([], callerEnv(withVendor, { FAKE_CLAUDE_SIGNAL: "TERM" }));
277
+ ok(
278
+ "[QK:CLAUDELAUNCH-SIGNAL-PASSTHROUGH] a vendor killed by a signal is reported as that signal, not as a shell's 128+n status",
279
+ r.status === null && r.signal === "SIGTERM",
280
+ `status=${r.status} signal=${r.signal}`,
281
+ );
282
+ }
283
+
284
+ // ── 11. an absent vendor is a NAMED refusal, never a quiet success ──────────
285
+ {
286
+ const r = launch([], callerEnv(pathWithoutVendor));
287
+ ok(
288
+ "[QK:CLAUDELAUNCH-VENDOR-ABSENT] with no `claude` on PATH the launch refuses by name and non-zero, and runs nothing",
289
+ r.status === 1 && r.out.includes("no 'claude' executable found on PATH") && r.pid === "",
290
+ `status=${r.status}\n${r.out}`,
291
+ );
292
+ }
293
+
294
+ // ── 12. a PATH hit that is not a regular file is refused before exec ────────
295
+ {
296
+ const fifoBin = path.join(root, "fifobin");
297
+ mkdirSync(fifoBin, { recursive: true });
298
+ const made = spawnSync("mkfifo", [path.join(fifoBin, "claude")], { encoding: "utf8" });
299
+ assert.equal(made.status, 0, `mkfifo failed: ${made.stderr}`);
300
+ chmodSync(path.join(fifoBin, "claude"), 0o755);
301
+ const r = launch([], callerEnv(`${fifoBin}:${pathWithoutVendor}`));
302
+ ok(
303
+ "[QK:CLAUDELAUNCH-NOT-REGULAR] an executable PATH `claude` that is not a regular file (a FIFO) is refused by name, not handed to exec",
304
+ r.status === 1 && r.out.includes("is not an executable regular file") && r.pid === "",
305
+ `status=${r.status}\n${r.out}`,
306
+ );
307
+ }
308
+
309
+ // ── 13. the sentinel fence ──────────────────────────────────────────────────
310
+ {
311
+ const r = launch([], callerEnv(withVendor, { [SENTINEL]: "1" }));
312
+ ok(
313
+ "[QK:CLAUDELAUNCH-RECURSION-FENCE] a re-entered launch refuses by name instead of spinning behind a hung terminal",
314
+ r.status === 1 && r.out.includes("recursive managed launch detected") && r.pid === "",
315
+ `status=${r.status}\n${r.out}`,
316
+ );
317
+ }
318
+
319
+ // ── 14. the resolved-path fence: a PATH `claude` that IS run.sh ─────────────
320
+ {
321
+ // Two hops, the first relative, so the walk itself is exercised: loop/claude -> ../hop/claude
322
+ // -> run.sh. The argv is EMPTY on purpose (see header): without this fence the re-entry would
323
+ // print the root page and exit 0, never run a verb.
324
+ const loopBin = path.join(root, "loop");
325
+ const hop = path.join(root, "hop");
326
+ mkdirSync(loopBin, { recursive: true });
327
+ mkdirSync(hop, { recursive: true });
328
+ symlinkSync(RUN_SH, path.join(hop, "claude"));
329
+ symlinkSync(path.join("..", "hop", "claude"), path.join(loopBin, "claude"));
330
+ const r = launch([], callerEnv(`${loopBin}:${pathWithoutVendor}`));
331
+ ok(
332
+ "[QK:CLAUDELAUNCH-SELF-EXEC-FENCE] a PATH `claude` that resolves through symlinks to this run.sh is refused by name — with nothing injected, re-entry would make the operator's argv an entwurf verb",
333
+ r.status === 1 && r.out.includes(`resolves to entwurf's own '${realpathSync(RUN_SH)}'`) && r.pid === "",
334
+ `status=${r.status}\n${r.out.slice(0, 400)}`,
335
+ );
336
+ }
337
+
338
+ console.log(`\ncheck-claude-launch: ${passed} checks passed`);
339
+ } finally {
340
+ rmSync(root, { recursive: true, force: true });
341
+ }
@@ -25,7 +25,7 @@
25
25
  * - R5: taxonomy covers the table reasons + pre-claims bad-target /
26
26
  * target-locked (so bucket B F2 won't reopen it), and
27
27
  * is PRE-DISPATCH only (no send-fail-fallback member).
28
- * - schema ↔ types drift guard: the TypeBox input/receipt property keysets and
28
+ * - schema ↔ types drift guard: the pi-schema input/receipt property keysets and
29
29
  * the StringEnum members match the hand-written contract constants.
30
30
  */
31
31
 
@@ -82,7 +82,7 @@ function eq(label: string, actual: unknown, expected: unknown): void {
82
82
  }
83
83
 
84
84
  // Pull the literal members out of a StringEnum / Optional(StringEnum) schema,
85
- // whichever shape typebox emits — so the schema↔const drift guard is real.
85
+ // whichever shape the schema builder emits — so the schema↔const drift guard is real.
86
86
  function enumValues(schema: unknown): string[] {
87
87
  const s = schema as { enum?: unknown[]; anyOf?: { const?: unknown }[] };
88
88
  if (Array.isArray(s?.enum)) return s.enum.map(String);
@@ -626,8 +626,8 @@ ok(
626
626
  !("action" in rej) && !("transport" in rej) && !("ownership" in rej),
627
627
  );
628
628
  eq("receipt.reject.reason enum === ENTWURF_V2_REJECT_REASONS", enumValues(rej.reason), [...ENTWURF_V2_REJECT_REASONS]);
629
- // ?6: reject.observedLiveness is a required-nullable union — Type.Union([StringEnum
630
- // (FACT_LIVENESSES), Type.Null()]) — NOT Optional and NOT a bare StringEnum. The
629
+ // ?6: reject.observedLiveness is a required-nullable union — union([StringEnum
630
+ // (FACT_LIVENESSES), nul()]) — NOT Optional and NOT a bare StringEnum. The
631
631
  // key is always present (required), the value may be a 4-value liveness OR null.
632
632
  const rejLiveness = rej.observedLiveness as { anyOf?: { type?: string }[] };
633
633
  eq("?6: receipt.reject.observedLiveness is a 2-branch union (liveness | null)", rejLiveness.anyOf?.length, 2);
@@ -176,7 +176,7 @@ function assertDormantHonesty(tag: string, rawText: string): void {
176
176
  * be satisfiable by adding a per-row action/routing field, which is why it is asserted on the
177
177
  * DESCRIPTION and paired with a negative that forbids the row-level fix. What the description owes
178
178
  * a caller is that `dead` is a reported fact carrying no delivery invitation. A separately
179
- * requested, proven-dormant Pi/Claude lifecycle can reopen the same id without submitting a prompt.
179
+ * requested, proven-dormant Pi/pi-durable/Claude lifecycle can reopen the same id without submitting a prompt.
180
180
  */
181
181
  function assertPeersDeadRowHonesty(tag: string, rawBlock: string): void {
182
182
  const text = rawBlock;
@@ -187,7 +187,7 @@ function assertPeersDeadRowHonesty(tag: string, rawBlock: string): void {
187
187
  /not an invitation to dispatch/.test(text) &&
188
188
  /no entwurf_v2 delivery is available while it is dormant/.test(text) &&
189
189
  /Only on an explicit operator request, the separate entwurf_resume_call/.test(text) &&
190
- /proven-dormant Pi or Claude Code citizen under the same id, submitting no prompt/.test(text),
190
+ /proven-dormant Pi, pi-durable or Claude Code citizen under the same id, submitting no prompt/.test(text),
191
191
  );
192
192
  ok(
193
193
  `${tag} — entwurf_peers does not turn delivery dormancy into a ban on every lifecycle verb`,
@@ -18,6 +18,11 @@
18
18
  * FCD-NO-RAIL-PARAMETER no caller-facing input can choose a rail
19
19
  * FCD-NO-FALLBACK an incomplete herdr context refuses by its herdr reason
20
20
  * FCD-HERDR-BACKEND-FIRST a non-pilot backend refuses before any preflight and any mutation
21
+ * FCD-HERDR-PI-DURABLE-LAYOUT inside herdr pi-durable reaches the layout branch, which is told
22
+ * only WHETHER the caller is a Codex citizen and never falls back from
23
+ * its missing record cwd to this process's own (#157 A-L1)
24
+ * FCD-HERDR-NO-THREAD-ID the herdr branch builds its request from an explicit field list in
25
+ * which the Codex thread id appears only as that boolean (#157 A-L1 D5)
21
26
  * FCD-CODEX-PREFLIGHT-TMUX the Codex preflight still gates the tmux rail, and only that rail
22
27
  * FCD-ONE-NONCE one nonce is minted per call and reaches the selected rail
23
28
  * FCD-SURFACE-ROOT-ONLY the one public surface (the bridge; pi reaches it through Pi's
@@ -28,6 +33,8 @@
28
33
  * FCD-RECOVERY-VISIBLE a post-split failure shows closed vs orphan-unreclaimed:reason
29
34
  * FCD-ACP-MODEL-EXACT a pi `entwurf/<id>` that is not an exact curated ACP id refuses on
30
35
  * either rail before anything runs (#128)
36
+ * FCD-RESUME-RAIL-SHARED a same-id visible resume reaches the same exact rail choice through
37
+ * its own entry point, with no fallback in either direction (#157 G1a)
31
38
  */
32
39
 
33
40
  import assert from "node:assert/strict";
@@ -36,6 +43,7 @@ import * as path from "node:path";
36
43
  import { fileURLToPath } from "node:url";
37
44
  import {
38
45
  dispatchFreshCall,
46
+ dispatchResumeLaunch,
39
47
  renderDispatchedFreshCall,
40
48
  selectFreshCallRail,
41
49
  } from "../pi-extensions/lib/fresh-call-dispatch.ts";
@@ -180,25 +188,45 @@ async function main(): Promise<void> {
180
188
  !herdrBranch.includes("codexCallerFreshPreflight"),
181
189
  );
182
190
 
183
- // #129: pi-durable joined the tmux fresh set, NOT the herdr pilot set (GLG, 2026-10-06: no herdr
184
- // pi-durable support in 0.31). Same axis as the codex cell: refused by the herdr reason, nothing
185
- // spawned, no tmux fallback, and its installed-carrier preflight is never asked on this branch.
191
+ // #157 A-L1 (main 0a6f9b relaying GLG's #157 grant; supersedes the #129 "not in herdr" cell):
192
+ // inside herdr pi-durable reaches the herdr LAYOUT branch, which never runs the herdr CLI. The
193
+ // root hands that branch one boolean — the caller IS a record-backed Codex citizen — and the
194
+ // branch, not this root, owns the pi-durable preflight. Both calls below are refused before any
195
+ // socket is opened (this env names none), so nothing here can reach a herdr server.
186
196
  const durable = recordingSpawn();
187
- const durableRefused = await dispatchFreshCall(
188
- { ...REQUEST, backend: "pi-durable", model: "loopback/scripted" },
197
+ const durableRequest = { ...REQUEST, backend: "pi-durable", model: "loopback/scripted" };
198
+ const durablePlain = await dispatchFreshCall(durableRequest, HERDR_ENV, durable.spawn);
199
+ const durableCodexCaller = await dispatchFreshCall(
200
+ { ...durableRequest, callerNativeSessionId: "019a0000-0000-7000-8000-000000000000" },
189
201
  HERDR_ENV,
190
202
  durable.spawn,
191
203
  );
192
204
  ok(
193
- "[QK:FCD-HERDR-PI-DURABLE-UNSUPPORTED] inside herdr pi-durable is not a pilot backend: it refuses by the herdr reason with nothing spawned, never falls back to a tmux window, and its runtime preflight is never consulted there",
194
- durableRefused.rail === "herdr" &&
195
- !durableRefused.result.ok &&
196
- durableRefused.result.reason === "herdr-backend-unsupported" &&
205
+ "[QK:FCD-HERDR-PI-DURABLE-LAYOUT] inside herdr pi-durable is no longer refused as unsupported: with the caller's own process cwd it reaches the layout branch's socket-path refusal, while a known Codex caller with no record cwd is refused as codex-caller-cwd-unavailable instead of falling back to this process's cwd — the root passes Codex-ness as a boolean, nothing spawns the herdr CLI, no tmux fallback, and the root's herdr branch names no pi-durable preflight",
206
+ durablePlain.rail === "herdr" &&
207
+ !durablePlain.result.ok &&
208
+ durablePlain.result.reason === "herdr-socket-path-missing" &&
209
+ durableCodexCaller.rail === "herdr" &&
210
+ !durableCodexCaller.result.ok &&
211
+ durableCodexCaller.result.reason === "codex-caller-cwd-unavailable" &&
197
212
  durable.calls.length === 0 &&
198
213
  herdrBranchLocated &&
199
214
  !herdrBranch.includes("piDurable"),
200
215
  );
201
216
 
217
+ // #157 A-L1 D5: the Codex thread id is a tmux seat input and STOPS at this root. The herdr branch
218
+ // therefore spells its request field by field — a spread of the whole request would carry the id
219
+ // along even if no herdr code read it today — and names the id once, inside the boolean.
220
+ const threadIdMentions = herdrBranch.split("callerNativeSessionId").length - 1;
221
+ ok(
222
+ "[QK:FCD-HERDR-NO-THREAD-ID] the herdr branch hands its rail an explicit field list, not a spread of the request, and the Codex thread id appears in it exactly once — as `callerIsCodex: request.callerNativeSessionId !== undefined` — so only a boolean and the record cwd cross to herdr while the tmux request stays whole",
223
+ herdrBranchLocated &&
224
+ !/\.\.\.request\b/.test(herdrBranch) &&
225
+ threadIdMentions === 1 &&
226
+ herdrBranch.includes("callerIsCodex: request.callerNativeSessionId !== undefined,") &&
227
+ herdrBranch.includes("callerCwd: request.callerCwd"),
228
+ );
229
+
202
230
  // ── the tmux rail keeps its pre-existing ordering ────────────────────────────────────
203
231
  // The import line names the preflight too, so the body is what gets counted: the claim is
204
232
  // "called once, on one path", not "the word appears once".
@@ -292,6 +320,8 @@ async function main(): Promise<void> {
292
320
  backend: "pi",
293
321
  requestedKind: "pi",
294
322
  model: "m/1",
323
+ cwd: "/repo/dir",
324
+ cwdSource: "caller-process",
295
325
  herdrAgentName: "entwurf-abc",
296
326
  herdrWorkspaceId: "w7",
297
327
  herdrTabId: "w7:t3",
@@ -354,6 +384,37 @@ async function main(): Promise<void> {
354
384
  !unknown.text.includes("orphan-unreclaimed"),
355
385
  );
356
386
 
387
+ // ── #157 G1a: a visible resume reaches the SAME rail choice ──────────────────────────
388
+ // The root's second entry point owns only the rail choice for a same-id visible resume. Its tmux
389
+ // half is whatever the surface hands in, so a recording stub stands for it; its herdr half is the
390
+ // real herdr resume launch, driven with an incomplete herdr context so it refuses before any
391
+ // runner exists. No existing cell exercises this entry point: a resume entry that read the marker
392
+ // loosely, or fell back to the surface's tmux mapping, would leave every cell above green.
393
+ {
394
+ const RESUME_INPUT = { backend: "pi", cwd: "/x/project", runtimeArgs: ["--session", "/x/s.jsonl"] } as const;
395
+ const tmuxCalls: unknown[] = [];
396
+ const tmuxLaunch = (input: typeof RESUME_INPUT) => {
397
+ tmuxCalls.push(input);
398
+ return { ok: false as const, reason: "tmux-stub" };
399
+ };
400
+ const resumeSpawn = recordingSpawn();
401
+ const inHerdr = await dispatchResumeLaunch(RESUME_INPUT, tmuxLaunch, { HERDR_ENV: "1" }, resumeSpawn.spawn);
402
+ const tmuxCallsInHerdr = tmuxCalls.length;
403
+ const elsewhere = [{ HERDR_ENV: "0" }, { HERDR_ENV: "true" }, { HERDR_ENV: "" }, { HERDR_ENV: " 1" }, {}].map(
404
+ (env) => dispatchResumeLaunch(RESUME_INPUT, tmuxLaunch, env, resumeSpawn.spawn),
405
+ );
406
+ ok(
407
+ "[QK:FCD-RESUME-RAIL-SHARED] a same-id visible resume reaches the SAME rail choice fresh call does, through its own entry point: exactly `HERDR_ENV=1` goes to the herdr resume launch and, with that herdr context incomplete, refuses by the herdr reason without ever calling the surface's tmux mapping; every other value, and an absent variable, goes to that tmux mapping with the record-derived input unchanged — a second, looser predicate or a fallback either way would reopen a citizen where the operator is not looking",
408
+ !inHerdr.ok &&
409
+ inHerdr.reason === "herdr-context-missing" &&
410
+ tmuxCallsInHerdr === 0 &&
411
+ resumeSpawn.calls.length === 0 &&
412
+ elsewhere.every((r) => !("then" in r) && r.reason === "tmux-stub") &&
413
+ tmuxCalls.length === elsewhere.length &&
414
+ tmuxCalls.every((input) => input === RESUME_INPUT),
415
+ );
416
+ }
417
+
357
418
  console.log(`\n[check-fresh-call-dispatch] ${passed} assertions ok`);
358
419
  }
359
420
 
@@ -63,6 +63,7 @@ export HOME="$SANDBOX/home"
63
63
  export XDG_DATA_HOME="$SANDBOX/home/.local/share"
64
64
  export XDG_STATE_HOME="$SANDBOX/home/.local/state"
65
65
  export XDG_CACHE_HOME="$SANDBOX/home/.cache"
66
+ export XDG_CONFIG_HOME="$SANDBOX/home/.config"
66
67
  export PI_CODING_AGENT_DIR="$SANDBOX/home/.pi/agent"
67
68
  export ENTWURF_META_SESSIONS_DIR="$SANDBOX/store"
68
69
  export ENTWURF_META_MAILBOX_DIR="$SANDBOX/mailbox"
@@ -1460,6 +1461,11 @@ fake_pkg="$SANDBOX/nm/node_modules/@junghanacs/entwurf"
1460
1461
  mkdir -p "$fake_pkg/scripts"
1461
1462
  cp "$REPO/run.sh" "$fake_pkg/run.sh"
1462
1463
  cp "$REPO/scripts/meta-bridge-store-doctor.ts" "$fake_pkg/scripts/"
1464
+ # Sourcing run.sh with no argv still walks its dispatch to the root usage, which renders
1465
+ # ENTWURF-CLI.json through scripts/cli-help.mjs (#153). Without those two files that render fails
1466
+ # first, under run.sh's own errexit, and the doctor branch below is never reached.
1467
+ cp "$REPO/ENTWURF-CLI.json" "$fake_pkg/ENTWURF-CLI.json"
1468
+ cp "$REPO/scripts/cli-help.mjs" "$fake_pkg/scripts/"
1463
1469
  set +e
1464
1470
  out="$(RUNSH="$fake_pkg/run.sh" bash -c 'set --; source "$RUNSH" >/dev/null; preflight_v3_store install' 2>&1)"; rc=$?
1465
1471
  set -e
@@ -1485,19 +1491,27 @@ rm -rf "$SANDBOX/nm"
1485
1491
  # names — the point is not that failures are nonzero, it is that a caller can BRANCH.
1486
1492
  echo "[check-fresh-cut-gate] J. exit contract"
1487
1493
 
1488
- # J1/J2 — the two states that need no host at all.
1494
+ # J1/J2 — the two states that need no host at all. Streams are kept apart: the leaf's own
1495
+ # usage line is now only the address of the description (#153), and the contract text itself —
1496
+ # exit numbers included — is the public page `entwurf meta-bridge-fresh-cut --help` prints, which
1497
+ # check-install-surface S9u holds against this verb's ce92dc7 text and FRESH_CUT_EXIT.
1498
+ fc_pointer='meta-bridge-fresh-cut: see `entwurf help meta-bridge-fresh-cut` (from that checkout'"'"'s root: `./run.sh help meta-bridge-fresh-cut`)'
1489
1499
  set +e
1490
- help_out="$(node --experimental-strip-types "${FRESH_CUT[@]}" --help 2>&1)"; rc=$?
1500
+ node --experimental-strip-types "${FRESH_CUT[@]}" --help >"$SANDBOX/j1.out" 2>"$SANDBOX/j1.err"; rc=$?
1491
1501
  set -e
1492
- if [ "$rc" = 0 ]; then ok "J1 --help exits 0"; else bad "J1 --help exited $rc" "$help_out"; fi
1493
- case "$help_out" in
1494
- *"EXIT CONTRACT"*) ok "J1b --help PRINTS the contract (an operator can read it where they hit it)" ;;
1495
- *) bad "J1b --help never printed the exit contract" "$help_out" ;;
1496
- esac
1502
+ if [ "$rc" = 0 ]; then ok "J1 --help exits 0"; else bad "J1 --help exited $rc" "$(cat "$SANDBOX/j1.err")"; fi
1497
1503
  set +e
1498
- bad_out="$(node --experimental-strip-types "${FRESH_CUT[@]}" --wat 2>&1)"; rc=$?
1504
+ node --experimental-strip-types "${FRESH_CUT[@]}" --wat >"$SANDBOX/j2.out" 2>"$SANDBOX/j2.err"; rc2=$?
1499
1505
  set -e
1500
- if [ "$rc" = 2 ]; then ok "J2 an unknown argument is USAGE (exit 2), never a store verdict"; else bad "J2 unknown arg exited $rc, want 2" "$bad_out"; fi
1506
+ if [ "$rc2" = 2 ]; then ok "J2 an unknown argument is USAGE (exit 2), never a store verdict"; else bad "J2 unknown arg exited $rc2, want 2" "$(cat "$SANDBOX/j2.err")"; fi
1507
+ if [ "$rc" = 0 ] && [ "$rc2" = 2 ] && [ ! -s "$SANDBOX/j1.out" ] && [ ! -s "$SANDBOX/j2.out" ] \
1508
+ && [ "$(cat "$SANDBOX/j1.err")" = "$fc_pointer" ] && [ "$(wc -l <"$SANDBOX/j1.err")" = 1 ] \
1509
+ && cmp -s "$SANDBOX/j1.err" "$SANDBOX/j2.err"; then
1510
+ ok "J1b --help (exit 0) and an unknown argument (exit 2) print nothing on stdout and one stderr line pointing at \`entwurf help meta-bridge-fresh-cut\`"
1511
+ else
1512
+ bad "[QK:FRESHCUT-HELP-POINTER] J1b the leaf's usage is not exactly the one pointer line on stderr with an empty stdout" \
1513
+ "help rc=$rc stdout=$(head -c 200 "$SANDBOX/j1.out") stderr=$(head -c 400 "$SANDBOX/j1.err") | wat rc=$rc2 stdout=$(head -c 200 "$SANDBOX/j2.out") stderr=$(head -c 400 "$SANDBOX/j2.err")"
1514
+ fi
1501
1515
 
1502
1516
  # J3 — the success state, distinct from every failure below.
1503
1517
  reset_world prevgen
@@ -3467,30 +3467,35 @@ let manifestCount: number;
3467
3467
  "compaction-send-guard": 7,
3468
3468
  "control-socket-disconnect": 4,
3469
3469
  "demo-reproducibility": 12,
3470
+ "dev-gate-dispatch": 9,
3471
+ "cli-help-source": 36,
3472
+ "claude-launch": 12,
3470
3473
  "copilot-birth": 19,
3471
3474
  "copilot-launch": 14,
3472
3475
  "pi-launch": 9,
3473
- "pi-floor": 3,
3476
+ "pi-floor": 4,
3474
3477
  "pi-bridge-sender": 4,
3475
3478
  "pi-mcp-bridge": 2,
3476
3479
  "pi-mcp-register": 3,
3477
- "pi-durable": 95,
3480
+ "pi-durable": 186,
3478
3481
  "copilot-receive": 20,
3479
3482
  "entwurf-peers": 1,
3480
- "fresh-call-dispatch": 15,
3481
- "fresh-cut": 3,
3483
+ "fresh-call-dispatch": 18,
3484
+ "fresh-cut": 4,
3482
3485
  "gate-qualification": 10,
3483
3486
  "herdr-placement": 13,
3484
- "herdr-plugin": 25,
3487
+ "herdr-plugin": 26,
3485
3488
  "herdr-plugin-profile": 14,
3486
- "herdr-activation": 34,
3487
- "herdr-plugin-build": 20,
3489
+ "herdr-activation": 42,
3490
+ "herdr-plugin-build": 25,
3488
3491
  "herdr-dev-checkout": 4,
3489
- "herdr-runtime-bootstrap": 31,
3490
- "herdr-fresh-call": 38,
3492
+ "herdr-operator-link": 19,
3493
+ "herdr-runtime-bootstrap": 35,
3494
+ "herdr-fresh-call": 61,
3495
+ "herdr-resume-call": 24,
3491
3496
  "herdr-supply": 11,
3492
- "meta-facts": 4,
3493
- "peer-facts": 8,
3497
+ "meta-facts": 5,
3498
+ "peer-facts": 9,
3494
3499
  "meta-hook-session-switch": 25,
3495
3500
  "meta-identity": 9,
3496
3501
  "meta-retire": 4,
@@ -3501,7 +3506,7 @@ let manifestCount: number;
3501
3506
  "pack-install": 9,
3502
3507
  "pi-package-ownership": 8,
3503
3508
  "qualification-ledger": 42,
3504
- "mux-resume-call": 15,
3509
+ "mux-resume-call": 20,
3505
3510
  "omp-birth": 13,
3506
3511
  "omp-fresh": 25,
3507
3512
  "omp-receive": 11,
@@ -3518,10 +3523,10 @@ let manifestCount: number;
3518
3523
  "resume-launch-identity": 10,
3519
3524
  "self-address": 8,
3520
3525
  "setup-verdict": 14,
3521
- "source-install": 8,
3526
+ "source-install": 11,
3522
3527
  "typing-call-fence": 1,
3523
3528
  "v2-surface": 16,
3524
- "v2-visible-resume": 41,
3529
+ "v2-visible-resume": 62,
3525
3530
  "win32-preview": 19,
3526
3531
  };
3527
3532
  const laneTally: Record<string, number> = {};