gentle-pi 2.7.0 → 3.0.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 (122) hide show
  1. package/README.md +24 -6
  2. package/assets/agents/gentle-ai-worker.md +5 -1
  3. package/assets/agents/sdd-apply.md +9 -7
  4. package/assets/agents/sdd-archive.md +42 -23
  5. package/assets/agents/sdd-proposal.md +2 -2
  6. package/assets/agents/sdd-remediate.md +4 -4
  7. package/assets/agents/sdd-research.md +20 -48
  8. package/assets/agents/sdd-tasks.md +5 -5
  9. package/assets/agents/sdd-verify.md +6 -28
  10. package/assets/chains/sdd-full.chain.md +4 -22
  11. package/assets/chains/sdd-verify.chain.md +3 -12
  12. package/assets/orchestrator-delegation.md +33 -3
  13. package/assets/orchestrator-memory.md +20 -7
  14. package/assets/orchestrator.md +5 -3
  15. package/assets/sdd-orchestrator-workflow.md +25 -58
  16. package/assets/support/sdd-status-contract.md +9 -12
  17. package/docs/gentle-shell.md +14 -4
  18. package/docs/readme-reference.md +171 -32
  19. package/extensions/codegraph-tools.ts +2 -0
  20. package/extensions/gentle-agents.ts +281 -361
  21. package/extensions/gentle-ai.ts +588 -117
  22. package/extensions/gentle-shell.ts +74 -30
  23. package/extensions/pi-pretty.ts +63 -14
  24. package/extensions/quiet-tools.ts +1 -2
  25. package/extensions/startup-banner.ts +10 -9
  26. package/lib/agent-home.ts +8 -0
  27. package/lib/agent-profile-pin.ts +336 -0
  28. package/lib/agent-profiles.ts +28 -8
  29. package/lib/agents-config.ts +24 -2
  30. package/lib/agents-history.ts +3 -97
  31. package/lib/agents-keys.ts +27 -0
  32. package/lib/agents-protocol.ts +2 -15
  33. package/lib/agents-runner.ts +67 -111
  34. package/lib/agents-session-transport.ts +691 -0
  35. package/lib/command-palette-catalog.ts +87 -0
  36. package/lib/command-palette.ts +346 -0
  37. package/lib/native-choice-list.ts +5 -0
  38. package/lib/native-review-cli.ts +10 -97
  39. package/lib/review-publication-gate.ts +11 -1
  40. package/lib/review-repository.ts +1 -1
  41. package/lib/review-snapshot.ts +1 -0
  42. package/lib/review-transaction.ts +4 -2
  43. package/lib/sdd-preflight.ts +2 -1
  44. package/lib/sdd-research-capabilities.ts +18 -152
  45. package/lib/sdd-status.ts +7 -779
  46. package/lib/session-change-capture.ts +2 -1
  47. package/lib/session-changes.ts +8 -1
  48. package/lib/shell-bar.ts +21 -12
  49. package/lib/shell-card.ts +8 -12
  50. package/lib/shell-changes.ts +3 -2
  51. package/lib/shell-prompt.ts +25 -8
  52. package/lib/shell-sidebar-banner.ts +2 -2
  53. package/lib/shell-sidebar-layout.ts +5 -2
  54. package/lib/windows-session-transport.ts +877 -0
  55. package/package.json +3 -3
  56. package/runtime/native-review-cli.mjs +9 -96
  57. package/runtime/windows-session-transport.ps1 +791 -0
  58. package/scripts/test-packed-runner.mjs +1668 -20
  59. package/scripts/verify-package-files.mjs +0 -1
  60. package/tests/agent-home.test.ts +52 -0
  61. package/tests/agent-profiles.test.ts +30 -1
  62. package/tests/agents-config.test.ts +44 -0
  63. package/tests/agents-history.test.ts +12 -24
  64. package/tests/agents-runner.test.ts +307 -58
  65. package/tests/agents-session-transport-process.test.ts +249 -0
  66. package/tests/agents-session-transport.test.ts +823 -0
  67. package/tests/artifact-language.test.ts +10 -7
  68. package/tests/command-palette.test.ts +378 -0
  69. package/tests/delegated-key-learnings-contract.test.ts +2 -2
  70. package/tests/fixtures/agents-session-transport-process.mjs +108 -0
  71. package/tests/fixtures/legacy/sdd-research-v2.5.0.md +54 -0
  72. package/tests/fixtures/windows-session-bootstrap.ps1 +129 -0
  73. package/tests/fixtures/windows-session-compile.ps1 +110 -0
  74. package/tests/gentle-agents.test.ts +849 -356
  75. package/tests/gentle-ai.test.ts +472 -4
  76. package/tests/gentle-shell.test.ts +201 -8
  77. package/tests/native-choice-list.test.ts +13 -0
  78. package/tests/native-review-cli.test.ts +0 -33
  79. package/tests/odd-routing-contract.test.ts +208 -0
  80. package/tests/orchestrator-budget.test.ts +17 -2
  81. package/tests/package-manifest.test.ts +115 -27
  82. package/tests/persona-single-channel.test.ts +3 -3
  83. package/tests/pi-pretty.test.ts +45 -0
  84. package/tests/profile-pin.test.ts +370 -0
  85. package/tests/quiet-tool-rendering.test.ts +32 -5
  86. package/tests/review-contract-prompt.test.ts +9 -0
  87. package/tests/review-controller.test.ts +0 -44
  88. package/tests/review-session-standing-permission-ipc.test.ts +427 -13
  89. package/tests/runtime-harness.mjs +4 -4
  90. package/tests/sdd-agent-tools.test.ts +15 -36
  91. package/tests/sdd-archive-replay.test.ts +82 -0
  92. package/tests/sdd-classical-continuation.test.ts +74 -0
  93. package/tests/sdd-execution-routing-contract.test.ts +18 -2
  94. package/tests/sdd-managed-runtime-settlement.test.ts +42 -330
  95. package/tests/sdd-native-managed-uptake.test.ts +11 -21
  96. package/tests/sdd-no-attempts-contract.test.ts +15 -0
  97. package/tests/sdd-odd-integration.test.ts +33 -0
  98. package/tests/sdd-optional-research.test.ts +124 -0
  99. package/tests/sdd-planning-routing-contract.test.ts +1 -1
  100. package/tests/sdd-preflight-rpc-input.test.ts +125 -0
  101. package/tests/sdd-preflight.test.ts +1 -1
  102. package/tests/sdd-research-capabilities.test.ts +20 -162
  103. package/tests/sdd-selection-transport.test.ts +180 -88
  104. package/tests/sdd-status.test.ts +5 -778
  105. package/tests/sdd-task-truth.test.ts +43 -0
  106. package/tests/session-change-capture.test.ts +20 -2
  107. package/tests/session-changes.test.ts +11 -0
  108. package/tests/shell-bar.test.ts +21 -0
  109. package/tests/shell-card.test.ts +8 -6
  110. package/tests/shell-changes.test.ts +8 -0
  111. package/tests/shell-prompt.test.ts +41 -7
  112. package/tests/shell-sidebar-banner.test.ts +4 -4
  113. package/tests/shell-sidebar-layout.test.ts +97 -13
  114. package/tests/startup-banner.test.ts +55 -2
  115. package/tests/windows-hidden-processes.test.ts +303 -0
  116. package/tests/windows-session-bootstrap.test.ts +1772 -0
  117. package/tests/windows-session-compile.test.ts +170 -0
  118. package/tests/windows-session-transport.test.ts +754 -0
  119. package/assets/agents/sdd-sync.md +0 -146
  120. package/lib/openspec-guardrails.ts +0 -99
  121. package/tests/native-sdd-attempt-authority.test.ts +0 -240
  122. package/tests/openspec-guardrails.test.ts +0 -71
