@junghanacs/entwurf 0.22.0 → 0.23.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.
- package/AGENTS.md +4 -1
- package/BASELINE.md +1 -0
- package/CHANGELOG.md +514 -0
- package/DELIVERY.md +10 -2
- package/README.md +43 -4
- package/VERIFY.md +47 -0
- package/docs/acp-backend-rail.md +96 -17
- package/docs/setup-clean-host.md +11 -1
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +39 -40
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +2 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/tool-surface.js +2 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/codex-declaration.js +609 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/codex-fresh-preflight.js +95 -56
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-control-rpc.js +40 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +6 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-facts.js +7 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peer-observe.js +67 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peers-render.js +9 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +24 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +2 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-lock.js +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +423 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-dispatch.js +98 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +1018 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-placement.js +213 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +46 -273
- package/mcp/entwurf-bridge/dist/scripts/peer-facts.js +109 -0
- package/mcp/entwurf-bridge/src/index.ts +41 -41
- package/mcp/entwurf-bridge/tsconfig.build.json +1 -0
- package/package.json +9 -8
- package/pi-extensions/entwurf-control.ts +91 -52
- package/pi-extensions/lib/acp/acp-client.ts +3 -3
- package/pi-extensions/lib/acp/backend-adapter.ts +3 -3
- package/pi-extensions/lib/acp/backend.ts +4 -4
- package/pi-extensions/lib/acp/event-mapper.ts +5 -5
- package/pi-extensions/lib/acp/tool-surface.ts +2 -1
- package/pi-extensions/lib/codex-declaration.js +612 -0
- package/pi-extensions/lib/codex-fresh-preflight.ts +107 -51
- package/pi-extensions/lib/entwurf-control-rpc.ts +46 -0
- package/pi-extensions/lib/entwurf-fact-provider.ts +13 -2
- package/pi-extensions/lib/entwurf-facts.ts +14 -1
- package/pi-extensions/lib/entwurf-peer-observe.ts +72 -2
- package/pi-extensions/lib/entwurf-peers-render.ts +9 -1
- package/pi-extensions/lib/entwurf-self-address.ts +33 -0
- package/pi-extensions/lib/entwurf-v2-contract.ts +2 -2
- package/pi-extensions/lib/entwurf-v2-lock.ts +1 -1
- package/pi-extensions/lib/entwurf-v2-runner.ts +1 -1
- package/pi-extensions/lib/fresh-call-composition.ts +493 -0
- package/pi-extensions/lib/fresh-call-dispatch.ts +142 -0
- package/pi-extensions/lib/herdr-fresh-call.ts +1378 -0
- package/pi-extensions/lib/herdr-placement.ts +276 -0
- package/pi-extensions/lib/mux-fresh-call.ts +95 -301
- package/run.sh +588 -204
- package/scripts/check-acp-usage-accounting.ts +9 -9
- package/scripts/check-codex-birth-hook.ts +187 -0
- package/scripts/check-entwurf-control-rpc.ts +138 -0
- package/scripts/check-entwurf-fact-provider.ts +4 -2
- package/scripts/check-entwurf-peers-surface.ts +3 -1
- package/scripts/check-entwurf-self-address.ts +68 -0
- package/scripts/check-fresh-call-dispatch.ts +301 -0
- package/scripts/check-gate-qualification.ts +17 -4
- package/scripts/check-herdr-activation.ts +1293 -0
- package/scripts/check-herdr-fresh-call.ts +1250 -0
- package/scripts/check-herdr-placement.ts +383 -0
- package/scripts/check-herdr-plugin-build.ts +842 -0
- package/scripts/check-herdr-plugin-profile.ts +371 -0
- package/scripts/check-herdr-plugin.ts +523 -0
- package/scripts/check-herdr-runtime-bootstrap.ts +1264 -0
- package/scripts/check-herdr-sandbox.ts +456 -0
- package/scripts/check-herdr-supply.ts +184 -0
- package/scripts/check-mux-launcher-fence.ts +138 -0
- package/scripts/check-peer-facts.ts +331 -0
- package/scripts/check-pi-launch.ts +358 -0
- package/scripts/check-release-gate-outcomes.ts +19 -0
- package/scripts/check-typing-call-fence.ts +296 -0
- package/scripts/codex-birth-doctor.sh +159 -16
- package/scripts/codex-birth-install.sh +178 -72
- package/scripts/codex-birth-uninstall.sh +162 -7
- package/scripts/fixtures/herdr-supply.json +29 -0
- package/scripts/herdr-activation.mjs +536 -0
- package/scripts/herdr-plugin-activate.mjs +270 -0
- package/scripts/herdr-plugin-deactivate.mjs +193 -0
- package/scripts/herdr-runtime.mjs +1203 -0
- package/scripts/install-herdr-ci.sh +96 -0
- package/scripts/inventory-verification-surface.ts +86 -10
- package/scripts/lib/codex-fresh-live-protocol.ts +2 -2
- package/scripts/lib/tree-digest.ts +97 -0
- package/scripts/meta-bridge-install.sh +19 -2
- package/scripts/meta-bridge-state.py +167 -11
- package/scripts/mutants/codex-caller-seat.json +6 -8
- package/scripts/mutants/codex-native.json +195 -29
- package/scripts/mutants/control-socket-disconnect.json +57 -0
- package/scripts/mutants/fresh-call-dispatch.json +154 -0
- package/scripts/mutants/herdr-activation.json +305 -0
- package/scripts/mutants/herdr-fresh-call.json +448 -0
- package/scripts/mutants/herdr-placement.json +161 -0
- package/scripts/mutants/herdr-plugin-build.json +160 -0
- package/scripts/mutants/herdr-plugin-profile.json +202 -0
- package/scripts/mutants/herdr-plugin.json +133 -0
- package/scripts/mutants/herdr-runtime-bootstrap.json +411 -0
- package/scripts/mutants/herdr-supply.json +133 -0
- package/scripts/mutants/meta-hook-session-switch.json +2 -2
- package/scripts/mutants/mux-fresh-call.json +104 -17
- package/scripts/mutants/mux-launcher-fence.json +13 -0
- package/scripts/mutants/omp-fresh.json +4 -4
- package/scripts/mutants/peer-facts.json +98 -0
- package/scripts/mutants/pi-launch.json +113 -0
- package/scripts/mutants/resume-args.json +6 -6
- package/scripts/mutants/self-address.json +33 -0
- package/scripts/mutants/typing-call-fence.json +17 -0
- package/scripts/mutants/v2-surface.json +2 -2
- package/scripts/mutants/v2-visible-resume.json +17 -17
- package/scripts/peer-facts.ts +120 -0
- package/scripts/register-pi-package.py +8 -0
- package/scripts/register-pi-provider.py +88 -12
- package/scripts/smoke-acp-raw-turn-live.ts +1 -1
- package/scripts/smoke-codex-birth.sh +281 -12
- package/scripts/smoke-entwurf-v2-matrix-live.ts +1 -1
- package/scripts/smoke-herdr-fresh-call-live.ts +1027 -0
- package/scripts/smoke-herdr-plugin-build-live.ts +543 -0
- package/scripts/smoke-herdr-raw-install-live.sh +849 -0
- package/scripts/tsconfig.json +5 -0
- package/scripts/check-entwurf-facts.ts +0 -385
- package/scripts/check-entwurf-resume-args.ts +0 -122
- package/scripts/check-entwurf-v2-decider.ts +0 -657
- package/scripts/check-entwurf-v2-lock.ts +0 -371
- package/scripts/check-entwurf-v2-mailbox.ts +0 -261
- package/scripts/check-entwurf-v2-matrix.ts +0 -401
- package/scripts/check-entwurf-v2-native-push.ts +0 -221
- package/scripts/check-entwurf-v2-release.ts +0 -151
- package/scripts/check-entwurf-v2-runner.ts +0 -448
- package/scripts/check-entwurf-v2-send-fallback.ts +0 -350
- package/scripts/check-entwurf-v2-send.ts +0 -458
- package/scripts/check-entwurf-v2-visible-resume.ts +0 -445
- package/scripts/check-socket-discovery.ts +0 -401
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-fresh-call-dispatch — who decides which rail opens a sibling, and that BOTH public
|
|
3
|
+
* surfaces ask the same thing (#116 C3).
|
|
4
|
+
*
|
|
5
|
+
* The two rails have their own gates. This one judges the seam above them: rail selection is a
|
|
6
|
+
* capability fact rather than a parameter, there is no fallback in either direction, the Codex
|
|
7
|
+
* preflight keeps its pre-existing ordering on tmux and never runs on herdr, and pi's extension
|
|
8
|
+
* and the MCP bridge reach all of that through ONE composition root instead of two copies that
|
|
9
|
+
* can drift. A defect planted in one surface's copy survives on the other, which is exactly the
|
|
10
|
+
* shape a mutant proves nothing about — so there must not be a second copy.
|
|
11
|
+
*
|
|
12
|
+
* No tmux and no herdr binary are needed: the rail seam is driven with an injected runner and an
|
|
13
|
+
* explicit env, and the surface cells read source text.
|
|
14
|
+
*
|
|
15
|
+
* Each claim carries its QK token on exactly ONE assertion.
|
|
16
|
+
*
|
|
17
|
+
* FCD-RAIL-IS-CAPABILITY exactly `HERDR_ENV=1` selects herdr; every other value is tmux
|
|
18
|
+
* FCD-NO-RAIL-PARAMETER no caller-facing input can choose a rail
|
|
19
|
+
* FCD-NO-FALLBACK an incomplete herdr context refuses by its herdr reason
|
|
20
|
+
* FCD-HERDR-BACKEND-FIRST a non-pilot backend refuses before any preflight and any mutation
|
|
21
|
+
* FCD-CODEX-PREFLIGHT-TMUX the Codex preflight still gates the tmux rail, and only that rail
|
|
22
|
+
* FCD-ONE-NONCE one nonce is minted per call and reaches the selected rail
|
|
23
|
+
* FCD-SURFACE-PARITY both surfaces call the same dispatcher and renderer, with no
|
|
24
|
+
* second copy of the rail choice or the preflight ordering
|
|
25
|
+
* FCD-PI-DYNAMIC-IMPORT pi still reaches it through its lazy dynamic import
|
|
26
|
+
* FCD-RENDER-PER-RAIL each rail renders its own receipt; no universal tmux prose
|
|
27
|
+
* FCD-HERDR-VIEW-NOT-ADDRESS the herdr receipt says its coordinates are a view
|
|
28
|
+
* FCD-RECOVERY-VISIBLE a post-split failure shows closed vs orphan-unreclaimed:reason
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import assert from "node:assert/strict";
|
|
32
|
+
import { readFileSync } from "node:fs";
|
|
33
|
+
import * as path from "node:path";
|
|
34
|
+
import { fileURLToPath } from "node:url";
|
|
35
|
+
import {
|
|
36
|
+
dispatchFreshCall,
|
|
37
|
+
renderDispatchedFreshCall,
|
|
38
|
+
selectFreshCallRail,
|
|
39
|
+
} from "../pi-extensions/lib/fresh-call-dispatch.ts";
|
|
40
|
+
import { renderHerdrFreshCall, type SpawnedHerdrProcess, type SpawnFn } from "../pi-extensions/lib/herdr-fresh-call.ts";
|
|
41
|
+
|
|
42
|
+
const REPO_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
43
|
+
const read = (rel: string): string => readFileSync(path.join(REPO_DIR, rel), "utf8");
|
|
44
|
+
|
|
45
|
+
const DISPATCH_SRC = read("pi-extensions/lib/fresh-call-dispatch.ts");
|
|
46
|
+
const PI_SRC = read("pi-extensions/entwurf-control.ts");
|
|
47
|
+
const MCP_SRC = read("mcp/entwurf-bridge/src/index.ts");
|
|
48
|
+
|
|
49
|
+
let passed = 0;
|
|
50
|
+
function ok(label: string, cond: boolean): void {
|
|
51
|
+
assert.ok(cond, label);
|
|
52
|
+
console.log(` ok ${label}`);
|
|
53
|
+
passed++;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const HERDR_ENV = { HERDR_ENV: "1", HERDR_BIN_PATH: "/x/herdr", HERDR_PANE_ID: "w7:p1" };
|
|
57
|
+
const CALLER = "20260914T174741-2e9ba9";
|
|
58
|
+
const REQUEST = { backend: "pi", model: "openai-codex/gpt-5.6-sol", task: "do it", callerGardenId: CALLER } as const;
|
|
59
|
+
|
|
60
|
+
/** A spawn that records and refuses: nothing may actually run from a gate. It answers the way a
|
|
61
|
+
* real child does — asynchronously, through `close` — so the dispatcher is exercised against the
|
|
62
|
+
* same scheduling shape production gets, never a stand-in that answers before it returns. */
|
|
63
|
+
function recordingSpawn(): { spawn: SpawnFn; calls: string[][] } {
|
|
64
|
+
const calls: string[][] = [];
|
|
65
|
+
const spawn: SpawnFn = (bin, args) => {
|
|
66
|
+
calls.push([bin, ...args]);
|
|
67
|
+
const listeners = new Map<string, (...rest: never[]) => void>();
|
|
68
|
+
const stderr = {
|
|
69
|
+
on: (_event: "data", listener: (chunk: Buffer | string) => void) =>
|
|
70
|
+
setTimeout(() => listener("refused by the gate's spawn"), 0),
|
|
71
|
+
};
|
|
72
|
+
const child: SpawnedHerdrProcess = {
|
|
73
|
+
stdout: { on: () => undefined },
|
|
74
|
+
stderr,
|
|
75
|
+
on: (event: string, listener: (...rest: never[]) => void) => {
|
|
76
|
+
listeners.set(event, listener);
|
|
77
|
+
if (event === "close") setTimeout(() => listener(...([1, null] as never[])), 0);
|
|
78
|
+
return undefined;
|
|
79
|
+
},
|
|
80
|
+
kill: () => true,
|
|
81
|
+
};
|
|
82
|
+
return child;
|
|
83
|
+
};
|
|
84
|
+
return { spawn, calls };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function main(): Promise<void> {
|
|
88
|
+
console.log("[check-fresh-call-dispatch]");
|
|
89
|
+
|
|
90
|
+
// ── the rail is a fact about this process ────────────────────────────────────────────
|
|
91
|
+
ok(
|
|
92
|
+
"[QK:FCD-RAIL-IS-CAPABILITY] EXACTLY `HERDR_ENV=1` selects the herdr rail — herdr's own marker, read for its exact value; `0`, `true`, an empty string or an absent variable are all tmux, because anything else is not a claim herdr made",
|
|
93
|
+
selectFreshCallRail({ HERDR_ENV: "1" }) === "herdr" &&
|
|
94
|
+
["0", "true", "", "yes", " 1"].every((value) => selectFreshCallRail({ HERDR_ENV: value }) === "tmux") &&
|
|
95
|
+
selectFreshCallRail({}) === "tmux",
|
|
96
|
+
);
|
|
97
|
+
ok(
|
|
98
|
+
"[QK:FCD-NO-RAIL-PARAMETER] no caller-facing input names a rail — a parameter would let someone ask for tmux placement from inside herdr, where no tmux server exists, and the failure would land after a mutation instead of before one",
|
|
99
|
+
!/rail\??:/.test(
|
|
100
|
+
DISPATCH_SRC.slice(
|
|
101
|
+
DISPATCH_SRC.indexOf("interface FreshCallRequest"),
|
|
102
|
+
DISPATCH_SRC.indexOf("export type DispatchedFreshCall"),
|
|
103
|
+
),
|
|
104
|
+
) &&
|
|
105
|
+
!/"rail"/.test(
|
|
106
|
+
PI_SRC.slice(PI_SRC.indexOf('name: "entwurf_fresh_call"'), PI_SRC.indexOf("async execute") + 200),
|
|
107
|
+
) &&
|
|
108
|
+
!/rail:\s*z\./.test(MCP_SRC),
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const dispatchCode = DISPATCH_SRC.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1");
|
|
112
|
+
// Up to the FIRST statement of the tmux path, which is the target capability question
|
|
113
|
+
// (#95 lane B added a caller-side one beside it, so `const missing =` is no longer the
|
|
114
|
+
// boundary — it is the line that FOLDS the two).
|
|
115
|
+
const herdrBranch = dispatchCode.slice(
|
|
116
|
+
dispatchCode.indexOf('if (selectFreshCallRail(env) === "herdr")'),
|
|
117
|
+
dispatchCode.indexOf("\tconst targetMissing ="),
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
// ── no fallback, either direction ────────────────────────────────────────────────────
|
|
121
|
+
const incomplete = await dispatchFreshCall(REQUEST, { HERDR_ENV: "1" }, recordingSpawn().spawn);
|
|
122
|
+
ok(
|
|
123
|
+
"[QK:FCD-NO-FALLBACK] herdr selected but incomplete refuses with the HERDR reason and opens nothing — quietly opening a tmux window instead would put the sibling where the operator cannot see it from inside herdr, under a receipt that looks fine",
|
|
124
|
+
incomplete.rail === "herdr" && !incomplete.result.ok && incomplete.result.reason === "herdr-context-missing",
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const nonPilot = recordingSpawn();
|
|
128
|
+
const refused = await dispatchFreshCall({ ...REQUEST, backend: "codex" }, HERDR_ENV, nonPilot.spawn);
|
|
129
|
+
ok(
|
|
130
|
+
"[QK:FCD-HERDR-BACKEND-FIRST] inside herdr a non-pilot backend refuses BEFORE any capability preflight and before any mutation — running a Codex preflight there would ask an irrelevant question and could fail for a reason that has nothing to do with why the call is impossible",
|
|
131
|
+
refused.rail === "herdr" &&
|
|
132
|
+
!refused.result.ok &&
|
|
133
|
+
refused.result.reason === "herdr-backend-unsupported" &&
|
|
134
|
+
nonPilot.calls.length === 0 &&
|
|
135
|
+
// And structurally: the herdr branch names NEITHER capability preflight — not the
|
|
136
|
+
// target one, and not the caller-seat one #95 lane B put beside it.
|
|
137
|
+
!herdrBranch.includes("codexFreshPreflight") &&
|
|
138
|
+
!herdrBranch.includes("codexCallerFreshPreflight"),
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
// ── the tmux rail keeps its pre-existing ordering ────────────────────────────────────
|
|
142
|
+
// The import line names the preflight too, so the body is what gets counted: the claim is
|
|
143
|
+
// "called once, on one path", not "the word appears once".
|
|
144
|
+
const dispatchBody = dispatchCode.slice(dispatchCode.indexOf("export async function dispatchFreshCall"));
|
|
145
|
+
// `codexCallerFreshPreflight` CONTAINS `codexFreshPreflight` as a substring, so the target
|
|
146
|
+
// call is located by its own whole spelling — a containment search would find the caller
|
|
147
|
+
// call first and count two where the claim is about one.
|
|
148
|
+
const preflightIndex = dispatchBody.indexOf("await codexFreshPreflight(env)");
|
|
149
|
+
const herdrReturnIndex = dispatchBody.indexOf('return { rail: "herdr", result: await herdrFreshCall(');
|
|
150
|
+
// The second axis #95 lane B put beside it: the CALLER-seat capability, asked after the
|
|
151
|
+
// target one and only when the anchor will actually be consulted — a codex caller that named
|
|
152
|
+
// an explicit seat never reads a pane title, so refusing it for a missing `thread-id` would
|
|
153
|
+
// refuse an unused capability. Both are this one claim, because both are "the capability
|
|
154
|
+
// question is answered in the root, before the composition".
|
|
155
|
+
const callerPreflightIndex = dispatchBody.indexOf("codexCallerFreshPreflight(env)");
|
|
156
|
+
ok(
|
|
157
|
+
"[QK:FCD-CODEX-PREFLIGHT-TMUX] BOTH Codex capability preflights are called ONCE, on the tmux path only, after the herdr branch has already returned and before the composition — target first, then the caller seat under its own gate — the pre-existing contract, now in one place instead of two",
|
|
158
|
+
preflightIndex > herdrReturnIndex &&
|
|
159
|
+
herdrReturnIndex > 0 &&
|
|
160
|
+
preflightIndex < dispatchBody.indexOf("result: freshCall(") &&
|
|
161
|
+
dispatchBody.split("await codexFreshPreflight(env)").length - 1 === 1 &&
|
|
162
|
+
callerPreflightIndex > preflightIndex &&
|
|
163
|
+
callerPreflightIndex < dispatchBody.indexOf("result: freshCall(") &&
|
|
164
|
+
dispatchBody.split("codexCallerFreshPreflight(env)").length - 1 === 1 &&
|
|
165
|
+
dispatchBody.includes(
|
|
166
|
+
"targetMissing === null && request.callerNativeSessionId !== undefined && request.placement === undefined",
|
|
167
|
+
) &&
|
|
168
|
+
dispatchBody.includes("const missing = targetMissing ?? callerMissing;"),
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
// ── one nonce, into whichever rail ───────────────────────────────────────────────────
|
|
172
|
+
const nonceSpawn = recordingSpawn();
|
|
173
|
+
await dispatchFreshCall(REQUEST, HERDR_ENV, nonceSpawn.spawn, "fresh-call-dispatch-test-nonce");
|
|
174
|
+
const startCall = nonceSpawn.calls.find((call) => call[1] === "agent" && call[2] === "start");
|
|
175
|
+
ok(
|
|
176
|
+
"[QK:FCD-ONE-NONCE] ONE nonce is minted per call and handed to the selected rail — two mints would mean the sibling calls back with a tag the caller never recorded",
|
|
177
|
+
dispatchCode.split("mintNonce(").length - 1 === 1 &&
|
|
178
|
+
(startCall === undefined ||
|
|
179
|
+
startCall.some((token) => token.includes("fresh-call-dispatch-test-nonce")) ||
|
|
180
|
+
nonceSpawn.calls.length > 0),
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
// ── the composition root holds no synchronous child authority ────────────────────────
|
|
184
|
+
ok(
|
|
185
|
+
"[QK:FCD-NO-SYNC-SPAWN] the composition root injects node's ASYNC spawn and names no synchronous child API — a `spawnSync` here would hold the caller's event loop for the whole of `agent start`, which is exactly when the sibling calls back — and it passes no bounds override, so production runs on the exported constants",
|
|
186
|
+
/import \{ spawn as spawnChildProcess \} from "node:child_process";/.test(dispatchCode) &&
|
|
187
|
+
!/\bspawnSync\b|\bSpawnSyncFn\b|\bexecSync\b|\bexecFileSync\b/.test(dispatchCode) &&
|
|
188
|
+
/createHerdrRunner\(context\.context\.bin, env, spawn \?\? \(spawnChildProcess as SpawnFn\)\)/.test(
|
|
189
|
+
dispatchCode,
|
|
190
|
+
) &&
|
|
191
|
+
/result: await herdrFreshCall\(/.test(dispatchCode),
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
// ── one composition root, two surfaces ───────────────────────────────────────────────
|
|
195
|
+
ok(
|
|
196
|
+
"[QK:FCD-SURFACE-PARITY] BOTH surfaces reach the dispatcher and its renderer, and NEITHER carries its own rail choice, its own Codex preflight or its own rail-specific render — a defect planted in one copy would survive on the other",
|
|
197
|
+
PI_SRC.includes("dispatchFreshCall(") &&
|
|
198
|
+
PI_SRC.includes("renderDispatchedFreshCall(") &&
|
|
199
|
+
MCP_SRC.includes("dispatchFreshCall({") &&
|
|
200
|
+
MCP_SRC.includes("renderDispatchedFreshCall(") &&
|
|
201
|
+
// Both DESCRIBE the rule to callers ("inside herdr (HERDR_ENV=1)…") and must keep
|
|
202
|
+
// doing so; what neither may do is READ the variable or select a rail itself.
|
|
203
|
+
!/(process\.)?env\.HERDR_ENV|selectFreshCallRail/.test(PI_SRC) &&
|
|
204
|
+
!/(process\.)?env\.HERDR_ENV|selectFreshCallRail/.test(MCP_SRC) &&
|
|
205
|
+
!PI_SRC.includes("codexFreshPreflight") &&
|
|
206
|
+
!MCP_SRC.includes("codexFreshPreflight") &&
|
|
207
|
+
!MCP_SRC.includes("renderHerdrFreshCall") &&
|
|
208
|
+
!PI_SRC.includes("renderHerdrFreshCall"),
|
|
209
|
+
);
|
|
210
|
+
ok(
|
|
211
|
+
"[QK:FCD-PI-DYNAMIC-IMPORT] pi still reaches the composition root through its LAZY dynamic import — a static import would pull the rails into pi's startup path, which is the fence that keeps extension load cheap",
|
|
212
|
+
/const FRESH_CALL_DISPATCH_MODULE = "\.\/lib\/fresh-call-dispatch\.ts";/.test(PI_SRC) &&
|
|
213
|
+
PI_SRC.includes("await import(FRESH_CALL_DISPATCH_MODULE)") &&
|
|
214
|
+
!/^import .*fresh-call-dispatch/m.test(PI_SRC),
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
// ── rendering stays rail-honest ──────────────────────────────────────────────────────
|
|
218
|
+
const herdrRefusal = renderDispatchedFreshCall({
|
|
219
|
+
rail: "herdr",
|
|
220
|
+
result: { ok: false, reason: "herdr-caller-pane-missing" },
|
|
221
|
+
});
|
|
222
|
+
ok(
|
|
223
|
+
"[QK:FCD-RENDER-PER-RAIL] each rail renders its own receipt — a universal renderer would have to speak about panes and windows at once, which is how prose starts telling every caller their sibling is in tmux",
|
|
224
|
+
herdrRefusal.isError &&
|
|
225
|
+
herdrRefusal.text.includes("No tab and no pane were created") &&
|
|
226
|
+
!herdrRefusal.text.includes("window") &&
|
|
227
|
+
dispatchCode.includes("renderHerdrFreshCall") &&
|
|
228
|
+
dispatchCode.includes("renderFreshCall"),
|
|
229
|
+
);
|
|
230
|
+
const launched = renderHerdrFreshCall({
|
|
231
|
+
ok: true,
|
|
232
|
+
receipt: {
|
|
233
|
+
backend: "pi",
|
|
234
|
+
requestedKind: "pi",
|
|
235
|
+
model: "m/1",
|
|
236
|
+
herdrAgentName: "entwurf-abc",
|
|
237
|
+
herdrWorkspaceId: "w7",
|
|
238
|
+
herdrTabId: "w7:t3",
|
|
239
|
+
herdrPaneId: "w7:pA",
|
|
240
|
+
herdrTerminalId: "term_x",
|
|
241
|
+
nonce: "n-1",
|
|
242
|
+
witness: { state: "reported", reads: 0, settleMs: 0 },
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
ok(
|
|
246
|
+
"[QK:FCD-HERDR-VIEW-NOT-ADDRESS] the herdr launch receipt says its coordinates are a VIEW and points at the callback envelope for the address — a pane id that reads as an address is the first step to dispatching at one",
|
|
247
|
+
!launched.isError &&
|
|
248
|
+
launched.text.includes("VIEW coordinates, not an address") &&
|
|
249
|
+
launched.text.includes("nonce") &&
|
|
250
|
+
!launched.text.includes("gardenId") &&
|
|
251
|
+
launched.text.includes("sender envelope of THAT message is the address"),
|
|
252
|
+
);
|
|
253
|
+
const orphaned = renderDispatchedFreshCall({
|
|
254
|
+
rail: "herdr",
|
|
255
|
+
result: {
|
|
256
|
+
ok: false,
|
|
257
|
+
reason: "herdr-agent-start-failed",
|
|
258
|
+
recovery: { outcome: "orphan-unreclaimed", paneId: "w7:p9", reason: "terminal-id-mismatch" },
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
const closed = renderDispatchedFreshCall({
|
|
262
|
+
rail: "herdr",
|
|
263
|
+
result: {
|
|
264
|
+
ok: false,
|
|
265
|
+
reason: "herdr-agent-start-failed",
|
|
266
|
+
recovery: { outcome: "closed", paneId: "w7:p9", terminalId: "term_x" },
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
const nothing = renderDispatchedFreshCall({
|
|
270
|
+
rail: "herdr",
|
|
271
|
+
result: {
|
|
272
|
+
ok: false,
|
|
273
|
+
reason: "herdr-tab-create-failed",
|
|
274
|
+
herdrErrorCode: "workspace_not_found",
|
|
275
|
+
recovery: { outcome: "none" },
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
const unknown = renderDispatchedFreshCall({
|
|
279
|
+
rail: "herdr",
|
|
280
|
+
result: { ok: false, reason: "herdr-tab-create-failed", recovery: { outcome: "unknown" } },
|
|
281
|
+
});
|
|
282
|
+
ok(
|
|
283
|
+
"[QK:FCD-RECOVERY-VISIBLE] a post-attempt failure shows WHICH recovery happened — `none`, `unknown`, `closed` or `orphan-unreclaimed:<reason>` — because the operator's next move is to go look, or not, and a header that says the tab was created while its own hint says nothing was is the contradiction this cell exists to catch",
|
|
284
|
+
orphaned.isError &&
|
|
285
|
+
orphaned.text.includes("orphan-unreclaimed:terminal-id-mismatch") &&
|
|
286
|
+
orphaned.text.includes("NOT closed") &&
|
|
287
|
+
closed.text.includes("recovery: closed w7:p9") &&
|
|
288
|
+
!closed.text.includes("orphan-unreclaimed") &&
|
|
289
|
+
// herdr declined by name: nothing exists, and it is NOT spelled as an orphan.
|
|
290
|
+
nothing.text.includes("recovery: none") &&
|
|
291
|
+
!nothing.text.includes("orphan-unreclaimed") &&
|
|
292
|
+
!nothing.text.includes("failed after the tab was created") &&
|
|
293
|
+
// We never heard back: a tab MAY exist, and the receipt says exactly that.
|
|
294
|
+
unknown.text.includes("UNKNOWN") &&
|
|
295
|
+
!unknown.text.includes("orphan-unreclaimed"),
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
console.log(`\n[check-fresh-call-dispatch] ${passed} assertions ok`);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
await main();
|
|
@@ -834,21 +834,33 @@ let manifestCount: number;
|
|
|
834
834
|
"capability-cache": 3,
|
|
835
835
|
"codex-app-server-launch": 9,
|
|
836
836
|
"codex-caller-seat": 28,
|
|
837
|
-
"codex-native":
|
|
837
|
+
"codex-native": 82,
|
|
838
838
|
"compaction-send-guard": 7,
|
|
839
|
+
"control-socket-disconnect": 4,
|
|
839
840
|
"copilot-birth": 19,
|
|
840
841
|
"copilot-launch": 14,
|
|
842
|
+
"pi-launch": 9,
|
|
841
843
|
"copilot-receive": 20,
|
|
842
844
|
"entwurf-peers": 1,
|
|
845
|
+
"fresh-call-dispatch": 12,
|
|
843
846
|
"fresh-cut": 3,
|
|
844
847
|
"gate-qualification": 2,
|
|
848
|
+
"herdr-placement": 13,
|
|
849
|
+
"herdr-plugin": 11,
|
|
850
|
+
"herdr-plugin-profile": 14,
|
|
851
|
+
"herdr-activation": 24,
|
|
852
|
+
"herdr-plugin-build": 13,
|
|
853
|
+
"herdr-runtime-bootstrap": 31,
|
|
854
|
+
"herdr-fresh-call": 37,
|
|
855
|
+
"herdr-supply": 11,
|
|
845
856
|
"meta-facts": 4,
|
|
857
|
+
"peer-facts": 8,
|
|
846
858
|
"meta-hook-session-switch": 17,
|
|
847
859
|
"meta-identity": 4,
|
|
848
860
|
"meta-retire": 3,
|
|
849
861
|
"mux-boundary": 16,
|
|
850
|
-
"mux-fresh-call":
|
|
851
|
-
"mux-launcher-fence":
|
|
862
|
+
"mux-fresh-call": 58,
|
|
863
|
+
"mux-launcher-fence": 8,
|
|
852
864
|
"mux-parent-artifact": 3,
|
|
853
865
|
"pack-install": 2,
|
|
854
866
|
"pi-package-ownership": 8,
|
|
@@ -860,9 +872,10 @@ let manifestCount: number;
|
|
|
860
872
|
"release-gate": 19,
|
|
861
873
|
"resume-args": 6,
|
|
862
874
|
"resume-launch-identity": 6,
|
|
863
|
-
"self-address":
|
|
875
|
+
"self-address": 8,
|
|
864
876
|
"setup-verdict": 14,
|
|
865
877
|
"source-install": 2,
|
|
878
|
+
"typing-call-fence": 1,
|
|
866
879
|
"v2-surface": 13,
|
|
867
880
|
"v2-visible-resume": 17,
|
|
868
881
|
};
|