@@ -0,0 +1,1772 @@
1
+ import assert from "node:assert/strict";
2
+ import { spawn } from "node:child_process";
3
+ import { EventEmitter } from "node:events";
4
+ import { mkdtemp, mkdir, readFile, stat } from "node:fs/promises";
5
+ import { createConnection } from "node:net";
6
+ import os from "node:os";
7
+ import { dirname, join } from "node:path";
8
+ import test from "node:test";
9
+ import { fileURLToPath } from "node:url";
10
+ import { FIXED_WINDOWS_POWERSHELL, WindowsActiveSessionClient, WindowsActiveSessionListener, WindowsSessionPresenceRegistry, WindowsSessionRegistryPhaseSequence, type WindowsSessionRegistryPhaseEvent, parseWindowsHostFrame } from "../lib/windows-session-transport.ts";
11
+ import { createDefaultSessionTransport } from "../extensions/gentle-agents.ts";
12
+ import { ActiveSessionClientError, FrameDecoder, encodeNotificationFrame, type AckFrame } from "../lib/agents-session-transport.ts";
13
+ import { decidePackedRunnerEntrypoint, deriveWindowsStartupTimingPathDelta, validateWindowsStartupTimingMachinePaths, WINDOWS_STARTUP_TIMING_WINDOWS_PATH_KEYS } from "../scripts/test-packed-runner.mjs";
14
+
15
+ const runtime = fileURLToPath(new URL("../runtime/windows-session-transport.ps1", import.meta.url));
16
+ const fixture = fileURLToPath(new URL("fixtures/windows-session-bootstrap.ps1", import.meta.url));
17
+ const packedRunner = fileURLToPath(new URL("../scripts/test-packed-runner.mjs", import.meta.url));
18
+
19
+ type CleanupChild = EventEmitter & { pid?: number; stdin: EventEmitter & { write(input: string): boolean; end(input?: string): void }; stdout: EventEmitter & { destroy?(): void }; stderr: EventEmitter & { resume?(): void; destroy?(): void }; kill(): boolean };
20
+ type ChildLifecycle = Readonly<{ child: CleanupChild; changed: EventEmitter; closeObserved: boolean; exitObserved: boolean; processError?: Error; stdinError?: Error; stdoutError?: Error; stderrError?: Error; stdinClosed: boolean; stdoutClosed: boolean; stderrClosed: boolean; exitCode: number }>;
21
+
22
+ function observeChildLifecycle(child: CleanupChild): ChildLifecycle {
23
+ const lifecycle = { child, changed: new EventEmitter(), closeObserved: false, exitObserved: false, processError: undefined as Error | undefined, stdinError: undefined as Error | undefined, stdoutError: undefined as Error | undefined, stderrError: undefined as Error | undefined, stdinClosed: false, stdoutClosed: false, stderrClosed: false, exitCode: -1 };
24
+ const changed = () => lifecycle.changed.emit("changed");
25
+ child.once("close", (code: number | null) => { lifecycle.closeObserved = true; lifecycle.exitCode = code ?? -1; changed(); });
26
+ child.once("exit", () => { lifecycle.exitObserved = true; changed(); });
27
+ child.on("error", (error: Error) => { lifecycle.processError = error; changed(); });
28
+ child.stdin.on("error", (error: Error) => { lifecycle.stdinError = error; changed(); });
29
+ child.stdout.on("error", (error: Error) => { lifecycle.stdoutError = error; changed(); });
30
+ child.stderr.on("error", (error: Error) => { lifecycle.stderrError = error; changed(); });
31
+ child.stdin.once("close", () => { lifecycle.stdinClosed = true; changed(); });
32
+ child.stdout.once("close", () => { lifecycle.stdoutClosed = true; changed(); });
33
+ child.stderr.once("close", () => { lifecycle.stderrClosed = true; changed(); });
34
+ return lifecycle;
35
+ }
36
+
37
+ function hasLifecycleError(lifecycle: ChildLifecycle): boolean {
38
+ return lifecycle.processError !== undefined || lifecycle.stdinError !== undefined || lifecycle.stdoutError !== undefined || lifecycle.stderrError !== undefined;
39
+ }
40
+
41
+ function noProcessStreamsClosed(lifecycle: ChildLifecycle): boolean {
42
+ return lifecycle.processError !== undefined && lifecycle.child.pid === undefined && lifecycle.stdinClosed && lifecycle.stdoutClosed && lifecycle.stderrClosed;
43
+ }
44
+
45
+ function waitForChildClose(lifecycle: ChildLifecycle, deadlineMs: number): Promise<boolean> {
46
+ if (lifecycle.closeObserved || noProcessStreamsClosed(lifecycle)) return Promise.resolve(true);
47
+ return new Promise((resolve) => {
48
+ let settled = false;
49
+ const finish = (closed: boolean) => {
50
+ if (settled) return;
51
+ settled = true;
52
+ clearTimeout(timer);
53
+ lifecycle.changed.removeListener("changed", onChanged);
54
+ resolve(closed);
55
+ };
56
+ const onChanged = () => { if (lifecycle.closeObserved || noProcessStreamsClosed(lifecycle)) finish(true); };
57
+ const timer = setTimeout(() => finish(false), deadlineMs);
58
+ lifecycle.changed.on("changed", onChanged);
59
+ onChanged();
60
+ });
61
+ }
62
+
63
+ function waitForStartupControlClose(lifecycle: ChildLifecycle, deadlineMs: number): Promise<boolean> {
64
+ if (lifecycle.closeObserved) return Promise.resolve(true);
65
+ if (hasLifecycleError(lifecycle)) return Promise.resolve(false);
66
+ return new Promise((resolve) => {
67
+ let settled = false;
68
+ const finish = (closed: boolean) => {
69
+ if (settled) return;
70
+ settled = true;
71
+ clearTimeout(timer);
72
+ lifecycle.changed.removeListener("changed", onChanged);
73
+ resolve(closed);
74
+ };
75
+ const onChanged = () => { if (lifecycle.closeObserved) finish(true); else if (hasLifecycleError(lifecycle)) finish(false); };
76
+ const timer = setTimeout(() => finish(false), deadlineMs);
77
+ lifecycle.changed.on("changed", onChanged);
78
+ onChanged();
79
+ });
80
+ }
81
+
82
+ async function settleOwnedChild(child: CleanupChild, lifecycle: ChildLifecycle, deadlines: Readonly<{ terminateMs: number; killMs: number }>): Promise<void> {
83
+ if (lifecycle.closeObserved || noProcessStreamsClosed(lifecycle)) return;
84
+ try { child.stdin.end(); } catch { /* cleanup continues through bounded settlement */ }
85
+ if (await waitForChildClose(lifecycle, deadlines.terminateMs)) return;
86
+ if (child.pid === undefined && lifecycle.processError !== undefined) {
87
+ child.stdout.destroy?.();
88
+ child.stderr.destroy?.();
89
+ if (await waitForChildClose(lifecycle, deadlines.killMs)) return;
90
+ throw new Error("owned Windows helper did not settle after spawn failure");
91
+ }
92
+ try { child.kill(); } catch { /* the second bounded wait determines settlement */ }
93
+ if (await waitForChildClose(lifecycle, deadlines.killMs)) return;
94
+ child.stdout.destroy?.();
95
+ child.stderr.destroy?.();
96
+ throw new Error("owned Windows helper did not settle after termination");
97
+ }
98
+
99
+ const maxBootstrapDiagnosticBytes = 512;
100
+ const bootstrapDiagnosticCategories = new Set(["compiler", "argument", "invalid-operation", "not-supported", "security", "assembly-load", "type-load", "other"]);
101
+ const bootstrapDiagnosticReasons = new Set(["compiler-errors", "source-code-error", "type-already-exists", "reference-load", "unsupported", "unknown"]);
102
+ const bootstrapLanguageModes = new Set(["full", "constrained", "restricted", "no-language", "unknown"]);
103
+ type BootstrapDiagnostic = Readonly<{ kind: "windows-session-bootstrap-diagnostic"; category: "compiler" | "argument" | "invalid-operation" | "not-supported" | "security" | "assembly-load" | "type-load" | "other"; compilerCodes: readonly string[]; reason: "compiler-errors" | "source-code-error" | "type-already-exists" | "reference-load" | "unsupported" | "unknown"; languageMode: "full" | "constrained" | "restricted" | "no-language" | "unknown" }>;
104
+
105
+ function parseBootstrapDiagnostic(stderr: string): BootstrapDiagnostic | undefined {
106
+ if (Buffer.byteLength(stderr, "utf8") > maxBootstrapDiagnosticBytes || !stderr.endsWith("\n")) return undefined;
107
+ const lines = stderr.slice(0, -1).split("\n");
108
+ if (lines.length !== 1 || lines[0].length === 0) return undefined;
109
+ let value: unknown;
110
+ try { value = JSON.parse(lines[0]); } catch { return undefined; }
111
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return undefined;
112
+ const record = value as Record<string, unknown>;
113
+ const keys = Object.keys(record).sort();
114
+ if (keys.length !== 5 || keys.join(",") !== "category,compilerCodes,kind,languageMode,reason" || record.kind !== "windows-session-bootstrap-diagnostic" || typeof record.category !== "string" || !bootstrapDiagnosticCategories.has(record.category) || typeof record.reason !== "string" || !bootstrapDiagnosticReasons.has(record.reason) || typeof record.languageMode !== "string" || !bootstrapLanguageModes.has(record.languageMode) || !Array.isArray(record.compilerCodes) || record.compilerCodes.length > 8 || record.compilerCodes.some((code) => typeof code !== "string")) return undefined;
115
+ const compilerCodes = record.compilerCodes as string[];
116
+ if (new Set(compilerCodes).size !== compilerCodes.length || compilerCodes.some((code) => !/^CS[0-9]{4}$/.test(code)) || (record.category !== "compiler" && compilerCodes.length !== 0)) return undefined;
117
+ return Object.freeze({ kind: "windows-session-bootstrap-diagnostic", category: record.category as BootstrapDiagnostic["category"], compilerCodes: Object.freeze([...compilerCodes]), reason: record.reason as BootstrapDiagnostic["reason"], languageMode: record.languageMode as BootstrapDiagnostic["languageMode"] });
118
+ }
119
+
120
+ function appendBoundedOutput(output: string, chunk: Buffer, limit: number): Readonly<{ output: string; overflow: boolean }> {
121
+ const remaining = limit - Buffer.byteLength(output, "utf8");
122
+ if (remaining <= 0) return { output, overflow: true };
123
+ if (chunk.length <= remaining) return { output: output + chunk.toString("utf8"), overflow: false };
124
+ let end = remaining;
125
+ while (end > 0 && (chunk[end] & 0xc0) === 0x80) end--;
126
+ return { output: output + chunk.subarray(0, end).toString("utf8"), overflow: true };
127
+ }
128
+
129
+ const bootstrapRejectionStages = new Set(["volume-open", "ancestor-open", "routing-open", "transport-create-or-open", "transport-assert-owned", "presence-create-or-open", "presence-assert-owned", "unknown"]);
130
+ type BootstrapRejectionDiagnostic = Readonly<{ kind: "windows-session-bootstrap-rejection"; stage: "volume-open" | "ancestor-open" | "routing-open" | "transport-create-or-open" | "transport-assert-owned" | "presence-create-or-open" | "presence-assert-owned" | "unknown"; ntstatus: number | null }>;
131
+ type BootstrapDiagnosticContext = Readonly<{ diagnostic(message: string): void }>;
132
+
133
+ function emitBootstrapRejection(context: BootstrapDiagnosticContext, diagnostic: BootstrapRejectionDiagnostic): void {
134
+ context.diagnostic(JSON.stringify(diagnostic));
135
+ }
136
+
137
+ function parseBootstrapRejectionDiagnostic(stderr: string): BootstrapRejectionDiagnostic | undefined {
138
+ if (Buffer.byteLength(stderr, "utf8") > maxBootstrapDiagnosticBytes || !stderr.endsWith("\n")) return undefined;
139
+ const lines = stderr.slice(0, -1).split("\n");
140
+ if (lines.length !== 1 || lines[0].length === 0) return undefined;
141
+ let value: unknown;
142
+ try { value = JSON.parse(lines[0]); } catch { return undefined; }
143
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return undefined;
144
+ const record = value as Record<string, unknown>;
145
+ const keys = Object.keys(record).sort();
146
+ if (keys.length !== 3 || keys.join(",") !== "kind,ntstatus,stage" || record.kind !== "windows-session-bootstrap-rejection" || typeof record.stage !== "string" || !bootstrapRejectionStages.has(record.stage) || (record.ntstatus !== null && (!Number.isInteger(record.ntstatus) || typeof record.ntstatus !== "number" || record.ntstatus < 0 || record.ntstatus > 0xffffffff))) return undefined;
147
+ return Object.freeze({ kind: "windows-session-bootstrap-rejection", stage: record.stage as BootstrapRejectionDiagnostic["stage"], ntstatus: record.ntstatus as number | null });
148
+ }
149
+
150
+ const maxFixtureFailureDiagnosticBytes = 256;
151
+ const fixtureFailureStages = new Set(["replacement-copy", "replacement-acl", "replacement-rename"]);
152
+ const fixtureFailureCodeKinds = new Set(["hresult", "win32", "unknown"]);
153
+ type FixtureFailureDiagnostic = Readonly<{ kind: "windows-session-bootstrap-fixture-failure"; stage: "replacement-copy" | "replacement-acl" | "replacement-rename"; codeKind: "hresult" | "win32" | "unknown"; code: number | null }>;
154
+
155
+ function parseFixtureFailureDiagnostic(stdout: string): FixtureFailureDiagnostic | undefined {
156
+ if (Buffer.byteLength(stdout, "utf8") > maxFixtureFailureDiagnosticBytes || !stdout.endsWith("\n")) return undefined;
157
+ const lines = stdout.slice(0, -1).split("\n");
158
+ if (lines.length !== 1 || lines[0].length === 0) return undefined;
159
+ let value: unknown;
160
+ try { value = JSON.parse(lines[0]); } catch { return undefined; }
161
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return undefined;
162
+ const record = value as Record<string, unknown>;
163
+ const keys = Object.keys(record).sort();
164
+ if (keys.length !== 5 || keys.join(",") !== "code,codeKind,kind,ok,stage" || record.ok !== false || record.kind !== "windows-session-bootstrap-fixture-failure" || typeof record.stage !== "string" || !fixtureFailureStages.has(record.stage) || typeof record.codeKind !== "string" || !fixtureFailureCodeKinds.has(record.codeKind)) return undefined;
165
+ const diagnosticCode = record.code;
166
+ if (diagnosticCode !== null && (typeof diagnosticCode !== "number" || !Number.isSafeInteger(diagnosticCode) || diagnosticCode < -0x80000000 || diagnosticCode > 0x7fffffff || (record.codeKind === "win32" && diagnosticCode <= 0) || (record.codeKind === "hresult" && diagnosticCode === 0) || record.codeKind === "unknown")) return undefined;
167
+ if (diagnosticCode === null && record.codeKind !== "unknown") return undefined;
168
+ return Object.freeze({ kind: "windows-session-bootstrap-fixture-failure", stage: record.stage as FixtureFailureDiagnostic["stage"], codeKind: record.codeKind as FixtureFailureDiagnostic["codeKind"], code: diagnosticCode as number | null });
169
+ }
170
+
171
+ function fixtureFailureMessage(code: number, stdout: string): string {
172
+ if (code === 0) return "Windows fixture failed";
173
+ const diagnostic = parseFixtureFailureDiagnostic(stdout);
174
+ return diagnostic ? `Windows replacement fixture failed: ${diagnostic.stage}:${diagnostic.codeKind}:${diagnostic.code ?? "unknown"}` : "Windows fixture failed";
175
+ }
176
+
177
+ async function runBootstrapStartupControl(options: Readonly<{ spawnProcess?: (...args: any[]) => CleanupChild; startupDeadlineMs?: number; terminateMs?: number; killMs?: number }> = {}): Promise<Readonly<{ code: number; stdout: string; stderr: string; outputOverflow: boolean }>> {
178
+ const child = (options.spawnProcess ?? spawn)(FIXED_WINDOWS_POWERSHELL, ["-NoLogo", "-NoProfile", "-NonInteractive", "-File", runtime], { shell: false, windowsHide: true, stdio: ["pipe", "pipe", "pipe"] }) as CleanupChild;
179
+ const lifecycle = observeChildLifecycle(child);
180
+ const deadlines = { startupDeadlineMs: options.startupDeadlineMs ?? 30_000, terminateMs: options.terminateMs ?? 2_500, killMs: options.killMs ?? 2_500 };
181
+ let stdout = "";
182
+ let stderr = "";
183
+ let outputOverflow = false;
184
+ child.stdout.on("data", (chunk: Buffer) => { const captured = appendBoundedOutput(stdout, chunk, maxBootstrapDiagnosticBytes); stdout = captured.output; outputOverflow ||= captured.overflow; });
185
+ child.stderr.on("data", (chunk: Buffer) => { const captured = appendBoundedOutput(stderr, chunk, maxBootstrapDiagnosticBytes); stderr = captured.output; outputOverflow ||= captured.overflow; });
186
+ let inputWriteFailed = false;
187
+ try { child.stdin.end('{"requestId":"start-1","operation":"start"}\n{"requestId":"shutdown-2","operation":"shutdown"}\n'); } catch { inputWriteFailed = true; }
188
+ const closed = inputWriteFailed ? false : await waitForStartupControlClose(lifecycle, deadlines.startupDeadlineMs);
189
+ if (!closed || hasLifecycleError(lifecycle)) {
190
+ let cleanupFailed = false;
191
+ try { await settleOwnedChild(child, lifecycle, deadlines); } catch { cleanupFailed = true; }
192
+ throw new Error(cleanupFailed ? "Windows bootstrap startup control did not settle" : "Windows bootstrap startup control did not complete");
193
+ }
194
+ if (outputOverflow) throw new Error("Windows bootstrap startup control exceeded bounded output");
195
+ return { code: lifecycle.exitCode, stdout, stderr, outputOverflow };
196
+ }
197
+
198
+ type StartupMarker = "script-entered" | "native-ready";
199
+ const maxHelperControlBytes = 16_384;
200
+
201
+ class HelperControlStream {
202
+ private markerOrdinal = 0;
203
+ private startReplySeen = false;
204
+ private readonly requireStartupMarkers: boolean;
205
+ private readonly errorMessage: string;
206
+ constructor(requireStartupMarkers: boolean, errorMessage: string) {
207
+ this.requireStartupMarkers = requireStartupMarkers;
208
+ this.errorMessage = errorMessage;
209
+ }
210
+ push(rawLine: string): ReturnType<typeof parseWindowsHostFrame> | undefined {
211
+ const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
212
+ if (Buffer.byteLength(line, "utf8") > maxHelperControlBytes) throw new Error(this.errorMessage);
213
+ const marker = this.startupMarker(line);
214
+ if (marker !== undefined) {
215
+ const expected = this.markerOrdinal === 0 ? "script-entered" : this.markerOrdinal === 1 ? "native-ready" : undefined;
216
+ if (this.startReplySeen || marker !== expected) throw new Error(this.errorMessage);
217
+ this.markerOrdinal++;
218
+ return undefined;
219
+ }
220
+ let reply: ReturnType<typeof parseWindowsHostFrame>;
221
+ try { reply = parseWindowsHostFrame(line); } catch { throw new Error(this.errorMessage); }
222
+ if (!this.startReplySeen) {
223
+ if (reply.requestId !== "start-1" || (this.requireStartupMarkers && this.markerOrdinal !== 2) || (!this.requireStartupMarkers && this.markerOrdinal === 1)) throw new Error(this.errorMessage);
224
+ this.startReplySeen = true;
225
+ }
226
+ return reply;
227
+ }
228
+ assertStartupComplete() {
229
+ if (!this.startReplySeen || (this.requireStartupMarkers && this.markerOrdinal !== 2)) throw new Error(this.errorMessage);
230
+ }
231
+ private startupMarker(line: string): StartupMarker | undefined {
232
+ let value: unknown;
233
+ try { value = JSON.parse(line); } catch { return undefined; }
234
+ if (!value || typeof value !== "object" || Array.isArray(value) || Object.getPrototypeOf(value) !== Object.prototype || (value as Record<string, unknown>).event !== "startup-marker") return undefined;
235
+ const marker = value as Record<string, unknown>;
236
+ if (Object.keys(marker).length === 2 && marker.marker === "script-entered" && line === '{"event":"startup-marker","marker":"script-entered"}') return "script-entered";
237
+ if (Object.keys(marker).length === 2 && marker.marker === "native-ready" && line === '{"event":"startup-marker","marker":"native-ready"}') return "native-ready";
238
+ throw new Error(this.errorMessage);
239
+ }
240
+ }
241
+
242
+ function parseHelperControlOutput(stdout: string, requireStartupMarkers: boolean, errorMessage: string): readonly ReturnType<typeof parseWindowsHostFrame>[] {
243
+ if (!stdout.endsWith("\n")) throw new Error(errorMessage);
244
+ const stream = new HelperControlStream(requireStartupMarkers, errorMessage);
245
+ const frames: ReturnType<typeof parseWindowsHostFrame>[] = [];
246
+ for (const line of stdout.slice(0, -1).split("\n")) {
247
+ if (line.length === 0) throw new Error(errorMessage);
248
+ const frame = stream.push(line);
249
+ if (frame !== undefined) frames.push(frame);
250
+ }
251
+ stream.assertStartupComplete();
252
+ return frames;
253
+ }
254
+
255
+ function parseStartupControlFrames(stdout: string): readonly ReturnType<typeof parseWindowsHostFrame>[] {
256
+ return parseHelperControlOutput(stdout, true, "Windows bootstrap startup control returned malformed protocol output");
257
+ }
258
+
259
+ test("Windows helper control stream enforces fixed marker framing and order", () => {
260
+ const start = '{"requestId":"start-1","ok":true,"result":{"state":"partial"}}';
261
+ const shutdown = '{"requestId":"shutdown-2","ok":true,"result":{"state":"partial"}}';
262
+ const entered = '{"event":"startup-marker","marker":"script-entered"}';
263
+ const ready = '{"event":"startup-marker","marker":"native-ready"}';
264
+ assert.deepEqual(parseHelperControlOutput(`${entered}\r\n${ready}\n${start}\r\n${shutdown}\n`, true, "invalid helper control stream").map((frame) => frame.requestId), ["start-1", "shutdown-2"]);
265
+ assert.deepEqual(parseHelperControlOutput(`${start}\n${shutdown}\n`, false, "invalid helper control stream").map((frame) => frame.requestId), ["start-1", "shutdown-2"], "explicit fixture compatibility permits an uninstrumented helper");
266
+ for (const stream of [
267
+ `${ready}\n${start}\n`,
268
+ `${entered}\n${entered}\n${start}\n`,
269
+ `${entered}\n${start}\n`,
270
+ `${entered} \n${ready}\n${start}\n`,
271
+ `${entered}\n{"event":"startup-marker","marker":"unknown"}\n${start}\n`,
272
+ ]) assert.throws(() => parseHelperControlOutput(stream, true, "invalid helper control stream"), /invalid helper control stream/);
273
+ });
274
+
275
+ async function runPowerShell(script: string, args: string[], input = "", options: Readonly<{ spawnProcess?: (...args: any[]) => CleanupChild }> = {}): Promise<{ code: number; stdout: string; stderr: string; stderrOverflow: boolean }> {
276
+ const child = (options.spawnProcess ?? spawn)(FIXED_WINDOWS_POWERSHELL, ["-NoLogo", "-NoProfile", "-NonInteractive", "-File", script, ...args], { shell: false, windowsHide: true, stdio: ["pipe", "pipe", "pipe"] }) as CleanupChild;
277
+ const lifecycle = observeChildLifecycle(child);
278
+ let stdout = "";
279
+ let stderr = "";
280
+ let stderrOverflow = false;
281
+ child.stdout.on("data", (chunk: Buffer) => { stdout += chunk.toString("utf8"); });
282
+ child.stderr.on("data", (chunk: Buffer) => { const captured = appendBoundedOutput(stderr, chunk, maxBootstrapDiagnosticBytes); stderr = captured.output; stderrOverflow ||= captured.overflow; });
283
+ try { child.stdin.end(input); } catch { await settleOwnedChild(child, lifecycle, { terminateMs: 2_500, killMs: 2_500 }); throw new Error("Windows helper input could not close"); }
284
+ if (!await waitForChildClose(lifecycle, 30_000) || hasLifecycleError(lifecycle)) {
285
+ try { await settleOwnedChild(child, lifecycle, { terminateMs: 2_500, killMs: 2_500 }); } catch { throw new Error("Windows helper did not settle"); }
286
+ throw new Error("Windows helper did not complete");
287
+ }
288
+ return { code: lifecycle.exitCode, stdout, stderr, stderrOverflow };
289
+ }
290
+
291
+ async function openInitializedHelper(agentHome: string, options: Readonly<{ diagnostics: BootstrapDiagnosticContext; spawnProcess?: (...args: any[]) => CleanupChild; initialDeadlineMs?: number; responseDeadlineMs?: number; terminateMs?: number; killMs?: number }>) {
292
+ const child = (options.spawnProcess ?? spawn)(FIXED_WINDOWS_POWERSHELL, ["-NoLogo", "-NoProfile", "-NonInteractive", "-File", runtime], { shell: false, windowsHide: true, stdio: ["pipe", "pipe", "pipe"] }) as CleanupChild;
293
+ const lifecycle = observeChildLifecycle(child);
294
+ const deadlines = { initialDeadlineMs: options.initialDeadlineMs ?? 25_000, responseDeadlineMs: options.responseDeadlineMs ?? 3_000, terminateMs: options.terminateMs ?? 3_000, killMs: options.killMs ?? 3_000 };
295
+ const frames: ReturnType<typeof parseWindowsHostFrame>[] = [];
296
+ // Fake spawned children predate startup markers; real helper launches require them.
297
+ const controlStream = new HelperControlStream(options.spawnProcess === undefined, "Windows helper returned malformed protocol output");
298
+ let buffered = Buffer.alloc(0);
299
+ let protocolError: Error | undefined;
300
+ let outputFinalized = false;
301
+ const recordProtocolError = () => {
302
+ if (protocolError !== undefined) return;
303
+ protocolError = new Error("Windows helper returned malformed protocol output");
304
+ buffered = Buffer.alloc(0);
305
+ lifecycle.changed.emit("changed");
306
+ };
307
+ const finishOutput = () => {
308
+ if (outputFinalized) return;
309
+ outputFinalized = true;
310
+ if (buffered.length !== 0) recordProtocolError();
311
+ };
312
+ let stderr = "";
313
+ let stderrOverflow = false;
314
+ const rejectionChanged = new EventEmitter();
315
+ child.stderr.resume();
316
+ child.stderr.on("data", (chunk: Buffer) => { const captured = appendBoundedOutput(stderr, chunk, maxBootstrapDiagnosticBytes); stderr = captured.output; stderrOverflow ||= captured.overflow; rejectionChanged.emit("changed"); });
317
+ const waitFor = (count: number, deadlineMs: number) => new Promise<void>((resolve, reject) => {
318
+ let settled = false;
319
+ let pollTimer: ReturnType<typeof setTimeout> | undefined;
320
+ const onChanged = () => poll();
321
+ const settle = (error?: Error) => {
322
+ if (settled) return;
323
+ settled = true;
324
+ clearTimeout(deadlineTimer);
325
+ if (pollTimer) clearTimeout(pollTimer);
326
+ lifecycle.changed.removeListener("changed", onChanged);
327
+ if (error) reject(error); else resolve();
328
+ };
329
+ const deadlineTimer = setTimeout(() => settle(new Error("Windows helper did not reply")), deadlineMs);
330
+ const poll = () => {
331
+ if (pollTimer) { clearTimeout(pollTimer); pollTimer = undefined; }
332
+ if (protocolError !== undefined) return settle(protocolError);
333
+ if (lifecycle.closeObserved) {
334
+ finishOutput();
335
+ return settle(protocolError ?? new Error("Windows helper exited before its reply"));
336
+ }
337
+ if (lifecycle.processError) return settle(lifecycle.processError);
338
+ if (lifecycle.exitObserved) return settle(new Error("Windows helper exited before its reply"));
339
+ if (frames.length >= count) return settle();
340
+ pollTimer = setTimeout(poll, 25);
341
+ };
342
+ lifecycle.changed.on("changed", onChanged);
343
+ poll();
344
+ });
345
+ const waitForUnsafeRejection = () => new Promise<BootstrapRejectionDiagnostic>((resolve, reject) => {
346
+ let settled = false;
347
+ const finish = (error?: Error, diagnostic?: BootstrapRejectionDiagnostic) => {
348
+ if (settled) return;
349
+ settled = true;
350
+ clearTimeout(timer);
351
+ rejectionChanged.removeListener("changed", check);
352
+ lifecycle.changed.removeListener("changed", check);
353
+ if (error) reject(error); else resolve(diagnostic!);
354
+ };
355
+ const check = () => {
356
+ if (protocolError !== undefined) return finish(protocolError);
357
+ if (stderrOverflow) return finish(new Error("Windows helper unsafe rejection diagnostic exceeded bounded output"));
358
+ const diagnostic = parseBootstrapRejectionDiagnostic(stderr);
359
+ if (diagnostic) return finish(undefined, diagnostic);
360
+ if (lifecycle.closeObserved || lifecycle.processError) return finish(new Error("Windows helper unsafe rejection diagnostic was missing"));
361
+ };
362
+ const timer = setTimeout(() => finish(new Error("Windows helper unsafe rejection diagnostic was missing")), deadlines.responseDeadlineMs);
363
+ rejectionChanged.on("changed", check);
364
+ lifecycle.changed.on("changed", check);
365
+ check();
366
+ });
367
+ const exitWithin = async () => {
368
+ if (await waitForChildClose(lifecycle, deadlines.responseDeadlineMs)) return;
369
+ try { await closeOwnedChild(); } catch { throw new Error("Windows helper did not exit after a fatal schema error"); }
370
+ throw new Error("Windows helper did not exit after a fatal schema error");
371
+ }; const closeOwnedChild = () => settleOwnedChild(child, lifecycle, { terminateMs: deadlines.terminateMs, killMs: deadlines.killMs });
372
+ const closeWithStreamCheck = async () => {
373
+ let cleanupError: unknown;
374
+ try { await closeOwnedChild(); } catch (error) { cleanupError = error; }
375
+ finally { finishOutput(); }
376
+ if (protocolError !== undefined) throw protocolError;
377
+ if (cleanupError !== undefined) throw cleanupError;
378
+ };
379
+ child.stdout.on("data", (chunk: Buffer) => {
380
+ if (protocolError !== undefined) return;
381
+ if (!Buffer.isBuffer(chunk)) { recordProtocolError(); return; }
382
+ const output = buffered.length === 0 ? chunk : Buffer.concat([buffered, chunk]);
383
+ let offset = 0;
384
+ for (;;) {
385
+ const newline = output.indexOf(10, offset);
386
+ if (newline < 0) {
387
+ const suffix = output.subarray(offset);
388
+ if (suffix.length > maxHelperControlBytes + 1) recordProtocolError();
389
+ else buffered = Buffer.from(suffix);
390
+ return;
391
+ }
392
+ const bytes = output.subarray(offset, newline);
393
+ offset = newline + 1;
394
+ if (bytes.length > maxHelperControlBytes + 1) { recordProtocolError(); return; }
395
+ try {
396
+ const line = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
397
+ const frame = controlStream.push(line);
398
+ if (frame !== undefined) frames.push(frame);
399
+ } catch { recordProtocolError(); return; }
400
+ }
401
+ });
402
+ child.stdout.once("end", finishOutput);
403
+ child.stdout.once("close", finishOutput);
404
+ child.once("close", finishOutput);
405
+ try {
406
+ child.stdin.write('{"requestId":"start-1","operation":"start"}\n');
407
+ child.stdin.write(`${JSON.stringify({ requestId: "initialize-2", operation: "initialize", agentHome })}\n`);
408
+ await waitFor(2, deadlines.initialDeadlineMs);
409
+ controlStream.assertStartupComplete();
410
+ if (!frames[1].ok && frames[1].error === "unsafe") {
411
+ const diagnostic = await waitForUnsafeRejection();
412
+ emitBootstrapRejection(options.diagnostics, diagnostic);
413
+ }
414
+ } catch (error) {
415
+ try { await closeWithStreamCheck(); } catch { /* preserve the startup failure after owned cleanup */ }
416
+ throw error;
417
+ }
418
+ const request = async (operation: "enumerate" | "shutdown" | "record" | "publish" | "list" | "resolve" | "remove" | "listen" | "stop-listener", values: Record<string, unknown> = {}) => {
419
+ if (protocolError !== undefined) throw protocolError;
420
+ const count = frames.length + 1;
421
+ const requestId = `${operation}-${count}`;
422
+ child.stdin.write(`${JSON.stringify({ requestId, operation, ...values })}\n`);
423
+ await waitFor(count, deadlines.responseDeadlineMs);
424
+ const frame = frames[count - 1];
425
+ assert.equal(frame.requestId, requestId);
426
+ return frame;
427
+ };
428
+ return {
429
+ get frames() { return frames; },
430
+ get exited() { return lifecycle.closeObserved; },
431
+ get rejectionDiagnostic() { return stderrOverflow ? undefined : parseBootstrapRejectionDiagnostic(stderr); },
432
+ enumerate: () => request("enumerate"),
433
+ shutdown: () => request("shutdown"),
434
+ presence: (operation: "record" | "publish" | "list" | "resolve" | "remove" | "listen" | "stop-listener", values: Record<string, unknown> = {}) => request(operation, values),
435
+ invalidStartSchema: async () => { child.stdin.write(`${JSON.stringify({ requestId: `invalid-${frames.length + 1}`, operation: "start", extra: true })}\n`); await exitWithin(); },
436
+ closeInput: closeWithStreamCheck,
437
+ };
438
+ }
439
+
440
+ type InitializedHelper = Awaited<ReturnType<typeof openInitializedHelper>>;
441
+ async function withInitializedHelpers<T>(agentHomes: readonly string[], action: (helpers: readonly InitializedHelper[]) => Promise<T>, options: Readonly<{ diagnostics: BootstrapDiagnosticContext; spawnProcess?: (...args: any[]) => CleanupChild; initialDeadlineMs?: number; responseDeadlineMs?: number; terminateMs?: number; killMs?: number }>): Promise<T> {
442
+ const opened = await Promise.allSettled(agentHomes.map((agentHome) => openInitializedHelper(agentHome, options)));
443
+ const helpers: InitializedHelper[] = [];
444
+ let initializationError: unknown;
445
+ for (const outcome of opened) {
446
+ if (outcome.status === "fulfilled") helpers.push(outcome.value);
447
+ else if (initializationError === undefined) initializationError = outcome.reason;
448
+ }
449
+ try {
450
+ if (initializationError !== undefined) throw initializationError;
451
+ return await action(helpers);
452
+ } finally {
453
+ const cleanup = await Promise.allSettled(helpers.map((helper) => helper.closeInput()));
454
+ const failed = cleanup.find((outcome) => outcome.status === "rejected");
455
+ if (failed?.status === "rejected") throw failed.reason;
456
+ }
457
+ }
458
+
459
+ type HelperRequest = Readonly<{ requestId: string; operation: "start" | "initialize" | "enumerate" | "shutdown"; agentHome?: string }>;
460
+ function plannedHelperRequests(agentHome: string, enumerate: boolean): readonly HelperRequest[] {
461
+ return Object.freeze([
462
+ { requestId: "start-1", operation: "start" },
463
+ { requestId: "initialize-2", operation: "initialize", agentHome },
464
+ ...(enumerate ? [{ requestId: "enumerate-3", operation: "enumerate" as const }] : []),
465
+ { requestId: `shutdown-${enumerate ? 4 : 3}`, operation: "shutdown" },
466
+ ]);
467
+ }
468
+
469
+ async function helper(agentHome: string, enumerate = false, options: Readonly<{ diagnostics: BootstrapDiagnosticContext; spawnProcess?: (...args: any[]) => CleanupChild }>) {
470
+ const requests = plannedHelperRequests(agentHome, enumerate);
471
+ const result = await runPowerShell(runtime, [], requests.map((request) => JSON.stringify(request)).join("\n") + "\n", options);
472
+ assert.equal(result.code, 0);
473
+ const frames = parseHelperControlOutput(result.stdout, options.spawnProcess === undefined, "Windows helper returned malformed protocol output");
474
+ assert.equal(frames.length, requests.length);
475
+ assert.deepEqual(frames.map((frame) => frame.requestId), requests.map((request) => request.requestId));
476
+ if (frames.some((frame) => !frame.ok && frame.error === "unsafe")) {
477
+ if (result.stderrOverflow) throw new Error("Windows helper unsafe rejection diagnostic exceeded bounded output");
478
+ const diagnostic = parseBootstrapRejectionDiagnostic(result.stderr);
479
+ if (!diagnostic) throw new Error("Windows helper unsafe rejection diagnostic was missing");
480
+ emitBootstrapRejection(options.diagnostics, diagnostic);
481
+ }
482
+ return frames;
483
+ }
484
+
485
+ async function fixtureResult(mode: "capture" | "equals" | "measure" | "add-extra-ace" | "junction" | "rename" | "replace-identical" | "hardlink" | "append" | "exclusive-open", path: string, extra: string[] = []) {
486
+ const result = await runPowerShell(fixture, ["-Mode", mode, "-Path", path, ...extra]);
487
+ assert.equal(result.code, 0, fixtureFailureMessage(result.code, result.stdout));
488
+ return JSON.parse(result.stdout) as Record<string, boolean>;
489
+ }
490
+
491
+ const publicHostErrors = new Set(["unavailable", "unsafe", "busy", "not_found", "invalid"]);
492
+ function requirePublicPresenceResult(reply: unknown): unknown {
493
+ if (reply && typeof reply === "object") {
494
+ const frame = reply as Record<string, unknown>;
495
+ if (frame.ok === true && Object.prototype.hasOwnProperty.call(frame, "result")) return frame.result;
496
+ if (frame.ok === false && typeof frame.error === "string" && publicHostErrors.has(frame.error)) assert.fail(`Windows presence reply failed: ${frame.error}`);
497
+ }
498
+ assert.fail("Windows presence reply failed: unknown");
499
+ }
500
+
501
+ test("presence reply assertion preserves results and redacts malformed errors", () => {
502
+ const result = Object.freeze({ records: Object.freeze([]) });
503
+ assert.strictEqual(requirePublicPresenceResult({ ok: true, result }), result);
504
+ assert.throws(() => requirePublicPresenceResult({ ok: false, error: "unsafe" }), /Windows presence reply failed: unsafe/);
505
+ assert.throws(() => requirePublicPresenceResult({ ok: false, error: "C:\\private" }), /Windows presence reply failed: unknown/);
506
+ assert.throws(() => requirePublicPresenceResult(undefined), /Windows presence reply failed: unknown/);
507
+ });
508
+
509
+ class FakeHelperChild extends EventEmitter {
510
+ pid: number | undefined = 42;
511
+ endCalls = 0;
512
+ killCalls = 0;
513
+ destroyCalls = 0;
514
+ killResult = true;
515
+ readonly stdin = Object.assign(new EventEmitter(), { write: (_value: string) => { this.onWrite?.(); return true; }, end: () => { this.endCalls++; this.onEnd?.(); } });
516
+ readonly stdout = Object.assign(new EventEmitter(), { destroy: () => { this.destroyCalls++; } });
517
+ readonly stderr = Object.assign(new EventEmitter(), { resume: () => {}, destroy: () => { this.destroyCalls++; } });
518
+ onWrite?: () => void;
519
+ onEnd?: () => void;
520
+ kill() { this.killCalls++; return this.killResult; }
521
+ }
522
+
523
+ const fakeCleanupDeadlines = Object.freeze({ initialDeadlineMs: 40, responseDeadlineMs: 20, terminateMs: 10, killMs: 10 });
524
+ const unexpectedBootstrapDiagnostic: BootstrapDiagnosticContext = Object.freeze({ diagnostic: () => assert.fail("unexpected Windows bootstrap rejection diagnostic") });
525
+
526
+ test("owned helper cleanup settles a spawn error without an exit event", async () => {
527
+ const child = new FakeHelperChild();
528
+ child.pid = undefined;
529
+ const spawnError = new Error("spawn failed");
530
+ queueMicrotask(() => { child.emit("error", spawnError); child.stdin.emit("close"); child.stdout.emit("close"); child.stderr.emit("close"); });
531
+ await assert.rejects(openInitializedHelper("C:\\profile\\agent", { diagnostics: unexpectedBootstrapDiagnostic, spawnProcess: () => child as unknown as CleanupChild, ...fakeCleanupDeadlines }), /spawn failed/);
532
+ assert.equal(child.endCalls, 0);
533
+ assert.equal(child.killCalls, 0);
534
+ });
535
+
536
+ test("owned helper cleanup reports failure after two bounded termination waits", async () => {
537
+ const child = new FakeHelperChild();
538
+ child.killResult = false;
539
+ await assert.rejects(settleOwnedChild(child as unknown as CleanupChild, observeChildLifecycle(child as unknown as CleanupChild), { terminateMs: 10, killMs: 10 }), /did not settle/);
540
+ assert.equal(child.endCalls, 1);
541
+ assert.equal(child.killCalls, 1);
542
+ assert.equal(child.destroyCalls, 2);
543
+ });
544
+
545
+ test("owned helper cleanup settles normally without escalation", async () => {
546
+ const child = new FakeHelperChild();
547
+ const lifecycle = observeChildLifecycle(child as unknown as CleanupChild);
548
+ child.onEnd = () => child.emit("close");
549
+ await settleOwnedChild(child as unknown as CleanupChild, lifecycle, { terminateMs: 20, killMs: 20 });
550
+ assert.equal(child.endCalls, 1);
551
+ assert.equal(child.killCalls, 0);
552
+ });
553
+
554
+ test("held helper reports delayed unsafe rejection before an assertion failure and closes input", async () => {
555
+ const child = new FakeHelperChild();
556
+ let writes = 0;
557
+ child.onWrite = () => {
558
+ writes++;
559
+ if (writes === 2) queueMicrotask(() => {
560
+ child.stdout.emit("data", Buffer.from('{"requestId":"start-1","ok":true,"result":{"state":"partial"}}\n'));
561
+ child.stdout.emit("data", Buffer.from('{"requestId":"initialize-2","ok":false,"error":"unsafe"}\n'));
562
+ setTimeout(() => child.stderr.emit("data", Buffer.from('{"kind":"windows-session-bootstrap-rejection","stage":"transport-assert-owned","ntstatus":null}\n')), 5);
563
+ });
564
+ };
565
+ child.onEnd = () => child.emit("close", 0);
566
+ const emitted: string[] = [];
567
+ const diagnostics: BootstrapDiagnosticContext = { diagnostic: (message) => emitted.push(message) };
568
+ let owned: InitializedHelper | undefined;
569
+ await assert.rejects(withInitializedHelpers(["C:\\profile\\agent"], async ([held]) => {
570
+ owned = held;
571
+ assert.deepEqual(emitted, ['{"kind":"windows-session-bootstrap-rejection","stage":"transport-assert-owned","ntstatus":null}']);
572
+ assert.equal(held.frames[1].ok, true, "deliberate assertion failure after initialization");
573
+ }, { spawnProcess: () => child as unknown as CleanupChild, diagnostics, ...fakeCleanupDeadlines }), /deliberate assertion failure/);
574
+ assert.equal(child.endCalls, 1);
575
+ assert.equal(child.killCalls, 0);
576
+ assert.equal(owned?.exited, true);
577
+ });
578
+
579
+ test("held helper bounds a missing unsafe rejection diagnostic and closes input", async () => {
580
+ const child = new FakeHelperChild();
581
+ let writes = 0;
582
+ child.onWrite = () => {
583
+ writes++;
584
+ if (writes === 2) queueMicrotask(() => {
585
+ child.stdout.emit("data", Buffer.from('{"requestId":"start-1","ok":true,"result":{"state":"partial"}}\n'));
586
+ child.stdout.emit("data", Buffer.from('{"requestId":"initialize-2","ok":false,"error":"unsafe"}\n'));
587
+ });
588
+ };
589
+ child.onEnd = () => child.emit("close", 0);
590
+ await assert.rejects(openInitializedHelper("C:\\profile\\agent", { diagnostics: unexpectedBootstrapDiagnostic, spawnProcess: () => child as unknown as CleanupChild, ...fakeCleanupDeadlines }), /unsafe rejection diagnostic/);
591
+ assert.equal(child.endCalls, 1);
592
+ assert.equal(child.killCalls, 0);
593
+ });
594
+
595
+ test("normal helper emits a validated unsafe rejection through its diagnostic context", async (t) => {
596
+ const child = new FakeHelperChild();
597
+ child.onEnd = () => {
598
+ child.stdout.emit("data", Buffer.from('{"requestId":"start-1","ok":true,"result":{"state":"partial"}}\n'));
599
+ child.stdout.emit("data", Buffer.from('{"requestId":"initialize-2","ok":false,"error":"unsafe"}\n'));
600
+ child.stdout.emit("data", Buffer.from('{"requestId":"shutdown-3","ok":true,"result":{"state":"partial"}}\n'));
601
+ setTimeout(() => {
602
+ child.stderr.emit("data", Buffer.from('{"kind":"windows-session-bootstrap-rejection","stage":"transport-assert-owned","ntstatus":null}\n'));
603
+ child.emit("close", 0);
604
+ }, 5);
605
+ };
606
+ const emitted: string[] = [];
607
+ const diagnostics: BootstrapDiagnosticContext = { diagnostic: (message) => { emitted.push(message); t.diagnostic(message); } };
608
+ const frames = await helper("C:\\profile\\agent", false, { spawnProcess: () => child as unknown as CleanupChild, diagnostics });
609
+ assert.equal(frames[1].error, "unsafe");
610
+ assert.deepEqual(emitted, ['{"kind":"windows-session-bootstrap-rejection","stage":"transport-assert-owned","ntstatus":null}']);
611
+ assert.equal(child.endCalls, 1);
612
+ });
613
+
614
+ test("held helper reader rejects deferred malformed and duplicate control frames", async () => {
615
+ for (const { prefix, deferred, cleanupRejects } of [
616
+ { prefix: "", deferred: '{"event":"startup-marker","marker":"unknown"}\n', cleanupRejects: true },
617
+ { prefix: '{"event":"startup-marker","marker":"script-entered"}\n{"event":"startup-marker","marker":"native-ready"}\n', deferred: '{"event":"startup-marker","marker":"native-ready"}\n', cleanupRejects: false },
618
+ ]) {
619
+ const child = new FakeHelperChild();
620
+ let writes = 0;
621
+ child.onWrite = () => {
622
+ if (++writes !== 2) return;
623
+ queueMicrotask(() => {
624
+ child.stdout.emit("data", Buffer.from(`${prefix}{"requestId":"start-1","ok":true,"result":{"state":"partial"}}\n{"requestId":"initialize-2","ok":true,"result":{"state":"initialized","bootstrap":"complete"}}\n`));
625
+ child.stdout.emit("data", Buffer.from(deferred));
626
+ });
627
+ };
628
+ if (cleanupRejects) child.killResult = false;
629
+ else child.onEnd = () => child.emit("close", 0);
630
+ await assert.rejects(openInitializedHelper("C:\\profile\\agent", { diagnostics: unexpectedBootstrapDiagnostic, spawnProcess: () => child as unknown as CleanupChild, ...fakeCleanupDeadlines }), /malformed protocol output/);
631
+ assert.equal(child.endCalls, 1);
632
+ if (cleanupRejects) {
633
+ assert.equal(child.killCalls, 1);
634
+ assert.equal(child.destroyCalls, 2);
635
+ }
636
+ }
637
+ });
638
+
639
+ test("held helper reader rejects truncated and oversized suffixes after valid replies", async () => {
640
+ for (const suffix of [Buffer.from("{"), Buffer.alloc(maxHelperControlBytes + 2, 0x78)]) {
641
+ const child = new FakeHelperChild();
642
+ let writes = 0;
643
+ child.onWrite = () => {
644
+ if (++writes !== 2) return;
645
+ queueMicrotask(() => {
646
+ child.stdout.emit("data", Buffer.from('{"requestId":"start-1","ok":true,"result":{"state":"partial"}}\n{"requestId":"initialize-2","ok":true,"result":{"state":"initialized","bootstrap":"complete"}}\n'));
647
+ child.stdout.emit("data", suffix);
648
+ child.stdout.emit("end");
649
+ });
650
+ };
651
+ child.onEnd = () => child.emit("close", 0);
652
+ await assert.rejects(openInitializedHelper("C:\\profile\\agent", { diagnostics: unexpectedBootstrapDiagnostic, spawnProcess: () => child as unknown as CleanupChild, ...fakeCleanupDeadlines }), /malformed protocol output/);
653
+ assert.equal(child.endCalls, 1);
654
+ }
655
+ });
656
+
657
+ test("concurrent held helper ownership cleans fulfilled helpers after another initialization rejects", async () => {
658
+ const fulfilled = new FakeHelperChild();
659
+ let writes = 0;
660
+ fulfilled.onWrite = () => {
661
+ writes++;
662
+ if (writes === 2) queueMicrotask(() => {
663
+ fulfilled.stdout.emit("data", Buffer.from('{"requestId":"start-1","ok":true,"result":{"state":"partial"}}\n'));
664
+ fulfilled.stdout.emit("data", Buffer.from('{"requestId":"initialize-2","ok":true,"result":{"state":"initialized","bootstrap":"complete"}}\n'));
665
+ });
666
+ };
667
+ fulfilled.onEnd = () => fulfilled.emit("close", 0);
668
+ const rejected = new FakeHelperChild();
669
+ rejected.onWrite = () => queueMicrotask(() => rejected.emit("close", 1));
670
+ await assert.rejects(withInitializedHelpers(["C:\\profile\\agent", "C:\\profile\\agent"], async () => assert.fail("should not run after initialization rejection"), {
671
+ diagnostics: unexpectedBootstrapDiagnostic,
672
+ spawnProcess: (() => { let calls = 0; return () => (++calls === 1 ? fulfilled : rejected) as unknown as CleanupChild; })(),
673
+ ...fakeCleanupDeadlines,
674
+ }), /exited before its reply/);
675
+ assert.equal(fulfilled.endCalls, 1);
676
+ assert.equal(fulfilled.killCalls, 0);
677
+ });
678
+
679
+ test("owned helper cleanup waits for close after exit", async () => {
680
+ const child = new FakeHelperChild();
681
+ const lifecycle = observeChildLifecycle(child as unknown as CleanupChild);
682
+ queueMicrotask(() => child.emit("exit", 0));
683
+ setTimeout(() => child.emit("close", 0), 15);
684
+ assert.equal(await waitForChildClose(lifecycle, 40), true);
685
+ assert.equal(lifecycle.closeObserved, true);
686
+ });
687
+
688
+ test("owned helper cleanup fails bounded exit without close", async () => {
689
+ const child = new FakeHelperChild();
690
+ const lifecycle = observeChildLifecycle(child as unknown as CleanupChild);
691
+ queueMicrotask(() => child.emit("exit", 0));
692
+ assert.equal(await waitForChildClose(lifecycle, 15), false);
693
+ });
694
+
695
+ test("owned helper cleanup accepts an already observed close", async () => {
696
+ const child = new FakeHelperChild();
697
+ const lifecycle = observeChildLifecycle(child as unknown as CleanupChild);
698
+ child.emit("close", 0);
699
+ assert.equal(await waitForChildClose(lifecycle, 15), true);
700
+ });
701
+
702
+ test("startup control contains asynchronous stdin errors and waits for close", async () => {
703
+ const child = new FakeHelperChild();
704
+ child.onEnd = () => queueMicrotask(() => { child.stdin.emit("error", new Error("input failed")); child.emit("close", 1); });
705
+ await assert.rejects(runBootstrapStartupControl({ spawnProcess: () => child as unknown as CleanupChild, startupDeadlineMs: 20, terminateMs: 10, killMs: 10 }), /did not complete/);
706
+ assert.equal(child.endCalls, 1);
707
+ assert.equal(child.killCalls, 0);
708
+ });
709
+
710
+ test("startup control reports a bounded failure when stdin error never closes", async () => {
711
+ const child = new FakeHelperChild();
712
+ child.onEnd = () => queueMicrotask(() => child.stdin.emit("error", new Error("input failed")));
713
+ await assert.rejects(runBootstrapStartupControl({ spawnProcess: () => child as unknown as CleanupChild, startupDeadlineMs: 20, terminateMs: 10, killMs: 10 }), /did not settle/);
714
+ assert.equal(child.endCalls, 2);
715
+ assert.equal(child.killCalls, 1);
716
+ assert.equal(child.destroyCalls, 2);
717
+ });
718
+
719
+ test("premature helper close rejects initialization and bounded cleanup settles", async () => {
720
+ const child = new FakeHelperChild();
721
+ child.onWrite = () => child.emit("close");
722
+ await assert.rejects(openInitializedHelper("C:\\profile\\agent", { diagnostics: unexpectedBootstrapDiagnostic, spawnProcess: () => child as unknown as CleanupChild, ...fakeCleanupDeadlines }), /exited before its reply/);
723
+ assert.equal(child.killCalls, 0);
724
+ });
725
+
726
+ test("Windows helper constructs the native Volume GUID path with exactly one native prefix", async () => {
727
+ const source = await readFile(runtime, "utf8");
728
+ assert.ok(source.includes('return @"\\??\\" + volume.Substring(4);'));
729
+ });
730
+
731
+ test("Windows bootstrap source guard permits object-manager alias resolution only for the canonical volume root", async (t) => {
732
+ t.diagnostic("source guard, not native Windows proof");
733
+ const source = await readFile(runtime, "utf8");
734
+ assert.match(source, /static OpenResult OpenVolume\(string volumePath\)/);
735
+ assert.match(source, /static IntPtr RequireVolumeOpen\(string volumePath, uint volumeSerial\)/);
736
+ assert.match(source, /SetStage\("volume-open"\); IntPtr volume = RequireVolumeOpen\(VolumePath\(agentHome, out volumeSerial\), volumeSerial\)/);
737
+ assert.doesNotMatch(source, /RequireOpen\(IntPtr\.Zero, VolumePath\(agentHome\)/);
738
+ const volumeStart = source.indexOf("static OpenResult OpenVolume(string volumePath)");
739
+ const volumeEnd = source.indexOf("static void AssertDirectory", volumeStart);
740
+ assert.ok(volumeStart >= 0 && volumeEnd > volumeStart, "source guard: canonical-volume root opener was not found");
741
+ const volumeOpen = source.slice(volumeStart, volumeEnd);
742
+ assert.match(volumeOpen, /attributes\.Attributes = OBJ_CASE_INSENSITIVE;/);
743
+ assert.doesNotMatch(volumeOpen, /OBJ_DONT_REPARSE/);
744
+ assert.match(volumeOpen, /FILE_DIRECTORY_FILE \| FILE_SYNCHRONOUS_IO_NONALERT \| FILE_OPEN_REPARSE_POINT/);
745
+ const componentStart = source.indexOf("static OpenResult Open(IntPtr root, string name, bool privateDirectory, bool create, byte[] descriptor)");
746
+ const componentEnd = source.indexOf("// OBJ_DONT_REPARSE", componentStart);
747
+ assert.ok(componentStart >= 0 && componentEnd > componentStart, "source guard: component opener was not found");
748
+ const componentOpen = source.slice(componentStart, componentEnd);
749
+ assert.match(componentOpen, /attributes\.Attributes = OBJ_CASE_INSENSITIVE \| OBJ_DONT_REPARSE;/);
750
+ assert.match(componentOpen, /FILE_DIRECTORY_FILE \| FILE_SYNCHRONOUS_IO_NONALERT \| FILE_OPEN_REPARSE_POINT/);
751
+ assert.match(source, /if \(!GetFileInformationByHandle\(result\.Handle, out info\) \|\| info\.VolumeSerialNumber != volumeSerial\) Fail\("unsafe"\);/);
752
+ });
753
+
754
+ test("Windows bootstrap bridge admits only explicit partial or initialized public states", () => {
755
+ assert.deepEqual(parseWindowsHostFrame('{"requestId":"start-1","ok":true,"result":{"state":"partial"}}'), {
756
+ requestId: "start-1", ok: true, result: { state: "partial" },
757
+ });
758
+ assert.deepEqual(parseWindowsHostFrame('{"requestId":"initialize-2","ok":true,"result":{"state":"initialized","bootstrap":"complete"}}'), {
759
+ requestId: "initialize-2", ok: true, result: { state: "initialized", bootstrap: "complete" },
760
+ });
761
+ assert.deepEqual(parseWindowsHostFrame('{"requestId":"enumerate-3","ok":true,"result":{"state":"initialized","bootstrap":"complete","entries":2}}'), {
762
+ requestId: "enumerate-3", ok: true, result: { state: "initialized", bootstrap: "complete", entries: 2 },
763
+ });
764
+ assert.throws(() => parseWindowsHostFrame('{"requestId":"start-1","ok":true,"result":{"ready":true}}'), /invalid Windows transport frame/);
765
+ });
766
+
767
+ test("Windows helper request plans correlate standalone and enumeration reply counts", () => {
768
+ assert.deepEqual(plannedHelperRequests("C:\\profile\\agent", false).map((request) => request.requestId), ["start-1", "initialize-2", "shutdown-3"]);
769
+ assert.deepEqual(plannedHelperRequests("C:\\profile\\agent", true).map((request) => request.requestId), ["start-1", "initialize-2", "enumerate-3", "shutdown-4"]);
770
+ });
771
+
772
+ test("Windows startup marker source emits fixed ordinal control records", async (t) => {
773
+ t.diagnostic("source guard, not native Windows timing proof");
774
+ const source = await readFile(runtime, "utf8");
775
+ const scriptEntered = source.indexOf("[Console]::Out.WriteLine('{\"event\":\"startup-marker\",\"marker\":\"script-entered\"}')");
776
+ const strictMode = source.indexOf("Set-StrictMode -Version Latest");
777
+ const addType = source.indexOf("Add-Type -ErrorAction Stop");
778
+ const nativeReady = source.indexOf("[WindowsSessionBootstrap]::WriteControl('{\"event\":\"startup-marker\",\"marker\":\"native-ready\"}')");
779
+ assert.ok(scriptEntered >= 0 && strictMode > scriptEntered && addType > strictMode && nativeReady > addType, "startup markers must bound, not replace, the bootstrap interval");
780
+ assert.match(source.slice(scriptEntered, strictMode), /^\[Console\]::Out\.WriteLine\('\{"event":"startup-marker","marker":"script-entered"\}'\)\r?\n$/);
781
+ assert.match(source.slice(nativeReady, source.indexOf("\n", nativeReady)), /^\s*\[WindowsSessionBootstrap\]::WriteControl\('\{"event":"startup-marker","marker":"native-ready"\}'\)\r?$/);
782
+ });
783
+
784
+ test("packed Windows startup timing source guard uses the installed helper direct driver", async (t) => {
785
+ t.diagnostic("source guard, not hosted Windows timing proof");
786
+ const source = await readFile(packedRunner, "utf8");
787
+ assert.match(source, /const WINDOWS_STARTUP_TIMING_BUDGET_MS = 25_000;/);
788
+ assert.ok(source.includes('const WINDOWS_STARTUP_TIMING_POWERSHELL = "C:\\\\Windows\\\\System32\\\\WindowsPowerShell\\\\v1.0\\\\powershell.exe";'));
789
+ assert.match(source, /spawn\(WINDOWS_STARTUP_TIMING_POWERSHELL, \["-NoLogo", "-NoProfile", "-NonInteractive", "-File", runtimeScript\], \{ cwd, env, shell: false, windowsHide: true, stdio: \["pipe", "pipe", "pipe"\] \}\)/);
790
+ assert.match(source, /child\.stdin\.end\(WINDOWS_STARTUP_TIMING_START_REQUEST/);
791
+ assert.match(source, /WINDOWS_STARTUP_TIMING_VALID_START_REPLIES\.has\(line\) \|\| markerOrdinal !== 2/);
792
+ assert.match(source, /WINDOWS_STARTUP_TIMING_REJECTED_START_REPLY\.test\(line\)/);
793
+ assert.match(source, /line\.length >= 3 && line\[0\] === 0xef && line\[1\] === 0xbb && line\[2\] === 0xbf/);
794
+ assert.match(source, /const elapsedMs = Number\(process\.hrtime\.bigint\(\) - startedAt\) \/ 1e6;/);
795
+ assert.match(source, /mode: "windows-startup-timing"/);
796
+ assert.doesNotMatch(source, /new WindowsSessionTransportHost\(\{[^}]*rpcDeadlineMs: WINDOWS_STARTUP_TIMING_BUDGET_MS/);
797
+ const helper = await readFile(runtime, "utf8");
798
+ assert.match(helper, /function Write-Reply\([\s\S]*?@\{ requestId = \$requestId; ok = \$true; result = \$result \} \| ConvertTo-Json -Compress -Depth 4/);
799
+ const timingDriver = source.slice(source.indexOf("function runWindowsStartupTimingProbe"), source.indexOf("async function testHookedPackedRunner"));
800
+ assert.doesNotMatch(timingDriver, /JSON\.parse/);
801
+ });
802
+
803
+ test("Windows startup environment delta admits only the fixed machine path allowlist", () => {
804
+ const source = {
805
+ ProgramFiles: "C:\\Program Files",
806
+ "ProgramFiles(x86)": "C:\\Program Files (x86)",
807
+ ProgramW6432: "C:\\Program Files",
808
+ SystemRoot: "C:\\Windows",
809
+ };
810
+ const delta = deriveWindowsStartupTimingPathDelta(source);
811
+ assert.equal(delta.ready, true);
812
+ assert.deepEqual(delta.pathAdditionKeys, WINDOWS_STARTUP_TIMING_WINDOWS_PATH_KEYS);
813
+ assert.deepEqual(delta.values, {
814
+ ProgramFiles: "C:\\Program Files",
815
+ "ProgramFiles(x86)": "C:\\Program Files (x86)",
816
+ ProgramW6432: "C:\\Program Files",
817
+ CommonProgramFiles: "C:\\Program Files\\Common Files",
818
+ "CommonProgramFiles(x86)": "C:\\Program Files (x86)\\Common Files",
819
+ CommonProgramW6432: "C:\\Program Files\\Common Files",
820
+ PSModulePath: "C:\\Program Files\\WindowsPowerShell\\Modules;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\Modules",
821
+ });
822
+ for (const invalid of [
823
+ { ...source, ProgramFiles: "C:\\Program Files\n" },
824
+ { ...source, ProgramFiles: "C:\\Program Files\0" },
825
+ { ProgramFiles: source.ProgramFiles, "ProgramFiles(x86)": source["ProgramFiles(x86)"], SystemRoot: source.SystemRoot },
826
+ { ...source, programfiles: "D:\\Program Files" },
827
+ { ...source, ProgramFiles: "C:\\Program Files\\..\\Users" },
828
+ ]) assert.equal(deriveWindowsStartupTimingPathDelta(invalid).ready, false);
829
+ assert.equal(deriveWindowsStartupTimingPathDelta({ ...source, programfiles: source.ProgramFiles }).ready, true, "same-value aliases have an explicit deterministic policy");
830
+ });
831
+
832
+ test("Windows startup environment operational validation rejects noncanonical machine paths", () => {
833
+ const delta = deriveWindowsStartupTimingPathDelta({
834
+ ProgramFiles: "C:\\Program Files", "ProgramFiles(x86)": "C:\\Program Files (x86)", ProgramW6432: "C:\\Program Files", SystemRoot: "C:\\Windows",
835
+ });
836
+ const filesystem = { lstat: () => ({ isDirectory: () => true, isSymbolicLink: () => false }), realpath: (path: string) => path };
837
+ assert.equal(validateWindowsStartupTimingMachinePaths(delta, filesystem), true);
838
+ assert.equal(validateWindowsStartupTimingMachinePaths(delta, { ...filesystem, realpath: () => "C:\\Users" }), false);
839
+ assert.equal(validateWindowsStartupTimingMachinePaths(delta, { ...filesystem, lstat: () => ({ isDirectory: () => true, isSymbolicLink: () => true }) }), false);
840
+ });
841
+
842
+ test("Windows packed runner entrypoint guard distinguishes imports, aliases, and unresolved entries", () => {
843
+ const resolvePath = (path: string) => path;
844
+ const inert = { identity: "import", runModes: false, exitCode: null };
845
+ assert.deepEqual(decidePackedRunnerEntrypoint("/repo/runner.mjs", undefined, "linux", { resolvePath, realpath: (path: string) => path }), inert);
846
+ assert.deepEqual(decidePackedRunnerEntrypoint("/repo/runner.mjs", "/repo/alias.mjs", "linux", { resolvePath, realpath: () => "/repo/runner.mjs" }), { identity: "main", runModes: true, exitCode: null });
847
+ assert.deepEqual(decidePackedRunnerEntrypoint("C:\\Repo Dir\\Runner.mjs", "c:\\repo dir\\runner.mjs", "win32", { resolvePath, realpath: (path: string) => path }), { identity: "main", runModes: true, exitCode: null });
848
+ assert.deepEqual(decidePackedRunnerEntrypoint("/repo/runner.mjs", "/repo/other.mjs", "linux", { resolvePath, realpath: (path: string) => path }), inert);
849
+ assert.deepEqual(decidePackedRunnerEntrypoint("/repo/runner.mjs", "/foreign-cli.mjs", "linux", { resolvePath, realpath: () => { throw new Error("unresolved"); } }), inert, "a foreign importer with an unresolvable argv entry cannot set an exit code or run a mode");
850
+ assert.deepEqual(decidePackedRunnerEntrypoint("/repo/runner.mjs", "/repo/runner.mjs", "linux", { resolvePath, realpath: () => { throw new Error("unresolved"); } }), { identity: "direct-unresolved", runModes: false, exitCode: 1 });
851
+ });
852
+
853
+ test("Windows packed startup environment experiment source guard selects the paired CI case", async (t) => {
854
+ t.diagnostic("source guard, not hosted Windows environment experiment proof");
855
+ const source = await readFile(packedRunner, "utf8");
856
+ assert.match(source, /WINDOWS_STARTUP_TIMING_ENVIRONMENT_CASE_NAMES = Object\.freeze\(\["baseline", "windows-paths"\]\)/);
857
+ assert.match(source, /export function deriveWindowsStartupTimingPathDelta\(source\)/);
858
+ assert.match(source, /const pathDelta = deriveWindowsStartupTimingPathDelta\(process\.env\)/);
859
+ assert.match(source, /const treatmentPathDelta = validateWindowsStartupTimingMachinePaths\(pathDelta\) \? pathDelta : undefined/);
860
+ assert.match(source, /isTreatment \? Object\.assign\(\{\}, isolatedEnv, treatmentPathDelta\.values\) : isolatedEnv/);
861
+ assert.match(source, /caseOrder: "baseline-first-fixed"/);
862
+ assert.match(source, /sharedState: "shared-owned-home-and-cache"/);
863
+ assert.match(source, /confounders: "baseline-first-order-and-cache-effects"/);
864
+ assert.match(source, /conclusion: "no-causal-attribution-not-product-ready"/);
865
+ assert.match(source, /mode: "windows-startup-timing-environment"/);
866
+ assert.match(source, /receipt\.cases\[0\]\.physicalCloseObserved !== true/);
867
+ const environmentFactory = source.slice(source.indexOf("function isValidatedWindowsMachineRoot"), source.indexOf("function assertPackResult"));
868
+ const environmentExperiment = source.slice(source.indexOf("async function testWindowsStartupTimingEnvironmentExperiment"), source.indexOf("async function testUnhookedPackedImports"));
869
+ assert.doesNotMatch(environmentFactory, /\.\.\.process\.env/);
870
+ assert.doesNotMatch(environmentExperiment, /\.\.\.process\.env/);
871
+ assert.doesNotMatch(environmentFactory, /PSModulePath:\s*process\.env/);
872
+ const workflow = await readFile(fileURLToPath(new URL("../.github/workflows/windows-session-bootstrap.yml", import.meta.url)), "utf8");
873
+ assert.match(workflow, /workflow_dispatch:\s+inputs:\s+run_windows_startup_experiment:\s+description: "Run the completed paired Windows startup experiment"\s+required: false\s+default: false\s+type: boolean/);
874
+ assert.match(workflow, /Measure paired packed Windows helper startup environment experiment \(experimental\)/);
875
+ assert.match(workflow, /if: "!cancelled\(\) && inputs\.run_windows_startup_experiment == true && matrix\.platform == 'windows' && steps\.install_windows_dependencies\.outcome == 'success'"/);
876
+ assert.match(workflow, /Prove packed real SDK session lifecycle \(Windows\)\s+if: "!cancelled\(\) && matrix\.platform == 'windows' && steps\.install_windows_dependencies\.outcome == 'success'"/);
877
+ assert.match(workflow, /node scripts\\test-packed-runner\.mjs --windows-startup-timing-environment/);
878
+ for (const title of [
879
+ "Windows startup environment delta admits only the fixed machine path allowlist",
880
+ "Windows startup environment operational validation rejects noncanonical machine paths",
881
+ "Windows packed startup environment experiment source guard selects the paired CI case",
882
+ "Windows packed runner entrypoint guard distinguishes imports, aliases, and unresolved entries",
883
+ ]) assert.ok(workflow.includes(title));
884
+ assert.doesNotMatch(workflow, /node scripts\\test-packed-runner\.mjs --windows-startup-timing\n/);
885
+ });
886
+
887
+ test("Windows bootstrap Add-Type failures use an owned bounded diagnostic", async () => {
888
+ const source = await readFile(runtime, "utf8");
889
+ assert.match(source, /Add-Type -ErrorAction Stop -ErrorVariable \+addTypeErrors -TypeDefinition @'/);
890
+ assert.match(source, /catch \{\s*\$nativeReady = \$false\s*Write-BootstrapDiagnostic \(@\(\$addTypeErrors\) \+ @\(\$_\)\)\s*\}/);
891
+ });
892
+
893
+ test("Windows bootstrap captures only local Add-Type records and fixed metadata", async () => {
894
+ const source = await readFile(runtime, "utf8");
895
+ assert.match(source, /\$addTypeErrors = @\(\)/);
896
+ assert.match(source, /-ErrorVariable \+addTypeErrors/);
897
+ assert.match(source, /reason = \$reason; languageMode = \$languageMode/);
898
+ assert.doesNotMatch(source, /\$Error\b/);
899
+ });
900
+
901
+ test("Windows bootstrap diagnostic guards wrapped Add-Type entries under StrictMode", async () => {
902
+ const source = await readFile(runtime, "utf8");
903
+ assert.match(source, /function Get-BootstrapProperty/);
904
+ assert.match(source, /function ConvertTo-BootstrapDiagnosticRecord/);
905
+ assert.match(source, /\.PSObject\.Properties\[\$name\]/);
906
+ assert.match(source, /\$candidate -is \[System\.Management\.Automation\.ErrorRecord\]/);
907
+ assert.match(source, /\$wrapped = Get-BootstrapProperty \$candidate 'ErrorRecord'/);
908
+ assert.match(source, /\$wrapped -is \[System\.Management\.Automation\.ErrorRecord\]/);
909
+ assert.match(source, /function Write-BootstrapDiagnosticFallback/);
910
+ assert.match(source, /catch \{ Write-BootstrapDiagnosticFallback \}/);
911
+ assert.doesNotMatch(source, /\$record\.CategoryInfo|\$record\.ErrorDetails|\$record\.Exception/);
912
+ });
913
+
914
+ test("Windows bootstrap source guard—not native proof—extracts only structured compiler ErrorNumber values", async (t) => {
915
+ t.diagnostic("source guard, not native Windows proof");
916
+ const source = await readFile(runtime, "utf8");
917
+ assert.match(source, /TargetObject/);
918
+ assert.match(source, /function Get-BootstrapCompilerErrorCode/);
919
+ assert.match(source, /\$target -isnot \[System\.CodeDom\.Compiler\.CompilerError\]/);
920
+ assert.match(source, /Get-BootstrapProperty \$target 'ErrorNumber'/);
921
+ assert.ok(source.includes(String.raw`$errorNumber -cmatch '\ACS[0-9]{4}\z'`));
922
+ assert.doesNotMatch(source, /TargetObject\.ToString/);
923
+ assert.doesNotMatch(source, /Get-BootstrapProperty \$target 'ErrorText'/);
924
+ });
925
+
926
+ test("Windows bootstrap rejection diagnostic is fixed-stage evidence, not native Windows compile proof", async (t) => {
927
+ t.diagnostic("source guard, not native Windows compile proof");
928
+ const source = await readFile(runtime, "utf8");
929
+ assert.match(source, /public readonly uint\? NtStatus/);
930
+ assert.match(source, /SetNtStatus\(result\.Status\)/);
931
+ assert.match(source, /Write-BootstrapRejectionDiagnostic \$_\.Exception/);
932
+ assert.match(source, /kind = 'windows-session-bootstrap-rejection'; stage = \$stage; ntstatus = \$ntstatus/);
933
+ assert.doesNotMatch(source, /new BootstrapFailure\("unsafe"\)/);
934
+ const rejectionWriter = source.match(/function Write-BootstrapRejectionDiagnostic[\s\S]*?\n\}/)?.[0];
935
+ assert.ok(rejectionWriter);
936
+ assert.doesNotMatch(rejectionWriter, /\.HasValue|\.Value|GetLastErrorText|ToString\(\)|Message|StackTrace/);
937
+ });
938
+
939
+ test("Windows bootstrap diagnostic parser accepts fixed Add-Type evidence", () => {
940
+ assert.deepEqual(parseBootstrapDiagnostic('{"kind":"windows-session-bootstrap-diagnostic","category":"compiler","compilerCodes":["CS1001","CS1739"],"reason":"source-code-error","languageMode":"full"}\n'), {
941
+ kind: "windows-session-bootstrap-diagnostic", category: "compiler", compilerCodes: ["CS1001", "CS1739"], reason: "source-code-error", languageMode: "full",
942
+ });
943
+ assert.deepEqual(parseBootstrapDiagnostic('{"kind":"windows-session-bootstrap-diagnostic","category":"other","compilerCodes":[],"reason":"unknown","languageMode":"constrained"}\n'), {
944
+ kind: "windows-session-bootstrap-diagnostic", category: "other", compilerCodes: [], reason: "unknown", languageMode: "constrained",
945
+ });
946
+ assert.deepEqual(parseBootstrapDiagnostic('{"kind":"windows-session-bootstrap-diagnostic","category":"other","compilerCodes":[],"reason":"unknown","languageMode":"unknown"}\n'), {
947
+ kind: "windows-session-bootstrap-diagnostic", category: "other", compilerCodes: [], reason: "unknown", languageMode: "unknown",
948
+ });
949
+ });
950
+
951
+ test("Windows bootstrap diagnostic parser fails closed for unsafe input", () => {
952
+ assert.equal(parseBootstrapDiagnostic('{"kind":"windows-session-bootstrap-diagnostic","category":"other","compilerCodes":["CS1001"],"reason":"unknown","languageMode":"full"}\n'), undefined);
953
+ assert.equal(parseBootstrapDiagnostic('{"kind":"windows-session-bootstrap-diagnostic","category":"compiler","compilerCodes":["CS1001","CS1001"],"reason":"source-code-error","languageMode":"full"}\n'), undefined);
954
+ assert.equal(parseBootstrapDiagnostic('{"kind":"windows-session-bootstrap-diagnostic","category":"compiler","compilerCodes":[],"reason":"untrusted-error-id","languageMode":"full"}\n'), undefined);
955
+ assert.equal(parseBootstrapDiagnostic("x".repeat(maxBootstrapDiagnosticBytes + 1)), undefined);
956
+ });
957
+
958
+ test("Windows bootstrap rejection parser admits only fixed native phase evidence", () => {
959
+ assert.deepEqual(parseBootstrapRejectionDiagnostic('{"kind":"windows-session-bootstrap-rejection","stage":"transport-assert-owned","ntstatus":null}\n'), {
960
+ kind: "windows-session-bootstrap-rejection", stage: "transport-assert-owned", ntstatus: null,
961
+ });
962
+ assert.deepEqual(parseBootstrapRejectionDiagnostic('{"kind":"windows-session-bootstrap-rejection","stage":"ancestor-open","ntstatus":3221225524}\n'), {
963
+ kind: "windows-session-bootstrap-rejection", stage: "ancestor-open", ntstatus: 3221225524,
964
+ });
965
+ assert.equal(parseBootstrapRejectionDiagnostic('{"kind":"windows-session-bootstrap-rejection","stage":"transport-assert-owned","ntstatus":-1}\n'), undefined);
966
+ assert.equal(parseBootstrapRejectionDiagnostic('{"kind":"windows-session-bootstrap-rejection","stage":"transport-assert-owned","ntstatus":1.5}\n'), undefined);
967
+ assert.equal(parseBootstrapRejectionDiagnostic('{"kind":"windows-session-bootstrap-rejection","stage":"transport-assert-owned","ntstatus":0,"sid":"S-1-5-18"}\n'), undefined);
968
+ assert.equal(parseBootstrapRejectionDiagnostic('{"kind":"windows-session-bootstrap-rejection","stage":"transport-assert-owned","ntstatus":null}' + " ".repeat(maxBootstrapDiagnosticBytes) + "\n"), undefined);
969
+ });
970
+
971
+ test("Windows fixture replacement failure parser admits only fixed diagnostic evidence", () => {
972
+ const copyFailure = '{"ok":false,"kind":"windows-session-bootstrap-fixture-failure","stage":"replacement-copy","codeKind":"hresult","code":-2147024864}\n';
973
+ assert.deepEqual(parseFixtureFailureDiagnostic(copyFailure), { kind: "windows-session-bootstrap-fixture-failure", stage: "replacement-copy", codeKind: "hresult", code: -2147024864 });
974
+ assert.deepEqual(parseFixtureFailureDiagnostic('{"ok":false,"kind":"windows-session-bootstrap-fixture-failure","stage":"replacement-rename","codeKind":"unknown","code":null}\n'), { kind: "windows-session-bootstrap-fixture-failure", stage: "replacement-rename", codeKind: "unknown", code: null });
975
+ assert.equal(fixtureFailureMessage(1, copyFailure), "Windows replacement fixture failed: replacement-copy:hresult:-2147024864");
976
+ assert.equal(fixtureFailureMessage(1, '{"ok":false,"kind":"windows-session-bootstrap-fixture-failure","stage":"replacement-copy","codeKind":"hresult","code":-2147024864,"path":"private"}\n'), "Windows fixture failed");
977
+ assert.equal(parseFixtureFailureDiagnostic('{"ok":false,"kind":"windows-session-bootstrap-fixture-failure","stage":"replacement-acl","codeKind":"win32","code":-1}\n'), undefined);
978
+ assert.equal(parseFixtureFailureDiagnostic('{"ok":false,"kind":"windows-session-bootstrap-fixture-failure","stage":"replacement-acl","codeKind":"win32","code":0}\n'), undefined);
979
+ assert.equal(parseFixtureFailureDiagnostic('{"ok":false,"kind":"windows-session-bootstrap-fixture-failure","stage":"replacement-acl","codeKind":"hresult","code":0}\n'), undefined);
980
+ assert.equal(parseFixtureFailureDiagnostic('{"ok":false,"kind":"windows-session-bootstrap-fixture-failure","stage":"replacement-copy","codeKind":"unknown","code":0}\n'), undefined);
981
+ assert.equal(parseFixtureFailureDiagnostic("x".repeat(maxFixtureFailureDiagnosticBytes + 1)), undefined);
982
+ });
983
+
984
+ test("Windows fixture replacement failures expose only fixed stages and numeric codes", async (t) => {
985
+ t.diagnostic("source guard, not native Windows proof");
986
+ const source = await readFile(fixture, "utf8");
987
+ assert.match(source, /\$replacementStage = 'replacement-copy'[\s\S]*?\[IO\.File\]::Copy/);
988
+ assert.match(source, /\$replacementStage = 'replacement-acl'\s*Set-Acl/);
989
+ assert.match(source, /\$original = "\$Path\.original-\$\(\[Guid\]::NewGuid\(\)\.ToString\('N'\)\)"/);
990
+ assert.match(source, /\$replacementStage = 'replacement-rename'[\s\S]*?MoveFileEx\(\$Path, \$original, 0\)/);
991
+ assert.match(source, /MoveFileEx\(\$temp, \$Path, 0\)/);
992
+ assert.doesNotMatch(source, /MoveFileEx\(\$temp, \$Path, 1\)/);
993
+ assert.match(source, /\[Runtime\.InteropServices\.Marshal\]::GetLastWin32Error\(\)/);
994
+ assert.match(source, /kind = 'windows-session-bootstrap-fixture-failure'; stage = \$replacementStage; codeKind = \$replacementCodeKind; code = \$replacementCode/);
995
+ assert.doesNotMatch(source, /replacementStage[\s\S]*?\.Message|replacementStage[\s\S]*?\.ToString\(\)|replacementStage[\s\S]*?StackTrace/);
996
+ });
997
+
998
+ test("Windows presence source guard uses rooted no-replace publication and same-handle deletion", async (t) => {
999
+ t.diagnostic("source guard, not native Windows proof");
1000
+ const source = await readFile(runtime, "utf8");
1001
+ assert.match(source, /static OpenResult OpenRecord\(IntPtr root, string name, bool create, byte\[\] descriptor, bool allowDeleteSharing\)/);
1002
+ assert.match(source, /attributes\.Attributes = OBJ_CASE_INSENSITIVE \| OBJ_DONT_REPARSE/);
1003
+ assert.match(source, /NtSetInformationFile\(file, out io, memory, \(uint\)\(header \+ chars\.Length\), 10\)/);
1004
+ assert.match(source, /const int FileDispositionInformation = 13/);
1005
+ assert.match(source, /NtSetInformationFile\(file, out io, memory, 1, FileDispositionInformation\)/);
1006
+ assert.doesNotMatch(source, /NtSetInformationFile\(file, out io, memory, 1, 4\)/);
1007
+ assert.match(source, /RecordIdentity identity = AssertRecord\(file, sid\);/);
1008
+ assert.match(source, /SafeFileHandle Handle/);
1009
+ assert.match(source, /new SafeFileHandle\(handle, true\)/);
1010
+ assert.match(source, /OpenRecord\(Presence, temporary, true, descriptor, true\)/);
1011
+ assert.match(source, /OpenRecord\(Presence, name, false, null, true\)/);
1012
+ assert.match(source, /FILE_SHARE_READ \| FILE_SHARE_WRITE \| \(allowDeleteSharing \? FILE_SHARE_DELETE : 0\)/);
1013
+ assert.match(source, /OwnedPublications\.Add\(owned\)/);
1014
+ assert.match(source, /AssertRetainedPublication\(owned\.Handle, owned\.Sid\)/);
1015
+ assert.match(source, /owned\.Dispose\(\)/);
1016
+ assert.match(source, /info\.NumberOfLinks != 1/);
1017
+ assert.match(source, /!identity\.Equals\(retained\)/);
1018
+ assert.match(source, /try \{\s*if \(owned\.Sid != sid\) Fail\("unsafe"\); RecordIdentity retained = AssertRetainedPublication/);
1019
+ assert.match(source, /function Write-Reply\([\s\S]*?result = \$result \} \| ConvertTo-Json -Compress -Depth 4/);
1020
+ assert.match(source, /public static PresenceRecord\[\] List\(string sid\) \{ return List\(null, sid\); \}/);
1021
+ assert.match(source, /public static PresenceRecord\[\] List\(string excluded, string sid\)/);
1022
+ assert.match(source, /\$nativeRecords = if \(\$hasExcludeSessionId\) \{ \[WindowsSessionBootstrap\]::List\(\$excludeSessionId, \$identity\.Sid\) \} else \{ \[WindowsSessionBootstrap\]::List\(\$identity\.Sid\) \}/);
1023
+ assert.match(source, /public static void RemoveOwn\(string sessionId, string endpoint, long createdAt, string sid\)/);
1024
+ });
1025
+
1026
+ test("Windows bootstrap startup control", { skip: process.platform !== "win32", timeout: 40_000 }, async (t) => {
1027
+ const result = await runBootstrapStartupControl();
1028
+ assert.equal(result.code, 0, "Windows bootstrap startup control exited unsuccessfully");
1029
+ const frames = parseStartupControlFrames(result.stdout);
1030
+ assert.deepEqual(frames.map((frame) => frame.requestId), ["start-1", "shutdown-2"]);
1031
+ const [start, shutdown] = frames;
1032
+ assert.deepEqual(shutdown, { requestId: "shutdown-2", ok: true, result: { state: "partial" } });
1033
+ if (!start.ok && start.error === "unavailable") {
1034
+ const diagnostic = parseBootstrapDiagnostic(result.stderr);
1035
+ if (!diagnostic) assert.fail("Windows bootstrap startup diagnostic was missing or malformed");
1036
+ t.diagnostic(JSON.stringify(diagnostic));
1037
+ assert.fail("Windows bootstrap start unavailable");
1038
+ }
1039
+ assert.deepEqual(start, { requestId: "start-1", ok: true, result: { state: "partial" } });
1040
+ if (result.stderr !== "") assert.fail("Windows bootstrap startup control emitted unexpected diagnostics");
1041
+ });
1042
+
1043
+ test("Windows-native bootstrap pins ancestors, creates exact private boundaries, and remains partial", { skip: process.platform !== "win32", timeout: 20_000 }, async (t) => {
1044
+ const diagnostics: BootstrapDiagnosticContext = t;
1045
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-bootstrap-"));
1046
+ const agentHome = join(root, "profile", "agent");
1047
+ const routing = join(agentHome, "gentle-agents");
1048
+ const baseline = join(root, "ancestor.sd");
1049
+ const ancestorBaselines = [root, join(root, "profile"), agentHome, routing].map((path, index) => ({ path, baseline: join(root, `ancestor-${index}.sd`) }));
1050
+ await mkdir(routing, { recursive: true });
1051
+ for (const candidate of ancestorBaselines) assert.equal((await fixtureResult("capture", candidate.path, ["-BaselinePath", candidate.baseline])).equal, true);
1052
+ assert.equal((await fixtureResult("capture", routing, ["-BaselinePath", baseline])).equal, true);
1053
+ const frames = await helper(agentHome, false, { diagnostics });
1054
+ assert.deepEqual(frames.map((frame) => frame.ok ? frame.result : frame.error), [{ state: "partial" }, { state: "initialized", bootstrap: "complete" }, { state: "partial" }]);
1055
+ assert.equal((await fixtureResult("equals", routing, ["-BaselinePath", baseline])).equal, true);
1056
+ for (const candidate of ancestorBaselines) assert.equal((await fixtureResult("equals", candidate.path, ["-BaselinePath", candidate.baseline])).equal, true);
1057
+ assert.deepEqual(await fixtureResult("measure", join(routing, "transport")), { ok: true, directory: true, reparse: false, ownerCurrent: true, privateBoundary: true });
1058
+ assert.deepEqual(await fixtureResult("measure", join(routing, "transport", "presence")), { ok: true, directory: true, reparse: false, ownerCurrent: true, privateBoundary: true });
1059
+ await mkdir(join(routing, "transport", "presence", "seed-a"));
1060
+ await mkdir(join(routing, "transport", "presence", "seed-b"));
1061
+ assert.deepEqual((await helper(agentHome, true, { diagnostics }))[2].result, { state: "initialized", bootstrap: "complete", entries: 2 });
1062
+ });
1063
+
1064
+ test("Windows-native presence publishes, resolves, lists, and removes only its own record", { skip: process.platform !== "win32", timeout: 30_000 }, async (t) => {
1065
+ const diagnostics: BootstrapDiagnosticContext = t;
1066
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-presence-"));
1067
+ const agentHome = join(root, "profile", "agent");
1068
+ await mkdir(join(agentHome, "gentle-agents"), { recursive: true });
1069
+ const held = await openInitializedHelper(agentHome, { diagnostics });
1070
+ try {
1071
+ const recorded = await held.presence("record", { sessionId: "session-a", createdAt: 1 });
1072
+ assert.equal(recorded.ok, true);
1073
+ const record = recorded.result as Record<string, unknown>;
1074
+ assert.deepEqual(Object.keys(record).sort(), ["createdAt", "endpoint", "sessionId", "version"]);
1075
+ assert.equal(record.sessionId, "session-a");
1076
+ assert.match(record.endpoint as string, /^\\\\\.\\pipe\\gentle-pi-[0-9a-f]{32}$/);
1077
+ assert.equal((await held.presence("publish", { record })).ok, true);
1078
+ assert.equal((await held.presence("publish", { record })).error, "busy", "no-replace collision preserves the published record");
1079
+ assert.deepEqual(requirePublicPresenceResult(await held.presence("list")), { records: [record] }, "an omitted excludeSessionId lists one record");
1080
+ const secondReply = await held.presence("record", { sessionId: "session-b", createdAt: 2 });
1081
+ assert.equal(secondReply.ok, true);
1082
+ const secondRecord = secondReply.result as Record<string, unknown>;
1083
+ assert.equal((await held.presence("publish", { record: secondRecord })).ok, true);
1084
+ assert.deepEqual(requirePublicPresenceResult(await held.presence("list")), { records: [record, secondRecord] }, "an omitted excludeSessionId lists multiple records");
1085
+ assert.deepEqual(requirePublicPresenceResult(await held.presence("list", { excludeSessionId: "session-b" })), { records: [record] }, "a valid excludeSessionId is honored");
1086
+ assert.equal((await held.presence("list", { excludeSessionId: "" })).error, "invalid", "an explicit malformed excludeSessionId is rejected");
1087
+ assert.equal((await held.presence("remove", { record: secondRecord })).ok, true);
1088
+ assert.deepEqual((await held.presence("resolve", { sessionId: "session-a" })).result, record);
1089
+ const token = (record.endpoint as string).slice("\\\\.\\pipe\\gentle-pi-".length);
1090
+ const publishedPath = join(agentHome, "gentle-agents", "transport", "presence", `session-a.${token}.json`);
1091
+ assert.deepEqual(await fixtureResult("replace-identical", publishedPath), { ok: true, replaced: true });
1092
+ assert.deepEqual(requirePublicPresenceResult(await held.presence("list")), { records: [record] }, "the replacement retains the public record and accepted ACL");
1093
+ assert.equal((await held.presence("remove", { record })).error, "unsafe", "a replacement with identical public bytes and ACL is not owned");
1094
+ await stat(publishedPath);
1095
+ } finally { await held.closeInput(); }
1096
+ });
1097
+
1098
+ test("Windows-native owned publication removes its unchanged rooted record", { skip: process.platform !== "win32", timeout: 30_000 }, async (t) => {
1099
+ const diagnostics: BootstrapDiagnosticContext = t;
1100
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-presence-"));
1101
+ const agentHome = join(root, "profile", "agent");
1102
+ await mkdir(join(agentHome, "gentle-agents"), { recursive: true });
1103
+ const held = await openInitializedHelper(agentHome, { diagnostics });
1104
+ try {
1105
+ const recorded = await held.presence("record", { sessionId: "session-remove", createdAt: 1 });
1106
+ assert.equal(recorded.ok, true);
1107
+ const record = recorded.result as Record<string, unknown>;
1108
+ assert.equal((await held.presence("publish", { record })).ok, true);
1109
+ assert.equal((await held.presence("remove", { record })).ok, true);
1110
+ assert.deepEqual(requirePublicPresenceResult(await held.presence("list")), { records: [] });
1111
+ assert.equal((await held.presence("resolve", { sessionId: "session-remove" })).error, "not_found");
1112
+ } finally { await held.closeInput(); }
1113
+ });
1114
+
1115
+ test("Windows-native shutdown releases and cleans unchanged owned publications", { skip: process.platform !== "win32", timeout: 30_000 }, async (t) => {
1116
+ const diagnostics: BootstrapDiagnosticContext = t;
1117
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-presence-"));
1118
+ const agentHome = join(root, "profile", "agent");
1119
+ await mkdir(join(agentHome, "gentle-agents"), { recursive: true });
1120
+ const held = await openInitializedHelper(agentHome, { diagnostics });
1121
+ let publishedPath = "";
1122
+ try {
1123
+ const recorded = await held.presence("record", { sessionId: "session-shutdown", createdAt: 1 });
1124
+ assert.equal(recorded.ok, true);
1125
+ const record = recorded.result as Record<string, unknown>;
1126
+ assert.equal((await held.presence("publish", { record })).ok, true);
1127
+ const token = (record.endpoint as string).slice("\\\\.\\pipe\\gentle-pi-".length);
1128
+ publishedPath = join(agentHome, "gentle-agents", "transport", "presence", `session-shutdown.${token}.json`);
1129
+ } finally { await held.closeInput(); }
1130
+ await assert.rejects(stat(publishedPath));
1131
+ });
1132
+
1133
+ test("Windows-native invalid owned ACL removal preserves the record and releases ownership before shutdown", { skip: process.platform !== "win32", timeout: 30_000 }, async (t) => {
1134
+ const diagnostics: BootstrapDiagnosticContext = t;
1135
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-presence-"));
1136
+ const agentHome = join(root, "profile", "agent");
1137
+ await mkdir(join(agentHome, "gentle-agents"), { recursive: true });
1138
+ const held = await openInitializedHelper(agentHome, { diagnostics });
1139
+ try {
1140
+ const recorded = await held.presence("record", { sessionId: "session-invalid-acl", createdAt: 1 });
1141
+ assert.equal(recorded.ok, true);
1142
+ const record = recorded.result as Record<string, unknown>;
1143
+ assert.equal((await held.presence("publish", { record })).ok, true);
1144
+ const token = (record.endpoint as string).slice("\\\\.\\pipe\\gentle-pi-".length);
1145
+ const publishedPath = join(agentHome, "gentle-agents", "transport", "presence", `session-invalid-acl.${token}.json`);
1146
+ assert.deepEqual(await fixtureResult("add-extra-ace", publishedPath), { ok: true, changed: true });
1147
+ assert.equal((await held.presence("remove", { record })).error, "unsafe");
1148
+ await stat(publishedPath);
1149
+ assert.deepEqual(await fixtureResult("exclusive-open", publishedPath), { ok: true, exclusive: true }, "owned retained handle was released before shutdown");
1150
+ } finally { await held.closeInput(); }
1151
+ });
1152
+
1153
+ test("Windows-native presence rejects hardlinks, corrupted ACLs, and oversized records", { skip: process.platform !== "win32", timeout: 30_000 }, async (t) => {
1154
+ const diagnostics: BootstrapDiagnosticContext = t;
1155
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-presence-"));
1156
+ const agentHome = join(root, "profile", "agent");
1157
+ await mkdir(join(agentHome, "gentle-agents"), { recursive: true });
1158
+ const held = await openInitializedHelper(agentHome, { diagnostics });
1159
+ try {
1160
+ const presence = join(agentHome, "gentle-agents", "transport", "presence");
1161
+ assert.deepEqual(await fixtureResult("junction", join(presence, "reparse.0123456789abcdef0123456789abcdef.json"), ["-Target", root]), { ok: true, reparse: true });
1162
+ assert.deepEqual(requirePublicPresenceResult(await held.presence("list")), { records: [] }, "a reparse record is ignored");
1163
+ for (const [sessionId, mutation] of [["hardlink", "hardlink"], ["bad-acl", "add-extra-ace"], ["oversize", "append"]] as const) {
1164
+ const recorded = await held.presence("record", { sessionId, createdAt: 1 });
1165
+ assert.equal(recorded.ok, true);
1166
+ const record = recorded.result as Record<string, unknown>;
1167
+ assert.equal((await held.presence("publish", { record })).ok, true);
1168
+ const token = (record.endpoint as string).slice("\\\\.\\pipe\\gentle-pi-".length);
1169
+ const publishedPath = join(agentHome, "gentle-agents", "transport", "presence", `${sessionId}.${token}.json`);
1170
+ if (mutation === "hardlink") await fixtureResult("hardlink", publishedPath, ["-Target", join(dirname(publishedPath), `other.${token}.json`)]);
1171
+ else await fixtureResult(mutation, publishedPath);
1172
+ assert.deepEqual(requirePublicPresenceResult(await held.presence("list")), { records: [] });
1173
+ assert.equal((await held.presence("resolve", { sessionId })).error, "not_found");
1174
+ }
1175
+ } finally { await held.closeInput(); }
1176
+ });
1177
+
1178
+ test("Windows-native bootstrap rejects a corrupted private boundary and preserves a failed bootstrap without recursive cleanup", { skip: process.platform !== "win32", timeout: 20_000 }, async (t) => {
1179
+ const emitted: string[] = [];
1180
+ const diagnostics: BootstrapDiagnosticContext = { diagnostic: (message) => { emitted.push(message); t.diagnostic(message); } };
1181
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-bootstrap-"));
1182
+ const agentHome = join(root, "profile", "agent");
1183
+ const routing = join(agentHome, "gentle-agents");
1184
+ const badBoundary = join(routing, "transport");
1185
+ const badBaseline = join(root, "bad-boundary.sd");
1186
+ await mkdir(badBoundary, { recursive: true });
1187
+ await fixtureResult("add-extra-ace", badBoundary);
1188
+ assert.equal((await fixtureResult("capture", badBoundary, ["-BaselinePath", badBaseline])).equal, true);
1189
+ const frames = await helper(agentHome, false, { diagnostics });
1190
+ assert.equal(frames[1].ok, false);
1191
+ assert.equal(frames[1].error, "unsafe");
1192
+ assert.deepEqual(emitted, ['{"kind":"windows-session-bootstrap-rejection","stage":"transport-assert-owned","ntstatus":null}']);
1193
+ await stat(badBoundary);
1194
+ assert.equal((await fixtureResult("equals", badBoundary, ["-BaselinePath", badBaseline])).equal, true);
1195
+ await assert.rejects(stat(join(badBoundary, "presence")));
1196
+ });
1197
+
1198
+ test("Windows-native bootstrap releases handles on shutdown before its stdin closes", { skip: process.platform !== "win32", timeout: 20_000 }, async (t) => {
1199
+ const diagnostics: BootstrapDiagnosticContext = t;
1200
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-bootstrap-"));
1201
+ const agentHome = join(root, "profile", "agent");
1202
+ const routing = join(agentHome, "gentle-agents");
1203
+ await mkdir(routing, { recursive: true });
1204
+ const held = await openInitializedHelper(agentHome, { diagnostics });
1205
+ try {
1206
+ assert.deepEqual(held.frames[1].result, { state: "initialized", bootstrap: "complete" });
1207
+ await held.shutdown();
1208
+ assert.equal(held.exited, false);
1209
+ assert.deepEqual(await fixtureResult("rename", routing, ["-Target", join(root, "routing-after-shutdown")]), { ok: true, renamed: true });
1210
+ } finally { await held.closeInput(); }
1211
+ });
1212
+
1213
+ test("Windows-native bootstrap exits on an invalid recognized schema while stdin remains open", { skip: process.platform !== "win32", timeout: 20_000 }, async (t) => {
1214
+ const diagnostics: BootstrapDiagnosticContext = t;
1215
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-bootstrap-"));
1216
+ const agentHome = join(root, "profile", "agent");
1217
+ const routing = join(agentHome, "gentle-agents");
1218
+ await mkdir(routing, { recursive: true });
1219
+ const held = await openInitializedHelper(agentHome, { diagnostics });
1220
+ try {
1221
+ await held.invalidStartSchema();
1222
+ assert.equal(held.exited, true);
1223
+ assert.equal(held.frames[2].error, "invalid");
1224
+ assert.deepEqual(await fixtureResult("rename", routing, ["-Target", join(root, "routing-after-invalid")]), { ok: true, renamed: true });
1225
+ } finally { await held.closeInput(); }
1226
+ });
1227
+
1228
+ test("Windows-native failed bootstrap releases its handles before stdin closes", { skip: process.platform !== "win32", timeout: 20_000 }, async (t) => {
1229
+ const diagnostics: BootstrapDiagnosticContext = t;
1230
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-bootstrap-"));
1231
+ const agentHome = join(root, "profile", "agent");
1232
+ const routing = join(agentHome, "gentle-agents");
1233
+ await mkdir(join(routing, "transport"), { recursive: true });
1234
+ await fixtureResult("add-extra-ace", join(routing, "transport"));
1235
+ const held = await openInitializedHelper(agentHome, { diagnostics });
1236
+ try {
1237
+ assert.equal(held.frames[1].error, "unsafe");
1238
+ assert.deepEqual(held.rejectionDiagnostic, { kind: "windows-session-bootstrap-rejection", stage: "transport-assert-owned", ntstatus: null });
1239
+ assert.equal(held.exited, false);
1240
+ assert.deepEqual(await fixtureResult("rename", routing, ["-Target", join(root, "routing-after-failure")]), { ok: true, renamed: true });
1241
+ } finally { await held.closeInput(); }
1242
+ });
1243
+
1244
+ test("Windows-native bootstrap closes pinned handles after malformed input", { skip: process.platform !== "win32", timeout: 20_000 }, async () => {
1245
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-bootstrap-"));
1246
+ const agentHome = join(root, "profile", "agent");
1247
+ const routing = join(agentHome, "gentle-agents");
1248
+ await mkdir(routing, { recursive: true });
1249
+ const input = ['{"requestId":"start-1","operation":"start"}', JSON.stringify({ requestId: "initialize-2", operation: "initialize", agentHome }), "{"].join("\n") + "\n";
1250
+ const result = await runPowerShell(runtime, [], input);
1251
+ assert.equal(result.code, 0);
1252
+ const frame = parseHelperControlOutput(result.stdout, true, "Windows helper returned malformed protocol output")[1];
1253
+ assert.ok(frame.ok && frame.result !== undefined && "state" in frame.result);
1254
+ assert.equal(frame.result.state, "initialized");
1255
+ assert.deepEqual(await fixtureResult("rename", routing, ["-Target", join(root, "routing-released")]), { ok: true, renamed: true });
1256
+ });
1257
+
1258
+ test("Windows-native bootstrap rejects a reparse routing parent and concurrent initialize does not hang", { skip: process.platform !== "win32", timeout: 20_000 }, async (t) => {
1259
+ const emitted: string[] = [];
1260
+ const diagnostics: BootstrapDiagnosticContext = { diagnostic: (message) => { emitted.push(message); t.diagnostic(message); } };
1261
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-bootstrap-"));
1262
+ const agentHome = join(root, "profile", "agent");
1263
+ const routing = join(agentHome, "gentle-agents");
1264
+ const target = join(root, "routing-target");
1265
+ await mkdir(join(agentHome), { recursive: true });
1266
+ await mkdir(target);
1267
+ await fixtureResult("junction", routing, ["-Target", target]);
1268
+ assert.equal((await helper(agentHome, false, { diagnostics }))[1].error, "unsafe");
1269
+ assert.equal(emitted.length, 1);
1270
+ const rejection = JSON.parse(emitted[0]) as BootstrapRejectionDiagnostic;
1271
+ assert.equal(rejection.kind, "windows-session-bootstrap-rejection");
1272
+ assert.equal(rejection.stage, "routing-open");
1273
+ assert.ok(rejection.ntstatus === 0xC000050B || rejection.ntstatus === null);
1274
+ const concurrentRoot = await mkdtemp(join(os.tmpdir(), "gentle-pi-bootstrap-"));
1275
+ const concurrentHome = join(concurrentRoot, "profile", "agent");
1276
+ await mkdir(join(concurrentHome, "gentle-agents"), { recursive: true });
1277
+ await withInitializedHelpers([concurrentHome, concurrentHome], async (helpers) => {
1278
+ const results = await Promise.all(helpers.map((candidate) => candidate.enumerate()));
1279
+ for (const frame of results) assert.deepEqual(frame.result, { state: "initialized", bootstrap: "complete", entries: 0 });
1280
+ await Promise.all(helpers.map((candidate) => candidate.shutdown()));
1281
+ }, { diagnostics });
1282
+ });
1283
+
1284
+ async function withWindowsNativeListener<T>(callback: (notification: Readonly<{ id: string; senderSessionId: string; message: string }>) => Promise<void>, action: (value: Readonly<{ listener: WindowsActiveSessionListener; client: WindowsActiveSessionClient; agentHome: string }>) => Promise<T>, createRegistry: (home: string) => Promise<WindowsSessionPresenceRegistry> = (home) => WindowsSessionPresenceRegistry.create(home)): Promise<T> {
1285
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-listener-"));
1286
+ const agentHome = join(root, "profile", "agent");
1287
+ await mkdir(join(agentHome, "gentle-agents"), { recursive: true });
1288
+ let listenerRegistry: WindowsSessionPresenceRegistry | undefined;
1289
+ let clientRegistry: WindowsSessionPresenceRegistry | undefined;
1290
+ let listener: WindowsActiveSessionListener | undefined;
1291
+ let client: WindowsActiveSessionClient | undefined;
1292
+ let listenerClosed = false;
1293
+ try {
1294
+ listenerRegistry = await createRegistry(agentHome);
1295
+ clientRegistry = await createRegistry(agentHome);
1296
+ listener = new WindowsActiveSessionListener(listenerRegistry, "recipient", callback);
1297
+ client = new WindowsActiveSessionClient(clientRegistry, "sender");
1298
+ await listener.start();
1299
+ return await action({ listener, client, agentHome });
1300
+ } finally {
1301
+ client?.close();
1302
+ if (listener) { await listener.close().then(() => { listenerClosed = true; }, () => {}); }
1303
+ if (listenerRegistry && !listenerClosed) await listenerRegistry.close().catch(() => {});
1304
+ if (clientRegistry) await clientRegistry.close().catch(() => {});
1305
+ }
1306
+ }
1307
+
1308
+ function waitWindowsNativeSignal(signal: Promise<void>, message: string) {
1309
+ return new Promise<void>((resolve, reject) => {
1310
+ const timer = setTimeout(() => reject(new Error(message)), 2_500);
1311
+ void signal.then(() => { clearTimeout(timer); resolve(); }, () => { clearTimeout(timer); reject(new Error(message)); });
1312
+ });
1313
+ }
1314
+
1315
+ test("Windows native listener setup closes the first acquired registry when the second acquisition rejects", async () => {
1316
+ let closes = 0;
1317
+ const first = { close: async () => { closes++; } } as unknown as WindowsSessionPresenceRegistry;
1318
+ let calls = 0;
1319
+ await assert.rejects(withWindowsNativeListener(async () => {}, async () => assert.fail("action must not run"), async () => {
1320
+ if (++calls === 1) return first;
1321
+ throw new Error("second registry failed");
1322
+ }), /second registry failed/);
1323
+ assert.equal(closes, 1);
1324
+ });
1325
+
1326
+ test("Windows default transport creates a registry without an observer", { skip: process.platform !== "win32", timeout: 20_000 }, async () => {
1327
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-observer-"));
1328
+ const agentHome = join(root, "profile", "agent");
1329
+ await mkdir(join(agentHome, "gentle-agents"), { recursive: true });
1330
+ const registry = await createDefaultSessionTransport("win32").createRegistry(agentHome);
1331
+ try {
1332
+ assert.deepEqual(await registry.listActivations(), []);
1333
+ } finally {
1334
+ await registry.close();
1335
+ }
1336
+ });
1337
+
1338
+ test("Windows default transport emits fixed ordered phase events for its own registry", { skip: process.platform !== "win32", timeout: 20_000 }, async () => {
1339
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-observer-"));
1340
+ const agentHome = join(root, "profile", "agent");
1341
+ await mkdir(join(agentHome, "gentle-agents"), { recursive: true });
1342
+ const events: WindowsSessionRegistryPhaseEvent[] = [];
1343
+ const sequence = new WindowsSessionRegistryPhaseSequence();
1344
+ const registry = await createDefaultSessionTransport("win32").createRegistry(agentHome, (event) => {
1345
+ events.push(event);
1346
+ return sequence.observe(event);
1347
+ });
1348
+ try {
1349
+ assert.deepEqual(events, [
1350
+ { phase: "start", status: "succeeded", error: null, lastStartupMarker: "native-ready" },
1351
+ { phase: "initialize", status: "succeeded", error: null, lastStartupMarker: "native-ready" },
1352
+ ]);
1353
+ for (const event of events) assert.deepEqual(Object.keys(event).sort(), ["error", "lastStartupMarker", "phase", "status"], "events expose only fixed startup progress");
1354
+ } finally {
1355
+ await registry.close();
1356
+ }
1357
+ assert.deepEqual(events, [
1358
+ { phase: "start", status: "succeeded", error: null, lastStartupMarker: "native-ready" },
1359
+ { phase: "initialize", status: "succeeded", error: null, lastStartupMarker: "native-ready" },
1360
+ { phase: "cleanup", status: "succeeded", error: null, lastStartupMarker: "native-ready" },
1361
+ ]);
1362
+ assert.equal(sequence.admitsFullSuccess, true, "the seam callback retains the reducer receiver through its wrapper");
1363
+ });
1364
+
1365
+ test("Windows default transport rejects asynchronous observer setup without awaiting it", { skip: process.platform !== "win32", timeout: 20_000 }, async () => {
1366
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-observer-"));
1367
+ const agentHome = join(root, "profile", "agent");
1368
+ await mkdir(join(agentHome, "gentle-agents"), { recursive: true });
1369
+ await assert.rejects(createDefaultSessionTransport("win32").createRegistry(agentHome, () => Promise.reject(new Error("observer rejected")) as never));
1370
+ await new Promise<void>((resolve) => setImmediate(resolve));
1371
+ const recovered = await createDefaultSessionTransport("win32").createRegistry(agentHome);
1372
+ await recovered.close();
1373
+ });
1374
+
1375
+ const successfulPhase = (phase: WindowsSessionRegistryPhaseEvent["phase"], lastStartupMarker: StartupMarker | null = null): WindowsSessionRegistryPhaseEvent => Object.freeze({ phase, status: "succeeded", error: null, lastStartupMarker });
1376
+ const failedPhase = (phase: WindowsSessionRegistryPhaseEvent["phase"], error: NonNullable<WindowsSessionRegistryPhaseEvent["error"]> = Object.freeze({ class: "rejected", code: "unknown" }), lastStartupMarker: StartupMarker | null = null): WindowsSessionRegistryPhaseEvent => Object.freeze({ phase, status: "failed", error, lastStartupMarker });
1377
+
1378
+ test("Windows phase sequence preserves failed start with successful cleanup", () => {
1379
+ const sequence = new WindowsSessionRegistryPhaseSequence();
1380
+ sequence.observe(failedPhase("start"));
1381
+ sequence.observe(successfulPhase("cleanup"));
1382
+ assert.equal(sequence.operationSucceeded, false);
1383
+ assert.equal(sequence.terminalSequenceValid, true);
1384
+ assert.equal(sequence.cleanupComplete, true);
1385
+ assert.equal(sequence.admitsFullSuccess, false);
1386
+ assert.deepEqual(sequence.snapshot(), { availability: "observed", provenance: "owned-instance", restoration: "not-required", startCalls: 1, initializeCalls: 0, cleanupCalls: 1, firstFailurePhase: "start", firstFailureClass: "rejected", firstFailureCode: "unknown", lastStartupMarker: null });
1387
+ });
1388
+
1389
+ test("Windows phase sequence preserves failed initialize with successful cleanup", () => {
1390
+ const sequence = new WindowsSessionRegistryPhaseSequence();
1391
+ sequence.observe(successfulPhase("start"));
1392
+ sequence.observe(failedPhase("initialize"));
1393
+ sequence.observe(successfulPhase("cleanup"));
1394
+ assert.equal(sequence.operationSucceeded, false);
1395
+ assert.equal(sequence.terminalSequenceValid, true);
1396
+ assert.equal(sequence.cleanupComplete, true);
1397
+ assert.equal(sequence.admitsFullSuccess, false);
1398
+ assert.deepEqual(sequence.snapshot(), { availability: "observed", provenance: "owned-instance", restoration: "not-required", startCalls: 1, initializeCalls: 1, cleanupCalls: 1, firstFailurePhase: "initialize", firstFailureClass: "rejected", firstFailureCode: "unknown", lastStartupMarker: null });
1399
+ });
1400
+
1401
+ test("Windows phase sequence admits only complete successful operations", () => {
1402
+ const sequence = new WindowsSessionRegistryPhaseSequence();
1403
+ sequence.observe(successfulPhase("start"));
1404
+ assert.equal(sequence.terminalSequenceValid, false);
1405
+ assert.equal(sequence.admitsFullSuccess, false);
1406
+ sequence.observe(successfulPhase("initialize"));
1407
+ sequence.observe(successfulPhase("cleanup"));
1408
+ assert.equal(sequence.operationSucceeded, true);
1409
+ assert.equal(sequence.terminalSequenceValid, true);
1410
+ assert.equal(sequence.cleanupComplete, true);
1411
+ assert.equal(sequence.admitsFullSuccess, true);
1412
+ });
1413
+
1414
+ test("Windows phase sequence preserves an operation failure when cleanup fails", () => {
1415
+ const sequence = new WindowsSessionRegistryPhaseSequence();
1416
+ sequence.observe(failedPhase("start", Object.freeze({ class: "rejected", code: "spawn" })));
1417
+ sequence.observe(failedPhase("cleanup", Object.freeze({ class: "rejected", code: "unknown" })));
1418
+ assert.equal(sequence.terminalSequenceValid, true);
1419
+ assert.equal(sequence.cleanupComplete, false);
1420
+ assert.deepEqual(sequence.snapshot(), { availability: "observed", provenance: "owned-instance", restoration: "not-required", startCalls: 1, initializeCalls: 0, cleanupCalls: 1, firstFailurePhase: "start", firstFailureClass: "rejected", firstFailureCode: "spawn", lastStartupMarker: null });
1421
+ });
1422
+
1423
+ test("Windows phase sequence preserves bounded rejection sites and the first operation failure", () => {
1424
+ for (const failure of [
1425
+ Object.freeze({ class: "timed-out" as const, code: "deadline" as const }),
1426
+ Object.freeze({ class: "rejected" as const, code: "write" as const }),
1427
+ Object.freeze({ class: "rejected" as const, code: "spawn" as const }),
1428
+ Object.freeze({ class: "rejected" as const, code: "protocol" as const }),
1429
+ ]) {
1430
+ const sequence = new WindowsSessionRegistryPhaseSequence();
1431
+ sequence.observe(failedPhase("start", failure));
1432
+ sequence.observe(failedPhase("cleanup", Object.freeze({ class: "rejected", code: "unknown" })));
1433
+ assert.equal(sequence.snapshot().firstFailureCode, failure.code);
1434
+ }
1435
+ });
1436
+
1437
+ test("Windows phase sequence retains a last observed startup marker through deadline and cleanup", () => {
1438
+ const sequence = new WindowsSessionRegistryPhaseSequence();
1439
+ sequence.observe(failedPhase("start", Object.freeze({ class: "timed-out", code: "deadline" }), "script-entered"));
1440
+ sequence.observe(successfulPhase("cleanup", "script-entered"));
1441
+ assert.equal(sequence.admitsFullSuccess, false, "a startup marker is not readiness");
1442
+ assert.deepEqual(sequence.snapshot(), { availability: "observed", provenance: "owned-instance", restoration: "not-required", startCalls: 1, initializeCalls: 0, cleanupCalls: 1, firstFailurePhase: "start", firstFailureClass: "timed-out", firstFailureCode: "deadline", lastStartupMarker: "script-entered" });
1443
+ });
1444
+
1445
+ test("Windows phase sequence rejects duplicate, out-of-order, and invalid events permanently", () => {
1446
+ for (const events of [
1447
+ [successfulPhase("cleanup")],
1448
+ [successfulPhase("start"), successfulPhase("start")],
1449
+ [{ phase: "start", status: "failed", error: { class: "timed-out", code: "unknown" } }],
1450
+ [{ phase: "start", status: "failed", error: { class: "rejected", code: "deadline" } }],
1451
+ [{ phase: "start", status: "failed", error: { class: "rejected", code: "native-code" } }],
1452
+ ] as const) {
1453
+ const sequence = new WindowsSessionRegistryPhaseSequence();
1454
+ for (const event of events) sequence.observe(event);
1455
+ sequence.observe(successfulPhase("cleanup"));
1456
+ assert.equal(sequence.terminalSequenceValid, false);
1457
+ assert.equal(sequence.cleanupComplete, false);
1458
+ assert.equal(sequence.admitsFullSuccess, false);
1459
+ assert.deepEqual(sequence.snapshot(), { availability: "unavailable", provenance: "ambiguous", restoration: "not-required", startCalls: null, initializeCalls: null, cleanupCalls: null, firstFailurePhase: null, firstFailureClass: null, firstFailureCode: null, lastStartupMarker: null });
1460
+ }
1461
+ });
1462
+
1463
+ test("Windows registry source guard preserves operation failure through observer cleanup", async (t) => {
1464
+ t.diagnostic("source guard, not native Windows proof");
1465
+ const source = await readFile(fileURLToPath(new URL("../lib/windows-session-transport.ts", import.meta.url)), "utf8");
1466
+ assert.match(source, /catch \(error\) \{\s*try \{ await run\("cleanup", \(\) => host\.close\(\)\); \} catch \{[^}]*\}\s*registryError\(error\);/);
1467
+ assert.match(source, /export type WindowsSessionRegistryPhaseObserver = \(event: WindowsSessionRegistryPhaseEvent\) => undefined;/);
1468
+ assert.match(source, /transportError\("Windows transport host unavailable", "spawn"\)/);
1469
+ assert.match(source, /transportError\("Windows transport request timed out", "deadline"\)/);
1470
+ assert.match(source, /transportError\("Windows transport host exited", "write"\)/);
1471
+ assert.match(source, /lastStartupMarker: this\.readLastStartupMarker\(\)/);
1472
+ assert.match(source, /new WindowsSessionRegistryObserver\(observePhase, \(\) => host\.lastStartupMarker\)/);
1473
+ assert.match(source, /this\.abort\("Windows transport host unavailable", true, "protocol"\)/);
1474
+ assert.match(source, /if \(result === undefined\) return;\s*this\.active = false;\s*try \{ Promise\.resolve\(result\)\.catch\(\(\) => \{\}\);/);
1475
+ assert.doesNotMatch(source, /WindowsSessionTransportHostObserver|observeHost\?\.\(host\)|Object\.defineProperty\(candidate/);
1476
+ });
1477
+
1478
+ test("packed lifecycle source uses the exported phase sequence", async (t) => {
1479
+ t.diagnostic("source guard, not packed lifecycle proof");
1480
+ const source = await readFile(fileURLToPath(new URL("../scripts/test-packed-runner.mjs", import.meta.url)), "utf8");
1481
+ assert.match(source, /const \{ WindowsSessionRegistryPhaseSequence \} = await within\(load\(jiti\.import/);
1482
+ assert.match(source, /const createWindowsRegistryObservation = \(PhaseSequence\) => \{\s*if \(process\.platform === "win32"\) return new PhaseSequence\(\);/);
1483
+ assert.match(source, /createWindowsRegistryObservation\(WindowsSessionRegistryPhaseSequence\)/);
1484
+ assert.match(source, /windowsRegistryObservation\.startupSucceeded/);
1485
+ assert.match(source, /windowsRegistryObservation\.cleanupComplete/);
1486
+ assert.match(source, /windowsRegistryObservation\.admitsFullSuccess/);
1487
+ assert.match(source, /lastStartupMarker: null/);
1488
+ assert.match(source, /windowsRegistryObservation\.lastStartupMarker === "native-ready"/);
1489
+ assert.match(source, /const SDK_LIFECYCLE_WINDOWS_BIND_DEADLINE_MS = 30_000 \+ 2_000 \+ 2_000 \+ 6_000;/);
1490
+ assert.match(source, /const SDK_LIFECYCLE_WINDOWS_REGISTRY_DEADLINE_MS = 30_000 \+ 2_000 \+ 2_000 \+ 2 \* 500 \+ 5_000;/);
1491
+ assert.match(source, /const SDK_LIFECYCLE_WINDOWS_LIST_DEADLINE_MS = 2_000;/);
1492
+ assert.match(source, /const SDK_LIFECYCLE_PROBE_TIMEOUT_MS = 4 \* 30_000 \+ 2 \* 30_000 \+ 2 \* 40_000 \+ 40_000 \+ 3 \* 2_000 \+ 2 \* 15_000 \+ 15_000 \+ 4_000 \+ 5_000;/);
1493
+ assert.match(source, /bindExtensions\(\{ mode: "json", onError: recordExtensionError \}\), SDK_LIFECYCLE_WINDOWS_BIND_DEADLINE_MS/);
1494
+ assert.match(source, /createRegistry\(agentHome, \(event\) => windowsRegistryObservation\.observe\(event\)\), SDK_LIFECYCLE_WINDOWS_REGISTRY_DEADLINE_MS/);
1495
+ assert.match(source, /within\(observer\.listActivations\(\), SDK_LIFECYCLE_WINDOWS_LIST_DEADLINE_MS\)/);
1496
+ assert.match(source, /setTimeout\(\(\) => requestStop\(new SdkLifecycleFailure\("lifecycle-probe", "timed-out"\)\), SDK_LIFECYCLE_PROBE_TIMEOUT_MS\)/);
1497
+ assert.doesNotMatch(source, /createRegistry\(agentHome,[\s\S]{0,160}(?:startupDeadlineMs|rpcDeadlineMs)/);
1498
+ assert.doesNotMatch(source, /Object\.defineProperty\(candidate|Host\.prototype|windowsRegistryObservation\.restore|let expected = "start"/);
1499
+ });
1500
+
1501
+ function openWindowsNativePipe(endpoint: string) {
1502
+ return new Promise<ReturnType<typeof createConnection>>((resolve, reject) => {
1503
+ const socket = createConnection(endpoint);
1504
+ const timer = setTimeout(() => { socket.destroy(); reject(new Error("Windows native pipe did not connect")); }, 2_000);
1505
+ socket.once("connect", () => { clearTimeout(timer); resolve(socket); });
1506
+ socket.once("error", () => { clearTimeout(timer); reject(new Error("Windows native pipe did not connect")); });
1507
+ });
1508
+ }
1509
+
1510
+ function readWindowsNativeAck(socket: ReturnType<typeof createConnection>, expectedId: string) {
1511
+ return new Promise<AckFrame>((resolve, reject) => {
1512
+ const decoder = new FrameDecoder();
1513
+ const timer = setTimeout(() => { socket.destroy(); reject(new Error("Windows native ACK did not arrive")); }, 2_500);
1514
+ const finish = (error?: Error, ack?: AckFrame) => { clearTimeout(timer); socket.removeAllListeners("data"); socket.removeAllListeners("end"); socket.removeAllListeners("error"); error ? reject(error) : resolve(ack!); };
1515
+ socket.on("data", (chunk: Buffer) => { try { decoder.push(chunk); } catch { finish(new Error("Windows native ACK was invalid")); } });
1516
+ socket.once("end", () => { try { const frame = decoder.finish(); if (frame.kind !== "ack" || frame.id !== expectedId) throw new Error(); finish(undefined, frame); } catch { finish(new Error("Windows native ACK was invalid")); } });
1517
+ socket.once("error", () => finish(new Error("Windows native ACK failed")));
1518
+ });
1519
+ }
1520
+
1521
+ function probeWindowsNativeEndpoint(endpoint: string) {
1522
+ return new Promise<string>((resolve, reject) => {
1523
+ const socket = createConnection(endpoint);
1524
+ const timer = setTimeout(() => { socket.destroy(); reject(new Error("Windows native endpoint release timed out")); }, 1_000);
1525
+ socket.once("connect", () => { clearTimeout(timer); socket.destroy(); reject(new Error("Windows native endpoint remained connectable")); });
1526
+ socket.once("error", (error: NodeJS.ErrnoException) => { clearTimeout(timer); resolve(error.code ?? "unknown"); });
1527
+ });
1528
+ }
1529
+
1530
+ test("Windows-native listener accepts legacy listen then rejects stale epochs and accepts a newer epoch", { skip: process.platform !== "win32", timeout: 30_000 }, async (t) => {
1531
+ const root = await mkdtemp(join(os.tmpdir(), "gentle-pi-listen-compat-"));
1532
+ const agentHome = join(root, "profile", "agent");
1533
+ await mkdir(join(agentHome, "gentle-agents"), { recursive: true });
1534
+ const held = await openInitializedHelper(agentHome, { diagnostics: t });
1535
+ try {
1536
+ const legacy = await held.presence("listen", { sessionId: "legacy", createdAt: 1 });
1537
+ assert.equal(legacy.ok, true, "the legacy four-field request remains accepted");
1538
+ const record = legacy.result as Record<string, unknown>;
1539
+ assert.equal((await held.presence("stop-listener", { record })).ok, true);
1540
+ assert.equal((await held.presence("listen", { sessionId: "invalid", createdAt: 2, generation: 1 })).error, "invalid");
1541
+ const newer = await held.presence("listen", { sessionId: "newer", createdAt: 3, generation: 2 });
1542
+ assert.equal(newer.ok, true, "a newer host epoch follows a legacy allocation");
1543
+ } finally { await held.closeInput(); }
1544
+ });
1545
+
1546
+ test("Windows listener source guard publishes only from its Gate-protected readiness transition", async (t) => {
1547
+ t.diagnostic("source guard, not native Windows proof");
1548
+ const source = await readFile(runtime, "utf8");
1549
+ const listenStart = source.indexOf("public static PresenceRecord Listen(");
1550
+ const listenEnd = source.indexOf("public static void Acknowledge", listenStart);
1551
+ assert.ok(listenStart >= 0 && listenEnd > listenStart, "source guard: listener readiness transition was not found");
1552
+ const listen = source.slice(listenStart, listenEnd);
1553
+ assert.match(listen, /byte\[\] pipeDescriptor, byte\[\] presenceDescriptor, string sid/);
1554
+ const lockStart = listen.indexOf("lock (Gate)");
1555
+ const open = listen.indexOf("{", lockStart);
1556
+ assert.ok(lockStart >= 0 && open > lockStart, "source guard: listener readiness must acquire Gate");
1557
+ let depth = 0, close = -1;
1558
+ for (let index = open; index < listen.length; index++) { if (listen[index] === "{") depth++; else if (listen[index] === "}" && --depth === 0) { close = index; break; } }
1559
+ assert.ok(close > open, "source guard: listener readiness Gate region was not balanced");
1560
+ const guarded = listen.slice(open + 1, close);
1561
+ assert.match(guarded, /ArmAccept\(listener\)[\s\S]*?listener\.Publication = PublishOwned\(record\.SessionId, record\.Endpoint, record\.CreatedAt, presenceDescriptor, sid\)[\s\S]*?return record/);
1562
+ assert.match(guarded, /catch \{ FailListener\(listener\); throw; \}/);
1563
+ const cleanupStart = source.indexOf("static void RemoveListenerPublication(");
1564
+ const cleanupEnd = source.indexOf("public static void RemoveOwn", cleanupStart);
1565
+ assert.ok(cleanupStart >= 0 && cleanupEnd > cleanupStart, "source guard: listener publication authority was not found");
1566
+ const cleanup = source.slice(cleanupStart, cleanupEnd);
1567
+ assert.match(cleanup, /OwnedPublication owned = listener\.Publication; listener\.Publication = null;/);
1568
+ assert.match(cleanup, /owned == null \|\| !OwnedPublications\.Contains\(owned\)/);
1569
+ assert.match(cleanup, /RemoveOwnedPublication\(owned\);/);
1570
+ const failureStart = source.indexOf("static void FailListener(");
1571
+ const failureEnd = source.indexOf("static void ClosePipe", failureStart);
1572
+ const failure = source.slice(failureStart, failureEnd);
1573
+ assert.match(failure, /RemoveListenerPublication\(listener\)/);
1574
+ assert.doesNotMatch(failure, /RemoveOwn\(/);
1575
+ });
1576
+
1577
+ test("Windows listener failure source guard emits only a fixed post-cleanup generation event", async (t) => {
1578
+ t.diagnostic("source guard, not native Windows proof");
1579
+ const source = await readFile(runtime, "utf8");
1580
+ const reportStart = source.indexOf("static void ReportListenerFailure(");
1581
+ const reportEnd = source.indexOf("static void FailListener(", reportStart);
1582
+ assert.ok(reportStart >= 0 && reportEnd > reportStart, "source guard: failure reporter was not found");
1583
+ const report = source.slice(reportStart, reportEnd);
1584
+ assert.match(report, /ThreadPool\.QueueUserWorkItem/);
1585
+ assert.match(report, /WriteControl\("\{\\"event\\":\\"listener-failed\\",\\"generation\\":" \+ generation\.ToString\(System\.Globalization\.CultureInfo\.InvariantCulture\) \+ ",\\"error\\":\\"unavailable\\"\}"\)/);
1586
+ assert.doesNotMatch(report, /lock\s*\(Gate\)/);
1587
+ const failureStart = reportEnd;
1588
+ const failureEnd = source.indexOf("static void ClosePipe", failureStart);
1589
+ assert.ok(failureEnd > failureStart, "source guard: failed-listener cleanup was not found");
1590
+ const failure = source.slice(failureStart, failureEnd);
1591
+ assert.match(failure, /RemoveListenerPublication\(listener\)[\s\S]*?foreach \(PipeClient client in listener\.Clients\.ToArray\(\)\) ClosePipe\(client\);[\s\S]*?ReportListenerFailure\(listener\.Generation\);/);
1592
+ const stopStart = source.indexOf("public static void StopListener(");
1593
+ const stopEnd = source.indexOf("public static void Initialize", stopStart);
1594
+ assert.ok(stopEnd > stopStart, "source guard: explicit listener stop was not found");
1595
+ assert.doesNotMatch(source.slice(stopStart, stopEnd), /ReportListenerFailure\(/);
1596
+ });
1597
+
1598
+ test("Windows listener source guard retains owned pipe continuity across the last close", async (t) => {
1599
+ t.diagnostic("source guard, not native Windows proof");
1600
+ const source = await readFile(runtime, "utf8");
1601
+ assert.match(source, /public bool Closed, Writing, Accepting;/);
1602
+ const closeStart = source.indexOf("static void ClosePipe(");
1603
+ const closeEnd = source.indexOf("static void SendEvent", closeStart);
1604
+ assert.ok(closeStart >= 0 && closeEnd > closeStart, "source guard: pipe close transition was not found");
1605
+ const close = source.slice(closeStart, closeEnd);
1606
+ assert.match(close, /listener\.Clients\.Count == 1[\s\S]*?ArmAccept\(listener, client\)[\s\S]*?client\.Pipe\.Dispose/);
1607
+ assert.match(close, /!ArmAccept\(listener, null\)\) FailListener\(listener\);/);
1608
+ const armStart = source.indexOf("static bool ArmAccept(");
1609
+ const armEnd = source.indexOf("static void AcceptPipe", armStart);
1610
+ assert.ok(armStart >= 0 && armEnd > armStart, "source guard: accept ownership transition was not found");
1611
+ const arm = source.slice(armStart, armEnd);
1612
+ assert.match(arm, /candidate != retiring && !candidate\.Closed && candidate\.Accepting/);
1613
+ assert.match(arm, /client\.Accepting = true;[\s\S]*?client\.Pipe\.BeginWaitForConnection/);
1614
+ const failureStart = source.indexOf("static void FailListener(");
1615
+ const failureEnd = source.indexOf("static void ClosePipe", failureStart);
1616
+ assert.ok(failureStart >= 0 && failureEnd > failureStart, "source guard: failed-listener cleanup was not found");
1617
+ const failure = source.slice(failureStart, failureEnd);
1618
+ assert.match(failure, /listener\.Stopped = true;[\s\S]*?RemoveListenerPublication\(listener\)[\s\S]*?ClosePipe/);
1619
+ const stopStart = source.indexOf("public static void StopListener(");
1620
+ const stopEnd = source.indexOf("public static void Initialize", stopStart);
1621
+ assert.ok(stopStart >= 0 && stopEnd > stopStart, "source guard: explicit listener stop was not found");
1622
+ const stop = source.slice(stopStart, stopEnd);
1623
+ assert.match(stop, /listener\.Stopped = true; try \{ RemoveListenerPublication\(listener\); \} finally \{ foreach \(PipeClient client in listener\.Clients\.ToArray\(\)\) ClosePipe/);
1624
+ });
1625
+
1626
+ test("Windows listener ACK watchdog source guard releases Gate before asynchronous write", async (t) => {
1627
+ t.diagnostic("source guard, not native Windows proof");
1628
+ const source = await readFile(runtime, "utf8");
1629
+ const prepareStart = source.indexOf("static bool PrepareAckLocked(");
1630
+ const prepareEnd = source.indexOf("static void BeginAck(", prepareStart);
1631
+ assert.ok(prepareStart >= 0 && prepareEnd > prepareStart, "source guard: ACK state transition must be separated from I/O");
1632
+ const prepare = source.slice(prepareStart, prepareEnd);
1633
+ assert.match(prepare, /client\.Writing = true;/);
1634
+ assert.match(prepare, /client\.Timer\.Change\(PipeDeadlineMilliseconds, Timeout\.Infinite\)/);
1635
+ const beginStart = prepareEnd;
1636
+ const beginEnd = source.indexOf("static void OnPipeTimeout", beginStart);
1637
+ assert.ok(beginEnd > beginStart, "source guard: asynchronous ACK dispatch was not found");
1638
+ const begin = source.slice(beginStart, beginEnd);
1639
+ assert.match(begin, /client\.Pipe\.BeginWrite/);
1640
+ assert.doesNotMatch(begin, /lock\s*\(Gate\)[\s\S]*?BeginWrite/);
1641
+ const acknowledgeStart = source.indexOf("public static void Acknowledge(");
1642
+ const acknowledgeEnd = source.indexOf("public static void StopListener", acknowledgeStart);
1643
+ assert.ok(acknowledgeStart >= 0 && acknowledgeEnd > acknowledgeStart, "source guard: acknowledgement entry point was not found");
1644
+ const acknowledge = source.slice(acknowledgeStart, acknowledgeEnd);
1645
+ assert.match(acknowledge, /PrepareAckLocked\(selected, out ackId\)[\s\S]*?\}\s*BeginAck\(selected, ackId/);
1646
+ const timeoutStart = source.indexOf("static void OnPipeTimeout(");
1647
+ const timeoutEnd = source.indexOf("public static PresenceRecord Listen", timeoutStart);
1648
+ assert.ok(timeoutStart >= 0 && timeoutEnd > timeoutStart, "source guard: ACK watchdog callback was not found");
1649
+ const timeout = source.slice(timeoutStart, timeoutEnd);
1650
+ assert.match(timeout, /if \(String\.IsNullOrEmpty\(timed\.Id\) \|\| timed\.Writing\) \{ ClosePipe\(timed\); return; \}/);
1651
+ });
1652
+
1653
+ test("Windows-native listener readiness registers callback before publication and ACKs only accepted semantic delivery", { skip: process.platform !== "win32", timeout: 30_000 }, async () => {
1654
+ let release!: () => void;
1655
+ const callbackGate = new Promise<void>((resolve) => { release = resolve; });
1656
+ let callbackSeen!: () => void;
1657
+ const seen = new Promise<void>((resolve) => { callbackSeen = resolve; });
1658
+ await withWindowsNativeListener(async (notification) => {
1659
+ assert.deepEqual(notification, { id: "ready-1", senderSessionId: "sender", message: "hello" });
1660
+ callbackSeen();
1661
+ await callbackGate;
1662
+ }, async ({ listener, client }) => {
1663
+ assert.equal(listener.status, "active");
1664
+ const sent = client.sendNotification("recipient", "hello", { id: "ready-1" });
1665
+ void sent.catch(() => {});
1666
+ await waitWindowsNativeSignal(seen, "Windows native callback did not begin");
1667
+ let settled = false;
1668
+ void sent.then(() => { settled = true; }, () => { settled = true; });
1669
+ await new Promise<void>((resolve) => setImmediate(resolve));
1670
+ assert.equal(settled, false, "ACK must wait for semantic callback acceptance");
1671
+ release();
1672
+ assert.deepEqual(await sent, { id: "ready-1", accepted: true });
1673
+ });
1674
+ });
1675
+
1676
+ test("Windows-native listener returns a rejected ACK when semantic delivery rejects", { skip: process.platform !== "win32", timeout: 30_000 }, async () => {
1677
+ await withWindowsNativeListener(async () => { throw new Error("rejected"); }, async ({ client }) => {
1678
+ await assert.rejects(client.sendNotification("recipient", "hello", { id: "reject-1" }), (error: unknown) => error instanceof ActiveSessionClientError && error.code === "remote_rejected");
1679
+ });
1680
+ });
1681
+
1682
+ test("Windows-native listener isolates one held partial pipe while a parallel complete client succeeds", { skip: process.platform !== "win32", timeout: 30_000 }, async () => {
1683
+ await withWindowsNativeListener(async () => {}, async ({ listener, client }) => {
1684
+ let partial: ReturnType<typeof createConnection> | undefined;
1685
+ try {
1686
+ partial = await openWindowsNativePipe(listener.record!.endpoint);
1687
+ partial.write(Buffer.from('{"version":1,"kind":"notification","id":"partial-1"', "utf8"));
1688
+ assert.deepEqual(await client.sendNotification("recipient", "parallel", { id: "parallel-1" }), { id: "parallel-1", accepted: true });
1689
+ } finally { partial?.destroy(); }
1690
+ });
1691
+ });
1692
+
1693
+ test("Windows-native malformed wire is isolated to its connection and does not stop the helper listener", { skip: process.platform !== "win32", timeout: 30_000 }, async () => {
1694
+ await withWindowsNativeListener(async () => {}, async ({ listener, client }) => {
1695
+ let malformed: ReturnType<typeof createConnection> | undefined;
1696
+ try {
1697
+ malformed = await openWindowsNativePipe(listener.record!.endpoint);
1698
+ malformed.write(Buffer.from('{"version":1,"kind":"notification","id":"malformed-1","senderSessionId":"sender"}\n', "utf8"));
1699
+ await new Promise<void>((resolve) => setTimeout(resolve, 25));
1700
+ assert.deepEqual(await client.sendNotification("recipient", "still-live", { id: "after-malformed-1" }), { id: "after-malformed-1", accepted: true });
1701
+ } finally { malformed?.destroy(); }
1702
+ });
1703
+ });
1704
+
1705
+ test("Windows-native stop closes active delivery, removes publication, and releases the endpoint", { skip: process.platform !== "win32", timeout: 30_000 }, async () => {
1706
+ let callbackSeen!: () => void;
1707
+ const seen = new Promise<void>((resolve) => { callbackSeen = resolve; });
1708
+ await withWindowsNativeListener(async () => {
1709
+ callbackSeen();
1710
+ await new Promise<void>(() => {});
1711
+ }, async ({ listener, client, agentHome }) => {
1712
+ const record = listener.record!;
1713
+ const token = record.endpoint.slice("\\\\.\\pipe\\gentle-pi-".length);
1714
+ const publication = join(agentHome, "gentle-agents", "transport", "presence", `recipient.${token}.json`);
1715
+ const pending = client.sendNotification("recipient", "hold", { id: "stop-1" });
1716
+ void pending.catch(() => {});
1717
+ await waitWindowsNativeSignal(seen, "Windows native stop callback did not begin");
1718
+ await listener.close();
1719
+ await assert.rejects(pending);
1720
+ await assert.rejects(stat(publication));
1721
+ assert.equal(listener.status, "closed");
1722
+ });
1723
+ });
1724
+
1725
+ test("Windows-native listener restores full partial-frame accept capacity after deadline closure", { skip: process.platform !== "win32", timeout: 30_000 }, async () => {
1726
+ let callbacks = 0;
1727
+ await withWindowsNativeListener(async () => { callbacks++; }, async ({ listener, client }) => {
1728
+ const partials: ReturnType<typeof createConnection>[] = [];
1729
+ try {
1730
+ for (let index = 0; index < 4; index++) {
1731
+ const socket = await openWindowsNativePipe(listener.record!.endpoint);
1732
+ partials.push(socket);
1733
+ socket.write(Buffer.from(`{"version":1,"kind":"notification","id":"capacity-${index}"`, "utf8"));
1734
+ }
1735
+ await new Promise<void>((resolve) => setTimeout(resolve, 2_250));
1736
+ assert.deepEqual(await client.sendNotification("recipient", "after-capacity", { id: "after-capacity-1" }), { id: "after-capacity-1", accepted: true });
1737
+ assert.equal(callbacks, 1);
1738
+ } finally { for (const socket of partials) socket.destroy(); }
1739
+ });
1740
+ });
1741
+
1742
+ test("Windows-native listener returns the exact rejected ACK after its semantic callback executes", { skip: process.platform !== "win32", timeout: 30_000 }, async () => {
1743
+ let callbacks = 0;
1744
+ await withWindowsNativeListener(async () => { callbacks++; throw new Error("rejected"); }, async ({ listener }) => {
1745
+ const socket = await openWindowsNativePipe(listener.record!.endpoint);
1746
+ try {
1747
+ const id = "raw-reject-1";
1748
+ const ack = readWindowsNativeAck(socket, id);
1749
+ socket.write(encodeNotificationFrame({ version: 1, kind: "notification", id, senderSessionId: "sender", recipientSessionId: "recipient", message: "reject" }));
1750
+ const frame = await ack;
1751
+ assert.equal(callbacks, 1);
1752
+ assert.deepEqual(frame, { version: 1, kind: "ack", id, accepted: false, error: "rejected" });
1753
+ } finally { socket.destroy(); }
1754
+ });
1755
+ });
1756
+
1757
+ test("Windows-native stop removes publication, settles delivery, and releases its returned endpoint", { skip: process.platform !== "win32", timeout: 30_000 }, async () => {
1758
+ let callbackSeen!: () => void;
1759
+ const seen = new Promise<void>((resolve) => { callbackSeen = resolve; });
1760
+ await withWindowsNativeListener(async () => { callbackSeen(); await new Promise<void>(() => {}); }, async ({ listener, client, agentHome }) => {
1761
+ const record = listener.record!;
1762
+ const token = record.endpoint.slice("\\\\.\\pipe\\gentle-pi-".length);
1763
+ const publication = join(agentHome, "gentle-agents", "transport", "presence", `recipient.${token}.json`);
1764
+ const pending = client.sendNotification("recipient", "stop", { id: "stop-probe-1" });
1765
+ void pending.catch(() => {});
1766
+ await waitWindowsNativeSignal(seen, "Windows native endpoint stop callback did not begin");
1767
+ await listener.close();
1768
+ await assert.rejects(pending);
1769
+ await assert.rejects(stat(publication));
1770
+ assert.ok(["ENOENT", "ECONNREFUSED"].includes(await probeWindowsNativeEndpoint(record.endpoint)));
1771
+ });
1772
+ });