diff --git a/build.zig b/build.zig index 62a570a5..a38324f6 100644 --- a/build.zig +++ b/build.zig @@ -156,6 +156,7 @@ pub fn build(b: *std.Build) void { unit_tests.root_module.addAnonymousImport("spec_prompt_cache", .{ .root_source_file = b.path("spec/kernels/prompt_cache.json") }); unit_tests.root_module.addAnonymousImport("spec_prompt_prefix", .{ .root_source_file = b.path("spec/kernels/prompt_prefix.json") }); unit_tests.root_module.addAnonymousImport("spec_prompt_stable", .{ .root_source_file = b.path("spec/kernels/prompt_stable.json") }); + unit_tests.root_module.addAnonymousImport("spec_acp_early_init", .{ .root_source_file = b.path("spec/kernels/acp_early_init.json") }); const run_tests = b.addRunArtifact(unit_tests); const test_step = b.step("test", "Run unit and subprocess integration tests"); test_step.dependOn(&run_tests.step); @@ -178,6 +179,9 @@ pub fn build(b: *std.Build) void { const acp_preauth_test = b.addSystemCommand(&.{ "python3", "scripts/test-acp-preauth.py" }); acp_preauth_test.addArtifactArg(exe); test_step.dependOn(&acp_preauth_test.step); + const acp_early_init_test = b.addSystemCommand(&.{ "python3", "scripts/test-acp-early-init.py" }); + acp_early_init_test.addArtifactArg(exe); + test_step.dependOn(&acp_early_init_test.step); const issue_acp_test = b.addSystemCommand(&.{ "python3", "scripts/test-issue-acp.py" }); issue_acp_test.addArtifactArg(exe); test_step.dependOn(&issue_acp_test.step); diff --git a/docs/adr/0336-the-repl-update-notice-reads-a-cache.md b/docs/adr/0336-the-repl-update-notice-reads-a-cache.md new file mode 100644 index 00000000..993fca8a --- /dev/null +++ b/docs/adr/0336-the-repl-update-notice-reads-a-cache.md @@ -0,0 +1,53 @@ +# 0336. The REPL update notice reads a cache; the network never holds the banner + +Status: accepted 2026-11-12 + +## Context + +The interactive REPL banner called `version_status.checkLatest`, a blocking +GET of GitHub's latest-release endpoint, on every launch. There was no cache +and no time bound beyond the HTTP client's own. With the check on, the banner +phase took about 320–350 ms on a normal network (25–28 ms when the request +failed fast), the largest REPL startup cost. `-p`, ACP and `--json` already +skipped it; `GRAFF_NO_UPDATE_CHECK=1` disabled it. + +## Decision + +The banner notice is stale-while-revalidate (`src/update_check_cache.zig`), +the same shape as model catalogs ([0306](0306-model-catalogs-never-hold-startup.md)): + +- The banner reads `~/.graff/update-check.json` + (`{"v":1,"tag":"","checked_ms":,"tried_ms":}`, + `tried_ms` optional) and renders the notice from it. Boot makes no + network call. +- When that file is missing, unreadable, a different `v`, holds an + unparseable tag, or is 24 h old or more (or dated in the future), one + detached thread refetches the tag and atomically rewrites the file. It has + a private `Io` and allocator, nothing waits for it, and exit never joins + it. +- The refresh first records `tried_ms`, keeping the cached tag, and only + then sends the request. A success rewrites the file without `tried_ms`. A + refresh that fails, hangs, or is cut off by exit therefore holds the + following launches off for 30 minutes, not just until the next launch. + When the file cannot be written at all, a process starts at most one + refresh. The 24 h TTL still applies to successes. +- The file is untrusted input. Numbers outside i64, or that are not + integers, fail the parse and the file reads as missing. Ages are computed + with overflow checks: any i64 timestamp, including the extremes, reads as + stale or as no back-off, never as a crash. A tag that is not a plain + release tag (letters, digits, `.-+`, at most 64 bytes, three or four u32 + parts) never reaches the terminal. +- `GRAFF_NO_UPDATE_CHECK` reads no file and starts no thread. +- The notice wording and the version comparison (`version_status.compare`) + are unchanged; a cached tag not newer than the running build shows nothing. +- `graff update` and `/version` still fetch live, and write the tag they see + to the same file. + +## Consequences + +A new release shows its notice one launch late, and on the first launch +ever there is no notice. A machine that cannot reach the release endpoint +makes at most one request per 30 minutes. If HOME cannot be written, it +makes one per launch, the same as the old per-launch check. Revisit if the +notice must be same-launch accurate; that needs a bounded wait, not a +return to the blocking fetch. diff --git a/docs/adr/0337-a-one-shot-prewarms-the-companion-handshake.md b/docs/adr/0337-a-one-shot-prewarms-the-companion-handshake.md new file mode 100644 index 00000000..6da37c5a --- /dev/null +++ b/docs/adr/0337-a-one-shot-prewarms-the-companion-handshake.md @@ -0,0 +1,108 @@ +# 0337. A one-shot prewarms the companion handshake; teardown ends retry pauses + +Status: accepted 2026-11-12 + +## Context + +`-p` connects the companion (`codedb-pro --mcp`) on the boot thread: +ADR 0230 defers it only for interactive and ACP sessions +(`companion_boot.deferCompanion`), so the first request's catalog already +holds the companion. Its spawn and handshake ran in series after +credentials, the plugin scan and the MCP merge. With no tool cache, a +hermetic one-shot with a stub companion sent its first request at a median +of 24.2 ms, against 14.0 ms with no companion on PATH. + +Teardown had the opposite problem. `Registry.deinit` joins every pending +start, and a start that failed transiently slept 1.5 s before its one retry, +with no way to wake it. A REPL whose companion failed at once was ready in +about 50 ms but took about 1.54 s to exit. + +## Decision + +- **Overlap, not defer.** A one-shot starts the companion connect on its own + task (`boot_prewarm.startCompanion`) once credentials have resolved and + the banner has settled the cwd. `main` defers `boot_prewarm.discard` + right after the start. The boot thread joins the task in + `connectCompanion`, exactly where `addServer` ran. + The handshake is not deferred past the first request, so the first + request's tools, prompt and cache key are byte-identical to the serial + path. +- **Only when the outcome is known in advance.** The prewarm starts only + when the registry will be the empty one and this companion is the one + `connectCompanion` would try first: lean `-p`, no positionals, no `-w`, no + project `.mcp.json`, none of `GRAFF_MCP_PROBE`, `GRAFF_MCP_EAGER`, + `GRAFF_MCP_HANDSHAKE_SECS` or `GRAFF_MCP_PROBE_MS`, not opted out in + `.harness/settings.json`, and on `PATH`. Every other session keeps the + serial path. +- **Join at the consumer, or discard.** `take` adopts the result only if the + cwd, home and registry settings still match, awaits it, and merges it + under the registry mutex (ADR 0197). Discard stops the attempt's child, + joins the task and tears the outcome down. It applies to a mismatch, or to + a prewarm nobody adopted, at three points: in `connectCompanion`, in + `Registry.deinitAtExit`, and on any return between the start and the + registry (`main`'s defer). The task is never cancelled: a cancel delivered + inside the bounded handshake's `Io.Select` returns before the select's + read task stops. Instead, the worker's task-local registry publishes each + child it spawns (`Registry.spawn_watch`, `boot_prewarm.Watch`). Discard + kills that child, so the handshake read ends at once. The worker forgets + its child before it reaps it, under the same lock, so a pid that may + already be reused is never signalled. +- **One attempt.** An attempt that ran to a result is the attempt the serial + path made. Its error is returned as `addServer`'s would have been, with the + same (empty) diagnostics; the companion is not started again. Only when no + attempt ran to a result (none started, or discarded on a mismatch) does the + consumer call `addServer` inline. +- **Teardown ends retry pauses.** Each registry owns a heap event, + `retry_abort`. `Registry.deinit` sets it before joining, and the pause in + `mcp_start` waits on it. A start waiting to retry stops waiting and + records its first failure. The registry still joins every task, so no + thread outlives `io` (#325). +- **Formal evidence.** `formal/BootPrewarm.tla` models the fatal exits, the + early error return and both discards. Each of these invariants has a + negative control: `ExitClean` (no live companion and no unjoined worker + once the process exits), `NoExitStall`, `NoRepeatAfterResult`, + `JoinedBeforeUse`, `NoStaleAdoption` and `NoRetryAfterAbort`. The model + also checks `NoUseAfterTeardown`, but the runtime's join rules that out by + construction (`formal/boot-prewarm.md`). + +## Consequences + +- The gain applies to a cold MCP tool cache only: the first `-p` per HOME, + or the first after the companion binary changes. There, `-p` reaches its + first request in about `max(companion, rest of boot)` instead of their + sum. With a warm cache the companion is restored dormant in both paths: + the prewarm task spawns no process, and gains and costs nothing + measurable. The pre-series binary spawned none either. +- Measured on macOS, hermetic `-p hi --model lmstudio`, fresh HOME with 15 + plugins, a stub companion that answers after 6 ms. Medians of the first + POST, 20 runs each, alternating with the pre-series binary: + + | Companion | Pre-series | Now | Companion spawns per run | + | --- | --- | --- | --- | + | answers, cold tool cache | 22.1 ms | 18.6 ms | 1 / 1 | + | answers, warm tool cache | 12.6 ms | 12.4 ms | 0 / 0 | + | fails (exits 1) | 24.5 ms | 20.2 ms | 2 / 2 | + | not on PATH | 11.6 ms | 11.7 ms | 0 / 0 | + + A failing companion is spawned twice by both, because the stdio probe + respawns a process that closed. The first revision of this change retried + the failed attempt inline: 4 spawns and 32.2 ms. +- The companion's connect line on stderr can print earlier than other boot + diagnostics. +- A run that fails on credentials or in the banner spawns no companion, as + before. Those paths exit through `std.process.fatal`, which runs no defer. + Credential resolution measures about 0 ms for a one-shot with an + environment key, so starting after it costs no overlap. With a + Keychain-only credential the lookups no longer overlap the handshake. +- On Windows, `Watch` has no signal, so a discard waits for the attempt, + which the handshake timeout bounds. +- An interrupted retry is not attempted again in that process; the next + session starts the server again. +- The plugin scan is not prewarmed. `plugins.applyEnv` stores + `plugins.disabled` on the boot thread while a scan worker would read it in + `discoverFresh`. With the companion prewarmed, the scan already overlaps + the longer handshake. Revisit it if `applyEnv` stops storing an unchanged + value, or if the scan becomes the longest boot phase. +- Moving the one-shot companion to the background entirely, as ADR 0230 + does for interactive sessions, would make the first request's catalog + depend on timing. That stays an owner decision. diff --git a/docs/adr/0338-acp-answers-initialize-during-boot.md b/docs/adr/0338-acp-answers-initialize-during-boot.md new file mode 100644 index 00000000..18cd9132 --- /dev/null +++ b/docs/adr/0338-acp-answers-initialize-during-boot.md @@ -0,0 +1,85 @@ +# 0338. ACP answers `initialize` during boot + +Status: accepted 2026-11-12 + +## Context + +An ACP client spawns `graff acp` and sends `initialize` first. The dispatch +loop started only after the root Agent existed, so the answer waited for the +whole boot: worktree identity, MCP registry, settings, companion, approvals, +system prompt and root construction. The response itself reads none of that. +It depends on the request, the `GRAFF_ACP_V2` gate (ADR 0206), the version +string and whether the dispatch can load sessions. The credential-free path +already answers it without an Agent. + +Answering earlier has three ways to go wrong. The request could be answered +twice, or not at all. A stdin byte could be lost or reordered between an +early reader and the loop's reader. Or the live `Dispatch` and the process +latches that `initialize` sets could differ from the late path's. + +## Decision + +- Each boot phase mark is also a check, and so is the point where stdin and + stdout are created. The check runs on the main thread. It reads stdin only + while `poll` reports it readable, so boot never waits for the client. It + never reads past a full buffer, and it never reads outside ACP. +- There is one stdin reader. The ACP inbox pump later reads the same reader, + so the bytes after the first line stay where they were. +- For a complete first line that is an `initialize` request with an id, the + engine's own `handleLine` renders the answer on a fresh dispatch whose + `can_load` matches the live one. The answer is written only to a clean + protocol stdout. Only after the whole line was written and flushed is the + request taken off the reader and kept. If rendering or the write fails, + nothing stays buffered, the line stays on the reader and the checks stop. + The loop then answers it, or fails the way it would have anyway. + (Bytes the OS accepted before a write error cannot be taken back. The + transport is broken by then, and the loop's write fails too.) +- Any other first line (no `initialize`, a notification, invalid JSON, or a + line larger than the buffer) is left in place. So is an incomplete one. + After a non-`initialize` first line the checks stop. +- When the loop starts, the kept line is dispatched through the normal loop + body first, and its output is discarded. The live dispatch fields and the + latches are rebuilt by the code the late path runs. The latches are + last-writer-wins: the v2 message-id seed is the live dispatch's. +- One pure `step` makes the decision. It is modelled in + `lean-proofs/Graff/AcpEarlyInit.lean`, and the Zig code calls it. Over + every boot trace, including ones where the early answer fails, the model + proves line bookkeeping only: + - the first `initialize` is answered exactly once; + - a line is taken only after its answer was sent; + - the replay writes nothing; + - a non-`initialize` first line reaches the loop unchanged; + - stdout and the dispatch history equal the late path's. + It assumes that the response is a function of the request alone, and that + equal dispatch history means equal dispatch state. It says nothing about + bytes, the poll, the reader or timing. +- The byte-equality claim rests on two tests, not on the Lean kernel: + - the Zig conformance test, which runs the real engine early and late on + each of the 360 cells of the `initialize` cube and compares bytes and + latches; + - `scripts/test-acp-early-init.py`, which drives the built binary at + random write offsets during boot and compares stdout with a client that + writes after boot. +- A build without ACP (`-Dacp=false`, `-Dminimal`) declines at comptime, so + the engine is not compiled in. +- No thread is added, so no TLA+ model is needed (`formal/README.md`). + +## Consequences + +`initialize` arrives within one boot phase of the request instead of after +root construction. `session/new` and everything after it still wait for the +loop. The no-credential pre-auth path is unchanged. + +Differences from the late path: + +- If boot fails after the early answer, the client has seen `initialize` + succeed and then sees EOF. Before this change it saw EOF alone. +- The handshake log's `startup` phase still measures time to the loop. It + times the replay, not when the client was answered. +- A request that arrives during root construction is answered at the + `root agent` mark, just before the loop would have answered it. With + worktree identity resolved in-process that phase takes about 2 ms, so + `buildRootAgent` has no checks of its own. If it grows long again, it + needs a check between its steps; none exists today. +- Windows has no `poll` on stdin. There, only bytes already buffered count, + which in practice means the late path. diff --git a/docs/adr/0339-a-one-shot-joins-the-companion-handshake-with-a-budget.md b/docs/adr/0339-a-one-shot-joins-the-companion-handshake-with-a-budget.md new file mode 100644 index 00000000..83750649 --- /dev/null +++ b/docs/adr/0339-a-one-shot-joins-the-companion-handshake-with-a-budget.md @@ -0,0 +1,216 @@ +# 0339. A one-shot joins the companion handshake with a budget + +Status: accepted 2026-11-12 + +## Context + +[ADR 0337](0337-a-one-shot-prewarms-the-companion-handshake.md) prewarms the +companion (`codedb-pro --mcp`) so a lean `-p` one-shot's first request already +carries its tools, and joins it in `connectCompanion` +(`boot_prewarm.take`). The join was unbounded, and the attempt's own ceilings +are the stdio probe's 5 s (`GRAFF_MCP_PROBE_MS`) plus `initialize`'s 15 s +(`GRAFF_MCP_HANDSHAKE_SECS`). A companion that spawns and then never answers +held the first request for 20.1 s — measured on macOS with a stub first on +PATH, on a run whose answer otherwise takes ~25 ms. Nothing on screen names +the wait, and a user cannot tell it from a stalled model. A healthy companion +answers in ~6-50 ms and a missing one is not started at all, so the unbounded +join only ever bought patience for the pathological case. + +The documented knobs did not reach it. `GRAFF_MCP_HANDSHAKE_SECS` and +`GRAFF_MCP_PROBE_MS` are applied by `mcp_rpc.applyHandshakeTimeoutEnv`, which +runs in `mcp_boot.initWithMerged` — the path `oneshotSkipsImportedMcp` skips on +a lean `-p` — and `boot_prewarm.wantsCompanion` refuses to prewarm at all when +any of those variables is set. The one case where a shorter handshake would +help was the one case where it could not be asked for. + +The first version of this change bounded the join and got three things wrong, +all three found by review against it and fixed here: teardown was only bounded +on POSIX (`signal` returned early on Windows, so `stopAtExit` still awaited the +attempt, up to the probe plus handshake caps); a companion that failed *after* +the budget was reported as a successful connect and its error was dropped; and +the two late-merge tests were order-dependent, so a failure in one corrupted +the run instead of failing where it happened. + +A second review against that fix found a fourth, and it is the one a user would +have seen: teardown's own kill came back out as a connect failure. Ending a +healthy companion because the run is ending is not the companion failing, but +the worker reported the `McpClosed` that kill produces exactly like one, so a +normal `-p` exit printed `companion: codedbpro failed to connect after the boot +budget (McpClosed); native tools only` on its way out — after the tools it was +claiming had failed to arrive. + +## Decision + +- **A join budget, not an unbounded await.** `take` waits + `boot_prewarm.default_budget_ms` for the attempt and then returns. 250 ms is + the `acp_mcp_servers.attach_budget_ms` precedent for the same decision, 1500 + ms on Windows as there. `GRAFF_MCP_COMPANION_BOOT_MS` overrides it; unset, + `0` or unparsable mean the default, and anything above the 60 s cap is + clamped to the cap — a typo buys a long bound, never the unbounded join, and + never a silent fall back to the default either. It is read where the prewarm + starts (`startCompanion`) — not by `applyHandshakeTimeoutEnv` — and it is + deliberately not in `wantsCompanion`'s disable list: a knob for this path + must not turn the path off. The wait is an `Io.Event` deadline set by the + worker's last write, not a poll: a 2 ms `io.sleep` costs ~5 ms of overshoot on + macOS, which turned a 250 ms budget into a 355 ms wait. +- **Over budget, the attempt keeps running and merges itself.** `take` hands + `reg` to the watch (`Watch.late_merge`, written once under the same lock as + `Watch.done`, asserted null before the write) and reports `.late`, so + `connectCompanion` neither waits nor falls back to `addServer`: one spawn + either way. Whichever side gets there first consumes the outcome exactly + once — `take` awaits the future and adopts, or the worker merges through + `mcp_boot.adoptStarted`, the single merge point, which drops a latecomer + whose server name is already connected (#505: two copies of every tool make a + strict Responses endpoint reject the request) and keeps its arena in + `task_arenas` for the normal teardown. +- **`.late` is not "connected", and a late failure is not a success.** `take` + and `connect` return `Adopted`: `.connected` (the catalog is in the + registry), `.late` (still running, this registry is its merge target), or an + error. A failure that lands before the budget keeps the contract the serial + path had — `take` returns it, `error.McpClosed` included. A failure that + lands *after* the budget has no request left to return to, so the worker + records it (`lateOutcome` / `lateError`) and prints one line to stderr + (`companion: failed to connect after the boot budget (); native + tools only`). `connectCompanion` names the other half of the same fact for + `.late` (`companion: still connecting after the boot budget`). Both + lines go to **stderr**, which is the only destination this path can reach: + the dim engine notice `connectCompanion` prefers needs `GRAFF_REPL_DEBUG` + *and* an interactive session, and every interactive session — REPL and ACP + alike — queues the companion on `pending_starts` instead, so the branch that + could reach the sink is the one only `-p` and `--json` take, where `speak` is + already false. Silence is what made a late failure indistinguishable from a + connect; one line on stderr is what it gets instead. +- **A stop the exit path asked for is not a failure.** `stopAtExit` ends the + attempt the run can no longer wait for, and the child's death arrives as a + `McpClosed` like any other. Reported as one, a healthy companion printed the + failure line above on a normal exit. `Watch.settle` now reads the stop intent + in the same critical section as the merge target, so an attempt whose read + returned `McpClosed` because teardown killed it publishes `.stopped`: the + outcome is recorded, never printed, and `lateError` stays null — `.failed` is + the only state that carries an error. A companion that genuinely failed at + the instant teardown asked it to stop is indistinguishable and is recorded as + `.stopped`, which is the quiet direction a dying run can afford. `stopAtExit` + returns that outcome because the slot and its watch are freed at exit, so + `lateOutcome` has nothing left to read; `boot_prewarm_tests` pins `.stopped` + against `.failed` there. +- **`discard` keeps its meaning; `stopAtExit` is new and bounded on both + platforms.** `discard` still means "nobody wants it: stop, join, tear down", + and now leaves a handed-off attempt alone — it is running on purpose. + `Registry.deinitAtExit` calls `stopAtExit` instead: end the child, join the + worker, tear down. `Watch.signal` ends the child on both platforms — POSIX + `SIGKILL`, and on Windows `NtTerminateProcess` on the process handle + (`Child.Id` is that handle there) — without waiting or freeing the `Child`, + which the worker still reaps. So the join is bounded by "the read sees end of + stream", not by the 5 s probe plus the 15 s handshake, and that runs before + `reg.deinit()`, which is what makes the worker's late merge safe at exit. +- **The one-shot's own exits take the same path.** `std.process.exit` unwinds + no `defer`, so `main`'s `deinitAtExit` never runs on the two exits inside + `oneshot.run` — the provider-failure one and the `budget_exhausted` / + `unfinished_work` one a `-p` run actually takes. Both call + `boot_prewarm.stopAtExit(io)` first. They still skip the rest of the + registry's teardown, as they did before; what they no longer do is abandon a + live worker and, on Windows, orphan the companion process. +- **A run that is going to fatal prewarms nothing.** The side finding that + framed this work — a keyless `-p` spawning the companion before exiting 1 — + does not reproduce on this tree. `main` starts the prewarm after + `resolveKeysOrRunAcpPreAuth` returns, and that call is an `orelse return`, so + the credential fatal returns first: `-p hi` with no key and a stub on PATH + spawns nothing and exits in ~66 ms. `boot_prewarm_tests` pins the ordering. + +## Consequences + +- The pathological case is gone, and nothing is given up in the normal one. + Measured on macOS, hermetic `-p hi --model lmstudio`, stub `codedb-pro` first + on PATH, stub answers after N ms, medians of wall clock over the binaries + built from the same tree with and without this change: + + | Stub companion | Before | After | First request's companion tools | + | --- | --- | --- | --- | + | answers in 6 ms (n=8) | 23.3 ms (22.0-24.8) | 23.0 ms (22.1-25.4) | `codedbpro (search, read)` in 8/8 both | + | answers in 600 ms (n=5) | 624.6 ms (618.4-642.6) | 265.9 ms (264.8-266.9) | present before, absent after | + | never answers (n=5) | 20 134.0 ms (20 125.7-20 179.4) | 266.1 ms (263.9-300.5) | absent both | + + Re-measured on the fixed tree: a 6 ms stub answers in 20.3 ms (n=8) with + `codedbpro (search, read)` on the first request in 8/8, and a silent stub + costs 263.5-265.0 ms (n=5, three runs) with one spawn per run. The silent row + is why this is not a regression for it: the unbounded join paid 20 s and + still ended with no companion tools, because the attempt failed at its own + timeout. +- **Teardown is bounded too, and that is measured, not argued.** With a silent + child, the handshake cap lowered to 1200 ms and the join already handed off, + `stopAtExit` on macOS takes 0-1 ms (n=3) with the child kill in place and + 1025-1037 ms (n=3) with it suppressed — the attempt's own handshake timeout, + which is what the reviewer measured as 1191 ms against the version this + fixes. **Windows is unmeasured; what is verified there is a cross-compile.** + `zig build -Dtarget=x86_64-windows` builds the Windows branch and is the + command that passes — the whole binary, not the test binary: `zig build + test-bin -Dtarget=x86_64-windows` does not link, leaving `fchdir`, `setenv` + and `unsetenv` undefined from `src/git_dirs_tests.zig`. That builds the + branch, but it does not run it, so it says nothing about whether a + terminated child's pipe reads return promptly on Windows, and therefore + nothing about whether the join there is ~0 ms or one handshake timeout. What + is known by reading: `Child.Id` is the process handle on Windows, and + `NtTerminateProcess` is what `Child.kill` itself issues before it reaps. The + kill is a signal, not a cancellation: the worker is never cancelled (a + cancel that lands inside the bounded handshake's `Io.Select` returns before + the select's read task stops, and that task would outlive its frame). +- The trade-off is the middle row: a cold-and-slow companion can miss the + one-shot catalog. It keeps connecting, and a late merge is the same event + `/mcp add` causes — the next request sees the tools and the prompt cache is + busted from that turn (ADR 0221) — but it can also land after the run's last + request and never be seen at all. Nothing here can both hold the first + request and keep the catalog of a companion that has not answered. That the + degradation is now visible (`.late` plus a one-line notice) is the only claim + made about it: the catalog itself is still lost. +- **The exit path is quiet, and measured on the binary as well.** A stub that + answers in 200 ms, `GRAFF_MCP_COMPANION_BOOT_MS=1`, and a `-p hi --model + lmstudio` run that finishes in ~18 ms: teardown kills the attempt in its + handshake, and the version this fixes prints `companion: codedbpro failed to + connect after the boot budget (McpClosed); native tools only` on stderr in + 3/3 runs, this one in 0/3, recording `.stopped` instead. The silent row of + the table above is the same defect seen from the other side: a stub that + never answers printed that line 3/3 before and 0/3 now, and the wall clock it + measures did not move — 266.7-274.3 ms (n=12, two invocations, medians 268.3 + and 268.1) against the 263.5-265.0 ms recorded here before. The other + direction is unchanged: a companion that exits 1 at 300 ms while the run is + still waiting on the model (1 s response) still prints that line exactly once + (3/3 before, 3/3 after), and a healthy 5 ms companion still shows its catalog + and no such line, at the 250 ms default and at a 1 ms budget alike (3/3 + each). +- **What is still not fixed, stated plainly.** A companion whose handshake has + not finished when the run ends is now lost quietly: no failure line, and no + catalog either, because the exit path kills it rather than waiting. `.stopped` + and `.failed` cannot be told apart when a companion dies at the same instant + teardown asks it to stop; the record says `.stopped`. The Windows join time + and the Windows pipe behaviour on a terminated child have not been run. A + late merge can land after the run's last request, so the catalog exists and is + never seen. And the budget is clamped at 60 s, so a genuinely slow companion + cannot be waited for through the knob. +- Interactive and ACP sessions are untouched: they queue the companion on + `pending_starts` (ADR 0230) and never create a prewarm slot, so the budget + exists only on the `-p` path. The one shared line, `Registry.deinitAtExit`, + is a no-op when no slot exists. +- The worker now merges from a task thread rather than the boot thread. Every + reader that matters takes the registry mutex (`snapshotTools`), the same + assumption a deferred start's join already makes. +- **The late-merge tests own their fixtures.** Each defers `stopAtExit` before + its first assertion, so a failed `expect` still joins the worker before the + registry it merges into is deinited; otherwise one failure leaks the slot and + the next test crashes inside a merge into freed memory. Each states its own + premise (`.late`, empty catalog) instead of depending on a fixture that has + not landed yet, and each names its property through the worker's published + outcome (`.merged`, `.duplicate`, `.failed`) rather than through "nothing + visibly went wrong" — a dropped latecomer and a merge that never happened + look identical from the registry otherwise. Proved by mutation, each applied + to the fixed tests and run over the whole filtered suite: deleting + `and !s.watch.handOff(reg)` fails all three budget tests in `waitForLate` + (`TestExpectedLateMerge`) — `take` still reports `.late`, but nothing ever + merges it — with the other 120 passing; deleting `w.late_merge = reg` fails + the same three the same way, and the tests that follow still pass with no + leaked allocations, which is the case that used to segfault the next test; + deleting `done_event.set(io)` fails only the join-wake test, at + `expect(ms < 500)` (1200 ms budget, one instant answer), with 122 passing. +- Revisit by raising `default_budget_ms`, not by restoring the unbounded join; + measure with `scripts/bench-startup.py --companion` plus a first-request + body capture (the schema gate's `Deferred now:` line names what was left + out). diff --git a/docs/adr/0340-a-cold-catalog-cache-never-holds-boot.md b/docs/adr/0340-a-cold-catalog-cache-never-holds-boot.md new file mode 100644 index 00000000..3c288231 --- /dev/null +++ b/docs/adr/0340-a-cold-catalog-cache-never-holds-boot.md @@ -0,0 +1,116 @@ +# 0340. A cold catalog cache never holds boot + +Status: accepted 2026-11-12 + +## Context + +`startup.resolveKeysOptional` runs `router_catalog.ensureForStartup` before the +prompt. For every keyed dynamic provider with **no** disk cache it started a +live `/v1/models` GET and waited for it in `catalog_bounded.Batch.wait` (a 5 ms +poll, capped at `startup_budget`, 800 ms). A cached catalog, fresh or stale, +never waited: it activated and refreshed behind. So the wait was paid exactly +when there was nothing on disk — every first-ever boot, every fresh `HOME`, and +every boot after a rejected key, because a 401 writes no cache. + +Anthropic is dynamic (`models_url` `https://api.anthropic.com/v1/models`), so a +run with an Anthropic key and no cache paid one TLS round trip to that host +before it accepted a keystroke: 237-261 ms by `curl` from the machine measured, +plus the poll quantum and the thread spawn. An external startup benchmark +(fresh `HOME`, tmux, loopback mock model, dummy OpenAI and Anthropic keys) +reads exactly that: time to first accepted keystroke ~310-320 ms with both keys, +~71-76 ms with only the OpenAI key (OpenAI's list is baked, nothing spawns). + +The list only feeds the model pickers, `/models`, and context windows of +discovered rows. The baked rows in `pricing.zig` are the documented fallback +and already what a boot sees when the fetch misses the budget or fails. + +## Decision + +- **A cold cache detaches, like a stale one.** `startSpec` (now in + `router_catalog_boot.zig`) activates a fresh or stale cache exactly as + before; with no cache it marks the provider in `catalog_landing` and hands + the fetch to `catalog_bounded.detach`. Boot proceeds on the baked rows. Kimi's + account catalog takes the same path in `startKimi`, with its existing + `"baked fallback — live catalog still loading"` source line. +- **The list activates when the fetch lands, on the main thread.** The worker + cannot touch the model table or the session arena, so it only reports + (`catalog_landing.settle`: static atomics). `activateLanded` takes each + landed slot once and activates the cache the worker wrote; it runs at the + top of `router_catalog.ensureForQuery`, the beat every `/model` picker, + `set_model`, and the stdin chat REPL already go through. `/models` refetches + live anyway (`refreshForListing`), and `--schema` / ACP model options read + every cache (`loadCachedAll`); ACP model options also run `activateLanded` + at every `acp_model_option.hydrate`, the same beat shape as the REPL picker. + A stale cache's refresh is not marked, so it + still lands for the next process only — that path is byte-for-byte unchanged. +- **One case still waits, bounded as before: a `--model` the baked rows cannot + resolve.** Startup resolves `--model` before the prompt and fatals on an + unknown row (`qualifiedProvider`, `resolveModelName`). On a cold cache a model + the provider serves but the baked table lacks would be refused without the + live list, so `needsLiveRows` keeps that fetch in the batch under + `startup_budget`. A provider name, an exact baked row, a saved model (a + catalog omission never changes it), or no flag never waits. +- **Failure stays quiet and is not retried.** A failed or rejected fetch + clears its landing mark, activates nothing, and writes no cache. Its status + is recorded in `catalog_failures` as before, which only the listing commands + print; boot prints nothing. The once-per-process attempt latch is set before + the detach, so neither `ensureForQuery` nor a second startup pass starts + another GET. The next process tries once more, as it always did. +- **Exit never waits for the worker, and the worker writes nothing exit + frees.** As in ADR 0336 and `catalog_bounded`, joining is not an option: a + worker parked in `getaddrinfo` cannot be cancelled. Unlike ADR 0339's late + merge, nothing here needs a `stopAtExit`, because the worker's only outputs + are the cache file (an atomic replace), its own `smp_allocator` task, and + static atomics (`catalog_landing`, `catalog_failures`). The one input that + lived in freed memory was the workspace router's spec, parsed into the + session arena that `main` frees on return; `router_config.load` now copies + its strings into never-freed memory (`outliveSession`), which also covers + the stale-refresh and over-budget paths that already detached it. + +## Consequences + +- Measured with the same external rig and measurement path, `graff` REPL, + fresh `HOME`, both dummy keys, binaries built with + `zig build graff -Doptimize=ReleaseSafe -Dlearn=false` from the base and from + this change, three rounds of n=12 each, alternating before/after: time to + first accepted keystroke **312.0 ms before (n=36, 298.3-340.1, IQR + 305.9-322.7) → 57.2 ms after (n=36, 55.0-74.3, IQR 56.0-61.3)**. The + catalog still lands: with a loopback `/v1/models` behind a Z.AI key + (`GRAFF_ZAI_URL`), a fresh-`HOME` boot writes `zai-models.json` while + sitting at the prompt, the first `/model` picker lists the fetched rows, and + a later `graff models` lists them from the cache with the endpoint down. + The dummy Anthropic key itself gets a 401, so that run writes no cache. +- **The trade-off: a first-ever boot's `/model` picker briefly shows baked + rows.** Until the fetch lands (one round trip, ~250 ms against Anthropic) the + provider's slice is the baked one; the first picker opened after that shows + the live list. ACP model options read the caches once per live session + (`acp_model_option.hydrate`), so a session built before the landing kept + the baked list until a `/model`. That gap is now closed and measured: + `hydrate` runs `activateLanded` on every beat, and with a fresh `HOME`, a + loopback `/v1/models` behind a dummy Z.AI key (`GRAFF_ZAI_URL`) answering + after 1.2 s, and `graff acp` initialized as t3-code, `session/new` before + the landing served the 7 baked zai rows; after the fetch landed, the same + session's model options (re-read through a `session/set_config_option` + response) and the `graff/models` view listed the landed row, no `/model` + issued — the pre-fix binary kept the 7 baked rows on both re-reads. A boot + whose fetch fails sees the baked rows, as it did when the fetch failed + inside the budget. +- **Rejected: a small blocking budget (e.g. 100 ms) on a cold cache.** It still + adds up to that much to every first keystroke, and the fetch it protects is + ~250 ms to a real provider, so it would almost always expire anyway and buy + nothing but the delay. The one boot whose correctness depends on the live + list — `--model` naming an unbaked row — keeps the full budget instead. +- A cold `--model` that names an unbaked row still pays up to 800 ms, as before. + Revisit if that shows up in a benchmark; the fix there is a lazy model + validation, not a shorter wait. +- Tests (`router_catalog_boot_tests.zig`) drive the real `ensureForStartup` + against a loopback catalog that answers after `startup_budget + 700` ms: + boot returns in under a quarter of the budget, the list activates through + `ensureForQuery` once the worker lands, a stale cache still activates now and + refreshes for the next process, a 401 activates nothing and starts no second + GET. Restoring the batched cold path fails the first at its elapsed-time + assertion; dropping the `activateLanded` call fails it at the activation. + `acp_model_option.zig` pins the ACP half: a session that hydrated before a + landing must activate the landed rows on its next `hydrate`, and removing + that call fails the test at the same assertion (mutation-verified in a + tree copy). diff --git a/docs/adr/README.md b/docs/adr/README.md index 288dea9e..c904178e 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -360,6 +360,11 @@ record only when you need the evidence or the edge cases. | [0333](0333-bots-are-folders-and-routines-need-a-tick.md) | A Bot is the folder `.graff/bots//` (job, `memory.md`, `log.md`, routines); a run is one headless turn with those appended to the system prompt. Routines fire only when `graff bot tick` or a client's `graff bot due --claim` runs: there is no daemon. Approvals stay the headless default unless the bot was created with `--yolo`; an event payload is data, not instructions. | | [0334](0334-bots-can-be-per-user-and-a-late-check-reports-what-it-missed.md) | `graff bot --user` is the same store in `~/.graff/bots`, with a `project` its runs work in, one `primary` bot and a client's `chat` id. `tick`/`due --claim` record the last check; with `--stale-after` an old slot is recorded as missed (`graff bot missed`) and not run late. In a client's chat a bot changes its store with `graff bot remember\|forget\|log`, not file edits. `graff bot state --json` is one call for everything a client draws. Bots are off until `graff bot enable` writes `~/.graff/bots/enabled` (`GRAFF_BOTS=1\|0` decides for one process); while off every other `graff bot` command refuses. | | [0335](0335-the-primary-bot-works-across-projects.md) | The primary bot is the user's main bot: one thread for every project. In a client's chat it starts each piece of work as its own chat where it belongs (Harness: `list_projects`, `create_chat`), ends its turn, and reports when the reply comes back; it asks only when the project is unclear, and leaves publishing, sending, paying and deleting to the user. Headless, it names the project and gives the command. Single-job bots are helpers it hands work to. All of it is prompt text; the store is unchanged. | +| [0336](0336-the-repl-update-notice-reads-a-cache.md) | The REPL banner's update notice is read from `~/.graff/update-check.json` and boot makes no network call; a missing, corrupt or 24 h-old cache is refreshed on a detached worker with a private Io that exit never joins, so a new release shows one launch late. A refresh records `tried_ms` first, so a failed or interrupted one holds later launches off for 30 minutes, and an unwritable cache is tried once per process; any timestamp reads as stale, never as a crash. `GRAFF_NO_UPDATE_CHECK` reads and starts nothing; `graff update` and `/version` still fetch live and write the cache. | +| [0337](0337-a-one-shot-prewarms-the-companion-handshake.md) | A lean `-p` that will build the empty registry starts the companion connect once credentials resolved and the banner settled the cwd, and joins it in `connectCompanion` where `addServer` ran, so the first request's catalog is byte-identical. The attempt is the one attempt: its error is returned, not retried inline. A mismatch or an unadopted prewarm is stopped (its child killed, never a task cancel), joined and torn down, including on any return before the registry (`main` defers the discard). The gain is for a cold tool cache only. `Registry.deinit` sets `retry_abort` so exit never waits out a start's retry pause, and still joins it. Modelled in `formal/BootPrewarm.tla`. | +| [0338](0338-acp-answers-initialize-during-boot.md) | `graff acp` answers `initialize` at a boot phase boundary: a non-blocking check takes a complete first `initialize` off the one stdin reader, answers it through the engine's `handleLine`, takes it off the reader only once the whole answer was flushed, and replays it silently at loop start so dispatch state is rebuilt by the late-path code; any other first line, or a failed answer, is left for the loop. `Graff.AcpEarlyInit` proves the line bookkeeping only; byte equality rests on the Zig real-engine cube test and `scripts/test-acp-early-init.py`. Builds without ACP compile none of it. | +| [0339](0339-a-one-shot-joins-the-companion-handshake-with-a-budget.md) | A one-shot joins the prewarmed companion with a 250 ms budget (`GRAFF_MCP_COMPANION_BOOT_MS`, 1500 ms on Windows; unset/0/garbage mean the default, above the 60 s cap clamps to it). Over budget the attempt keeps running and merges into the live registry when it lands instead of being cancelled or restarted, so a warm companion's catalog is unchanged and a silent one costs the budget, not the probe plus handshake caps. The join reports `.late`, never "connected"; a failure that lands after the budget is recorded and printed (stderr on `-p`), and a stop teardown asked for is recorded as `.stopped` and printed as nothing. Teardown kills the child and joins the worker on both platforms (`stopAtExit`, also on the one-shot's own `std.process.exit` paths); macOS measured at ~0 ms, the Windows branch cross-compiled only (`zig build -Dtarget=x86_64-windows`) and unmeasured. A cold-and-slow companion can miss the one-shot catalog, visibly. | +| [0340](0340-a-cold-catalog-cache-never-holds-boot.md) | Boot never waits on a live model-catalog GET to show the prompt: a keyed dynamic provider (or Kimi) with no disk cache boots on its baked rows, its fetch runs on a detached worker, and its list activates on the main thread at the next `ensureForQuery` beat after it lands (`catalog_landing`, `router_catalog_boot.activateLanded`). Only a `--model` naming a row the baked table lacks keeps the bounded 800 ms wait. A failed fetch activates nothing, prints nothing at boot, and is not retried in-process. A 100 ms cold budget was rejected: it costs every first keystroke and almost never covers a real round trip. | ## When to write one diff --git a/docs/harness-latency.md b/docs/harness-latency.md index 946d3c3a..66db9bd3 100644 --- a/docs/harness-latency.md +++ b/docs/harness-latency.md @@ -98,3 +98,67 @@ JSON containers and escaped string lengths directly, retaining the standard serializer where its formatting is needed. This preserves byte counts and context policy while avoiding unnecessary formatting. See [ADR 0115](adr/0115-context-estimates-count-json-bytes.md). Compare both payload kinds and the tool-loop fixture when changing this path. + +`boot_prewarm` joins a one-shot's prewarmed companion handshake with a 250 ms +budget (`GRAFF_MCP_COMPANION_BOOT_MS`, [ADR 0339](adr/0339-a-one-shot-joins-the-companion-handshake-with-a-budget.md)) +instead of awaiting it: a companion that spawns and never answers used to hold +`c_first_request` for 20.1 s, and ends up with no companion tools either way. +When the budget expires the attempt keeps running and merges into the registry +when it lands, so a warm companion's catalog is unchanged and a cold-and-slow +one can miss the first catalog. Measure it with `--companion` (a stub that +answers) and a second run of a stub that does not. + +## Cold-start benchmark + +`scripts/bench-startup.py` times process startup, from spawn to each ready +point. It is hermetic: every sample gets a fresh copy of a temporary HOME and +an empty non-git cwd (`--git-repo` uses a one-commit repo with no remote). +The child environment is scrubbed to `TMPDIR`, `TERM`, a minimal `PATH` +(system dirs plus git; no `codedb-pro`/`muonry` unless `--companion`), and +`GRAFF_NO_TELEMETRY`, `GRAFF_NO_UPDATE_CHECK`, `GRAFF_AUTO_ISOLATE=off`, +`GRAFF_FLEET=off`, `GRAFF_NO_SMOLIFY`, `GRAFF_LEARN_AUTO=off` and `NO_COLOR`. +`security` is a stub that answers "not found", so the Keychain is never read. +The only network traffic is to the loopback mock on port 1234, the `lmstudio` +provider's fixed URL (no environment override exists). The script waits up to +120 s for the port to be free. Each sample sends its own `LMSTUDIO_API_KEY` +token, so a POST from another client on that port is recognised by its bearer +and the sample is retried (`env.foreign_retries` counts them). + +| Point | Ready when | +|---|---| +| `a_version`, `a_help` | `--version` / `--help` exits (n ≥ 100) | +| `b_repl_ready` | the REPL loop is reached with stdin=/dev/null: the first `final-save` stamp. This needs `GRAFF_SHUTDOWN_DEBUG=1`, the only debug env in the timing pass | +| `c_first_request` | `-p hi --model lmstudio`: the mock receives the first POST | +| `d_acp_initialize` | `graff acp`: the `initialize` response line on stdout, "handshake answered". graff can answer it during boot, before a session can be created, so it is not "ready". `_nokey` is the pre-auth path | +| `d_acp_session_usable` | `graff acp` with `initialize` and `session/new` written at spawn: the `session/new` response, "ACP session usable". This is the time a client waits before it can prompt | +| `floor` | `/usr/bin/true` and a compiled C hello, timed the same way | + +```sh +zig build graff -Doptimize=ReleaseSafe -Dlearn=false +cp zig-out/bin/graff /tmp/graff-before # immutable baseline +python3 scripts/bench-startup.py --graff /tmp/graff-before --out /tmp/before.json +# ...change, rebuild, then: +python3 scripts/bench-startup.py --out /tmp/after.json --compare /tmp/before.json \ + --budgets scripts/startup-budgets.json +python3 scripts/bench-startup.py --load /tmp/after.json --compare /tmp/before.json +``` + +The default is 3 warm-up rounds and 30 timed rounds. Points are interleaved, with +the order rotated each round, so drift is spread across all points. After the +timing pass, a `GRAFF_BOOT_DEBUG=1` pass records median per-phase ms +(`phases_ms`). A PATH-shim pass counts `git`, `security` and companion spawns +(`spawns`, `spawn_detail`) and fails the run if git fetches or adds a worktree. +Children are spawned with `os.posix_spawn`, so the timer adds about 1 ms of +interpreter cost, compared with about 2.7 ms for `subprocess`. Subtract +`floor.hello_ms.median` to get graff-only time; `--compare` prints this as +`net`. The `--budgets` gates are median/floor ratios plus exact spawn counts, +never absolute ms. `--env KEY=VALUE` adds knobs such as `GRAFF_NO_PLUGINS=1`. + +On macOS, git resolves through `xcrun` to the real binary. The `/usr/bin/git` +shim costs 70–110 ms on its first call under each new HOME, and every sample has +a new HOME. Run-to-run medians move by about 5–15% with host load, and the floor +moves too, so compare `net` values and gate on ratios. For small deltas, run the +baseline and candidate binaries back to back, several times, in alternating +order. These numbers exclude user plugins, the companion handshake (unless +`--companion`), the update check, auto-isolation, cold model catalogs and real +Keychain latency. Each of those adds to startup on a real HOME. diff --git a/formal/BootPrewarm.cfg b/formal/BootPrewarm.cfg new file mode 100644 index 00000000..a18c9177 --- /dev/null +++ b/formal/BootPrewarm.cfg @@ -0,0 +1,20 @@ +SPECIFICATION Spec +CONSTANTS BypassJoin = FALSE + BypassCwdKey = FALSE + BypassTeardownJoin = FALSE + BypassRetryAbort = FALSE + StartBeforeKeys = FALSE + BypassWindowDiscard = FALSE + BypassStop = FALSE + RetryFailed = FALSE +INVARIANTS TypeOK + JoinedBeforeUse + NoStaleAdoption + NoUseAfterTeardown + ExitClean + NoExitStall + AtMostOneCompanion + NoRepeatAfterResult + NeverMissing + NoRetryAfterAbort +PROPERTIES TeardownFinishes diff --git a/formal/BootPrewarm.tla b/formal/BootPrewarm.tla new file mode 100644 index 00000000..59b4e15e --- /dev/null +++ b/formal/BootPrewarm.tla @@ -0,0 +1,328 @@ +------------------------------ MODULE BootPrewarm ------------------------------ +EXTENDS Naturals, TLC + +\* A finite abstraction of the one-shot companion prewarm (boot_prewarm.zig) +\* and of one registry start task's retry pause at teardown (mcp_start.zig). +\* The prewarm worker connects the companion before the registry exists; the +\* boot thread joins it at its one consumer (connectCompanion) or discards it +\* (stop the worker's child, then join). Boot can also leave early: a fatal +\* exit while resolving credentials or in the banner (no defer runs), or an +\* error return between the prewarm start and the registry (main's deferred +\* discard runs, then std.process.Init joins the remaining workers). +CONSTANTS BypassJoin, BypassCwdKey, BypassTeardownJoin, BypassRetryAbort, + StartBeforeKeys, BypassWindowDiscard, BypassStop, RetryFailed +ASSUME /\ BypassJoin \in BOOLEAN + /\ BypassCwdKey \in BOOLEAN + /\ BypassTeardownJoin \in BOOLEAN + /\ BypassRetryAbort \in BOOLEAN + /\ StartBeforeKeys \in BOOLEAN + /\ BypassWindowDiscard \in BOOLEAN + /\ BypassStop \in BOOLEAN + /\ RetryFailed \in BOOLEAN + +BootStates == {"keys", "banner", "start", "window", "pre", "consumer", "mismatch", + "inline", "connected", "noConsumer", "discarding", "joining", "exited"} +WorkerStates == {"none", "running", "done", "consumed"} +\* The companion process the prewarm spawned: owned by the worker or its +\* outcome ("alive"), adopted by the registry ("registry"), or reaped. +ChildStates == {"none", "alive", "registry", "reaped"} +TaskStates == {"idle", "attempt", "pause", "retry", "done"} + +VARIABLES boot, worker, result, child, hangs, stopReq, stalled, adopted, + inlined, taken, registered, cwdMoved, cwdAtTake, usedEarly, ioAlive, + regUp, task, abort, retriedAfterAbort + +vars == <> + +prewarm == <> +taskVars == <> +others == <> + +\* `hangs`: a companion that never answers its handshake (only the 15 s +\* handshake timeout, or the discard's stop, ends the attempt). With +\* StartBeforeKeys the gate ran before credentials, as it once did. +Init == + /\ boot = "keys" + /\ worker \in IF StartBeforeKeys THEN {"none", "running"} ELSE {"none"} + /\ child = IF worker = "running" THEN "alive" ELSE "none" + /\ hangs \in BOOLEAN + /\ result = "none" + /\ stopReq = FALSE + /\ stalled = FALSE + /\ adopted = FALSE + /\ inlined = FALSE + /\ taken = FALSE + /\ registered = 0 + /\ cwdMoved = FALSE + /\ cwdAtTake = FALSE + /\ usedEarly = FALSE + /\ ioAlive = TRUE + /\ regUp = FALSE + /\ task = "idle" + /\ abort = FALSE + /\ retriedAfterAbort = FALSE + +\* ---------------------------------------------------------------- boot + +KeysOk == + /\ boot = "keys" /\ boot' = "banner" + /\ UNCHANGED prewarm /\ UNCHANGED others /\ UNCHANGED taskVars + +\* resolveKeys or setupWorktreeAndBanner exits through std.process.fatal: +\* no defer runs, no worker is joined, a spawned child is left behind. +FatalExit == + /\ boot \in {"keys", "banner"} /\ boot' = "exited" + /\ UNCHANGED prewarm /\ UNCHANGED others /\ UNCHANGED taskVars + +BannerOk == + /\ boot = "banner" /\ boot' = "start" + /\ UNCHANGED prewarm /\ UNCHANGED others /\ UNCHANGED taskVars + +\* main: startCompanion (the gate declines or starts the worker, which +\* spawns the child), then `defer discard`. +Start == + /\ boot = "start" /\ boot' = "window" + /\ IF StartBeforeKeys + THEN UNCHANGED <> + ELSE \E w \in {"none", "running"}: + /\ worker' = w + /\ child' = IF w = "running" THEN "alive" ELSE "none" + /\ UNCHANGED <> + /\ UNCHANGED others /\ UNCHANGED taskVars + +\* A failed `try` before initRegistryConsent returns: the deferred discard +\* stops and joins the worker. +WindowError == + /\ boot = "window" + /\ IF BypassWindowDiscard + THEN boot' = "joining" /\ UNCHANGED stopReq + ELSE boot' = "discarding" /\ stopReq' = ~BypassStop + /\ UNCHANGED <> + /\ UNCHANGED others /\ UNCHANGED taskVars + +\* initRegistryConsent returned; `defer registry_storage.deinitAtExit()`. +RegistryUp == + /\ boot = "window" /\ boot' = "pre" + /\ regUp' = TRUE /\ task' = "attempt" + /\ UNCHANGED prewarm + /\ UNCHANGED <> + +\* Any chdir between the prewarm start and the consumer. +MoveCwd == + /\ boot \in {"window", "pre"} /\ ~cwdMoved + /\ cwdMoved' = TRUE + /\ UNCHANGED <> + /\ UNCHANGED prewarm /\ UNCHANGED taskVars + +ReachConsumer == + /\ boot = "pre" /\ boot' = "consumer" + /\ UNCHANGED prewarm /\ UNCHANGED others /\ UNCHANGED taskVars + +\* A path that exits after the registry exists without reaching the +\* consumer (--selftest-spinner); deinitAtExit discards the slot. +SkipConsumer == + /\ boot = "pre" /\ boot' = "noConsumer" + /\ UNCHANGED prewarm /\ UNCHANGED others /\ UNCHANGED taskVars + +\* ---------------------------------------------------------------- worker + +\* connectTask: one startServer on a task-local registry. A failure reaps +\* its child; success hands the child to the outcome. A stopped child ends +\* the handshake at once. +WorkerFinish == + /\ worker = "running" /\ ioAlive /\ boot # "exited" + /\ ~hangs \/ stopReq + /\ \E r \in {"ok", "fail"}: + /\ result' = r + /\ child' = IF r = "ok" THEN "alive" ELSE "reaped" + /\ worker' = "done" + /\ UNCHANGED <> + /\ UNCHANGED others /\ UNCHANGED taskVars + +\* A silent companion's attempt ends only at the handshake timeout; an exit +\* path that waits for it has stalled. +WorkerTimeout == + /\ worker = "running" /\ ioAlive /\ boot # "exited" + /\ hangs /\ ~stopReq + /\ result' = "fail" /\ child' = "reaped" /\ worker' = "done" + /\ stalled' = (boot \in {"discarding", "joining"}) + /\ UNCHANGED <> + /\ UNCHANGED others /\ UNCHANGED taskVars + +\* ---------------------------------------------------------------- consumer + +KeyMatches == ~cwdMoved \/ BypassCwdKey + +\* take(): await, then mergeOutcomes under the registry mutex. +TakeAdopt == + /\ boot = "consumer" /\ KeyMatches + /\ \/ worker = "done" /\ result = "ok" + \/ BypassJoin /\ worker = "running" + /\ usedEarly' = (worker = "running") + /\ cwdAtTake' = cwdMoved + /\ worker' = IF worker = "done" THEN "consumed" ELSE worker + /\ adopted' = TRUE /\ taken' = TRUE + /\ child' = "registry" + /\ registered' = registered + 1 + /\ boot' = "connected" + /\ UNCHANGED <> + /\ UNCHANGED taskVars + +\* A failed attempt is the one attempt: its error is what addServer would +\* have returned. RetryFailed is the earlier fallback that started it again. +TakeFailed == + /\ boot = "consumer" /\ KeyMatches + /\ worker = "done" /\ result = "fail" + /\ worker' = "consumed" /\ taken' = TRUE + /\ boot' = IF RetryFailed THEN "inline" ELSE "connected" + /\ UNCHANGED <> + /\ UNCHANGED others /\ UNCHANGED taskVars + +\* A key mismatch discards (stop the child, join, tear the outcome down), +\* then connects inline: no attempt's result was used. +TakeMismatch == + /\ boot = "consumer" /\ ~KeyMatches /\ worker # "none" + /\ stopReq' = ~BypassStop /\ boot' = "mismatch" + /\ UNCHANGED <> + /\ UNCHANGED others /\ UNCHANGED taskVars + +MismatchJoin == + /\ boot = "mismatch" /\ worker # "running" + /\ worker' = IF worker = "done" THEN "consumed" ELSE worker + /\ child' = IF child = "alive" THEN "reaped" ELSE child + /\ boot' = "inline" + /\ UNCHANGED <> + /\ UNCHANGED others /\ UNCHANGED taskVars + +TakeNone == + /\ boot = "consumer" /\ worker = "none" + /\ boot' = "inline" + /\ UNCHANGED prewarm /\ UNCHANGED others /\ UNCHANGED taskVars + +InlineConnect == + /\ boot = "inline" + /\ \E ok \in BOOLEAN: registered' = registered + (IF ok THEN 1 ELSE 0) + /\ inlined' = TRUE + /\ boot' = "connected" + /\ UNCHANGED prewarm /\ UNCHANGED <> /\ UNCHANGED taskVars + +\* ---------------------------------------------------------------- exit + +\* deinitAtExit: discard (stop the child, join the worker), then +\* Registry.deinit sets retry_abort and joins its start tasks. +Teardown == + /\ boot \in {"connected", "noConsumer"} + /\ boot' = "discarding" /\ stopReq' = ~BypassStop + /\ UNCHANGED <> + /\ UNCHANGED others /\ UNCHANGED taskVars + +\* discard's join and teardown, then (registry up) Registry.deinit. +DiscardJoin == + /\ boot = "discarding" + /\ worker # "running" \/ BypassTeardownJoin + /\ worker' = IF worker = "done" THEN "consumed" ELSE worker + /\ child' = IF child = "alive" \/ (child = "registry" /\ regUp) THEN "reaped" ELSE child + /\ abort' = (abort \/ regUp) + /\ boot' = "joining" + /\ UNCHANGED <> + /\ UNCHANGED <> /\ UNCHANGED taskVars + +\* main returns; std.process.Init joins its workers, then tears the Io down. +IoDown == + /\ boot = "joining" + /\ BypassTeardownJoin \/ (worker # "running" /\ task \in {"idle", "done"}) + /\ ioAlive' = FALSE + /\ boot' = "exited" + /\ UNCHANGED prewarm + /\ UNCHANGED <> /\ UNCHANGED taskVars + +\* ---------------------------------------------------------------- start task + +\* The registry's start task: one attempt, a transient failure pauses, and +\* the pause either times out into the one retry or ends on retry_abort. +AttemptEnds == + /\ task = "attempt" /\ ioAlive + /\ task' \in {"pause", "done"} + /\ UNCHANGED retriedAfterAbort + /\ UNCHANGED boot /\ UNCHANGED others /\ UNCHANGED prewarm + +PauseTimesOut == + /\ task = "pause" /\ ioAlive + /\ ~abort \/ BypassRetryAbort + /\ task' = "retry" + /\ retriedAfterAbort' = abort + /\ UNCHANGED boot /\ UNCHANGED others /\ UNCHANGED prewarm + +PauseAborted == + /\ task = "pause" /\ abort /\ ~BypassRetryAbort + /\ task' = "done" + /\ UNCHANGED retriedAfterAbort + /\ UNCHANGED boot /\ UNCHANGED others /\ UNCHANGED prewarm + +RetryEnds == + /\ task = "retry" /\ ioAlive + /\ task' = "done" + /\ UNCHANGED retriedAfterAbort + /\ UNCHANGED boot /\ UNCHANGED others /\ UNCHANGED prewarm + +Next == + \/ KeysOk \/ FatalExit \/ BannerOk \/ Start \/ WindowError \/ RegistryUp + \/ MoveCwd \/ ReachConsumer \/ SkipConsumer + \/ WorkerFinish \/ WorkerTimeout + \/ TakeAdopt \/ TakeFailed \/ TakeMismatch \/ MismatchJoin \/ TakeNone \/ InlineConnect + \/ Teardown \/ DiscardJoin \/ IoDown + \/ AttemptEnds \/ PauseTimesOut \/ PauseAborted \/ RetryEnds + +Spec == Init /\ [][Next]_vars + /\ WF_vars(WorkerFinish) /\ WF_vars(WorkerTimeout) + /\ WF_vars(TakeAdopt \/ TakeFailed \/ TakeMismatch \/ MismatchJoin \/ TakeNone \/ InlineConnect) + /\ WF_vars(Teardown) /\ WF_vars(DiscardJoin) /\ WF_vars(IoDown) + /\ WF_vars(AttemptEnds \/ PauseTimesOut \/ PauseAborted \/ RetryEnds) + +TypeOK == + /\ boot \in BootStates + /\ worker \in WorkerStates + /\ child \in ChildStates + /\ result \in {"none", "ok", "fail"} + /\ registered \in 0..2 + /\ task \in TaskStates + /\ {hangs, stopReq, stalled, adopted, inlined, taken, cwdMoved, cwdAtTake, + usedEarly, ioAlive, regUp, abort, retriedAfterAbort} \subseteq BOOLEAN + +\* The boot thread never uses the prewarm outcome before the worker ended. +JoinedBeforeUse == ~usedEarly + +\* A prewarm recorded in another directory is never adopted. +NoStaleAdoption == adopted => ~cwdAtTake + +\* No thread still uses the Io after it is torn down. std.process.Init joins +\* every worker before it deinitializes the Io, so the runtime rules this +\* out by construction; only BypassTeardownJoin (no such join) violates it. +NoUseAfterTeardown == ~ioAlive => (worker # "running" /\ task \in {"idle", "done"}) + +\* The hazard of every exit path: once the process has exited, no companion +\* the prewarm spawned is alive (prewarm-owned or registered) and no +\* prewarm worker was left unjoined. +ExitClean == boot = "exited" => (child \notin {"alive", "registry"} /\ worker # "running") + +\* No exit path waits out a silent companion's handshake timeout. +NoExitStall == ~stalled + +\* The companion is registered once at most: adopted or inline, never both. +AtMostOneCompanion == registered <= 1 /\ ~(adopted /\ inlined) + +\* An attempt that ran to a result is the one attempt. +NoRepeatAfterResult == ~(taken /\ inlined) + +\* Reaching the consumer always ends adopted, with an attempt's result, or +\* with the inline connect tried. +NeverMissing == boot = "connected" => (adopted \/ taken \/ inlined) + +\* Once teardown signals, no retry attempt starts. +NoRetryAfterAbort == ~retriedAfterAbort + +\* Under the fairness above, every exit that started finishes. +TeardownFinishes == (boot \in {"discarding", "joining"}) ~> (boot = "exited") +============================================================================= diff --git a/formal/BootPrewarmEarlyStart.cfg b/formal/BootPrewarmEarlyStart.cfg new file mode 100644 index 00000000..878f76a2 --- /dev/null +++ b/formal/BootPrewarmEarlyStart.cfg @@ -0,0 +1,10 @@ +SPECIFICATION Spec +CONSTANTS BypassJoin = FALSE + BypassCwdKey = FALSE + BypassTeardownJoin = FALSE + BypassRetryAbort = FALSE + StartBeforeKeys = TRUE + BypassWindowDiscard = FALSE + BypassStop = FALSE + RetryFailed = FALSE +INVARIANT ExitClean diff --git a/formal/BootPrewarmNoCwdKey.cfg b/formal/BootPrewarmNoCwdKey.cfg new file mode 100644 index 00000000..59673c8d --- /dev/null +++ b/formal/BootPrewarmNoCwdKey.cfg @@ -0,0 +1,10 @@ +SPECIFICATION Spec +CONSTANTS BypassJoin = FALSE + BypassCwdKey = TRUE + BypassTeardownJoin = FALSE + BypassRetryAbort = FALSE + StartBeforeKeys = FALSE + BypassWindowDiscard = FALSE + BypassStop = FALSE + RetryFailed = FALSE +INVARIANT NoStaleAdoption diff --git a/formal/BootPrewarmNoJoin.cfg b/formal/BootPrewarmNoJoin.cfg new file mode 100644 index 00000000..09aa186e --- /dev/null +++ b/formal/BootPrewarmNoJoin.cfg @@ -0,0 +1,10 @@ +SPECIFICATION Spec +CONSTANTS BypassJoin = TRUE + BypassCwdKey = FALSE + BypassTeardownJoin = FALSE + BypassRetryAbort = FALSE + StartBeforeKeys = FALSE + BypassWindowDiscard = FALSE + BypassStop = FALSE + RetryFailed = FALSE +INVARIANT JoinedBeforeUse diff --git a/formal/BootPrewarmNoRetryAbort.cfg b/formal/BootPrewarmNoRetryAbort.cfg new file mode 100644 index 00000000..ae806521 --- /dev/null +++ b/formal/BootPrewarmNoRetryAbort.cfg @@ -0,0 +1,10 @@ +SPECIFICATION Spec +CONSTANTS BypassJoin = FALSE + BypassCwdKey = FALSE + BypassTeardownJoin = FALSE + BypassRetryAbort = TRUE + StartBeforeKeys = FALSE + BypassWindowDiscard = FALSE + BypassStop = FALSE + RetryFailed = FALSE +INVARIANT NoRetryAfterAbort diff --git a/formal/BootPrewarmNoStop.cfg b/formal/BootPrewarmNoStop.cfg new file mode 100644 index 00000000..68d4d0ae --- /dev/null +++ b/formal/BootPrewarmNoStop.cfg @@ -0,0 +1,10 @@ +SPECIFICATION Spec +CONSTANTS BypassJoin = FALSE + BypassCwdKey = FALSE + BypassTeardownJoin = FALSE + BypassRetryAbort = FALSE + StartBeforeKeys = FALSE + BypassWindowDiscard = FALSE + BypassStop = TRUE + RetryFailed = FALSE +INVARIANT NoExitStall diff --git a/formal/BootPrewarmNoTeardownJoin.cfg b/formal/BootPrewarmNoTeardownJoin.cfg new file mode 100644 index 00000000..0549900c --- /dev/null +++ b/formal/BootPrewarmNoTeardownJoin.cfg @@ -0,0 +1,10 @@ +SPECIFICATION Spec +CONSTANTS BypassJoin = FALSE + BypassCwdKey = FALSE + BypassTeardownJoin = TRUE + BypassRetryAbort = FALSE + StartBeforeKeys = FALSE + BypassWindowDiscard = FALSE + BypassStop = FALSE + RetryFailed = FALSE +INVARIANT NoUseAfterTeardown diff --git a/formal/BootPrewarmNoWindowDiscard.cfg b/formal/BootPrewarmNoWindowDiscard.cfg new file mode 100644 index 00000000..f17d432a --- /dev/null +++ b/formal/BootPrewarmNoWindowDiscard.cfg @@ -0,0 +1,10 @@ +SPECIFICATION Spec +CONSTANTS BypassJoin = FALSE + BypassCwdKey = FALSE + BypassTeardownJoin = FALSE + BypassRetryAbort = FALSE + StartBeforeKeys = FALSE + BypassWindowDiscard = TRUE + BypassStop = FALSE + RetryFailed = FALSE +INVARIANT ExitClean diff --git a/formal/BootPrewarmRetryFailed.cfg b/formal/BootPrewarmRetryFailed.cfg new file mode 100644 index 00000000..f71e3317 --- /dev/null +++ b/formal/BootPrewarmRetryFailed.cfg @@ -0,0 +1,10 @@ +SPECIFICATION Spec +CONSTANTS BypassJoin = FALSE + BypassCwdKey = FALSE + BypassTeardownJoin = FALSE + BypassRetryAbort = FALSE + StartBeforeKeys = FALSE + BypassWindowDiscard = FALSE + BypassStop = FALSE + RetryFailed = TRUE +INVARIANT NoRepeatAfterResult diff --git a/formal/README.md b/formal/README.md index ad29451b..4db2f35f 100644 --- a/formal/README.md +++ b/formal/README.md @@ -12,6 +12,10 @@ are difficult to reproduce with ordinary tests. workers, offered choices, and responses racing with cancellation. - [HTTP/2 leases](http2-leases.md): exclusive ownership, idle pooling, cancellation, shutdown, and reuse only after stream completion. +- [Boot prewarm](boot-prewarm.md): a one-shot's companion connect joined at + its one consumer, discarded on a cwd or setting mismatch or on any early + exit with no child or worker left behind, and teardown ending a start's + retry pause while still joining it. Each model has a normal configuration and a deliberately broken configuration. The negative control must fail the intended invariant. A syntax error, timeout, diff --git a/formal/boot-prewarm.md b/formal/boot-prewarm.md new file mode 100644 index 00000000..ec7cf23a --- /dev/null +++ b/formal/boot-prewarm.md @@ -0,0 +1,94 @@ +# Boot prewarm and retry abort + +`BootPrewarm.tla` is a finite model of two lifecycles that decide whether a +worker, or a process it spawned, can outlive the decision to exit: + +- the companion prewarm (`src/boot_prewarm.zig`, ADR 0337): a + worker connects `codedb-pro --mcp` before the registry exists, and the boot + thread joins it at its one consumer, `connectCompanion`, or discards it; +- one registry start task's retry pause (`src/mcp_start.zig`): teardown must + not wait out the pause, and must still join the task (#325). + +| Model action | Implementation boundary | +| --- | --- | +| `KeysOk`, `FatalExit`, `BannerOk` | `startup.resolveKeysOrRunAcpPreAuth` and `session_start.setupWorktreeAndBanner`. Both can leave through `std.process.fatal` (no credential, `--add-dir`, isolation, `--experiment`), which runs no defer and joins nothing. | +| `Start` | `main` after `setupWorktreeAndBanner`: `boot_prewarm.startCompanion` (gate: `wantsCompanion`, no project `.mcp.json`, opt-out, PATH), then `defer boot_prewarm.discard(io)`. `start` launches `connectTask` with `io.concurrent`. | +| `WindowError` | Any `try` that fails between that start and `initRegistryConsent` returning: the deferred `discard` runs. | +| `RegistryUp` | `initRegistryConsent` returned; `defer registry_storage.deinitAtExit()` is armed. | +| `WorkerFinish`, `WorkerTimeout` | `connectTask`: one `startServer` on a task-local registry whose `spawn_watch` publishes every child (`Registry.spawnStdio`). A failure reaps its child; success hands the child to the outcome. A child that never answers ends the attempt only at the 15 s handshake timeout, or when `discard` stops it. | +| `MoveCwd` | Any chdir between the start and the consumer. Nothing in the code does this now that the start follows the banner; the cwd key is kept and checked. | +| `TakeAdopt`, `TakeFailed`, `TakeMismatch` + `MismatchJoin`, `TakeNone` | `boot_prewarm.take` (through `connect`): `matches` (cwd key, home, probe and lazy settings), `Future.await`, then `mcp_boot.adoptStarted` under the registry mutex. A failed attempt returns its error, the error `addServer` would have returned. A mismatch calls `discard` and the caller runs `addServer`. | +| `InlineConnect` | `boot_prewarm.connect` falling back to `Registry.addServer` when no attempt ran to a result. | +| `SkipConsumer`, `Teardown`, `DiscardJoin` | `connectCompanion`'s deferred `discard`, and `Registry.deinitAtExit` calling `discard`: `Watch.stop` (SIGKILL the published child; one spawned later is stopped as it is published), `Future.await`, tear the outcome down. Then `Registry.deinit` sets `retry_abort` before `joinPending`. | +| `IoDown` | `main` returns; `std.process.Init` deinitializes the threaded `Io` after joining its workers. | +| `AttemptEnds`, `PauseTimesOut`, `PauseAborted`, `RetryEnds` | `mcp_start.task` and `pauseBeforeRetry`: the pause is `Io.Event.waitTimeout` on the registry's heap-owned event. | + +The positive configuration checks the following over every interleaving of +these actions, including a companion that never answers: + +- `ExitClean`: once the process has exited, no companion the prewarm spawned + is alive, whether prewarm-owned or registered, and no prewarm worker was + left unjoined. This is the real hazard of every exit path. +- `NoExitStall`: no exit path waits out a silent companion's handshake timeout. +- `JoinedBeforeUse`: the outcome is never used before the worker ended. +- `NoStaleAdoption`: a prewarm recorded in another directory is never adopted. +- `NoRepeatAfterResult`: an attempt that ran to a result is the one attempt. +- `AtMostOneCompanion`: the companion is registered at most once. +- `NeverMissing`: the consumer always ends adopted, with an attempt's result, + or with the inline connect tried. +- `NoRetryAfterAbort`: no retry starts after teardown signalled. +- `NoUseAfterTeardown`: no worker or start task is live once the `Io` is down. +- `TeardownFinishes`: under weak fairness of the worker (including its + timeout), consumer, teardown and task steps, every exit that started + finishes. + +`NoUseAfterTeardown` is not evidence about this change. `std.process.Init` +joins every worker before it deinitializes the `Io`, so the runtime rules +that hazard out by construction. Its control removes that join from the +model. On the uncovered exit paths the actual failure was a stall plus a +leaked child, which `ExitClean` and `NoExitStall` capture. `ExitClean` +replaces the earlier `NoLeakAtExit`, which covered only the normal teardown. + +Run TLC from `formal/` with `-deadlock`, since exit is a terminal state. + +| Config | Deliberate mutation | Violated invariant | +| --- | --- | --- | +| `BootPrewarmNoJoin.cfg` | Adopt while the worker still runs | `JoinedBeforeUse` | +| `BootPrewarmNoCwdKey.cfg` | Adopt without comparing the cwd key | `NoStaleAdoption` | +| `BootPrewarmNoTeardownJoin.cfg` | Tear the `Io` down without joining the prewarm or the start task | `NoUseAfterTeardown` | +| `BootPrewarmNoRetryAbort.cfg` | Ignore `retry_abort` in the pause | `NoRetryAfterAbort` | +| `BootPrewarmEarlyStart.cfg` | Start the prewarm before credentials resolve (the first revision): a credential failure exits fatally with the child alive | `ExitClean` | +| `BootPrewarmNoWindowDiscard.cfg` | No deferred discard between the start and the registry: an error return leaves the connected child behind | `ExitClean` | +| `BootPrewarmNoStop.cfg` | `discard` only joins, without stopping the child: an exit waits for the handshake timeout | `NoExitStall` | +| `BootPrewarmRetryFailed.cfg` | A failed attempt falls back to a second, inline start (the first revision) | `NoRepeatAfterResult` | + +These are mutation checks of the model. Two of them, `EarlyStart` and +`RetryFailed`, are also the behavior of the first revision of the prewarm. +Runtime anchors that fail on that revision: + +- `boot prewarm: a failing companion is started exactly as often as the + inline path starts it`: two spawns against one on the first revision. +- `boot prewarm: an error return before the registry exists discards promptly + and leaves no child`. On a `discard` that cancels the worker, the child + survives or the test process faults: a cancel delivered inside the bounded + handshake's `Io.Select` returns before the select's read task stops. On a + `discard` that only joins, it waits for the 15 s handshake timeout. +- `src/mcp_start.zig` `teardown with a pending transient retry returns in well + under the pause` fails when `Registry.deinit` does not set the event. + +`boot prewarm: main starts it after credentials and the banner, and defers its +discard` checks only source placement, which is weaker evidence. The no-key +case was also checked end to end with a stub companion that ignores stdin: +the first revision left it running after `graff -p` exited 1, and the current +code spawns nothing. + +Omitted: + +- the handshake's own protocol states; +- the content of the catalog (the byte-comparison test covers it); +- a fatal exit after the registry exists (it does not involve the prewarm); +- Windows, where `Watch` has no signal and `discard` waits for the attempt, + bounded by the handshake timeout; +- more than one start task. + +The model does not establish that the Zig code refines it. diff --git a/formal/change-evidence.md b/formal/change-evidence.md index 355ea76f..3ef96c5e 100644 --- a/formal/change-evidence.md +++ b/formal/change-evidence.md @@ -29,6 +29,13 @@ For each behavioral change, retain this chain: | A synchronous predecessor stops early admission | `NoLateAdmission` | `src/agent_async_tools.zig`: `async tools do not cross a synchronous predecessor or execute partial arguments` | | Owned workers retire before their storage is freed | Async cancellation/reset model | `src/agent_async_tools.zig`: `async tools reset cancels and joins workers before freeing owned state` | | Permission replies belong to their live transport and session | ACP permission extension | Client-side evidence moved with the desktop app to Harness | +| A companion prewarm is joined before its result is used | `JoinedBeforeUse` | `src/boot_prewarm.zig`: `boot prewarm: the adopted companion matches the inline addServer catalog byte for byte` | +| A prewarm started in another cwd is never adopted | `NoStaleAdoption` | `src/boot_prewarm.zig`: `boot prewarm: a cwd change between start and consumer discards it and the inline path runs` | +| No prewarm worker outlives teardown (the runtime's join guarantees this by construction; see boot-prewarm.md) | `NoUseAfterTeardown` | `src/boot_prewarm.zig`: `boot prewarm: discard joins a pending handshake and tears it down` | +| No exit path leaves a prewarm-spawned companion or an unjoined worker: the prewarm starts after credentials and the banner, and main defers its discard | `ExitClean` (controls `BootPrewarmEarlyStart.cfg`, `BootPrewarmNoWindowDiscard.cfg`) | `src/boot_prewarm.zig`: `boot prewarm: an error return before the registry exists discards promptly and leaves no child`, `boot prewarm: main starts it after credentials and the banner, and defers its discard` (source placement only) | +| A discard stops the worker's child instead of cancelling the worker, so no exit waits out a silent companion's handshake | `NoExitStall` (control `BootPrewarmNoStop.cfg`) | `src/boot_prewarm.zig`: `boot prewarm: an error return before the registry exists discards promptly and leaves no child` (fails on the cancel-based discard: the child survives or the process faults) | +| A prewarm attempt that ran to a result is the one attempt, its error included | `NoRepeatAfterResult` (control `BootPrewarmRetryFailed.cfg`) | `src/boot_prewarm.zig`: `boot prewarm: a failing companion is started exactly as often as the inline path starts it` | +| Teardown ends a retry pause and the retry does not run | `NoRetryAfterAbort` | `src/mcp_start.zig`: `teardown with a pending transient retry returns in well under the pause` | These anchors connect intent and implementation tests. They do not establish that every modeled interleaving is exercised by a runtime test, or that the diff --git a/lean-proofs/Graff.lean b/lean-proofs/Graff.lean index 5f531ab8..5eb8ff50 100644 --- a/lean-proofs/Graff.lean +++ b/lean-proofs/Graff.lean @@ -13,3 +13,4 @@ import Graff.PromptStable import Graff.ResourceKernel import Graff.AcpLatency import Graff.ImageDelivery +import Graff.AcpEarlyInit diff --git a/lean-proofs/Graff/AcpEarlyInit.lean b/lean-proofs/Graff/AcpEarlyInit.lean new file mode 100644 index 00000000..1dc13efa --- /dev/null +++ b/lean-proofs/Graff/AcpEarlyInit.lean @@ -0,0 +1,483 @@ +/- + ACP early `initialize` kernel. + + `graff acp` answers the client's `initialize` during boot, at a phase + boundary, instead of after the root Agent exists. This file models the + decision and the line bookkeeping around it. + + What it proves: + (a) `step` over `State` × `Event` (the function `src/acp_early.zig` + calls): only a booting ACP process with a complete `initialize` first + line attempts an early answer; the line is taken off stdin only after + the whole answer was sent; only a taken line is replayed at loop start. + (b) `Sys` wraps `step` with an abstract stdin queue, stdout and dispatch + log. Over every boot trace, including traces where the early answer + fails, the first `initialize` is answered exactly once, the replay + writes nothing, a non-`initialize` first line is untouched, a failed + answer consumes nothing, and stdout and the dispatch history equal the + late path's. This is line bookkeeping: nothing is dropped, duplicated + or reordered. + + What it assumes (stated, not proved): + - The response is a function of the request alone (`answerOf`). That the + engine's answer does not depend on boot state is not shown here. + - The live dispatch's state is determined by the lines it has handled: + equal `disp` histories are taken to mean equal dispatch state. + - A failed early answer leaves nothing on stdout. The Zig code drops what + it still buffers; bytes the OS accepted before a write error are not + modelled (the transport is then broken for the late path too). + + What it is NOT: + - Anything about bytes: framing, CRLF, a BOM, a line longer than the stdin + buffer, JSON parsing, or how a line is classified. + - The non-blocking poll, the reader, or the discarding sink. + - A timing claim (when a boundary runs, or how fast). + - The cube (c) mirrors the engine's latch table; `early_eq_late` holds by + the model's construction (last writer wins). That `can_load` matches the + live dispatch is pinned by a Zig test of `live_can_load`, not here. + - A refinement proof. The Zig side is checked at fixture level: the + conformance test (`src/spec_acp_early_init_conformance.zig`) drives the + real `step` on every table cell and runs the real engine early and late + on every cube cell. The byte-equality claim rests on that test and on + `scripts/test-acp-early-init.py`, not on this file. + Executable port: spec/ref/acp_early_init.py. +-/ + +namespace Graff.AcpEarlyInit + +/-! ## (a) The decision -/ + +/-- `answering`: the early answer is being written; the line is still on stdin. -/ +inductive State where + | booting | answering | answered | passed | loop +deriving DecidableEq, Repr, BEq + +/-- What the shared stdin buffer holds at a check. -/ +inductive Line where + | none | incomplete | initialize | other +deriving DecidableEq, Repr, BEq + +/-- `acp` is ACP mode with a clean protocol stdout. `sent ok`: whether the +whole early answer reached the transport. -/ +inductive Event where + | boundary (acp : Bool) (line : Line) + | sent (ok : Bool) + | loopStart +deriving DecidableEq, Repr, BEq + +/-- `answer`: write the answer, consume nothing. `take`: consume and keep the +line. `replay`: hand the kept line to the loop. -/ +inductive Action where + | none | answer | take | replay +deriving DecidableEq, Repr, BEq + +def step : State → Event → State × Action + | .booting, .boundary false _ => (.passed, .none) + | .booting, .boundary true .none => (.booting, .none) + | .booting, .boundary true .incomplete => (.booting, .none) + | .booting, .boundary true .initialize => (.answering, .answer) + | .booting, .boundary true .other => (.passed, .none) + | .answering, .boundary _ _ => (.answering, .none) + | .answered, .boundary _ _ => (.answered, .none) + | .passed, .boundary _ _ => (.passed, .none) + | .loop, .boundary _ _ => (.loop, .none) + | .answering, .sent true => (.answered, .take) + | .answering, .sent false => (.passed, .none) + | .booting, .sent _ => (.booting, .none) + | .answered, .sent _ => (.answered, .none) + | .passed, .sent _ => (.passed, .none) + | .loop, .sent _ => (.loop, .none) + | .answered, .loopStart => (.loop, .replay) + | .booting, .loopStart => (.loop, .none) + | .answering, .loopStart => (.loop, .none) + | .passed, .loopStart => (.loop, .none) + | .loop, .loopStart => (.loop, .none) + +def allStates : List State := [.booting, .answering, .answered, .passed, .loop] +def allLines : List Line := [.none, .incomplete, .initialize, .other] +def allEvents : List Event := + ([false, true].flatMap fun acp => allLines.map fun l => Event.boundary acp l) ++ + [.sent false, .sent true, .loopStart] + +/- Sanity check, not a result: the table the fixture exports has 55 cells. -/ +example : allStates.length * allEvents.length = 55 := by native_decide + +/-- Only a booting process in ACP mode with a complete `initialize` attempts an answer. -/ +theorem step_answer_iff : + allStates.all (fun s => allEvents.all fun e => + ((step s e).2 == .answer) == (s == .booting && e == .boundary true .initialize)) = true := by + native_decide + +/-- The line is taken only once the whole answer was sent. -/ +theorem step_take_iff : + allStates.all (fun s => allEvents.all fun e => + ((step s e).2 == .take) == (s == .answering && e == .sent true)) = true := by + native_decide + +/-- An answer that failed gives up for good: the loop answers the line. -/ +theorem step_failed_passes : + allStates.all (fun s => allEvents.all fun e => + !(s == .answering && e == .sent false) || step s e == (.passed, .none)) = true := by + native_decide + +/-- Only loop start replays, and only after a taken answer. -/ +theorem step_replay_iff : + allStates.all (fun s => allEvents.all fun e => + ((step s e).2 == .replay) == (s == .answered && e == .loopStart)) = true := by + native_decide + +/-- Loop start always reaches the loop, and the loop is absorbing. -/ +theorem loop_start_reaches_loop (s : State) : (step s .loopStart).1 = .loop := by + cases s <;> rfl + +theorem loop_absorbing (e : Event) : step .loop e = (.loop, .none) := by + cases e with + | boundary acp l => cases acp <;> cases l <;> rfl + | sent ok => cases ok <;> rfl + | loopStart => rfl + +/-- Once answered, no boundary answers again. -/ +theorem answered_stays (acp : Bool) (l : Line) : + step .answered (.boundary acp l) = (.answered, .none) := by + cases acp <;> cases l <;> rfl + +/-! ## (a) The protocol around it -/ + +/-- A stdin line, tagged with its position. -/ +inductive Msg where + | init (i : Nat) + | other (i : Nat) +deriving DecidableEq, Repr, BEq + +/-- A stdout line answering the request at position `i`. -/ +inductive Out where + | resp (i : Nat) +deriving DecidableEq, Repr, BEq + +def answerOf : Msg → Out + | .init i => .resp i + | .other i => .resp i + +structure Sys where + st : State + /-- The first line is complete in the buffer. -/ + avail : Bool + /-- Unconsumed stdin (the one reader boot and loop share). -/ + input : List Msg + /-- The consumed `initialize`, kept for the replay. -/ + stash : Option Msg + /-- Protocol stdout. -/ + out : List Out + /-- Lines the live dispatch has handled, in order; its state is a fold of these. -/ + disp : List Msg +deriving DecidableEq, Repr + +def start (input : List Msg) : Sys := ⟨.booting, false, input, none, [], []⟩ + +def classify (s : Sys) : Line := + if s.avail then + match s.input with + | [] => .none + | .init _ :: _ => .initialize + | .other _ :: _ => .other + else .incomplete + +inductive BootEv where + /-- The client's first line becomes complete. -/ + | arrive + /-- A boot phase boundary checks. If it attempts an answer, the whole + answer reaches the client iff `ok` (the environment decides). -/ + | boundary (ok : Bool) +deriving DecidableEq, Repr, BEq + +/-- An answer attempt: the answer reaches stdout iff `ok`; the line is taken +iff `step` says so. A failed attempt writes nothing (assumption above). -/ +def attempt (s : Sys) (st : State) (ok : Bool) : Sys := + match step st (.sent ok), s.input with + | (st', .take), m :: rest => + { s with st := st', input := rest, stash := some m, + out := s.out ++ (if ok then [answerOf m] else []) } + | (st', _), _ => { s with st := st' } + +def bootStep (acp : Bool) (s : Sys) : BootEv → Sys + | .arrive => { s with avail := true } + | .boundary ok => + match step s.st (.boundary acp (classify s)) with + | (st, .answer) => attempt s st ok + | (st, _) => { s with st := st } + +def boot (acp : Bool) (s : Sys) : List BootEv → Sys + | [] => s + | e :: es => boot acp (bootStep acp s e) es + +def loopStart (s : Sys) : Sys := + match step s.st .loopStart, s.stash with + | (st, .replay), some m => { s with st := st, stash := none, disp := s.disp ++ [m] } + | (st, _), _ => { s with st := st } + +def drainFrom (s : Sys) : List Msg → Sys + | [] => s + | m :: ms => drainFrom { s with disp := s.disp ++ [m], out := s.out ++ [answerOf m] } ms + +def drain (s : Sys) : Sys := drainFrom { s with input := [] } s.input + +def runEarly (acp : Bool) (input : List Msg) (tr : List BootEv) : Sys := + drain (loopStart (boot acp (start input) tr)) + +/-- Today's order: no boundary ever looks. -/ +def runLate (input : List Msg) : Sys := drain (loopStart (start input)) + +/-- What boot can have done to the start state. -/ +def Inv (input : List Msg) (s : Sys) : Prop := + s.disp = [] ∧ + ((s.st = .booting ∨ s.st = .passed) ∧ s.stash = none ∧ s.input = input ∧ s.out = [] ∨ + ∃ i rest, input = .init i :: rest ∧ s.st = .answered ∧ s.stash = some (.init i) ∧ + s.input = rest ∧ s.out = [.resp i]) + +theorem inv_start (input : List Msg) : Inv input (start input) := + ⟨rfl, Or.inl ⟨Or.inl rfl, rfl, rfl, rfl⟩⟩ + +theorem inv_bootStep (acp : Bool) (input : List Msg) (s : Sys) (e : BootEv) + (h : Inv input s) : Inv input (bootStep acp s e) := by + obtain ⟨st, avail, inp, stash, out, disp⟩ := s + obtain ⟨hd, h⟩ := h + simp only at hd h + subst hd + cases e with + | arrive => + exact ⟨rfl, h⟩ + | boundary ok => + rcases h with ⟨hst | hst, hs, hi, ho⟩ | ⟨i, rest, hin, hst, hs, hi, ho⟩ + · subst hst hs hi ho + cases acp <;> cases avail <;> cases ok <;> rcases inp with _ | ⟨_ | _, _⟩ <;> + simp [bootStep, attempt, classify, step, Inv, answerOf] <;> + exact ⟨_, _, ⟨rfl, rfl⟩, rfl, rfl, rfl⟩ + · subst hst hs hi ho + cases acp <;> simp [bootStep, step, Inv] + · subst hst hs hi ho hin + cases acp <;> simp [bootStep, step, Inv] <;> exact ⟨_, _, ⟨rfl, rfl⟩, rfl, rfl, rfl⟩ + +theorem inv_boot (acp : Bool) (input : List Msg) (tr : List BootEv) : + ∀ s, Inv input s → Inv input (boot acp s tr) := by + induction tr with + | nil => intro s h; exact h + | cons e es ih => intro s h; exact ih _ (inv_bootStep acp input s e h) + +theorem drainFrom_out (s : Sys) (ms : List Msg) : + (drainFrom s ms).out = s.out ++ ms.map answerOf := by + induction ms generalizing s with + | nil => simp [drainFrom] + | cons m ms ih => simp [drainFrom, ih, List.append_assoc] + +theorem drainFrom_disp (s : Sys) (ms : List Msg) : + (drainFrom s ms).disp = s.disp ++ ms := by + induction ms generalizing s with + | nil => simp [drainFrom] + | cons m ms ih => simp [drainFrom, ih, List.append_assoc] + +theorem drain_out (s : Sys) : (drain s).out = s.out ++ s.input.map answerOf := drainFrom_out _ _ +theorem drain_disp (s : Sys) : (drain s).disp = s.disp ++ s.input := drainFrom_disp _ _ + +/-- The late path answers every line once, in order, and dispatches every line. -/ +theorem late_out (input : List Msg) : (runLate input).out = input.map answerOf := by + simp [runLate, drain_out, loopStart, start, step] + +theorem late_disp (input : List Msg) : (runLate input).disp = input := by + simp [runLate, drain_disp, loopStart, start, step] + +/-- The loop-start replay writes nothing on stdout. -/ +theorem replay_silent (s : Sys) : (loopStart s).out = s.out := by + unfold loopStart + split <;> rfl + +/-- Early and late write the same stdout, line for line. -/ +theorem early_out_eq_late (acp : Bool) (input : List Msg) (tr : List BootEv) : + (runEarly acp input tr).out = (runLate input).out := by + have h := inv_boot acp input tr (start input) (inv_start input) + rw [late_out] + unfold runEarly + generalize boot acp (start input) tr = s at h + obtain ⟨st, avail, inp, stash, out, disp⟩ := s + obtain ⟨hd, h⟩ := h + simp only at hd h + rcases h with ⟨hst | hst, hs, hi, ho⟩ | ⟨i, rest, hin, hst, hs, hi, ho⟩ <;> + subst hd <;> (try subst hst) <;> (try subst hs) <;> (try subst hi) <;> (try subst ho) <;> + (try subst hin) <;> simp [drain_out, loopStart, step, answerOf] + +/-- Early and late leave the live dispatch with the same history (equal state +under the assumption in the header). -/ +theorem early_disp_eq_late (acp : Bool) (input : List Msg) (tr : List BootEv) : + (runEarly acp input tr).disp = (runLate input).disp := by + have h := inv_boot acp input tr (start input) (inv_start input) + rw [late_disp] + unfold runEarly + generalize boot acp (start input) tr = s at h + obtain ⟨st, avail, inp, stash, out, disp⟩ := s + obtain ⟨hd, h⟩ := h + simp only at hd h + rcases h with ⟨hst | hst, hs, hi, ho⟩ | ⟨i, rest, hin, hst, hs, hi, ho⟩ <;> + subst hd <;> (try subst hst) <;> (try subst hs) <;> (try subst hi) <;> (try subst ho) <;> + (try subst hin) <;> simp [drain_disp, loopStart, step] + +/-- A first `initialize` is answered exactly once on every boot trace, whether +or not an early answer failed along the way. -/ +theorem initialize_answered_once (acp : Bool) (i : Nat) (rest : List Msg) (tr : List BootEv) + (fresh : ∀ m ∈ rest, answerOf m ≠ .resp i) : + (runEarly acp (.init i :: rest) tr).out.filter (fun o => decide (o = .resp i)) = [.resp i] := by + rw [early_out_eq_late, late_out] + simp only [List.map_cons, answerOf, List.filter_cons, decide_true, if_true, List.cons.injEq, true_and] + rw [List.filter_eq_nil_iff] + intro o ho + simp only [List.mem_map] at ho + obtain ⟨m, hm, rfl⟩ := ho + simpa using fresh m hm + +/-- Boot writes at most the one answer, and never touches the live dispatch. -/ +theorem boot_writes_at_most_one (acp : Bool) (input : List Msg) (tr : List BootEv) : + (boot acp (start input) tr).out.length ≤ 1 ∧ (boot acp (start input) tr).disp = [] := by + obtain ⟨hd, h⟩ := inv_boot acp input tr (start input) (inv_start input) + refine ⟨?_, hd⟩ + rcases h with ⟨_, _, _, ho⟩ | ⟨i, rest, _, _, _, _, ho⟩ <;> simp [ho] + +/-- A first line that is not `initialize` reaches the loop unchanged. -/ +theorem other_first_untouched (acp : Bool) (k : Nat) (rest : List Msg) (tr : List BootEv) : + (boot acp (start (.other k :: rest)) tr).input = .other k :: rest ∧ + (boot acp (start (.other k :: rest)) tr).stash = none ∧ + (boot acp (start (.other k :: rest)) tr).out = [] := by + obtain ⟨_, h⟩ := inv_boot acp _ tr (start _) (inv_start (.other k :: rest)) + rcases h with ⟨_, hs, hi, ho⟩ | ⟨i, r, hin, _⟩ + · exact ⟨hi, hs, ho⟩ + · cases hin + +/-- A check that sees no complete first line consumes nothing. -/ +theorem partial_not_consumed (acp ok : Bool) (s : Sys) (h : s.avail = false) : + (bootStep acp s (.boundary ok)).input = s.input ∧ (bootStep acp s (.boundary ok)).out = s.out := by + obtain ⟨st, avail, inp, stash, out, disp⟩ := s + simp only at h + subst h + cases st <;> cases acp <;> simp [bootStep, classify, step] + +/-- A check whose answer fails takes nothing off stdin, keeps nothing and +writes nothing, from any state. -/ +theorem failed_answer_not_consumed (acp : Bool) (s : Sys) : + (bootStep acp s (.boundary false)).input = s.input ∧ + (bootStep acp s (.boundary false)).stash = s.stash ∧ + (bootStep acp s (.boundary false)).out = s.out := by + obtain ⟨st, avail, inp, stash, out, disp⟩ := s + cases st <;> cases acp <;> cases avail <;> rcases inp with _ | ⟨_ | _, _⟩ <;> + simp [bootStep, attempt, classify, step] + +/-! ## (b) The response cube -/ + +inductive Pv where + | missing | v0 | v1 | v2 | v9 +deriving DecidableEq, Repr, BEq + +def Pv.requested : Pv → Nat + | .missing => 1 | .v0 => 0 | .v1 => 1 | .v2 => 2 | .v9 => 9 + +/-- `clientCapabilities.subagents`: absent, an object, or JSON null. -/ +inductive Sub where + | absent | object | null +deriving DecidableEq, Repr, BEq + +/-- `clientCapabilities._meta["graff/backgroundSubagents"]`. -/ +inductive Bg where + | absent | yes | no +deriving DecidableEq, Repr, BEq + +structure Cell where + pv : Pv + gate : Bool + sub : Sub + bg : Bg + canLoad : Bool + /-- T3 clientInfo + elicitation form + session compaction + v2 terminal auth. -/ + extras : Bool +deriving DecidableEq, Repr, BEq + +def allCells : List Cell := Id.run do + let mut acc : List Cell := [] + for pv in [Pv.missing, .v0, .v1, .v2, .v9] do + for gate in [false, true] do + for sub in [Sub.absent, .object, .null] do + for bg in [Bg.absent, .yes, .no] do + for canLoad in [false, true] do + for extras in [false, true] do + acc := acc ++ [{ pv, gate, sub, bg, canLoad, extras }] + return acc + +/- Sanity check, not a result: the cube has 360 cells. -/ +example : allCells.length = 360 := by native_decide + +/-- `acp_v2.negotiated`: v2 only behind the gate and on request (ADR 0206). -/ +def isV2 (c : Cell) : Bool := c.gate && decide (c.pv.requested ≥ 2) + +structure Resp where + protocolVersion : Nat + v2Shape : Bool + canLoad : Bool + authTerminal : Bool +deriving DecidableEq, Repr, BEq + +/-- `respondInitialize`: reads the cell and the dispatch's `can_load`, nothing else. -/ +def resp (c : Cell) (canLoad : Bool) : Resp := + { protocolVersion := if isV2 c then 2 else 1, v2Shape := isV2 c, canLoad, + authTerminal := !isV2 c || c.extras } + +/-- Process latches plus the dispatch fields `initialize` writes. -/ +structure Latch where + v2 : Bool + seed : Nat + t3 : Bool + elicit : Bool + compaction : Bool + subagents : Bool + bg : Bool +deriving DecidableEq, Repr, BEq + +def bootLatch : Latch := ⟨false, 0, false, false, false, false, false⟩ + +/-- Handling `initialize` with dispatch seed `seed`. The v2 message-id seed +is written only on a v2 connection; every other latch is overwritten. -/ +def latch (l : Latch) (c : Cell) (seed : Nat) : Latch := + { v2 := isV2 c, seed := if isV2 c then seed else l.seed, t3 := c.extras, elicit := c.extras, + compaction := c.extras || isV2 c, subagents := !isV2 c && c.sub == .object, bg := c.bg == .yes } + +/-- Late: the live dispatch (seed `s`) handles the line and writes the response. -/ +def late (l : Latch) (c : Cell) (s : Nat) : Latch × Resp := (latch l c s, resp c c.canLoad) + +/-- Early: a scratch dispatch (seed 0) writes the response; the replay on the +live dispatch writes the latches again and its response is discarded. The +response is `resp c c.canLoad` by construction: that the engine's bytes +agree is the Zig conformance test's job, not this model's. -/ +def early (l : Latch) (c : Cell) (s : Nat) : Latch × Resp := + (latch (latch l c 0) c s, resp c c.canLoad) + +/-- The model's latch table is last-writer-wins: a second `initialize` handling +overwrites everything the first one wrote. -/ +theorem latch_last_writer_wins (l : Latch) (c : Cell) (s₀ s : Nat) : + latch (latch l c s₀) c s = latch l c s := by + unfold latch + cases isV2 c <;> simp + +/-- Early + replay equals late in the model. Immediate from +`latch_last_writer_wins`; it records the design, the Zig test checks it. -/ +theorem early_eq_late (l : Latch) (c : Cell) (s : Nat) : early l c s = late l c s := by + simp [early, late, latch_last_writer_wins] + +/- Sanity check, not a result: `early_eq_late` on every cube cell and seed. -/ +example : + allCells.all (fun c => [0, 1, 0x5eed].all fun s => early bootLatch c s == late bootLatch c s) = true := by + native_decide + +/- Sanity check: the draft child-session stream is a v1 shape, so v2 never +latches it (true by the definition of `latch`). -/ +example : + allCells.all (fun c => !(isV2 c && (late bootLatch c 7).1.subagents)) = true := by + native_decide + +/- Sanity check, not a result: 72 cells are gated and ask for ≥ 2. -/ +example : (allCells.filter isV2).length = 72 := by native_decide + +end Graff.AcpEarlyInit diff --git a/lean-proofs/KERNELS.md b/lean-proofs/KERNELS.md index 1f173e58..043d57e8 100644 --- a/lean-proofs/KERNELS.md +++ b/lean-proofs/KERNELS.md @@ -25,7 +25,14 @@ is delivered once or refused, never dropped; a request is in call order whichever read finished first; a trailer ref is an image block or its line; the port is the `Model` in `src/image_inbox.zig`, run against the queue over every sequence of six events). They are not Turing -machines: no tape, no halt state. +machines: no tape, no halt state. `AcpEarlyInit` is the decision +`src/acp_early.zig` consults. It proves line bookkeeping on every boot +trace, including traces where the early answer fails: the first +`initialize` is answered once, a line is taken only after its answer was +sent, the loop-start replay writes nothing, a non-`initialize` first line +reaches the loop unchanged, and stdout and dispatch history equal the late +path's. It assumes, and does not prove, that the response is a function of +the request alone and that equal dispatch history means equal state. The shape of a subagent fleet is not a cube. `Shape` is the observation ladder of one turn and stays a cube. How many children spawn, which @@ -65,6 +72,7 @@ not a skip: TUI, prompts, and SSE bytes stay out of Lean on purpose. |---|---|---| | `BashPolicy` | finite command cube: `isSimple`, `escapesCwd`, `readOnlyAllowed`, `readOnlyExternal` | live argv quoting, Windows cmd.exe | | `ImageDelivery` | 102 admit cells + `Event`/`step` (inbox) + the trailer promotion fold | base64 bytes, provider wire shape, which read finishes first | +| `AcpEarlyInit` | 55 `step` cells + boot-trace theorems (∀ traces, early answers that fail included) + 360 `initialize` response cells; 6 mutants rejected | proof that the response is independent of boot state (the model's `answerOf` is a pure function of the request) or that equal dispatch history means equal state (assumed); bytes, framing, CRLF, BOM, overlong lines; the poll, the reader, the discard sink; `can_load` equality (a Zig test pins it); timing; Zig refinement beyond the fixture. The cube's `early_eq_late` holds by the model's construction. Byte equality rests on the conformance test (real engine, early vs late, every cube cell) and `scripts/test-acp-early-init.py` | ### Never (accounted for; eval / tier 2) diff --git a/scripts/bench-startup.py b/scripts/bench-startup.py new file mode 100755 index 00000000..24067c73 --- /dev/null +++ b/scripts/bench-startup.py @@ -0,0 +1,376 @@ +#!/usr/bin/env python3 +"""Hermetic cold-start benchmark for graff; see docs/harness-latency.md. + +Times four ready points from process spawn, with no network and no credentials: + a_version / a_help `--version` / `--help` exit (wall) + b_repl_ready line REPL reaches its loop (stdin=/dev/null; first + GRAFF_SHUTDOWN_DEBUG `final-save` stamp on stderr) + c_first_request `-p hi --model lmstudio`: first POST at the loopback mock + d_acp_initialize `graff acp`: the `initialize` response line on stdout, + "handshake answered" (graff may answer it before the + session exists; `_nokey` variant: no credential, pre-auth) + d_acp_session_usable `graff acp` with `initialize` and `session/new` written + at spawn: the `session/new` response, "ACP session usable" +plus a floor (/usr/bin/true and a compiled C hello) timed the same way. + +The mock sits on the lmstudio provider's fixed port 127.0.0.1:1234. Each +sample gets its own LMSTUDIO_API_KEY token, so a POST from another client on +that port is recognised by its bearer and the sample is retried. +""" +from __future__ import annotations + +import argparse +import hashlib +import json +import math +import os +import platform +import re +import shutil +import signal +import statistics +import subprocess +import sys +import tempfile +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent)) +from bench_startup_lib import ( # noqa: E402 + LIVE, BenchError, Fixture, check_budgets, compare, cpu_name, parse_spawns, print_summary, + reap_group, run_stream, run_wall, start_mock, stats, tail, +) + +SCHEMA = 1 +INIT = b'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":1}}\n' +FOREIGN_RETRIES = 5 # samples redone after a stray client hit the shared mock port +BOOT_LINE = re.compile(r"^\[boot \+(\d+)ms, phase (\d+)ms\] (.+)$") +# Safety vars are fixed; --env may not override them. +PROTECTED = {"HOME", "PATH", "GRAFF_NO_TELEMETRY", "GRAFF_NO_UPDATE_CHECK", "GRAFF_AUTO_ISOLATE", + "LMSTUDIO_API_KEY"} +# Git subcommands that reach a remote or mean auto-isolation fired. Any of them fails the run. +FORBIDDEN_GIT = ("fetch", "pull", "push", "clone", "ls-remote", "remote update", "worktree add") + + +# ---------------------------------------------------------------- points + +def acp_response(want_id): + def ready(tag, line): + if tag != "out": + return False + try: + message = json.loads(line) + except ValueError: + return False + return isinstance(message, dict) and message.get("id") == want_id and ("result" in message or "error" in message) + return ready + + +acp_ready = acp_response(1) + + +def init_then_session(work): + """`initialize` and `session/new` back to back, as a client that wants a session.""" + session = {"jsonrpc": "2.0", "id": 2, "method": "session/new", "params": {"cwd": str(work), "mcpServers": []}} + return INIT + json.dumps(session).encode() + b"\n" + + +def repl_ready(tag, line): + return tag == "err" and line.startswith("[shutdown") and "final-save" in line + + +POINTS = { + # name: argv tail, kind, metric names, key, extra env, ready predicate, stdin + "a_version": (["--version"], "wall", True, {}, None, None), + "a_help": (["--help"], "wall", True, {}, None, None), + # The only REPL "loop reached" stamp is the shutdown trace; acceptable debug env. + "b_repl_ready": (["--model", "lmstudio"], "stream", True, {"GRAFF_SHUTDOWN_DEBUG": "1"}, repl_ready, None), + "c_first_request": (["-p", "hi", "--model", "lmstudio"], "post", True, {}, None, None), + "d_acp_initialize": (["acp", "--model", "lmstudio"], "stream", True, {}, acp_ready, INIT), + "d_acp_initialize_nokey": (["acp"], "stream", False, {}, acp_ready, INIT), + "d_acp_session_usable": (["acp", "--model", "lmstudio"], "stream", True, {}, acp_response(2), init_then_session), +} +READY_METRIC = {"b_repl_ready": "ready_ms", "c_first_request": "request_ms", + "d_acp_initialize": "response_ms", "d_acp_initialize_nokey": "response_ms", + "d_acp_session_usable": "response_ms"} + + +class ForeignRequest(BenchError): + pass + + +def stdin_for(stdin_data, work): + return stdin_data(work) if callable(stdin_data) else stdin_data + + +def sample(fx, mock, binary, name, template, timeout, extra=None, path=None): + """One timed run; redone when a stray client posted to the shared mock port.""" + for attempt in range(FOREIGN_RETRIES + 1): + try: + return sample_once(fx, mock, binary, name, template, timeout, extra, path) + except ForeignRequest as exc: + fx.foreign_retries = getattr(fx, "foreign_retries", 0) + 1 + if attempt == FOREIGN_RETRIES: + raise BenchError(f"{exc} (still after {FOREIGN_RETRIES} retries)") from exc + + +def sample_once(fx, mock, binary, name, template, timeout, extra=None, path=None): + tail_argv, kind, key, env_extra, ready, stdin_data = POINTS[name] + dest, home, work = fx.fresh(template) + token = f"local-bench-{os.getpid()}-{fx.counter}" + env = fx.env(home, key=key, extra=dict(env_extra, **(extra or {})), path=path) + if key: + env["LMSTUDIO_API_KEY"] = token + mine = (lambda auth: auth == f"Bearer {token}") if key else (lambda auth: auth is None) + argv = [binary] + tail_argv + with mock._lock: + before = len(mock.posts) + try: + if kind == "stream": + got = run_stream(argv, env, str(work), timeout, ready, stdin_for(stdin_data, work)) + row = {READY_METRIC[name]: got["ready_ms"], "wall_ms": got["wall_ms"], "cpu_ms": got["cpu_ms"]} + lines = got["lines"] + if name.startswith("d_"): + reply = next(json.loads(l) for _, t, l in lines if t == "out" and ready(t, l)) + if "result" not in reply: + raise BenchError(f"{name}: the request returned an error: {reply.get('error')}") + else: + got = run_wall(argv, env, str(work), timeout, str(dest / "stderr")) + if got["rc"] != 0: + raise BenchError(f"{name}: exit {got['rc']}\n{tail(dest / 'stderr')}") + row = {"wall_ms": got["wall_ms"], "cpu_ms": got["cpu_ms"]} + lines = [(0, "err", l) for l in tail(dest / "stderr", 1 << 20).splitlines()] + with mock._lock: + seen = mock.posts[before:] + posts = [stamp for stamp, auth in seen if mine(auth)] + if len(posts) != len(seen): + raise ForeignRequest(f"{name}: {len(seen) - len(posts)} request(s) from another client on the mock port") + if kind == "post": + if not posts: + raise BenchError(f"{name}: the mock never received a request\n{tail(dest / 'stderr')}") + row["request_ms"] = (posts[0] - got["started"]) / 1e6 + elif posts: + raise BenchError(f"{name}: unexpected model request ({len(posts)}) during startup") + row["posts"] = len(posts) + return row, lines + finally: + shutil.rmtree(dest, ignore_errors=True) + + +def floor_sample(fx, prog, timeout): + work = fx.root / "floorcwd" + work.mkdir(exist_ok=True) + return run_wall([prog], fx.env(fx.root), str(work), timeout, str(fx.root / "floor.err"))["wall_ms"] + + +def measure(args, binary): + mock = start_mock() + fx = None + try: + fx = Fixture(args) + names = [n for n in POINTS if n in args.points] + templates = {n: fx.template(n) for n in names if not n.startswith("a_")} + a_template = fx.template("a") + for n in names: + templates.setdefault(n, a_template) + per_round = {n: (math.ceil(100 / args.runs) if n.startswith("a_") else 1) for n in names} + floors = [("true_ms", "/usr/bin/true")] + ([("hello_ms", fx.hello)] if fx.hello else []) + samples = {n: {} for n in names} + floor_samples = {k: [] for k, _ in floors} + load = [os.getloadavg()[0]] + + def log(msg): + if not args.quiet: + print(msg, file=sys.stderr, flush=True) + + # Warm-up runs in the templates so each copied sample sees steady state. + for _ in range(args.warmup): + for n in names: + tail_argv, kind, key, env_extra, ready, stdin_data = POINTS[n] + home, work = templates[n] + env = fx.env(home, key=key, extra=env_extra) + if kind == "stream": + run_stream([binary] + tail_argv, env, str(work), args.timeout, ready, stdin_for(stdin_data, work)) + else: + run_wall([binary] + tail_argv, env, str(work), args.timeout, str(fx.root / "warm.err")) + for _, prog in floors: + floor_sample(fx, prog, args.timeout) + # Timing pass: interleaved rounds, rotated order, no debug env except b's marker. + order = [("floor", k, p) for k, p in floors] + [("point", n, None) for n in names] + for r in range(args.runs): + rotated = order[r % len(order):] + order[:r % len(order)] + for kind, n, prog in rotated: + if kind == "floor": + for _ in range(math.ceil(50 / args.runs)): + floor_samples[n].append(floor_sample(fx, prog, args.timeout)) + continue + for _ in range(per_round[n]): + row, _ = sample(fx, mock, binary, n, templates[n], args.timeout) + for metric, value in row.items(): + samples[n].setdefault(metric, []).append(value) + log(f"round {r + 1}/{args.runs}") + load.append(os.getloadavg()[0]) + points = {} + for n in names: + points[n] = {m: stats(v) for m, v in samples[n].items() if m != "posts"} + points[n]["model_requests"] = max(samples[n].get("posts", [0])) + # Diagnostic pass: per-phase medians from GRAFF_BOOT_DEBUG. + for n in names: + if n.startswith("a_") or args.diag_runs <= 0: + continue + phases = {} + for _ in range(args.diag_runs): + _, lines = sample(fx, mock, binary, n, templates[n], args.timeout, {"GRAFF_BOOT_DEBUG": "1"}) + seen = {} + for _, tag, line in lines: + match = BOOT_LINE.match(line) if tag == "err" else None + if match: + seen[match.group(3)] = seen.get(match.group(3), 0) + int(match.group(2)) + for label, ms in seen.items(): + phases.setdefault(label, []).append(ms) + points[n]["phases_ms"] = {k: statistics.median(v) for k, v in phases.items()} + log(f"diag {n}") + # Spawn pass: PATH shims log every git/security/companion spawn. + roots = [str(fx.root), os.path.realpath(str(fx.root))] + for n in names: + runs = [] + for _ in range(max(1, args.shim_runs)): + if fx.log.exists(): + fx.log.unlink() + sample(fx, mock, binary, n, templates[n], args.timeout, path=fx.shim_path) + runs.append(parse_spawns(fx.log, roots)) + tools = ["git", "security"] + sorted(fx.companions) + counts = {t: max(c.get(t, 0) for c, _ in runs) for t in tools} + points[n]["spawns"] = counts + if any(c != runs[0][0] for c, _ in runs): + points[n]["spawns_nondeterministic"] = [c for c, _ in runs] + points[n]["spawn_detail"] = runs[0][1] + for line in runs[0][1]: + if line.startswith("git ") and any(f" {cmd}" in line for cmd in FORBIDDEN_GIT): + raise BenchError(f"{n}: network/auto-isolation git command observed: {line}") + log(f"spawns {n}: {counts}") + return {"floor": {k: stats(v) for k, v in floor_samples.items()}, "points": points, + "samples": {"floor": floor_samples, **samples}, "load": load, + "path_dirs": ["/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"], + "companions": sorted(fx.companions), "git": fx.git_version, + "foreign_retries": getattr(fx, "foreign_retries", 0)} + finally: + for pid in list(LIVE): + reap_group(pid) + mock.stop() + if fx is not None: + fx.cleanup() + + + +def main(): + parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + root = Path(__file__).resolve().parents[1] + parser.add_argument("--graff", type=Path, default=root / "zig-out/bin/graff") + parser.add_argument("--runs", type=int, default=30, help="timed rounds (a_* points take ≥100 samples)") + parser.add_argument("--warmup", type=int, default=3) + parser.add_argument("--diag-runs", type=int, default=5, help="GRAFF_BOOT_DEBUG runs per point (0 to skip)") + parser.add_argument("--shim-runs", type=int, default=2, help="spawn-counting runs per point") + parser.add_argument("--timeout", type=float, default=30, help="per-run deadline in seconds") + parser.add_argument("--points", default=",".join(POINTS), help="comma-separated subset") + parser.add_argument("--git-repo", action="store_true", help="cwd is a throwaway one-commit repo, no remote") + parser.add_argument("--companion", action="store_true", help="put codedb-pro/muonry on PATH") + parser.add_argument("--env", action="append", default=[], metavar="KEY=VALUE", + help="extra child env (knob experiments); safety vars cannot be overridden") + parser.add_argument("--out", type=Path, help="write the result JSON here") + parser.add_argument("--load", type=Path, help="use an existing result instead of measuring") + parser.add_argument("--compare", type=Path, help="print deltas against an earlier result") + parser.add_argument("--budgets", type=Path, help="gate on ratio-over-floor and spawn counts") + parser.add_argument("--quiet", action="store_true") + args = parser.parse_args() + args.extra_env = {} + for item in args.env: + k, sep, v = item.partition("=") + if not sep or not k: + parser.error(f"--env wants KEY=VALUE, got {item!r}") + if k in PROTECTED: + parser.error(f"--env may not override {k}") + args.extra_env[k] = v + args.points = [p.strip() for p in args.points.split(",") if p.strip()] + unknown = [p for p in args.points if p not in POINTS] + if unknown: + parser.error(f"unknown points {unknown}; choose from {list(POINTS)}") + if args.runs < 1 or args.warmup < 0 or args.timeout <= 0: + parser.error("runs ≥ 1, warmup ≥ 0, timeout > 0") + + if args.load: + result = json.loads(args.load.read_text()) + else: + if not args.out: + parser.error("--out is required unless --load is given") + binary = os.path.realpath(str(args.graff)) + if not os.path.isfile(binary) or not os.access(binary, os.X_OK): + raise BenchError(f"graff binary not found or not executable: {args.graff} " + "(build with: zig build graff -Doptimize=ReleaseSafe -Dlearn=false)") + data = Path(binary).read_bytes() + digest = hashlib.sha256(data).hexdigest() + cwd = os.getcwd() + try: + try: + with tempfile.TemporaryDirectory(prefix="graff-startup-version-") as scratch: + version = subprocess.run( + [binary, "--version"], capture_output=True, text=True, timeout=10, cwd=scratch, + env={"PATH": "/usr/bin:/bin", "HOME": scratch, "GRAFF_NO_TELEMETRY": "1", + "GRAFF_NO_UPDATE_CHECK": "1", "GRAFF_AUTO_ISOLATE": "off"}, + ).stdout.strip().splitlines()[:1] + except subprocess.TimeoutExpired as exc: + raise BenchError(f"{binary} --version did not exit within 10s") from exc + measured = measure(args, binary) + finally: + os.chdir(cwd) + if hashlib.sha256(Path(binary).read_bytes()).hexdigest() != digest: + raise BenchError("binary changed during measurement; rerun against a stable copy") + result = { + "schema": SCHEMA, + "graff": {"path": binary, "sha256": digest, "size": len(data), "version": (version or [""])[0]}, + "host": {"os": platform.system(), "release": platform.release(), "arch": platform.machine(), + "cpu": cpu_name(), "ncpu": os.cpu_count(), "python": platform.python_version(), + "load1": measured["load"]}, + "env": {"hermetic": True, "git_repo": args.git_repo, "companion": args.companion, + "companions_found": measured["companions"], "auto_isolate": "off", + "git": measured["git"], "foreign_retries": measured["foreign_retries"], + "extra_env": sorted(args.extra_env), "path": measured["path_dirs"], + "security": "stub (exit 44, Keychain never read)", + "debug_env": {"b_repl_ready": "GRAFF_SHUTDOWN_DEBUG=1 (ready marker)", + "phases_ms": "GRAFF_BOOT_DEBUG=1 (separate diagnostic pass)"}}, + "timer": {"method": "os.posix_spawn + wait4, perf_counter_ns from before spawn", + "note": "includes the interpreter's spawn cost; subtract floor.*.median for graff-only time"}, + "runs": args.runs, "warmup": args.warmup, "diag_runs": args.diag_runs, "shim_runs": args.shim_runs, + "floor": measured["floor"], "points": measured["points"], "samples": measured["samples"], + } + args.out.parent.mkdir(parents=True, exist_ok=True) + args.out.write_text(json.dumps(result, indent=1) + "\n") + print_summary(result) + if args.compare: + print() + compare(json.loads(args.compare.read_text()), result) + if args.budgets: + print() + failures = check_budgets(result, json.loads(args.budgets.read_text())) + if failures: + print(f"startup budgets exceeded: {', '.join(failures)}") + return 1 + return 0 + + +def _terminate(signum, _frame): + raise SystemExit(128 + signum) + + +if __name__ == "__main__": + signal.signal(signal.SIGTERM, _terminate) + try: + code = main() + except BenchError as exc: + print(f"bench-startup: {exc}", file=sys.stderr) + code = 2 + except KeyboardInterrupt: + code = 130 + finally: + for pid in list(LIVE): + reap_group(pid) + sys.exit(code) diff --git a/scripts/bench_startup_lib.py b/scripts/bench_startup_lib.py new file mode 100644 index 00000000..091c314c --- /dev/null +++ b/scripts/bench_startup_lib.py @@ -0,0 +1,510 @@ +"""Process, fixture and report helpers for scripts/bench-startup.py. + +Split out of the benchmark script (hand-written files stay under 600 lines); +behaviour is unchanged. Nothing here is a benchmark point: the points, the +sampling loop and the CLI live in bench-startup.py. +""" +from __future__ import annotations + +import math +import os +import platform +import queue +import shutil +import signal +import socket +import statistics +import subprocess +import sys +import tempfile +import threading +import time +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent / "eval")) +from mock_model import ScriptedModel # noqa: E402 + +clock = time.perf_counter_ns +PORT = 1234 # the built-in lmstudio provider URL is fixed to 127.0.0.1:1234 +LIVE = set() # process groups still to reap on exit + + + +class BenchError(Exception): + pass + + +# ---------------------------------------------------------------- processes + +def spawn(argv, env, cwd, stdin=None, stdout=None, stderr=None): + """os.posix_spawn in its own process group. ~1 ms floor versus ~2.7 ms for + subprocess on macOS, so less interpreter overhead lands in the timer. + stdin/stdout/stderr: None for /dev/null, else an fd to dup2.""" + actions = [] + for target, fd in ((0, stdin), (1, stdout), (2, stderr)): + if fd is None: + flags = os.O_RDONLY if target == 0 else os.O_WRONLY + actions.append((os.POSIX_SPAWN_OPEN, target, os.devnull, flags, 0)) + else: + actions.append((os.POSIX_SPAWN_DUP2, fd, target)) + os.chdir(cwd) # posix_spawn has no chdir action before Python 3.13 + pid = os.posix_spawn(argv[0], argv, env, file_actions=actions, setpgroup=0) + LIVE.add(pid) + return pid + + +def reap_group(pid): + try: + os.killpg(pid, signal.SIGKILL) + except OSError: + pass + LIVE.discard(pid) + + +class Watchdog: + """Kills the process group at the deadline so a stuck run cannot hang.""" + def __init__(self, timeout): + self.fired = False + self.pid = None + self.timer = threading.Timer(timeout, self._fire) + self.timer.daemon = True + self.timer.start() + + def _fire(self): + self.fired = True + if self.pid is not None: + reap_group(self.pid) + + def cancel(self): + self.timer.cancel() + + +def wait_child(pid, dog): + _, status, usage = os.wait4(pid, 0) + ended = clock() + dog.cancel() + reap_group(pid) # stray grandchildren (git, companions) must not outlive the sample + rc = os.waitstatus_to_exitcode(status) if hasattr(os, "waitstatus_to_exitcode") else ( + -os.WTERMSIG(status) if os.WIFSIGNALED(status) else os.WEXITSTATUS(status)) + return ended, rc, (usage.ru_utime + usage.ru_stime) * 1e3 + + +def tail(path, limit=1200): + try: + return Path(path).read_text(errors="replace")[-limit:] + except OSError: + return "" + + +def run_wall(argv, env, cwd, timeout, errfile): + """Spawn → exit. stdout to /dev/null, stderr to errfile (for failure reports).""" + errfd = os.open(errfile, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) + dog = Watchdog(timeout) + try: + started = clock() + pid = dog.pid = spawn(argv, env, cwd, stderr=errfd) + except OSError: + dog.cancel() + raise + finally: + os.close(errfd) + ended, rc, cpu = wait_child(pid, dog) + if dog.fired: + raise BenchError(f"{' '.join(argv[1:]) or argv[0]}: no exit within {timeout}s\n{tail(errfile)}") + return {"started": started, "wall_ms": (ended - started) / 1e6, "cpu_ms": cpu, "rc": rc} + + +def _reader(fd, tag, events): + buf = b"" + while True: + try: + chunk = os.read(fd, 65536) + except OSError: + chunk = b"" + stamp = clock() + if not chunk: + break + buf += chunk + while b"\n" in buf: + line, buf = buf.split(b"\n", 1) + events.put((stamp, tag, line.decode(errors="replace"))) + if buf: + events.put((clock(), tag, buf.decode(errors="replace"))) + events.put((clock(), tag, None)) + os.close(fd) + + +def run_stream(argv, env, cwd, timeout, ready, stdin_data=None): + """Spawn, optionally write stdin_data (stdin stays open), and stamp the first + line where ready(tag, line) holds. Then close stdin and time the exit.""" + events = queue.Queue() + out_r, out_w = os.pipe() + err_r, err_w = os.pipe() + in_r, in_w = os.pipe() if stdin_data is not None else (None, None) + readers = [threading.Thread(target=_reader, args=(fd, tag, events), daemon=True) + for fd, tag in ((out_r, "out"), (err_r, "err"))] + for thread in readers: + thread.start() + dog = Watchdog(timeout) + try: + started = clock() + pid = dog.pid = spawn(argv, env, cwd, stdin=in_r, stdout=out_w, stderr=err_w) + except OSError: + dog.cancel() # readers see EOF once the finally below closes the write ends + if in_w is not None: + os.close(in_w) + raise + finally: + for fd in (out_w, err_w, in_r): + if fd is not None: + os.close(fd) + deadline = time.monotonic() + timeout + lines, ready_at, eofs = [], None, 0 + try: + if stdin_data is not None: + os.write(in_w, stdin_data) + while ready_at is None and eofs < 2: + try: + stamp, tag, line = events.get(timeout=max(0.0, deadline - time.monotonic())) + except queue.Empty: + break + if line is None: + eofs += 1 + continue + lines.append((stamp, tag, line)) + if ready(tag, line): + ready_at = stamp + finally: + if in_w is not None: + try: + os.close(in_w) + except OSError: + pass + if ready_at is None: + reap_group(pid) # unblock wait4 now rather than at the watchdog deadline + ended, rc, cpu = wait_child(pid, dog) + for thread in readers: + thread.join(timeout=2) + while True: + try: + stamp, tag, line = events.get_nowait() + except queue.Empty: + break + if line is not None: + lines.append((stamp, tag, line)) + stderr_tail = "\n".join(l for _, t, l in lines if t == "err")[-1200:] + if ready_at is None: + why = "timed out" if time.monotonic() >= deadline or dog.fired else f"exited rc={rc}" + raise BenchError(f"{' '.join(argv[1:])}: ready marker never appeared ({why})\n{stderr_tail}") + return {"started": started, "ready_ms": (ready_at - started) / 1e6, + "wall_ms": (ended - started) / 1e6, "cpu_ms": cpu, "rc": rc, "lines": lines} + + +# ---------------------------------------------------------------- fixtures + +class _HeaderLog(list): + """ScriptedModel.request_headers that also keeps, per handler thread, the + headers of the request being answered: do_POST appends them and then + calls next_reply on the same thread.""" + def __init__(self): + super().__init__() + self.local = threading.local() + + def append(self, item): + self.local.last = item + super().append(item) + + +class Mock(ScriptedModel): + """scripts/eval/mock_model.py, plus a perf_counter_ns stamp per POST. The + stamp is taken once the request body has been read (loopback, sub-ms). + Each post keeps its Authorization header: the lmstudio port is fixed and + shared, so a sample tells its own requests (bearer = its per-sample key) + from a stray client's.""" + def __init__(self): + super().__init__([]) + self.posts = [] # (stamp, authorization or None) + self.request_headers = _HeaderLog() + + def next_reply(self, body): + stamp = clock() + auth = getattr(self.request_headers.local, "last", {}).get("authorization") + with self._lock: + self.posts.append((stamp, auth)) + return super().next_reply(body) + + +def start_mock(wait_s=120): + """Bind the mock on the fixed lmstudio port, waiting up to wait_s for + another listener (LM Studio, another benchmark) to let it go.""" + deadline = time.monotonic() + wait_s + while True: + probe = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + probe.settimeout(0.3) + try: + busy = probe.connect_ex(("127.0.0.1", PORT)) == 0 + finally: + probe.close() + if not busy: + mock = Mock() + try: + mock.start(PORT) + return mock + except OSError as exc: + busy_err = exc + else: + busy_err = None + if time.monotonic() >= deadline: + raise BenchError(f"127.0.0.1:{PORT} is busy (LM Studio or another mock?) for {wait_s}s. The " + f"lmstudio provider is fixed to that port; stop the listener and rerun." + + (f" ({busy_err})" if busy_err else "")) + time.sleep(1) + + +def which_in(name, path): + found = shutil.which(name, path=path) + return os.path.realpath(found) if found else None + + +def write_exe(path, text): + path.write_text(text) + path.chmod(0o755) + + +class Fixture: + """Scratch tree: bin/ (timing PATH), shim/ (spawn-logging PATH), template + HOME and cwd per point. Each sample runs in fresh copies of the templates.""" + def __init__(self, args): + self.root = Path(tempfile.mkdtemp(prefix="graff-startup-")).resolve() + try: + self._setup(args) + except BaseException: + self.cleanup() + raise + + def _setup(self, args): + self.args = args + user_path = os.environ.get("PATH", "") + self.git = which_in("git", user_path) + if not self.git: + raise BenchError("git not found on PATH") + if sys.platform == "darwin" and self.git == "/usr/bin/git": + # /usr/bin/git is the xcrun shim: its first call under each new HOME + # costs ~70-110 ms (then ~11 ms). Every sample has a fresh HOME, so + # the shim would bill that to graff on every run. Use the real git. + found = subprocess.run(["xcrun", "--find", "git"], capture_output=True, text=True).stdout.strip() + if found and os.access(found, os.X_OK): + self.git = found + self.git_version = subprocess.run([self.git, "--version"], capture_output=True, + text=True).stdout.strip() + self.bin = self.root / "bin" + self.shim = self.root / "shim" + self.log = self.root / "spawns.log" + self.bin.mkdir() + self.shim.mkdir() + os.symlink(self.git, self.bin / "git") + # Never reach the real Keychain: answer "not found" (44) like an empty one. + stub = "#!/bin/sh\n{log}echo 'security: The specified item could not be found in the keychain.' >&2\nexit 44\n" + write_exe(self.bin / "security", stub.format(log="")) + write_exe(self.shim / "security", stub.format(log=f'printf "%s\\n" "security $*" >> "{self.log}"\n')) + write_exe(self.shim / "git", f'#!/bin/sh\nprintf "%s\\n" "git $*" >> "{self.log}"\nexec "{self.git}" "$@"\n') + self.companions = {} + if args.companion: + for name in ("codedb-pro", "muonry"): + real = which_in(name, user_path) + if real: + self.companions[name] = real + os.symlink(real, self.bin / name) + write_exe(self.shim / name, f'#!/bin/sh\nprintf "%s\\n" "{name} $*" >> "{self.log}"\nexec "{real}" "$@"\n') + if "codedb-pro" not in self.companions: + raise BenchError("--companion needs codedb-pro on PATH") + self.path = os.pathsep.join([str(self.bin), "/usr/bin", "/bin", "/usr/sbin", "/sbin"]) + self.shim_path = str(self.shim) + os.pathsep + self.path + self.hello = None + cc = which_in("cc", user_path) + if cc: + (self.root / "hello.c").write_text('#include \nint main(void){write(1,"hi\\n",3);return 0;}\n') + if subprocess.run([cc, "-O2", "-o", str(self.root / "hello"), str(self.root / "hello.c")], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0: + self.hello = str(self.root / "hello") + self.counter = 0 + + def env(self, home, key=True, extra=None, path=None): + env = {k: os.environ[k] for k in ("TMPDIR", "TERM") if k in os.environ} + env.update(PATH=path or self.path, HOME=str(home), GRAFF_NO_TELEMETRY="1", + GRAFF_NO_UPDATE_CHECK="1", GRAFF_AUTO_ISOLATE="off", GRAFF_FLEET="off", + GRAFF_NO_SMOLIFY="1", GRAFF_LEARN_AUTO="off", NO_COLOR="1") + if key: + env["LMSTUDIO_API_KEY"] = "local" + env.update(self.args.extra_env) + env.update(extra or {}) + return env + + def git_env(self, home): + return dict(self.env(home, key=False), GIT_CONFIG_NOSYSTEM="1") + + def template(self, name): + base = self.root / "templates" / name + home, work = base / "home", base / "work" + home.mkdir(parents=True) + work.mkdir() + genv = self.git_env(home) + if self.args.git_repo: + (work / "README.md").write_text("startup benchmark fixture\n") + for cmd in (["init", "-q"], ["add", "README.md"], + ["-c", "user.name=bench", "-c", "user.email=bench@example.invalid", + "-c", "commit.gpgsign=false", "commit", "-q", "-m", "fixture"]): + subprocess.run([self.git] + cmd, cwd=work, env=genv, check=True, + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + else: + inside = subprocess.run([self.git, "rev-parse", "--is-inside-work-tree"], cwd=work, env=genv, + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0 + if inside: + raise BenchError(f"scratch dir {work} is inside a git repository; set TMPDIR elsewhere") + return home, work + + def fresh(self, template): + """Copy a template HOME+cwd so every sample sees identical state.""" + self.counter += 1 + dest = self.root / "runs" / str(self.counter) + home = dest / "home" + work = dest / "work" + shutil.copytree(template[0], home, symlinks=True) + shutil.copytree(template[1], work, symlinks=True) + return dest, home, work + + def cleanup(self): + shutil.rmtree(self.root, ignore_errors=True) + + + + +def stats(values): + ordered = sorted(values) + if not ordered: + return {"n": 0} + pick = lambda q: ordered[max(0, math.ceil(len(ordered) * q) - 1)] # noqa: E731 + return {"n": len(ordered), "min": round(ordered[0], 3), "median": round(statistics.median(ordered), 3), + "p95": round(pick(0.95), 3), "max": round(ordered[-1], 3)} + + +def parse_spawns(log, roots): + counts, detail = {}, [] + if log.exists(): + for line in log.read_text(errors="replace").splitlines(): + tool = line.split(" ", 1)[0] + counts[tool] = counts.get(tool, 0) + 1 + for root in roots: + line = line.replace(root, "") + detail.append(line) + return counts, detail + + +# ---------------------------------------------------------------- report + +def cpu_name(): + try: + if sys.platform == "darwin": + return subprocess.run(["sysctl", "-n", "machdep.cpu.brand_string"], capture_output=True, + text=True, timeout=5).stdout.strip() + for line in Path("/proc/cpuinfo").read_text().splitlines(): + if line.startswith("model name"): + return line.split(":", 1)[1].strip() + except (OSError, subprocess.SubprocessError): + pass + return platform.processor() + + +def floor_ref(result): + floor = result.get("floor", {}) + for key in ("hello_ms", "true_ms"): + if floor.get(key, {}).get("n"): + return key, floor[key]["median"] + return None, None + + +def headline(result): + rows = [] + for name, point in result["points"].items(): + for metric, value in point.items(): + if isinstance(value, dict) and "median" in value and metric != "cpu_ms": + rows.append((f"{name}.{metric}", value)) + return rows + + +def print_summary(result): + key, floor = floor_ref(result) + print(f"floor {key}: median {floor} ms (subtract for graff-only cost)" if floor else "floor: none") + for k, v in result["floor"].items(): + print(f" {k:28} n={v['n']:3} min {v['min']:8.2f} med {v['median']:8.2f} p95 {v['p95']:8.2f}") + for label, v in headline(result): + print(f" {label:44} n={v['n']:3} min {v['min']:8.2f} med {v['median']:8.2f} p95 {v['p95']:8.2f} max {v['max']:8.2f}") + for name, point in result["points"].items(): + if "spawns" in point: + print(f" {name:44} spawns {point['spawns']}") + + +def variant(result): + env = result.get("env", {}) + return "git_repo" if env.get("git_repo") else "default" + + +def compare(before, after): + if variant(before) != variant(after) or before["env"].get("companion") != after["env"].get("companion"): + print("WARNING: comparing different variants (git_repo/companion differ)") + if before.get("host", {}).get("cpu") != after.get("host", {}).get("cpu"): + print("WARNING: different hosts") + _, fb = floor_ref(before) + _, fa = floor_ref(after) + print(f"{'point.metric':44} {'before':>9} {'after':>9} {'delta':>9} {'delta%':>7} net(before→after)") + old = dict(headline(before)) + for label, v in headline(after): + if label not in old: + continue + b, a = old[label]["median"], v["median"] + net = f"{b - (fb or 0):7.2f}→{a - (fa or 0):.2f}" + pct = (a - b) / b * 100 if b else 0.0 + print(f"{label:44} {b:9.2f} {a:9.2f} {a - b:+9.2f} {pct:+6.1f}% {net}") + for name, point in after["points"].items(): + prev = before["points"].get(name, {}).get("spawns") + if prev is not None and "spawns" in point and prev != point["spawns"]: + print(f"{name + ' spawns':44} {prev} → {point['spawns']}") + + +def check_budgets(result, budgets): + failures, notes = [], [] + key, floor = floor_ref(result) + if budgets.get("floor") and budgets["floor"] != key: + notes.append(f"budget floor {budgets['floor']} unavailable; using {key}") + for label, rule in budgets.get("ratio_over_floor", {}).items(): + if label.startswith("_"): + continue + name, metric = label.split(".", 1) + stat = result["points"].get(name, {}).get(metric) + if not stat or not floor: + notes.append(f"skip {label}: not measured") + continue + ratio = stat["median"] / floor + status = "ok" if ratio <= rule["max"] else "FAIL" + print(f"budget {label:40} ratio {ratio:6.1f} ≤ {rule['max']:<6} {status}") + if status != "ok": + failures.append(label) + for name, tools in budgets.get("spawns", {}).get(variant(result), {}).items(): + if name.startswith("_"): + continue + point = result["points"].get(name, {}) + if "spawns" not in point: + notes.append(f"skip {name} spawns: not measured") + continue + for tool, rule in tools.items(): + if tool.startswith("_"): + continue + limit = rule["max"] if isinstance(rule, dict) else rule + got = point["spawns"].get(tool, 0) + status = "ok" if got <= limit else "FAIL" + print(f"budget {name + ' ' + tool + ' spawns':40} {got:6} ≤ {limit:<6} {status}") + if status != "ok": + failures.append(f"{name}.{tool}") + for note in notes: + print(note) + return failures diff --git a/scripts/check-formal.py b/scripts/check-formal.py index 08dacd4c..020e7c19 100644 --- a/scripts/check-formal.py +++ b/scripts/check-formal.py @@ -30,6 +30,15 @@ ("Http2Leases.tla", "Http2Leases.cfg", None), ("Http2Leases.tla", "Http2LeasesRetainIdle.cfg", "IdleActiveDisjoint"), ("Http2Leases.tla", "Http2LeasesEarlyReuse.cfg", "OnlyEndedIdle"), + ("BootPrewarm.tla", "BootPrewarm.cfg", None), + ("BootPrewarm.tla", "BootPrewarmNoJoin.cfg", "JoinedBeforeUse"), + ("BootPrewarm.tla", "BootPrewarmNoCwdKey.cfg", "NoStaleAdoption"), + ("BootPrewarm.tla", "BootPrewarmNoTeardownJoin.cfg", "NoUseAfterTeardown"), + ("BootPrewarm.tla", "BootPrewarmNoRetryAbort.cfg", "NoRetryAfterAbort"), + ("BootPrewarm.tla", "BootPrewarmEarlyStart.cfg", "ExitClean"), + ("BootPrewarm.tla", "BootPrewarmNoWindowDiscard.cfg", "ExitClean"), + ("BootPrewarm.tla", "BootPrewarmNoStop.cfg", "NoExitStall"), + ("BootPrewarm.tla", "BootPrewarmRetryFailed.cfg", "NoRepeatAfterResult"), ) diff --git a/scripts/eval/tier1-manifest.json b/scripts/eval/tier1-manifest.json index 76588eca..b0d8ed75 100644 --- a/scripts/eval/tier1-manifest.json +++ b/scripts/eval/tier1-manifest.json @@ -14,7 +14,7 @@ "src/main.zig", "src/repl.zig" ], - "test_count_baseline": 3882, + "test_count_baseline": 3927, "test_count_slack": 25, "required_invariants": [ { diff --git a/scripts/startup-budgets.json b/scripts/startup-budgets.json new file mode 100644 index 00000000..83c91830 --- /dev/null +++ b/scripts/startup-budgets.json @@ -0,0 +1,40 @@ +{ + "schema": 1, + "_about": "Gates for scripts/bench-startup.py --budgets. Time gates are median / floor median (floor = compiled C hello), not absolute ms, so a slower or busier machine scales both sides. Ratio maxima are about 2.5x the measured ratio so they hold under load; tighten them after an optimization lands. Spawn gates are exact counts from the PATH-shim pass and do not depend on load. 'target' is the planned value once further startup work lands; only 'max' is enforced.", + "floor": "hello_ms", + "ratio_over_floor": { + "_baseline": "Ratios before the startup work, hermetic, non-git cwd: a_version 1.6, a_help 1.5, b ready 10.3, c request 3.7, c wall 5.0, d response 10.2, d no-key 10.3. After in-process worktree identity and the early ACP initialize: b ready 3.8, b wall 4.2, d response 1.5 (1.4 / 3.0 / 3.4 with every core busy); --git-repo is similar. c and d no-key did not move in this benchmark.", + "a_version.wall_ms": {"max": 4}, + "a_help.wall_ms": {"max": 4}, + "b_repl_ready.ready_ms": {"max": 10}, + "b_repl_ready.wall_ms": {"max": 11}, + "c_first_request.request_ms": {"max": 10}, + "c_first_request.wall_ms": {"max": 13}, + "d_acp_initialize.response_ms": {"max": 5}, + "d_acp_initialize_nokey.response_ms": {"max": 26}, + "_d_acp_session_usable": "spawn to the session/new response written right after initialize: the session is usable. d_acp_initialize is only the handshake answered, which graff can send before the session exists. Ratio about 3.6-4.0 after the startup work (pre-series about 10.5).", + "d_acp_session_usable.response_ms": {"max": 9} + }, + "spawns": { + "default": { + "_tighten": "REPL/ACP boot resolves the worktree identity in-process (git_dirs.zig) and spawns no git. Tighten security on the no-key path once there is a Keychain index.", + "a_version": {"git": 0, "security": 0}, + "a_help": {"git": 0, "security": 0}, + "b_repl_ready": {"git": 0, "security": 0}, + "c_first_request": {"git": 0, "security": 0}, + "d_acp_initialize": {"git": 0, "security": 0}, + "d_acp_initialize_nokey": {"git": 0, "security": {"max": 26, "target": 0}}, + "d_acp_session_usable": {"git": 0, "security": 0} + }, + "git_repo": { + "_tighten": "Same as default: an ordinary one-commit repo is resolved in-process too (GRAFF_AUTO_ISOLATE=off is always set by the benchmark).", + "a_version": {"git": 0, "security": 0}, + "a_help": {"git": 0, "security": 0}, + "b_repl_ready": {"git": 0, "security": 0}, + "c_first_request": {"git": 0, "security": 0}, + "d_acp_initialize": {"git": 0, "security": 0}, + "d_acp_initialize_nokey": {"git": 0, "security": {"max": 26, "target": 0}}, + "d_acp_session_usable": {"git": 0, "security": 0} + } + } +} diff --git a/scripts/test-acp-early-init.py b/scripts/test-acp-early-init.py new file mode 100644 index 00000000..91518ed2 --- /dev/null +++ b/scripts/test-acp-early-init.py @@ -0,0 +1,202 @@ +#!/usr/bin/env python3 +"""`graff acp` answers `initialize` during boot (ADR 0338): the real wiring. + +The unit and conformance tests call `acp_early` directly. This drives the +built binary: `Boot.mark`, the shared stdin reader, the real stdout writer and +the loop-start replay into the discarding sink. A client that writes while the +process is booting must see byte for byte what a client that writes after boot +sees (the time-based session id masked), with `GRAFF_ACP_V2` off and on. + +Cases, each against the same bytes written after boot has finished: + - `initialize` then `session/new`, written at 0 ms and at seeded random + offsets up to 15 ms after spawn; + - `initialize` + `session/new` in one write; + - a first line that is not `initialize`; + - an `initialize` split across writes, completed a few ms later. + +Hermetic: temporary HOME and cwd per run, a loopback mock model on an +ephemeral port, no network. Every run has a timeout; children are killed by +process group. `GRAFF_EARLY_INIT_SEED` reproduces a failing seed. +""" + +import collections +import json +import os +import platform +import random +import re +import signal +import subprocess +import sys +import tempfile +import time +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent / "eval")) +from mock_model import ScriptedModel # noqa: E402 + +RUN_TIMEOUT = 20.0 +LATE_WAIT = 1.0 +LATE_TRIES = 4 # a loaded machine can boot a debug build slower than LATE_WAIT +OFFSETS = 6 +EARLY_STAMP = "[boot] acp initialize answered" + +INIT = json.dumps({"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { + "protocolVersion": 2, "clientInfo": {"name": "early-init-test", "version": "1"}, + "clientCapabilities": {"fs": {"readTextFile": True}, "subagents": {}}}}, separators=(",", ":")).encode() + b"\n" +NOT_INIT = b'{"jsonrpc":"2.0","id":7,"method":"graff/nope","params":{}}\n' + + +def session_new(cwd: str) -> bytes: + return json.dumps({"jsonrpc": "2.0", "id": 2, "method": "session/new", + "params": {"cwd": cwd, "mcpServers": []}}, separators=(",", ":")).encode() + b"\n" + + +def mask(out: bytes, root: str) -> bytes: + out = out.replace(root.encode(), b"") + out = re.sub(rb"session-\d+-\d+", b"session-X", out) + out = re.sub(rb"acp-[0-9a-f]+-", b"acp-X-", out) + return re.sub(rb"msg_([a-z]+)_[0-9a-f]+_", rb"msg_\1_X_", out) + + +class Runner: + def __init__(self, binary: Path, url: str) -> None: + self.binary = binary + self.url = url + self.live: list = [] + + def run(self, chunks, gate: str, wait: float, gap: float = 0.0): + """Spawn, sleep `wait`, write `chunks` (each a callable of cwd) `gap` apart, close stdin.""" + with tempfile.TemporaryDirectory(prefix="graff-acp-early-") as temp: + root = os.path.realpath(temp) + home, cwd, shim = (Path(root) / n for n in ("home", "cwd", "bin")) + for d in (home, cwd, shim): + d.mkdir() + (shim / "security").write_text("#!/bin/sh\nexit 44\n") # keep the macOS Keychain out + (shim / "security").chmod(0o755) + mcp = Path(root) / "mcp.json" + mcp.write_text('{"mcpServers":{}}') + env = { + "PATH": f"{shim}{os.pathsep}{os.environ.get('PATH', '/usr/bin:/bin')}", + "HOME": str(home), "TMPDIR": root, "TERM": "dumb", "NO_COLOR": "1", + "GRAFF_NO_TELEMETRY": "1", "GRAFF_NO_UPDATE_CHECK": "1", "GRAFF_AUTO_ISOLATE": "off", + "GRAFF_FLEET": "off", "GRAFF_NO_ADOPT": "1", "GRAFF_MCP_CONFIG": str(mcp), + "AI_GATEWAY_API_KEY": "local", "GRAFF_VERCEL_URL": self.url, + "GRAFF_ACP_V2": gate, "GRAFF_BOOT_DEBUG": "1", "PYTHONDONTWRITEBYTECODE": "1", + } + proc = subprocess.Popen([str(self.binary), "acp", "--model", "vercel"], cwd=cwd, env=env, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + start_new_session=True) + self.live.append(proc) + try: + if wait: + time.sleep(wait) + for i, chunk in enumerate(chunks): + if i and gap: + time.sleep(gap) + try: + proc.stdin.write(chunk(str(cwd))) + proc.stdin.flush() + except BrokenPipeError: + break + try: + proc.stdin.close() + except BrokenPipeError: + pass + proc.stdin = None # communicate() must not flush the closed pipe + try: + out, err = proc.communicate(timeout=RUN_TIMEOUT) + except subprocess.TimeoutExpired: + self.kill(proc) + out, err = proc.communicate() + raise AssertionError(f"graff acp hung (> {RUN_TIMEOUT}s); stderr tail:\n{err.decode(errors='replace')[-2000:]}") + finally: + self.kill(proc) + self.live.remove(proc) + return mask(out, root), err.decode(errors="replace"), proc.returncode + + @staticmethod + def kill(proc) -> None: + if proc.poll() is None: + try: + os.killpg(proc.pid, signal.SIGKILL) + except ProcessLookupError: + pass + proc.wait() + + def close(self) -> None: + for proc in list(self.live): + self.kill(proc) + + +def check(name: str, got, want) -> None: + out, err, rc = got + ref_out, _, ref_rc = want + if out != ref_out or rc != ref_rc: + raise AssertionError( + f"{name}: early stdout differs from the late path\n" + f"exit {rc} vs late {ref_rc}\nearly: {out!r}\nlate: {ref_out!r}\nstderr tail:\n{err[-2000:]}") + + +def late_run(runner: Runner, chunks, gate: str): + """A reference written after boot: retried with a doubled wait while boot outlasted it.""" + wait = LATE_WAIT + for _ in range(LATE_TRIES): + got = runner.run(chunks, gate, wait) + if EARLY_STAMP not in got[1]: + return got + wait *= 2 + raise AssertionError(f"GRAFF_ACP_V2={gate}: the late reference was answered during boot even after {wait / 2:.0f} s") + + +def main() -> None: + if os.name != "posix": + print("acp early initialize: POSIX only (no poll on Windows stdin; the early path is the late path there)") + return + binary = Path(sys.argv[1] if len(sys.argv) > 1 else "zig-out/bin/graff").resolve() + seed = int(os.environ.get("GRAFF_EARLY_INIT_SEED", "338")) + rng = random.Random(seed) + model = ScriptedModel([]) + port = model.start(0) + runner = Runner(binary, f"http://127.0.0.1:{port}/v1/chat/completions") + init, new = (lambda _cwd: INIT), session_new + cut = 25 + try: + fired = 0 + runs = 0 + where: collections.Counter = collections.Counter() + for gate in ("0", "1"): + late = late_run(runner, [init, new], gate) + lines = late[0].splitlines() + if len(lines) < 2 or not lines[0].startswith(b'{"jsonrpc":"2.0","id":1,"result"') or b'"id":2,"result"' not in lines[1]: + raise AssertionError(f"GRAFF_ACP_V2={gate}: late reference does not answer initialize then session/new: {late[0][:400]!r}") + late_other = late_run(runner, [lambda _c: NOT_INIT, init, new], gate) + cases = [(f"offset 0 ms", [init, new], 0.0, 0.0)] + cases += [(f"offset {o * 1000:.1f} ms", [init, new], o, 0.0) for o in (rng.uniform(0, 0.015) for _ in range(OFFSETS))] + cases += [ + ("initialize + session/new in one write", [lambda c: INIT + session_new(c)], 0.0, 0.0), + ("initialize split across writes", [lambda _c: INIT[:cut], lambda c: INIT[cut:] + session_new(c)], 0.0, 0.005), + ("initialize split, completed after 30 ms", [lambda _c: INIT[:cut], lambda c: INIT[cut:] + session_new(c)], 0.0, 0.030), + ] + for name, chunks, wait, gap in cases: + got = runner.run(chunks, gate, wait, gap) + check(f"GRAFF_ACP_V2={gate} {name}", got, late) + runs += 1 + fired += EARLY_STAMP in got[1] + where[(re.findall(r"answered (.*)", got[1]) or ["in the loop"])[0]] += 1 + got = runner.run([lambda _c: NOT_INIT, init, new], gate, 0.0) + if EARLY_STAMP in got[1]: + raise AssertionError(f"GRAFF_ACP_V2={gate}: a non-initialize first line was answered during boot") + check(f"GRAFF_ACP_V2={gate} non-initialize first line", got, late_other) + if fired == 0: + raise AssertionError(f"no run was answered during boot ({runs} runs); this test did not exercise the early path") + finally: + runner.close() + model.stop() + print(f"acp early initialize: ok ({runs} early runs, {fired} answered during boot, seed {seed}, {platform.system()})") + for label, n in sorted(where.items(), key=lambda kv: -kv[1]): + print(f" {n:3d} {label}") + + +if __name__ == "__main__": + main() diff --git a/spec/conformance.py b/spec/conformance.py index 539d8eab..abf7e3ee 100644 --- a/spec/conformance.py +++ b/spec/conformance.py @@ -68,6 +68,8 @@ from ref.bash_policy import payload as bash_model_payload from ref.structured_output import check_properties as sox_check_properties from ref.structured_output import payload as sox_model_payload +from ref.acp_early_init import check_properties as early_check_properties +from ref.acp_early_init import payload as early_payload ROOT = Path(__file__).resolve().parent KERNELS = ROOT / "kernels" @@ -82,6 +84,7 @@ SOX_FIXTURE = KERNELS / "structured_output.json" CACHE_FIXTURE = KERNELS / "prompt_cache.json" PREFIX_FIXTURE = KERNELS / "prompt_prefix.json" +EARLY_FIXTURE = KERNELS / "acp_early_init.json" LEAN_DIR = ROOT.parent / "lean-proofs" @@ -388,6 +391,7 @@ def check_bash() -> int: return _ref(bash_check_properties, "bash") def check_sox() -> int: return _ref(sox_check_properties, "sox") +def check_early() -> int: return _ref(early_check_properties, "acp_early_init") def prefixes_first(p: str) -> list[str]: @@ -420,6 +424,7 @@ def export() -> list[Path]: _write(CACHE_FIXTURE, cache_payload()), write_cache_md(KERNELS / "prompt_cache.md"), _write(PREFIX_FIXTURE, prefix_payload()), + _write(EARLY_FIXTURE, early_payload()), write_prefix_md(KERNELS / "prompt_prefix.md"), _write(KERNELS / "prompt_stable.json", __import__("ref.prompt_stable", fromlist=["payload"]).payload()), __import__("ref.prompt_stable", fromlist=["write_kernel_md"]).write_kernel_md(KERNELS / "prompt_stable.md"), @@ -445,6 +450,7 @@ def check_fixtures() -> None: _same(SOX_FIXTURE, sox_model_payload(), "structured_output") _same(CACHE_FIXTURE, cache_payload(), "prompt_cache") _same(PREFIX_FIXTURE, prefix_payload(), "prompt_prefix") + _same(EARLY_FIXTURE, early_payload(), "acp_early_init") from ref.prompt_stable import payload as stable_payload, kernel_md as stable_kernel_md _same(KERNELS / "prompt_stable.json", stable_payload(), "prompt_stable") from ref.goal_loop import kernel_md @@ -558,17 +564,18 @@ def main() -> int: n_sc = check_score() n_ba = check_bash() n_sx = check_sox() + n_ae = check_early() if args.export: paths = export() rel = ", ".join(p.relative_to(ROOT.parent).as_posix() for p in paths) - print(f"exported catalog={n_cat} transport={n_tr} provider={n_pr} goal={n_gl} cache={n_ck} prefix={n_px} stable={n_ps} path={n_pc} shape={n_sh} score={n_sc} bash={n_ba} sox={n_sx} → {rel}") + print(f"exported catalog={n_cat} transport={n_tr} provider={n_pr} goal={n_gl} cache={n_ck} prefix={n_px} stable={n_ps} path={n_pc} shape={n_sh} score={n_sc} bash={n_ba} sox={n_sx} acp_early={n_ae} → {rel}") else: check_fixtures() print( f"ok tool_catalog {n_cat} transport {n_tr} (1 ws) " f"provider {n_pr} goal_loop {n_gl} prompt_cache {n_ck} prompt_prefix {n_px} prompt_stable {n_ps} path_confine {n_pc} " f"shape {n_sh} score {n_sc} bash {n_ba} " - f"structured_output {n_sx}" + f"structured_output {n_sx} acp_early_init {n_ae}" ) if args.lean: try_lean() diff --git a/spec/kernels/acp_early_init.json b/spec/kernels/acp_early_init.json new file mode 100644 index 00000000..05557e5e --- /dev/null +++ b/spec/kernels/acp_early_init.json @@ -0,0 +1,9207 @@ +{ + "kernel": "acp_early_init", + "version": 1, + "universe": { + "states": [ + "booting", + "answering", + "answered", + "passed", + "loop" + ], + "lines": [ + "none", + "incomplete", + "initialize", + "other" + ], + "actions": [ + "none", + "answer", + "take", + "replay" + ] + }, + "mutants_rejected": [ + "answer-early-and-again-in-loop", + "replay-emits-response", + "consume-other-first-line", + "early-can-load-false", + "skip-replay", + "take-line-although-answer-failed" + ], + "step": [ + { + "state": "booting", + "event": { + "kind": "boundary", + "acp": false, + "line": "none" + }, + "next": "passed", + "action": "none" + }, + { + "state": "booting", + "event": { + "kind": "boundary", + "acp": false, + "line": "incomplete" + }, + "next": "passed", + "action": "none" + }, + { + "state": "booting", + "event": { + "kind": "boundary", + "acp": false, + "line": "initialize" + }, + "next": "passed", + "action": "none" + }, + { + "state": "booting", + "event": { + "kind": "boundary", + "acp": false, + "line": "other" + }, + "next": "passed", + "action": "none" + }, + { + "state": "booting", + "event": { + "kind": "boundary", + "acp": true, + "line": "none" + }, + "next": "booting", + "action": "none" + }, + { + "state": "booting", + "event": { + "kind": "boundary", + "acp": true, + "line": "incomplete" + }, + "next": "booting", + "action": "none" + }, + { + "state": "booting", + "event": { + "kind": "boundary", + "acp": true, + "line": "initialize" + }, + "next": "answering", + "action": "answer" + }, + { + "state": "booting", + "event": { + "kind": "boundary", + "acp": true, + "line": "other" + }, + "next": "passed", + "action": "none" + }, + { + "state": "booting", + "event": { + "kind": "sent", + "ok": false + }, + "next": "booting", + "action": "none" + }, + { + "state": "booting", + "event": { + "kind": "sent", + "ok": true + }, + "next": "booting", + "action": "none" + }, + { + "state": "booting", + "event": { + "kind": "loop_start" + }, + "next": "loop", + "action": "none" + }, + { + "state": "answering", + "event": { + "kind": "boundary", + "acp": false, + "line": "none" + }, + "next": "answering", + "action": "none" + }, + { + "state": "answering", + "event": { + "kind": "boundary", + "acp": false, + "line": "incomplete" + }, + "next": "answering", + "action": "none" + }, + { + "state": "answering", + "event": { + "kind": "boundary", + "acp": false, + "line": "initialize" + }, + "next": "answering", + "action": "none" + }, + { + "state": "answering", + "event": { + "kind": "boundary", + "acp": false, + "line": "other" + }, + "next": "answering", + "action": "none" + }, + { + "state": "answering", + "event": { + "kind": "boundary", + "acp": true, + "line": "none" + }, + "next": "answering", + "action": "none" + }, + { + "state": "answering", + "event": { + "kind": "boundary", + "acp": true, + "line": "incomplete" + }, + "next": "answering", + "action": "none" + }, + { + "state": "answering", + "event": { + "kind": "boundary", + "acp": true, + "line": "initialize" + }, + "next": "answering", + "action": "none" + }, + { + "state": "answering", + "event": { + "kind": "boundary", + "acp": true, + "line": "other" + }, + "next": "answering", + "action": "none" + }, + { + "state": "answering", + "event": { + "kind": "sent", + "ok": false + }, + "next": "passed", + "action": "none" + }, + { + "state": "answering", + "event": { + "kind": "sent", + "ok": true + }, + "next": "answered", + "action": "take" + }, + { + "state": "answering", + "event": { + "kind": "loop_start" + }, + "next": "loop", + "action": "none" + }, + { + "state": "answered", + "event": { + "kind": "boundary", + "acp": false, + "line": "none" + }, + "next": "answered", + "action": "none" + }, + { + "state": "answered", + "event": { + "kind": "boundary", + "acp": false, + "line": "incomplete" + }, + "next": "answered", + "action": "none" + }, + { + "state": "answered", + "event": { + "kind": "boundary", + "acp": false, + "line": "initialize" + }, + "next": "answered", + "action": "none" + }, + { + "state": "answered", + "event": { + "kind": "boundary", + "acp": false, + "line": "other" + }, + "next": "answered", + "action": "none" + }, + { + "state": "answered", + "event": { + "kind": "boundary", + "acp": true, + "line": "none" + }, + "next": "answered", + "action": "none" + }, + { + "state": "answered", + "event": { + "kind": "boundary", + "acp": true, + "line": "incomplete" + }, + "next": "answered", + "action": "none" + }, + { + "state": "answered", + "event": { + "kind": "boundary", + "acp": true, + "line": "initialize" + }, + "next": "answered", + "action": "none" + }, + { + "state": "answered", + "event": { + "kind": "boundary", + "acp": true, + "line": "other" + }, + "next": "answered", + "action": "none" + }, + { + "state": "answered", + "event": { + "kind": "sent", + "ok": false + }, + "next": "answered", + "action": "none" + }, + { + "state": "answered", + "event": { + "kind": "sent", + "ok": true + }, + "next": "answered", + "action": "none" + }, + { + "state": "answered", + "event": { + "kind": "loop_start" + }, + "next": "loop", + "action": "replay" + }, + { + "state": "passed", + "event": { + "kind": "boundary", + "acp": false, + "line": "none" + }, + "next": "passed", + "action": "none" + }, + { + "state": "passed", + "event": { + "kind": "boundary", + "acp": false, + "line": "incomplete" + }, + "next": "passed", + "action": "none" + }, + { + "state": "passed", + "event": { + "kind": "boundary", + "acp": false, + "line": "initialize" + }, + "next": "passed", + "action": "none" + }, + { + "state": "passed", + "event": { + "kind": "boundary", + "acp": false, + "line": "other" + }, + "next": "passed", + "action": "none" + }, + { + "state": "passed", + "event": { + "kind": "boundary", + "acp": true, + "line": "none" + }, + "next": "passed", + "action": "none" + }, + { + "state": "passed", + "event": { + "kind": "boundary", + "acp": true, + "line": "incomplete" + }, + "next": "passed", + "action": "none" + }, + { + "state": "passed", + "event": { + "kind": "boundary", + "acp": true, + "line": "initialize" + }, + "next": "passed", + "action": "none" + }, + { + "state": "passed", + "event": { + "kind": "boundary", + "acp": true, + "line": "other" + }, + "next": "passed", + "action": "none" + }, + { + "state": "passed", + "event": { + "kind": "sent", + "ok": false + }, + "next": "passed", + "action": "none" + }, + { + "state": "passed", + "event": { + "kind": "sent", + "ok": true + }, + "next": "passed", + "action": "none" + }, + { + "state": "passed", + "event": { + "kind": "loop_start" + }, + "next": "loop", + "action": "none" + }, + { + "state": "loop", + "event": { + "kind": "boundary", + "acp": false, + "line": "none" + }, + "next": "loop", + "action": "none" + }, + { + "state": "loop", + "event": { + "kind": "boundary", + "acp": false, + "line": "incomplete" + }, + "next": "loop", + "action": "none" + }, + { + "state": "loop", + "event": { + "kind": "boundary", + "acp": false, + "line": "initialize" + }, + "next": "loop", + "action": "none" + }, + { + "state": "loop", + "event": { + "kind": "boundary", + "acp": false, + "line": "other" + }, + "next": "loop", + "action": "none" + }, + { + "state": "loop", + "event": { + "kind": "boundary", + "acp": true, + "line": "none" + }, + "next": "loop", + "action": "none" + }, + { + "state": "loop", + "event": { + "kind": "boundary", + "acp": true, + "line": "incomplete" + }, + "next": "loop", + "action": "none" + }, + { + "state": "loop", + "event": { + "kind": "boundary", + "acp": true, + "line": "initialize" + }, + "next": "loop", + "action": "none" + }, + { + "state": "loop", + "event": { + "kind": "boundary", + "acp": true, + "line": "other" + }, + "next": "loop", + "action": "none" + }, + { + "state": "loop", + "event": { + "kind": "sent", + "ok": false + }, + "next": "loop", + "action": "none" + }, + { + "state": "loop", + "event": { + "kind": "sent", + "ok": true + }, + "next": "loop", + "action": "none" + }, + { + "state": "loop", + "event": { + "kind": "loop_start" + }, + "next": "loop", + "action": "none" + } + ], + "cases": [ + { + "pv": "missing", + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pvmissing.g0.subabsent.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pvmissing.g0.subabsent.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pvmissing.g0.subabsent.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pvmissing.g0.subabsent.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pvmissing.g0.subabsent.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":4,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pvmissing.g0.subabsent.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":5,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pvmissing.g0.subabsent.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":6,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pvmissing.g0.subabsent.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":7,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pvmissing.g0.subabsent.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":8,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pvmissing.g0.subabsent.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":9,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pvmissing.g0.subabsent.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":10,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pvmissing.g0.subabsent.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":11,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pvmissing.g0.subobject.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":12,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pvmissing.g0.subobject.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":13,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pvmissing.g0.subobject.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":14,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pvmissing.g0.subobject.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":15,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pvmissing.g0.subobject.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":16,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": "missing", + "gate": false, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pvmissing.g0.subobject.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":17,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": "missing", + "gate": false, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pvmissing.g0.subobject.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":18,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": "missing", + "gate": false, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pvmissing.g0.subobject.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":19,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": "missing", + "gate": false, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pvmissing.g0.subobject.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":20,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pvmissing.g0.subobject.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":21,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pvmissing.g0.subobject.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":22,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pvmissing.g0.subobject.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":23,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pvmissing.g0.subnull.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":24,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pvmissing.g0.subnull.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":25,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pvmissing.g0.subnull.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":26,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pvmissing.g0.subnull.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":27,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pvmissing.g0.subnull.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":28,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": false, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pvmissing.g0.subnull.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":29,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": false, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pvmissing.g0.subnull.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":30,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": false, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pvmissing.g0.subnull.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":31,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": false, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pvmissing.g0.subnull.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":32,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pvmissing.g0.subnull.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":33,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pvmissing.g0.subnull.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":34,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": false, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pvmissing.g0.subnull.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":35,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pvmissing.g1.subabsent.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":36,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pvmissing.g1.subabsent.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":37,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pvmissing.g1.subabsent.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":38,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pvmissing.g1.subabsent.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":39,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pvmissing.g1.subabsent.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":40,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pvmissing.g1.subabsent.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":41,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pvmissing.g1.subabsent.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":42,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pvmissing.g1.subabsent.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":43,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pvmissing.g1.subabsent.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":44,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pvmissing.g1.subabsent.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":45,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pvmissing.g1.subabsent.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":46,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pvmissing.g1.subabsent.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":47,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pvmissing.g1.subobject.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":48,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pvmissing.g1.subobject.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":49,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pvmissing.g1.subobject.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":50,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pvmissing.g1.subobject.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":51,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pvmissing.g1.subobject.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":52,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": "missing", + "gate": true, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pvmissing.g1.subobject.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":53,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": "missing", + "gate": true, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pvmissing.g1.subobject.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":54,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": "missing", + "gate": true, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pvmissing.g1.subobject.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":55,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": "missing", + "gate": true, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pvmissing.g1.subobject.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":56,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pvmissing.g1.subobject.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":57,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pvmissing.g1.subobject.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":58,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pvmissing.g1.subobject.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":59,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pvmissing.g1.subnull.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":60,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pvmissing.g1.subnull.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":61,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pvmissing.g1.subnull.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":62,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pvmissing.g1.subnull.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":63,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pvmissing.g1.subnull.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":64,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": true, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pvmissing.g1.subnull.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":65,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": true, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pvmissing.g1.subnull.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":66,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": true, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pvmissing.g1.subnull.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":67,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": "missing", + "gate": true, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pvmissing.g1.subnull.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":68,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pvmissing.g1.subnull.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":69,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pvmissing.g1.subnull.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":70,\"method\":\"initialize\",\"params\":{\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": "missing", + "gate": true, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pvmissing.g1.subnull.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":71,\"method\":\"initialize\",\"params\":{\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv0.g0.subabsent.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":72,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv0.g0.subabsent.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":73,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv0.g0.subabsent.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":74,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv0.g0.subabsent.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":75,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv0.g0.subabsent.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":76,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv0.g0.subabsent.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":77,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv0.g0.subabsent.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":78,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv0.g0.subabsent.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":79,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv0.g0.subabsent.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":80,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv0.g0.subabsent.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":81,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv0.g0.subabsent.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":82,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv0.g0.subabsent.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":83,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv0.g0.subobject.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":84,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv0.g0.subobject.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":85,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv0.g0.subobject.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":86,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv0.g0.subobject.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":87,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv0.g0.subobject.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":88,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": 0, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv0.g0.subobject.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":89,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": 0, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv0.g0.subobject.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":90,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": 0, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv0.g0.subobject.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":91,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": 0, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv0.g0.subobject.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":92,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv0.g0.subobject.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":93,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv0.g0.subobject.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":94,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv0.g0.subobject.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":95,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv0.g0.subnull.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":96,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv0.g0.subnull.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":97,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv0.g0.subnull.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":98,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv0.g0.subnull.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":99,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv0.g0.subnull.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":100,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv0.g0.subnull.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":101,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv0.g0.subnull.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":102,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv0.g0.subnull.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":103,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv0.g0.subnull.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":104,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv0.g0.subnull.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":105,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv0.g0.subnull.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":106,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv0.g0.subnull.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":107,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv0.g1.subabsent.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":108,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv0.g1.subabsent.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":109,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv0.g1.subabsent.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":110,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv0.g1.subabsent.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":111,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv0.g1.subabsent.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":112,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv0.g1.subabsent.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":113,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv0.g1.subabsent.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":114,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv0.g1.subabsent.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":115,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv0.g1.subabsent.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":116,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv0.g1.subabsent.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":117,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv0.g1.subabsent.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":118,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv0.g1.subabsent.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":119,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv0.g1.subobject.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":120,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv0.g1.subobject.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":121,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv0.g1.subobject.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":122,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv0.g1.subobject.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":123,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv0.g1.subobject.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":124,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": 0, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv0.g1.subobject.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":125,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": 0, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv0.g1.subobject.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":126,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": 0, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv0.g1.subobject.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":127,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": 0, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv0.g1.subobject.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":128,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv0.g1.subobject.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":129,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv0.g1.subobject.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":130,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv0.g1.subobject.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":131,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv0.g1.subnull.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":132,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv0.g1.subnull.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":133,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv0.g1.subnull.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":134,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv0.g1.subnull.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":135,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv0.g1.subnull.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":136,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv0.g1.subnull.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":137,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv0.g1.subnull.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":138,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv0.g1.subnull.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":139,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 0, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv0.g1.subnull.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":140,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv0.g1.subnull.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":141,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv0.g1.subnull.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":142,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 0, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv0.g1.subnull.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":143,\"method\":\"initialize\",\"params\":{\"protocolVersion\":0,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv1.g0.subabsent.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":144,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv1.g0.subabsent.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":145,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv1.g0.subabsent.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":146,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv1.g0.subabsent.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":147,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv1.g0.subabsent.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":148,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv1.g0.subabsent.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":149,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv1.g0.subabsent.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":150,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv1.g0.subabsent.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":151,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv1.g0.subabsent.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":152,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv1.g0.subabsent.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":153,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv1.g0.subabsent.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":154,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv1.g0.subabsent.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":155,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv1.g0.subobject.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":156,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv1.g0.subobject.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":157,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv1.g0.subobject.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":158,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv1.g0.subobject.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":159,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv1.g0.subobject.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":160,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": 1, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv1.g0.subobject.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":161,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": 1, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv1.g0.subobject.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":162,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": 1, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv1.g0.subobject.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":163,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": 1, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv1.g0.subobject.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":164,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv1.g0.subobject.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":165,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv1.g0.subobject.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":166,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv1.g0.subobject.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":167,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv1.g0.subnull.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":168,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv1.g0.subnull.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":169,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv1.g0.subnull.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":170,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv1.g0.subnull.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":171,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv1.g0.subnull.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":172,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv1.g0.subnull.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":173,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv1.g0.subnull.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":174,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv1.g0.subnull.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":175,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv1.g0.subnull.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":176,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv1.g0.subnull.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":177,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv1.g0.subnull.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":178,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv1.g0.subnull.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":179,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv1.g1.subabsent.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":180,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv1.g1.subabsent.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":181,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv1.g1.subabsent.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":182,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv1.g1.subabsent.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":183,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv1.g1.subabsent.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":184,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv1.g1.subabsent.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":185,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv1.g1.subabsent.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":186,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv1.g1.subabsent.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":187,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv1.g1.subabsent.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":188,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv1.g1.subabsent.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":189,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv1.g1.subabsent.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":190,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv1.g1.subabsent.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":191,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv1.g1.subobject.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":192,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv1.g1.subobject.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":193,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv1.g1.subobject.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":194,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv1.g1.subobject.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":195,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv1.g1.subobject.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":196,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": 1, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv1.g1.subobject.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":197,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": 1, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv1.g1.subobject.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":198,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": 1, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv1.g1.subobject.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":199,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": 1, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv1.g1.subobject.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":200,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv1.g1.subobject.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":201,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv1.g1.subobject.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":202,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv1.g1.subobject.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":203,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv1.g1.subnull.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":204,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv1.g1.subnull.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":205,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv1.g1.subnull.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":206,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv1.g1.subnull.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":207,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv1.g1.subnull.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":208,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv1.g1.subnull.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":209,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv1.g1.subnull.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":210,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv1.g1.subnull.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":211,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 1, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv1.g1.subnull.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":212,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv1.g1.subnull.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":213,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv1.g1.subnull.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":214,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 1, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv1.g1.subnull.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":215,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv2.g0.subabsent.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":216,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv2.g0.subabsent.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":217,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv2.g0.subabsent.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":218,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv2.g0.subabsent.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":219,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv2.g0.subabsent.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":220,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv2.g0.subabsent.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":221,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv2.g0.subabsent.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":222,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv2.g0.subabsent.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":223,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv2.g0.subabsent.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":224,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv2.g0.subabsent.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":225,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv2.g0.subabsent.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":226,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv2.g0.subabsent.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":227,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv2.g0.subobject.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":228,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv2.g0.subobject.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":229,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv2.g0.subobject.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":230,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv2.g0.subobject.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":231,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv2.g0.subobject.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":232,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": 2, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv2.g0.subobject.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":233,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": 2, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv2.g0.subobject.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":234,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": 2, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv2.g0.subobject.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":235,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": 2, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv2.g0.subobject.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":236,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv2.g0.subobject.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":237,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv2.g0.subobject.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":238,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv2.g0.subobject.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":239,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv2.g0.subnull.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":240,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv2.g0.subnull.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":241,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv2.g0.subnull.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":242,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv2.g0.subnull.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":243,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv2.g0.subnull.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":244,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv2.g0.subnull.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":245,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv2.g0.subnull.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":246,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv2.g0.subnull.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":247,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv2.g0.subnull.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":248,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv2.g0.subnull.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":249,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv2.g0.subnull.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":250,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv2.g0.subnull.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":251,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv2.g1.subabsent.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":252,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv2.g1.subabsent.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":253,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv2.g1.subabsent.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":254,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv2.g1.subabsent.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":255,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv2.g1.subabsent.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":256,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv2.g1.subabsent.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":257,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv2.g1.subabsent.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":258,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv2.g1.subabsent.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":259,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv2.g1.subabsent.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":260,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv2.g1.subabsent.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":261,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv2.g1.subabsent.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":262,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv2.g1.subabsent.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":263,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv2.g1.subobject.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":264,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv2.g1.subobject.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":265,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv2.g1.subobject.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":266,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv2.g1.subobject.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":267,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv2.g1.subobject.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":268,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv2.g1.subobject.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":269,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv2.g1.subobject.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":270,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv2.g1.subobject.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":271,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv2.g1.subobject.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":272,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv2.g1.subobject.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":273,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv2.g1.subobject.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":274,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv2.g1.subobject.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":275,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv2.g1.subnull.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":276,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv2.g1.subnull.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":277,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv2.g1.subnull.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":278,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv2.g1.subnull.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":279,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv2.g1.subnull.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":280,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv2.g1.subnull.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":281,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv2.g1.subnull.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":282,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv2.g1.subnull.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":283,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 2, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv2.g1.subnull.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":284,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv2.g1.subnull.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":285,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv2.g1.subnull.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":286,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 2, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv2.g1.subnull.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":287,\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv9.g0.subabsent.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":288,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv9.g0.subabsent.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":289,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv9.g0.subabsent.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":290,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv9.g0.subabsent.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":291,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv9.g0.subabsent.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":292,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv9.g0.subabsent.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":293,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv9.g0.subabsent.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":294,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": false, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv9.g0.subabsent.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":295,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv9.g0.subabsent.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":296,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv9.g0.subabsent.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":297,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv9.g0.subabsent.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":298,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv9.g0.subabsent.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":299,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv9.g0.subobject.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":300,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv9.g0.subobject.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":301,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv9.g0.subobject.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":302,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv9.g0.subobject.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":303,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv9.g0.subobject.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":304,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": 9, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv9.g0.subobject.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":305,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": 9, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv9.g0.subobject.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":306,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": true + } + }, + { + "pv": 9, + "gate": false, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv9.g0.subobject.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":307,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": true + } + }, + { + "pv": 9, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv9.g0.subobject.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":308,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv9.g0.subobject.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":309,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv9.g0.subobject.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":310,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": true, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv9.g0.subobject.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":311,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": true, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv9.g0.subnull.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":312,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv9.g0.subnull.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":313,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv9.g0.subnull.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":314,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv9.g0.subnull.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":315,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv9.g0.subnull.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":316,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv9.g0.subnull.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":317,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv9.g0.subnull.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":318,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": false, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv9.g0.subnull.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":319,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv9.g0.subnull.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":320,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv9.g0.subnull.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":321,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv9.g0.subnull.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":322,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": false, + "elicit": false, + "compaction": false, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": false, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv9.g0.subnull.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":323,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 1, + "v2_shape": false, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": false, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv9.g1.subabsent.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":324,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv9.g1.subabsent.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":325,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv9.g1.subabsent.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":326,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "absent", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv9.g1.subabsent.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":327,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv9.g1.subabsent.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":328,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv9.g1.subabsent.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":329,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv9.g1.subabsent.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":330,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": true, + "sub": "absent", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv9.g1.subabsent.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":331,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv9.g1.subabsent.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":332,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv9.g1.subabsent.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":333,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv9.g1.subabsent.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":334,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "absent", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv9.g1.subabsent.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":335,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv9.g1.subobject.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":336,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv9.g1.subobject.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":337,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv9.g1.subobject.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":338,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":{}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "object", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv9.g1.subobject.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":339,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv9.g1.subobject.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":340,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv9.g1.subobject.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":341,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv9.g1.subobject.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":342,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": true, + "sub": "object", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv9.g1.subobject.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":343,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv9.g1.subobject.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":344,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv9.g1.subobject.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":345,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv9.g1.subobject.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":346,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "object", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv9.g1.subobject.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":347,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": false, + "id": "pv9.g1.subnull.bgabsent.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":348,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": false, + "extras": true, + "id": "pv9.g1.subnull.bgabsent.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":349,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": false, + "id": "pv9.g1.subnull.bgabsent.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":350,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":null}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "null", + "bg": "absent", + "can_load": true, + "extras": true, + "id": "pv9.g1.subnull.bgabsent.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":351,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": false, + "id": "pv9.g1.subnull.bgtrue.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":352,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": false, + "extras": true, + "id": "pv9.g1.subnull.bgtrue.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":353,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": false, + "id": "pv9.g1.subnull.bgtrue.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":354,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": true, + "sub": "null", + "bg": "true", + "can_load": true, + "extras": true, + "id": "pv9.g1.subnull.bgtrue.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":355,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": true + } + }, + { + "pv": 9, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": false, + "id": "pv9.g1.subnull.bgfalse.cl0.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":356,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": false, + "extras": true, + "id": "pv9.g1.subnull.bgfalse.cl0.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":357,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": false, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": false, + "id": "pv9.g1.subnull.bgfalse.cl1.x0", + "request": "{\"jsonrpc\":\"2.0\",\"id\":358,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": false + }, + "latches": { + "v2": true, + "t3": false, + "elicit": false, + "compaction": true, + "subagents": false, + "bg": false + } + }, + { + "pv": 9, + "gate": true, + "sub": "null", + "bg": "false", + "can_load": true, + "extras": true, + "id": "pv9.g1.subnull.bgfalse.cl1.x1", + "request": "{\"jsonrpc\":\"2.0\",\"id\":359,\"method\":\"initialize\",\"params\":{\"protocolVersion\":9,\"clientInfo\":{\"name\":\"t3-code\",\"version\":\"1\"},\"capabilities\":{\"auth\":{\"terminal\":{}}},\"clientCapabilities\":{\"fs\":{},\"subagents\":null,\"_meta\":{\"graff/backgroundSubagents\":false},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "response": { + "protocol_version": 2, + "v2_shape": true, + "can_load": true, + "auth_terminal": true + }, + "latches": { + "v2": true, + "t3": true, + "elicit": true, + "compaction": true, + "subagents": false, + "bg": false + } + } + ] +} diff --git a/spec/manifest.json b/spec/manifest.json index b1cfd36e..b630fe69 100644 --- a/spec/manifest.json +++ b/spec/manifest.json @@ -120,6 +120,19 @@ "impl": "src/goal_state.zig:steeringGate+src/prompts.zig:pinStandingGoal+src/skill_docs.zig:execSkill", "cells_floor": 20, "cells_key": "cases" + }, + { + "id": "acp_early_init", + "lean": "lean-proofs/Graff/AcpEarlyInit.lean", + "ref": "spec/ref/acp_early_init.py", + "fixture": "spec/kernels/acp_early_init.json", + "zig": "src/spec_acp_early_init_conformance.zig", + "impl": "src/acp_early.zig:step", + "cells_floor": 415, + "cells_key": [ + "step", + "cases" + ] } ] } diff --git a/spec/ref/acp_early_init.py b/spec/ref/acp_early_init.py new file mode 100644 index 00000000..721c19fc --- /dev/null +++ b/spec/ref/acp_early_init.py @@ -0,0 +1,340 @@ +"""Executable port of lean-proofs/Graff/AcpEarlyInit.lean. + +`graff acp` answers `initialize` at a boot phase boundary. (a) `step` is the +decision `src/acp_early.zig` consults; the system around it (shared stdin, +protocol stdout, dispatch log) is checked over every boot trace up to a bound, +including boundaries whose early answer fails to reach the client. (b) The +response cube: the model's early answer + loop-start replay leave the same +response and latches as the late path in every cell (the Zig conformance test +checks the real engine's bytes on the same cells). + +`MUTANTS` are broken designs `check_properties` must reject. +""" + +from __future__ import annotations + +import json +from itertools import product + +STATES = ("booting", "answering", "answered", "passed", "loop") +LINES = ("none", "incomplete", "initialize", "other") +ACTIONS = ("none", "answer", "take", "replay") +EVENTS: tuple[tuple, ...] = ( + tuple(("boundary", acp, line) for acp in (False, True) for line in LINES) + + (("sent", False), ("sent", True), ("loop_start",)) +) + +MUTANTS = ( + "answer-early-and-again-in-loop", + "replay-emits-response", + "consume-other-first-line", + "early-can-load-false", + "skip-replay", + "take-line-although-answer-failed", +) + + +def step(s: str, e: tuple, mutant: str | None = None) -> tuple[str, str]: + if e[0] == "boundary": + _, acp, line = e + if s != "booting": + return s, "none" + if not acp: + return "passed", "none" + if line in ("none", "incomplete"): + return "booting", "none" + if line == "initialize": + return "answering", "answer" + if mutant == "consume-other-first-line": + return "answering", "answer" + return "passed", "none" + if e[0] == "sent": + if s != "answering": + return s, "none" + if e[1] or mutant == "take-line-although-answer-failed": + return "answered", "take" + return "passed", "none" + if e[0] == "loop_start": + if s == "answered" and mutant != "skip-replay": + return "loop", "replay" + return "loop", "none" + raise ValueError(f"unknown event {e!r}") + + +# ── (a) the protocol: Sys over a boot trace ─────────────────────────────── + + +def classify(sys: dict) -> str: + if not sys["avail"]: + return "incomplete" + if not sys["input"]: + return "none" + return "initialize" if sys["input"][0][0] == "init" else "other" + + +def answer_of(m: tuple) -> tuple: + return ("resp", m[1]) + + +def start(inp: list) -> dict: + return {"st": "booting", "avail": False, "input": list(inp), "stash": None, "out": [], "disp": []} + + +def boot_step(acp: bool, s: dict, ev: str, mutant: str | None) -> dict: + """`ev`: "arrive", "boundary" (an answer it attempts reaches the client) or + "fail" (a boundary whose answer attempt fails and writes nothing).""" + s = dict(s, input=list(s["input"]), out=list(s["out"]), disp=list(s["disp"])) + if ev == "arrive": + s["avail"] = True + return s + st, act = step(s["st"], ("boundary", acp, classify(s)), mutant) + s["st"] = st + if act != "answer": + return s + ok = ev == "boundary" + st, act = step(st, ("sent", ok), mutant) + s["st"] = st + if act == "take" and s["input"]: + m = s["input"].pop(0) + s["stash"] = m + if ok: + s["out"].append(answer_of(m)) + return s + + +def loop_start(s: dict, mutant: str | None) -> dict: + s = dict(s, input=list(s["input"]), out=list(s["out"]), disp=list(s["disp"])) + st, act = step(s["st"], ("loop_start",), mutant) + s["st"] = st + if act == "replay" and s["stash"] is not None: + m = s["stash"] + s["stash"] = None + if mutant == "answer-early-and-again-in-loop": + s["input"].insert(0, m) # handed back to the queue: the loop answers it again + else: + s["disp"].append(m) + if mutant == "replay-emits-response": + s["out"].append(answer_of(m)) + return s + + +def drain(s: dict) -> dict: + s = dict(s, out=list(s["out"]), disp=list(s["disp"])) + for m in s["input"]: + s["disp"].append(m) + s["out"].append(answer_of(m)) + s["input"] = [] + return s + + +def run_early(acp: bool, inp: list, trace: tuple, mutant: str | None = None) -> tuple[dict, dict, dict]: + s = start(inp) + for ev in trace: + s = boot_step(acp, s, ev, mutant) + booted = s + started = loop_start(s, mutant) + return booted, started, drain(started) + + +def run_late(inp: list) -> dict: + return drain(loop_start(start(inp), None)) + + +def inputs(max_len: int = 3) -> list[list]: + out = [] + for n in range(max_len + 1): + for kinds in product(("init", "other"), repeat=n): + out.append([(k, i) for i, k in enumerate(kinds)]) + return out + + +def traces(max_len: int = 5) -> list[tuple]: + out = [] + for n in range(max_len + 1): + out.extend(product(("arrive", "boundary", "fail"), repeat=n)) + return out + + +def check_protocol(mutant: str | None = None) -> int: + n = 0 + for acp, inp, tr in product((False, True), inputs(), traces()): + n += 1 + booted, started, early = run_early(acp, inp, tr, mutant) + late = run_late(inp) + where = f"acp={acp} input={inp} trace={tr}" + if early["out"] != late["out"]: + raise ValueError(f"early_out_eq_late: {where}: {early['out']} != {late['out']}") + if early["disp"] != late["disp"]: + raise ValueError(f"early_disp_eq_late: {where}: {early['disp']} != {late['disp']}") + if started["out"] != booted["out"]: + raise ValueError(f"replay_silent: {where}") + if len(booted["out"]) > 1 or booted["disp"]: + raise ValueError(f"boot_writes_at_most_one: {where}") + if inp and inp[0][0] == "init" and early["out"].count(("resp", 0)) != 1: + raise ValueError(f"initialize_answered_once: {where}") + if inp and inp[0][0] == "other" and (booted["input"] != inp or booted["out"]): + raise ValueError(f"other_first_untouched: {where}") + s = start(inp) + for ev in tr: + failed = boot_step(acp, s, "fail", mutant) + if (failed["input"], failed["stash"], failed["out"]) != (s["input"], s["stash"], s["out"]): + raise ValueError(f"failed_answer_not_consumed: {where} at {ev}") + s = boot_step(acp, s, ev, mutant) + return n + + +def check_step_table(mutant: str | None = None) -> int: + n = 0 + for s, e in product(STATES, EVENTS): + n += 1 + nxt, act = step(s, e, mutant) + if (act == "answer") != (s == "booting" and e == ("boundary", True, "initialize")): + raise ValueError(f"step_answer_iff: {s} {e}") + if (act == "take") != (s == "answering" and e == ("sent", True)): + raise ValueError(f"step_take_iff: {s} {e}") + if s == "answering" and e == ("sent", False) and (nxt, act) != ("passed", "none"): + raise ValueError(f"step_failed_passes: {s} {e}") + if (act == "replay") != (s == "answered" and e == ("loop_start",)): + raise ValueError(f"step_replay_iff: {s} {e}") + if e == ("loop_start",) and nxt != "loop": + raise ValueError(f"loop_start_reaches_loop: {s}") + if s == "loop" and (nxt, act) != ("loop", "none"): + raise ValueError(f"loop_absorbing: {e}") + return n + + +def step_rows() -> list[dict]: + rows = [] + for s, e in product(STATES, EVENTS): + nxt, act = step(s, e) + if e[0] == "loop_start": + ev = {"kind": "loop_start"} + elif e[0] == "sent": + ev = {"kind": "sent", "ok": e[1]} + else: + ev = {"kind": "boundary", "acp": e[1], "line": e[2]} + rows.append({"state": s, "event": ev, "next": nxt, "action": act}) + return rows + + +# ── (b) the response cube ────────────────────────────────────────────────── + +PVS = ("missing", 0, 1, 2, 9) +SUBS = ("absent", "object", "null") +BGS = ("absent", "true", "false") +SEEDS = (0, 1, 0x5EED) +BOOT_LATCH = {"v2": False, "seed": 0, "t3": False, "elicit": False, "compaction": False, "subagents": False, "bg": False} + + +def is_v2(c: dict) -> bool: + return c["gate"] and c["pv"] != "missing" and c["pv"] >= 2 + + +def resp(c: dict, can_load: bool) -> dict: + v2 = is_v2(c) + return {"protocol_version": 2 if v2 else 1, "v2_shape": v2, "can_load": can_load, "auth_terminal": (not v2) or c["extras"]} + + +def latch(prev: dict, c: dict, seed: int) -> dict: + v2 = is_v2(c) + return { + "v2": v2, + "seed": seed if v2 else prev["seed"], + "t3": c["extras"], + "elicit": c["extras"], + "compaction": c["extras"] or v2, + "subagents": (not v2) and c["sub"] == "object", + "bg": c["bg"] == "true", + } + + +def late(c: dict, seed: int) -> tuple[dict, dict]: + return latch(BOOT_LATCH, c, seed), resp(c, c["can_load"]) + + +def early(c: dict, seed: int, mutant: str | None = None) -> tuple[dict, dict]: + scratch = latch(BOOT_LATCH, c, 0) + can_load = False if mutant == "early-can-load-false" else c["can_load"] + out = resp(c, can_load) + if mutant == "skip-replay": + # The scratch dispatch's fields are dropped; the live one stays fresh. + return dict(scratch, subagents=False, bg=False), out + return latch(scratch, c, seed), out + + +def request(c: dict, idx: int) -> str: + caps: dict = {"fs": {}} + if c["sub"] == "object": + caps["subagents"] = {} + elif c["sub"] == "null": + caps["subagents"] = None + if c["bg"] != "absent": + caps["_meta"] = {"graff/backgroundSubagents": c["bg"] == "true"} + params: dict = {} + if c["pv"] != "missing": + params["protocolVersion"] = c["pv"] + if c["extras"]: + params["clientInfo"] = {"name": "t3-code", "version": "1"} + caps["elicitation"] = {"form": {}} + caps["session"] = {"compaction": True} + params["capabilities"] = {"auth": {"terminal": {}}} + params["clientCapabilities"] = caps + return json.dumps({"jsonrpc": "2.0", "id": idx, "method": "initialize", "params": params}, separators=(",", ":")) + + +def cells() -> list[dict]: + rows = [] + for pv, gate, sub, bg, can_load, extras in product(PVS, (False, True), SUBS, BGS, (False, True), (False, True)): + c = {"pv": pv, "gate": gate, "sub": sub, "bg": bg, "can_load": can_load, "extras": extras} + lat, out = late(c, SEEDS[-1]) + rows.append(dict( + c, + id=f"pv{pv}.g{int(gate)}.sub{sub}.bg{bg}.cl{int(can_load)}.x{int(extras)}", + request=request(c, len(rows)), + response=out, + latches={k: v for k, v in lat.items() if k != "seed"}, + )) + return rows + + +def check_cube(mutant: str | None = None) -> int: + n = 0 + for c in cells(): + n += 1 + for seed in SEEDS: + if early(c, seed, mutant) != late(c, seed): + raise ValueError(f"cube_early_eq_late: {c['id']} seed={seed}") + lat = late(c, 7)[0] + if lat["v2"] and lat["subagents"]: + raise ValueError(f"cube_v2_no_subagents: {c['id']}") + v2_cells = sum(1 for c in cells() if is_v2(c)) + if v2_cells != 72: + raise ValueError(f"cube_v2_cells: {v2_cells}") + return n + + +def _check(mutant: str | None) -> int: + return check_step_table(mutant) + check_protocol(mutant) + check_cube(mutant) + + +def check_properties() -> int: + """Cells checked (step table + cube); every mutant must be rejected.""" + _check(None) + for m in MUTANTS: + try: + _check(m) + except ValueError: + continue + raise ValueError(f"mutant survived: {m}") + return len(STATES) * len(EVENTS) + len(cells()) + + +def payload() -> dict: + return { + "kernel": "acp_early_init", + "version": 1, + "universe": {"states": list(STATES), "lines": list(LINES), "actions": list(ACTIONS)}, + "mutants_rejected": list(MUTANTS), + "step": step_rows(), + "cases": cells(), + } diff --git a/src/acp.zig b/src/acp.zig index 7edae59c..73aa89cd 100644 --- a/src/acp.zig +++ b/src/acp.zig @@ -257,17 +257,22 @@ pub fn runAcpCommand(gpa: Allocator, io: Io, environ_map: anytype, root: *agent_ var line_arena_state = std.heap.ArenaAllocator.init(gpa); defer line_arena_state.deinit(); var handshake: @import("acp_handshake_log.zig").Log = .{ .process_started = @import("startup_timing.zig").g_started }; + var replay_buf: [256]u8 = undefined; + var replay_sink: Io.Writer.Discarding = .init(&replay_buf); while (true) { defer @import("agent_request_scratch.zig").reset(&line_arena_state); const line_arena = line_arena_state.allocator(); - const event = (inbox.wait(line_arena) catch break) orelse break; + // An `initialize` answered during boot runs through the same handler + // first, its response discarded, so `d` and the latches match (acp_early.zig). + const replay = @import("acp_early.zig").loopStart(); + const event: @import("acp_inbox.zig").Inbox.Event = if (replay) |line| .{ .line = line } else (inbox.wait(line_arena) catch break) orelse break; switch (event) { .tick => @import("acp_idle.zig").maybeWake(&d, line_arena, wire, io, root.session_name) catch |err| { std.debug.print("acp: idle wake failed: {t}\n", .{err}); }, .line => |line| { const phase = handshake.before(io, line); // #1837 - handleLine(&d, line_arena, wire, line) catch |err| { + handleLine(&d, line_arena, if (replay != null) &replay_sink.writer else wire, line) catch |err| { std.debug.print("acp: dispatch failed: {t}\n", .{err}); break; }; diff --git a/src/acp_early.zig b/src/acp_early.zig new file mode 100644 index 00000000..a937ba44 --- /dev/null +++ b/src/acp_early.zig @@ -0,0 +1,239 @@ +//! `graff acp` answers the client's `initialize` during boot instead of after +//! the root Agent exists (ADR 0338). Single-threaded: at +//! each boot phase boundary the main thread asks stdin, without blocking, +//! whether a complete first line is buffered. If it is an `initialize` +//! request, the line is taken off the ONE stdin reader the dispatch loop later +//! reads, answered through the engine's own `handleLine`, and kept. At loop +//! start that line is dispatched again through the normal handler with its +//! output discarded, so the live `Dispatch` and the process latches are rebuilt +//! by the code that builds them on the late path. +//! +//! `step` is the decision the Lean kernel `Graff.AcpEarlyInit` models; nothing +//! here decides without it. A first line that is incomplete, not `initialize`, +//! or larger than the stdin buffer is left in place for the loop. So is an +//! `initialize` whose answer could not be rendered, written and flushed whole: +//! the line is taken off stdin only after the client has the full answer. +//! +//! A build without ACP (`-Dacp=false`, `-Dminimal`) compiles none of the +//! engine: `boundary` declines at comptime before anything reaches it. +const std = @import("std"); +const builtin = @import("builtin"); +const build_options = @import("build_options"); +const Io = std.Io; +const Allocator = std.mem.Allocator; +const engine = @import("acp_engine.zig"); +const proto = @import("acp_protocol.zig"); +const startup_timing = @import("startup_timing.zig"); + +// ── the kernel: lean-proofs/Graff/AcpEarlyInit.lean `step` ───────────────── + +/// `answering`: the answer is being written; the line is still on stdin. +pub const State = enum { booting, answering, answered, passed, loop }; +/// What the shared stdin buffer holds at a check. `none`/`incomplete`: no +/// complete first line yet; `initialize`: a complete `initialize` request +/// with an id; `other`: any other complete first line. +pub const Line = enum { none, incomplete, initialize, other }; +/// `acp` is ACP mode with a clean protocol stdout; false declines for good. +/// `sent`: whether the whole framed answer reached the transport. +pub const Event = union(enum) { boundary: struct { acp: bool, line: Line }, sent: bool, loop_start }; +/// `answer`: write the answer, consume nothing; `take`: consume and keep the +/// line; `replay`: hand the kept line to the loop. +pub const Action = enum { none, answer, take, replay }; +pub const Step = struct { next: State, action: Action }; + +pub fn step(s: State, e: Event) Step { + return switch (e) { + .boundary => |b| switch (s) { + .booting => if (!b.acp) .{ .next = .passed, .action = .none } else switch (b.line) { + .none, .incomplete => .{ .next = .booting, .action = .none }, + .initialize => .{ .next = .answering, .action = .answer }, + .other => .{ .next = .passed, .action = .none }, + }, + .answering, .answered, .passed, .loop => .{ .next = s, .action = .none }, + }, + // A failed answer leaves the line to the loop, which then fails or + // answers exactly as it would have without the early attempt. + .sent => |ok| if (s != .answering) .{ .next = s, .action = .none } else if (ok) .{ .next = .answered, .action = .take } else .{ .next = .passed, .action = .none }, + .loop_start => .{ .next = .loop, .action = if (s == .answered) .replay else .none }, + }; +} + +// ── the response ─────────────────────────────────────────────────────────── + +/// What the live CLI dispatch advertises as `can_load`: `acp_session_load. +/// configure` always installs a loader (pinned by a test below). +pub const live_can_load = true; + +fn noTurn(_: *anyopaque, _: Allocator, _: []const u8) anyerror![]const u8 { + return ""; +} + +fn noLoad(_: *anyopaque, _: Allocator, _: *Io.Writer, _: proto.Request) anyerror!void {} + +/// The `initialize` answer, written by the engine's `handleLine` on a fresh +/// dispatch whose only setting the response reads (`load_session != null`) +/// matches the live one. The process latches it sets are overwritten by the +/// replay at loop start (last writer wins, ADR 0206 latch). +/// +/// True only when the whole answer, one complete line, was written and +/// flushed. It is rendered aside first, so an engine or allocation failure +/// writes nothing. On a write failure the bytes still buffered in `w` are +/// dropped (`w` was empty on entry); bytes the OS already accepted cannot be +/// recalled, and the transport is then broken for the loop's write as well. +pub fn respond(gpa: Allocator, w: *Io.Writer, line: []const u8, can_load: bool) bool { + var arena = std.heap.ArenaAllocator.init(gpa); + defer arena.deinit(); + var rendered: Io.Writer.Allocating = .init(arena.allocator()); + var scratch: engine.Dispatch = .{ .turn = noTurn, .ctx = undefined, .load_session = if (can_load) noLoad else null }; + engine.implementation_version = build_options.version; + engine.handleLine(&scratch, arena.allocator(), &rendered.writer, line) catch return false; + const bytes = rendered.written(); + if (!std.mem.endsWith(u8, bytes, "\n")) return false; + w.writeAll(bytes) catch return dropBuffered(w); + w.flush() catch return dropBuffered(w); + return true; +} + +fn dropBuffered(w: *Io.Writer) bool { + w.undo(w.end); + return false; +} + +// ── the runtime ──────────────────────────────────────────────────────────── + +pub const Early = struct { + gpa: Allocator, + in: *Io.Reader, + out: *Io.Writer, + acp: bool, + /// Polled for readiness; null reads only what is already buffered. + fd: ?Io.File.Handle = null, + can_load: bool = live_can_load, + state: State = .booting, + /// The consumed `initialize`, owned until the loop has dispatched it. + stash: ?[]u8 = null, + handed: ?[]u8 = null, + + const max_reads_per_check = 8; + + /// One phase boundary: classify the first line, then do what `step` says. + pub fn boundary(self: *Early) bool { + if (comptime !build_options.acp) return false; + if (self.state != .booting) return false; + const ready = self.acp and self.out.buffered().len == 0; + var copy: ?[]u8 = null; + const line: Line = if (ready) self.probe(©) else .none; + const s = step(self.state, .{ .boundary = .{ .acp = ready, .line = line } }); + self.state = s.next; + if (s.action != .answer) { + if (copy) |c| self.gpa.free(c); + return false; + } + const taken = copy.?; + const t = step(self.state, .{ .sent = respond(self.gpa, self.out, taken, self.can_load) }); + self.state = t.next; + if (t.action != .take) { + self.gpa.free(taken); + return false; + } + self.in.toss(taken.len + 1); + self.stash = taken; + return true; + } + + /// Loop start: the line to dispatch with its output discarded, or null. + /// A slice handed out stays valid until the next call. + pub fn loopStart(self: *Early) ?[]const u8 { + if (self.handed) |h| self.gpa.free(h); + self.handed = null; + const s = step(self.state, .loop_start); + self.state = s.next; + if (s.action != .replay) return null; + self.handed = self.stash; + self.stash = null; + return self.handed; + } + + /// Never blocks: reads only while poll says stdin is readable, and never + /// past a full buffer. `copy` receives the line only for `.initialize`. + fn probe(self: *Early, copy: *?[]u8) Line { + const in = self.in; + var reads: usize = 0; + while (true) { + if (std.mem.indexOfScalar(u8, in.buffered(), '\n')) |n| return self.classify(in.buffered()[0..n], copy); + if (in.bufferedLen() == in.buffer.len) return .incomplete; + if (reads == max_reads_per_check or !self.readable()) break; + in.fillMore() catch break; + reads += 1; + } + return if (in.bufferedLen() == 0) .none else .incomplete; + } + + fn classify(self: *Early, line: []const u8, copy: *?[]u8) Line { + var arena = std.heap.ArenaAllocator.init(self.gpa); + defer arena.deinit(); + const req = proto.parseRequest(arena.allocator(), line) orelse return .other; + if (!std.mem.eql(u8, req.method, "initialize") or req.id == null) return .other; + // Out of memory: not consumed, so the loop still answers it. + copy.* = self.gpa.dupe(u8, line) catch return .incomplete; + return .initialize; + } + + fn readable(self: *Early) bool { + if (comptime builtin.os.tag == .windows or builtin.os.tag == .wasi) return false; + const fd = self.fd orelse return false; + var fds = [_]std.posix.pollfd{.{ .fd = fd, .events = std.posix.POLL.IN, .revents = 0 }}; + const n = std.posix.poll(&fds, 0) catch return false; + return n > 0 and fds[0].revents != 0; + } +}; + +// ── process wiring (main.zig, acp.zig) ───────────────────────────────────── + +var stdin_buf: [64 * 1024]u8 = undefined; +var stdin_reader: Io.File.Reader = undefined; +var g: ?Early = null; + +pub fn isAcp(positionals: []const []const u8) bool { + return (comptime build_options.acp) and positionals.len > 0 and std.mem.eql(u8, positionals[0], "acp"); +} + +/// Creates the process stdin reader (every frontend reads this one) and runs +/// the first check. Outside ACP the first `step` declines without reading. +pub fn arm(io: Io, gpa: Allocator, out: *Io.Writer, positionals: []const []const u8) *Io.Reader { + stdin_reader = Io.File.stdin().reader(io, &stdin_buf); + g = .{ .gpa = gpa, .in = &stdin_reader.interface, .out = out, .acp = isAcp(positionals), .fd = Io.File.stdin().handle }; + _ = g.?.boundary(); + return &stdin_reader.interface; +} + +/// The ACP loop's first-iteration hook; null outside a process that armed. +pub fn loopStart() ?[]const u8 { + if (g) |*e| return e.loopStart(); + return null; +} + +/// The boot tracker with a check at every phase boundary. +pub const Boot = struct { + inner: startup_timing.Tracker, + told: bool = false, + + /// With `GRAFF_BOOT_DEBUG`, names where the early answer happened: the + /// mark it followed, or the check `arm` runs when stdin is opened. + pub fn mark(self: *Boot, io: Io, label: []const u8) void { + self.inner.mark(io, label); + const e = if (g) |*e| e else return; + const now = e.boundary(); + if (!self.inner.debug or self.told or e.state != .answered) return; + self.told = true; + std.debug.print("[boot] acp initialize answered {s}{s}\n", .{ if (now) "after " else "when stdin was opened, before ", label }); + } + + pub fn attach(self: *Boot, tracer: anytype) void { + self.inner.attach(tracer); + } +}; + +test { + _ = @import("acp_early_tests.zig"); +} diff --git a/src/acp_early_tests.zig b/src/acp_early_tests.zig new file mode 100644 index 00000000..7620c25f --- /dev/null +++ b/src/acp_early_tests.zig @@ -0,0 +1,369 @@ +//! Tests for acp_early.zig: the early `initialize` answer against the late +//! dispatch path, the shared stdin buffer, and the pre-auth path. +const std = @import("std"); +const builtin = @import("builtin"); +const Io = std.Io; +const Allocator = std.mem.Allocator; +const testing = std.testing; +const early = @import("acp_early.zig"); +const engine = @import("acp_engine.zig"); +const v2 = @import("acp_v2.zig"); + +/// Everything handling `initialize` writes: the dispatch fields and the +/// process latches (v2 wire + message-id seed, T3, elicitation, compaction). +pub const Latches = struct { + subagents: bool, + background_subagents: bool, + v2: bool, + v2_seed: [24]u8, + t3: bool, + elicit: @TypeOf(@import("acp_elicit.zig").mode), + compaction: bool, + + pub fn of(d: *const engine.Dispatch) Latches { + var mint_buf: [48]u8 = undefined; + const id = v2.mint(&mint_buf, "x"); // msg_x__; the counter is not a latch + var it = std.mem.splitScalar(u8, id, '_'); + _ = it.next(); + _ = it.next(); + var seed: [24]u8 = @splat(0); + const s = it.next() orelse ""; + @memcpy(seed[0..@min(s.len, seed.len)], s[0..@min(s.len, seed.len)]); + return .{ + .subagents = d.subagents, + .background_subagents = d.background_subagents, + .v2 = v2.on(), + .v2_seed = seed, + .t3 = @import("acp_t3.zig").active(), + .elicit = @import("acp_elicit.zig").mode, + .compaction = @import("acp_compaction.zig").enabled(), + }; + } +}; + +fn noTurn(_: *anyopaque, _: Allocator, _: []const u8) anyerror![]const u8 { + return ""; +} + +fn noLoad(_: *anyopaque, _: Allocator, _: *Io.Writer, _: @import("acp_protocol.zig").Request) anyerror!void {} + +/// Reset every latch to the boot value so cells do not leak into each other. +pub fn resetLatches() void { + v2.negotiate(null, 0); + @import("acp_t3.zig").note(null); + @import("acp_elicit.zig").configure(null); + @import("acp_compaction.zig").noteInitialize(null); +} + +pub const Outcome = struct { bytes: []const u8, latches: Latches }; + +/// The late path: the live loop dispatches the line on a dispatch seeded `seed`. +pub fn late(arena: Allocator, line: []const u8, can_load: bool, seed: u64) !Outcome { + resetLatches(); + var aw: Io.Writer.Allocating = .init(arena); + var d: engine.Dispatch = .{ .turn = noTurn, .ctx = undefined, .seed = seed, .load_session = if (can_load) noLoad else null }; + engine.implementation_version = @import("build_options").version; + try engine.handleLine(&d, arena, &aw.writer, line); + return .{ .bytes = aw.writer.buffered(), .latches = .of(&d) }; +} + +/// The early path: a boundary check answers from the shared reader, then the +/// loop-start replay dispatches the kept line on the live dispatch, output discarded. +pub fn earlyThenReplay(arena: Allocator, line: []const u8, can_load: bool, seed: u64) !Outcome { + resetLatches(); + const input = try std.mem.concat(arena, u8, &.{ line, "\n" }); + var in: Io.Reader = .fixed(input); + var aw: Io.Writer.Allocating = .init(arena); + var e: early.Early = .{ .gpa = testing.allocator, .in = &in, .out = &aw.writer, .acp = true, .can_load = can_load }; + if (!e.boundary()) return error.NotAnsweredEarly; + try testing.expectEqual(@as(usize, 0), in.bufferedLen()); + var d: engine.Dispatch = .{ .turn = noTurn, .ctx = undefined, .seed = seed, .load_session = if (can_load) noLoad else null }; + const replay = e.loopStart() orelse return error.NoReplay; + var sink_buf: [64]u8 = undefined; + var sink: Io.Writer.Discarding = .init(&sink_buf); + try engine.handleLine(&d, arena, &sink.writer, replay); + try testing.expect(e.loopStart() == null); // handed exactly once; frees it + return .{ .bytes = aw.writer.buffered(), .latches = .of(&d) }; +} + +test "acp_early: early answer is byte-identical to the late one and leaves the same state" { + var state = std.heap.ArenaAllocator.init(testing.allocator); + defer state.deinit(); + const a = state.allocator(); + defer resetLatches(); + const saved = v2.gate; + defer v2.gate = saved; + for ([_]?bool{ false, true }) |gate| { + v2.gate = gate; + for ([_][]const u8{ + "{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1,\"clientCapabilities\":{\"fs\":{}}}}", + "{\"jsonrpc\":\"2.0\",\"id\":\"a\",\"method\":\"initialize\",\"params\":{\"protocolVersion\":2,\"clientInfo\":{\"name\":\"t3-code\"},\"clientCapabilities\":{\"subagents\":{},\"_meta\":{\"graff/backgroundSubagents\":true},\"elicitation\":{\"form\":{}},\"session\":{\"compaction\":true}}}}", + "{\"id\":3,\"method\":\"initialize\"}", + }) |line| for ([_]bool{ false, true }) |can_load| { + const l = try late(a, line, can_load, 0x5eed); + const e = try earlyThenReplay(a, line, can_load, 0x5eed); + try testing.expectEqualStrings(l.bytes, e.bytes); + try testing.expectEqual(l.latches, e.latches); + }; + } +} + +test "acp_early: a non-initialize first line is left untouched for the loop" { + for ([_][]const u8{ + "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"session/new\",\"params\":{}}\n{\"id\":2,\"method\":\"initialize\"}\n", + "{\"jsonrpc\":\"2.0\",\"method\":\"initialize\",\"params\":{}}\n", // a notification is not answered + "not json\n", + "\n{\"id\":1,\"method\":\"initialize\"}\n", + }) |input| { + var in: Io.Reader = .fixed(input); + var aw: Io.Writer.Allocating = .init(testing.allocator); + defer aw.deinit(); + var e: early.Early = .{ .gpa = testing.allocator, .in = &in, .out = &aw.writer, .acp = true }; + try testing.expect(!e.boundary()); + try testing.expect(!e.boundary()); // passed: never looks again + try testing.expectEqual(early.State.passed, e.state); + try testing.expectEqualStrings(input, in.buffered()); + try testing.expectEqual(@as(usize, 0), aw.writer.buffered().len); + try testing.expect(e.loopStart() == null); + } +} + +test "acp_early: a first line that fills the buffer, or a dirty stdout, is declined" { + var big: [64]u8 = @splat('x'); + var in: Io.Reader = .fixed(&big); // no newline anywhere in a full buffer + var aw: Io.Writer.Allocating = .init(testing.allocator); + defer aw.deinit(); + var e: early.Early = .{ .gpa = testing.allocator, .in = &in, .out = &aw.writer, .acp = true }; + try testing.expect(!e.boundary()); + try testing.expectEqual(early.State.booting, e.state); + try testing.expectEqual(big.len, in.bufferedLen()); + + var in2: Io.Reader = .fixed("{\"id\":1,\"method\":\"initialize\"}\n"); + try aw.writer.writeAll("junk"); + var dirty: early.Early = .{ .gpa = testing.allocator, .in = &in2, .out = &aw.writer, .acp = true }; + try testing.expect(!dirty.boundary()); + try testing.expectEqual(early.State.passed, dirty.state); + try testing.expectEqualStrings("junk", aw.writer.buffered()); +} + +fn pipePair() ![2]std.posix.fd_t { + if (comptime builtin.os.tag == .windows or builtin.os.tag == .wasi) return error.SkipZigTest; + var fds: [2]std.posix.fd_t = undefined; + if (std.c.pipe(&fds) != 0) return error.SkipZigTest; + return fds; +} + +fn writeFd(fd: std.posix.fd_t, bytes: []const u8) !void { + if (std.c.write(fd, bytes.ptr, bytes.len) != @as(isize, @intCast(bytes.len))) return error.ShortWrite; +} + +test "acp_early: a partial first line is not consumed and boot does not wait for the rest" { + resetLatches(); + defer resetLatches(); + const fds = try pipePair(); + defer _ = std.c.close(fds[0]); + defer _ = std.c.close(fds[1]); + var buf: [4096]u8 = undefined; + var reader = (Io.File{ .handle = fds[0], .flags = .{ .nonblocking = false } }).reader(testing.io, &buf); + var aw: Io.Writer.Allocating = .init(testing.allocator); + defer aw.deinit(); + var e: early.Early = .{ .gpa = testing.allocator, .in = &reader.interface, .out = &aw.writer, .acp = true, .fd = fds[0] }; + try testing.expect(!e.boundary()); // nothing written yet: returns at once + try testing.expectEqual(early.State.booting, e.state); + try writeFd(fds[1], "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initia"); + try testing.expect(!e.boundary()); + try testing.expectEqual(early.State.booting, e.state); + try testing.expectEqualStrings("{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initia", reader.interface.buffered()); + try testing.expectEqual(@as(usize, 0), aw.writer.buffered().len); + try writeFd(fds[1], "lize\"}\n{\"id\":2,\"method\":\"session/new\"}\n{\"id\":3,"); + try testing.expect(e.boundary()); + try testing.expectEqual(early.State.answered, e.state); + try testing.expect(std.mem.indexOf(u8, aw.writer.buffered(), "\"id\":1,\"result\"") != null); + // The bytes after the answered line stay in the one shared buffer, in order. + try testing.expectEqualStrings("{\"id\":2,\"method\":\"session/new\"}\n{\"id\":3,", reader.interface.buffered()); + const answered = aw.writer.buffered().len; + try testing.expect(!e.boundary()); // exactly once + try testing.expectEqual(answered, aw.writer.buffered().len); + try testing.expectEqualStrings("{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\"}", e.loopStart().?); + try testing.expect(e.loopStart() == null); + try testing.expectEqual(answered, aw.writer.buffered().len); +} + +test "acp_early: outside ACP the first check declines without reading stdin" { + const fds = try pipePair(); + defer _ = std.c.close(fds[0]); + defer _ = std.c.close(fds[1]); + try writeFd(fds[1], "{\"id\":1,\"method\":\"initialize\"}\n"); + var buf: [256]u8 = undefined; + var reader = (Io.File{ .handle = fds[0], .flags = .{ .nonblocking = false } }).reader(testing.io, &buf); + var aw: Io.Writer.Allocating = .init(testing.allocator); + defer aw.deinit(); + var e: early.Early = .{ .gpa = testing.allocator, .in = &reader.interface, .out = &aw.writer, .acp = false, .fd = fds[0] }; + try testing.expect(!e.boundary()); + try testing.expectEqual(early.State.passed, e.state); + try testing.expectEqual(@as(usize, 0), reader.interface.bufferedLen()); + try testing.expect(e.loopStart() == null); +} + +test "acp_early: live_can_load is what acp_session_load.configure installs" { + var state = std.heap.ArenaAllocator.init(testing.allocator); + defer state.deinit(); + const a = state.allocator(); + var root: @import("agent.zig").Agent = .{ + .gpa = testing.allocator, + .arena = a, + .io = testing.io, + .client = undefined, + .provider = .{ .id = "codex", .kind = .responses, .auth = .bearer, .url = "", .api_key = "", .model = "m", .context = 1 }, + .messages = std.json.Array.init(a), + .sub = false, + .label = "test", + .out = null, + }; + var live: @import("acp_live_turn.zig").LiveTurn = .{ .root = &root, .keys = undefined, .out = undefined }; + var d: engine.Dispatch = .{ .turn = noTurn, .ctx = &live }; + @import("acp_session_load.zig").configure(&d, &live); + try testing.expectEqual(early.live_can_load, d.load_session != null); +} + +test "acp_early: the pre-auth path still answers initialize like the engine with can_load false" { + var state = std.heap.ArenaAllocator.init(testing.allocator); + defer state.deinit(); + const a = state.allocator(); + defer resetLatches(); + const line = "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1}}"; + resetLatches(); + var pre: Io.Writer.Allocating = .init(a); + try engine.handlePreAuthLine(a, &pre.writer, line); + var direct: Io.Writer.Allocating = .init(a); + resetLatches(); + try testing.expect(early.respond(a, &direct.writer, line, false)); + try testing.expectEqualStrings(pre.writer.buffered(), direct.writer.buffered()); + var gated: Io.Writer.Allocating = .init(a); + try engine.handlePreAuthLine(a, &gated.writer, "{\"id\":2,\"method\":\"session/new\"}"); + try testing.expect(std.mem.indexOf(u8, gated.writer.buffered(), "\"error\"") != null); +} + +test "acp_early: step answers only a booting initialize, takes it only once sent, replays only a taken one" { + const lines = [_]early.Line{ .none, .incomplete, .initialize, .other }; + for (std.enums.values(early.State)) |s| { + for ([_]bool{ false, true }) |acp| for (lines) |l| { + const r = early.step(s, .{ .boundary = .{ .acp = acp, .line = l } }); + try testing.expectEqual(s == .booting and acp and l == .initialize, r.action == .answer); + try testing.expect(r.action != .replay and r.action != .take); + }; + for ([_]bool{ false, true }) |ok| { + const r = early.step(s, .{ .sent = ok }); + try testing.expectEqual(s == .answering and ok, r.action == .take); + if (s == .answering and !ok) try testing.expectEqual(early.State.passed, r.next); + } + const r = early.step(s, .loop_start); + try testing.expectEqual(early.State.loop, r.next); + try testing.expectEqual(s == .answered, r.action == .replay); + } +} + +const init_line = "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":1}}"; + +test "acp_early: an allocation failure anywhere in the early answer leaves the request for the loop" { + defer resetLatches(); + var fail_index: usize = 0; + while (true) : (fail_index += 1) { + resetLatches(); + var failing = std.testing.FailingAllocator.init(testing.allocator, .{ .fail_index = fail_index }); + var in: Io.Reader = .fixed(init_line ++ "\n"); + var aw: Io.Writer.Allocating = .init(testing.allocator); + defer aw.deinit(); + var e: early.Early = .{ .gpa = failing.allocator(), .in = &in, .out = &aw.writer, .acp = true }; + if (e.boundary()) { + // Answered: one complete framed response, and only then consumed. + const out = aw.writer.buffered(); + try testing.expect(std.mem.indexOf(u8, out, "\"id\":1,\"result\"") != null); + try testing.expectEqual(@as(usize, 1), std.mem.count(u8, out, "\n")); + try testing.expect(std.mem.endsWith(u8, out, "\n")); + try testing.expectEqual(@as(usize, 0), in.bufferedLen()); + try testing.expectEqualStrings(init_line, e.loopStart().?); + try testing.expect(e.loopStart() == null); + if (!failing.has_induced_failure) break; + } else { + // Not answered: nothing written, the line still where the loop reads. + try testing.expectEqual(@as(usize, 0), aw.writer.buffered().len); + try testing.expectEqualStrings(init_line ++ "\n", in.buffered()); + try testing.expect(e.loopStart() == null); + } + } +} + +/// A transport that accepts `budget` bytes in total, then fails every write: +/// budget 0 is a closed pipe, a small budget a write that dies mid-line. +const Short = struct { + budget: usize, + sink: [4096]u8 = undefined, + len: usize = 0, + buf: [64]u8 = undefined, + writer: Io.Writer, + + fn init(self: *Short, budget: usize) void { + self.* = .{ .budget = budget, .writer = .{ .vtable = &.{ .drain = drain }, .buffer = &self.buf } }; + } + + fn sent(self: *const Short) []const u8 { + return self.sink[0..self.len]; + } + + fn send(self: *Short, bytes: []const u8) Io.Writer.Error!void { + const take = @min(bytes.len, self.budget); + @memcpy(self.sink[self.len..][0..take], bytes[0..take]); + self.len += take; + self.budget -= take; + if (take < bytes.len) return error.WriteFailed; + } + + fn drain(w: *Io.Writer, data: []const []const u8, splat: usize) Io.Writer.Error!usize { + const self: *Short = @alignCast(@fieldParentPtr("writer", w)); + try self.send(w.buffer[0..w.end]); + w.end = 0; + var n: usize = 0; + for (data[0 .. data.len - 1]) |part| { + try self.send(part); + n += part.len; + } + for (0..splat) |_| try self.send(data[data.len - 1]); + return n + data[data.len - 1].len * splat; + } +}; + +/// The late path on `w`: the loop dispatches the line, then flushes the wire. +fn lateOn(w: *Io.Writer, line: []const u8) bool { + var arena = std.heap.ArenaAllocator.init(testing.allocator); + defer arena.deinit(); + var d: engine.Dispatch = .{ .turn = noTurn, .ctx = undefined, .load_session = noLoad }; + engine.implementation_version = @import("build_options").version; + engine.handleLine(&d, arena.allocator(), w, line) catch return false; + w.flush() catch return false; + return true; +} + +test "acp_early: a failed or short write of the early answer fails exactly as the late path" { + defer resetLatches(); + for ([_]usize{ 0, 1, 100 }) |budget| { + resetLatches(); + var early_out: Short = undefined; + early_out.init(budget); + var in: Io.Reader = .fixed(init_line ++ "\n"); + var e: early.Early = .{ .gpa = testing.allocator, .in = &in, .out = &early_out.writer, .acp = true }; + try testing.expect(!e.boundary()); // not claimed as answered + try testing.expectEqual(early.State.passed, e.state); + try testing.expectEqual(@as(usize, 0), early_out.writer.buffered().len); // no unframed bytes left behind + try testing.expectEqualStrings(init_line ++ "\n", in.buffered()); // the loop still reads it + try testing.expect(e.loopStart() == null); + // The loop then dispatches it on the same broken transport ... + try testing.expect(!lateOn(&early_out.writer, init_line)); + // ... and the client has seen exactly what the late path alone shows. + resetLatches(); + var late_out: Short = undefined; + late_out.init(budget); + try testing.expect(!lateOn(&late_out.writer, init_line)); + try testing.expectEqualStrings(late_out.sent(), early_out.sent()); + } +} diff --git a/src/acp_model_option.zig b/src/acp_model_option.zig index 4fa53e3b..3de3dfbf 100644 --- a/src/acp_model_option.zig +++ b/src/acp_model_option.zig @@ -34,6 +34,11 @@ pub fn hydrate(live: *LiveTurn) void { if (root.home.len > 0) @import("router_catalog.zig").loadCachedAll(root.io, root.arena, root.home); live.local_catalog_loaded = true; } + // A catalog boot detached with no cache may have landed since this + // session's first beat: activate it here, as the REPL picker does at its + // `ensureForQuery` beat (ADR 0340). One atomic load per slot when nothing + // landed; never a fetch. + @import("router_catalog_boot.zig").activateLanded(root.io, root.arena, root.home); } pub const Choice = struct { provider: []const u8, model: []const u8 }; @@ -113,3 +118,47 @@ test "model choices: reachable models only, current first, capped" { try std.testing.expectEqualStrings("gpt-b", list[0].model); for (list) |c| try std.testing.expect(!std.mem.eql(u8, c.provider, "anthropic")); } + +test "hydrate activates a boot-detached catalog that landed after the session's first beat" { + // ADR 0340: a first-ever ACP session can hydrate before a cold boot's + // detached catalog fetch lands; the next beat must activate the landed + // rows, as the REPL picker's `ensureForQuery` beat does. + const landing = @import("catalog_landing.zig"); + const provider_mod = @import("provider.zig"); + const io = std.testing.io; + var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator); + defer arena_state.deinit(); + const a = arena_state.allocator(); + var tmp = std.testing.tmpDir(.{}); + defer tmp.cleanup(); + const home = try tmp.dir.realPathFileAlloc(io, ".", std.testing.allocator); + defer std.testing.allocator.free(home); + + var root = try @import("agent_request_body_responses.zig").testAgentFor(a, "zai", .openai, "glm-5.3"); + root.home = home; + var keys: provider_mod.Keys = .{ .values = @splat(null) }; + var live: LiveTurn = .{ .root = &root, .keys = &keys, .out = undefined }; + const saved_table = pricing.active_model_table; + defer pricing.active_model_table = saved_table; + landing.reset(); + defer landing.reset(); + + // First beat on a fresh HOME: nothing on disk yet, the baked rows serve. + hydrate(&live); + try std.testing.expect(!pricing.providerModelInTable("zai", "glm-landed-test")); + + // The detached worker lands: its cache is on disk and its slot reports. + const spec = provider_mod.specFor("zai").?; + try tmp.dir.createDirPath(io, ".codegraff"); + const document = try std.fmt.allocPrint(a, "{{\"source\":\"{s}\",\"fetched_at_ms\":1,\"models\":[{{\"name\":\"glm-landed-test\"}}]}}\n", .{spec.models_url}); + const path = try std.fmt.allocPrint(a, "{s}/.codegraff/zai-models.json", .{home}); + try Io.Dir.cwd().writeFile(io, .{ .sub_path = path, .data = document }); + const job: @import("catalog_bounded.zig").Job = .{ .router = .{ .spec = spec, .source = .environment } }; + landing.expect(job); + landing.settle(job, true); + + // The session's next beat activates the landed rows, no /model needed. + hydrate(&live); + try std.testing.expect(pricing.providerModelInTable("zai", "glm-landed-test")); + try std.testing.expect(!landing.take(landing.slotOf(job))); +} diff --git a/src/boot_prewarm.zig b/src/boot_prewarm.zig new file mode 100644 index 00000000..b98ead0b --- /dev/null +++ b/src/boot_prewarm.zig @@ -0,0 +1,573 @@ +//! Boot prewarm: run the companion handshake (`codedb-pro --mcp`) while the +//! rest of a one-shot boots, and join it where `connectCompanion` would have +//! called `addServer` (ADR 0337; formal/BootPrewarm.tla). +//! +//! `-p` connects the companion synchronously (ADR 0230 defers only +//! interactive and ACP sessions), so its spawn + handshake used to sit in +//! series with credentials, the plugin scan and the MCP merge. Only the case +//! where the result is known in advance prewarms: lean `-p` (not a +//! subcommand), no `-w`, no project `.mcp.json` and no registry env override. There the +//! registry is the empty one (`oneshotSkipsImportedMcp`), so the companion is +//! the only server that can connect and the adopted outcome fills exactly the +//! slot `addServer` would have. Every other case keeps the serial path. +//! +//! One slot, touched only by the boot thread: `start` in `main` once +//! credentials resolved and the banner settled the cwd (a run that exits +//! there spawns nothing, as before), `take` in `connectCompanion` (await, +//! then merge under the registry mutex, ADR 0197), `discard` (stop, join, +//! tear down) when it is not adopted, on any return before the registry's +//! teardown, and `stopAtExit` at that teardown. A cwd or registry-setting +//! mismatch discards and the inline `addServer` runs; an attempt that ran to +//! a result is the one attempt, its error included. The worker owns copies of +//! everything it reads: `std.process.Init` frees `environ_map` before it +//! joins worker threads. +//! +//! The join is bounded (ADR 0339). A companion that is silent for the stdio +//! probe's 5 s and the handshake's 15 s held the first request for ~20.1 s; +//! `take` now waits `default_budget_ms` (250 ms, the ACP +//! `attach_budget_ms` precedent) and then returns, leaving the attempt +//! running: it merges into that registry the moment it lands, exactly where a +//! deferred start would. `GRAFF_MCP_COMPANION_BOOT_MS` is the knob; it is +//! read here, not in `mcp_rpc.applyHandshakeTimeoutEnv`, which +//! `oneshotSkipsImportedMcp` skips on this path. A slow-and-cold companion +//! can therefore miss the first catalog, and a late merge changes the catalog +//! mid-run (ADR 0221) — the two costs of not stalling. +//! +//! Reporting is exact on both sides of the budget, and about who ended the +//! attempt. A failure that lands before the budget is `take`'s error, +//! `error.McpClosed` included; one that lands after it has no request left to +//! return to, so the worker records it (`lateOutcome` / `lateError`) and names +//! it on stderr — `-p` prints no notices of its own — and `take` reports +//! `.late`, never `.connected`. A stop the exit path asked for is neither: it +//! ends the child on both platforms (`Watch.signal`) before it joins the +//! worker, and the `McpClosed` that kill produces is the run ending, so the +//! attempt publishes `.stopped` and says nothing. Before that distinction a +//! healthy companion printed "failed to connect" on its way out of a normal +//! exit (ADR 0339). The exit path costs the kill, not the probe plus handshake +//! caps. + +const std = @import("std"); +const Io = std.Io; +const Allocator = std.mem.Allocator; + +const args = @import("args.zig"); +const mcp = @import("mcp.zig"); +const mcp_boot = @import("mcp_boot.zig"); +const mcp_rpc = @import("mcp_rpc.zig"); +const mcp_teardown = @import("mcp_teardown.zig"); +const skills = @import("skills.zig"); + +/// What `addServer(name, command, args)` would start, plus the registry +/// settings `startServer` reads. `take` adopts only when the live registry +/// carries the same settings. +pub const Spec = struct { + name: []const u8, + command: []const u8, + args: []const []const u8 = &.{}, + home: []const u8 = "", + stdio_probe: bool = true, + lazy_stdio: bool = true, + show_diagnostics: bool = true, +}; + +const Joined = struct { outcome: mcp_boot.StartOutcome = .{}, err: ?anyerror = null }; + +/// What the attempt did (ADR 0339): merged into the registry it was handed, +/// dropped because the name connected meanwhile (#505), failed — or `.stopped`, +/// which is the exit path's own doing and no failure at all. `.none` means it +/// has not landed yet — or nobody handed it a registry. +pub const LateOutcome = enum { none, merged, duplicate, failed, stopped }; + +/// What `take` / `connect` report. `.connected`: the catalog is in the +/// registry. `.late`: the attempt is still running with this registry as its +/// merge target — not a catalog, and not a failure either, so no caller may +/// report it as connected. +pub const Adopted = enum { connected, late }; + +const Slot = struct { + future: Io.Future(Joined), + owned: std.heap.ArenaAllocator, + spec: Spec, + watch: *Watch, + /// `budgetMs` of the environment `main` started this run with. + budget_ms: u32 = default_budget_ms, + cwd: [std.fs.max_path_bytes]u8 = undefined, + cwd_len: usize = 0, +}; + +var slot: ?Slot = null; + +/// The worker's live child, so `discard` can end a handshake in progress by +/// stopping the child: the read sees end of stream, the attempt fails and +/// cleans up on its own, and `discard` joins it. The worker is never +/// cancelled: a cancel that lands inside the bounded handshake's `Io.Select` +/// returns before the select's read task stops, and that task outlives its +/// frame. The worker publishes each child it spawns (`Registry.spawnStdio`) +/// and forgets it before it reaps it, both under `lock`, so `stop` only ever +/// signals a child nobody has waited on: its pid cannot have been reused. +pub const Watch = struct { + lock: std.atomic.Mutex = .unlocked, + stopping: bool = false, + child: ?std.process.Child.Id = null, + /// Worker: it reached a result. Boot thread: that result is on the future + /// for it to await, or — with `late_merge` set — already merged. + done: bool = false, + /// Boot thread, over budget at the join: the live registry this attempt + /// merges into when it lands (ADR 0339). Under `lock` with `done`, so + /// exactly one side consumes the outcome. + late_merge: ?*mcp.Registry = null, + /// Worker: what that attempt then did — `.none` until it lands, `.stopped` + /// when the exit path ended it first. Under `lock`, read through `outcome`. + late_state: LateOutcome = .none, + /// Worker: the error a handed-off attempt ended with, when it failed. + late_err: ?anyerror = null, + /// Set by the worker's last write, so the join's bounded wait is a + /// deadline on the kernel timer rather than a poll: a 2 ms sleep on this + /// platform costs ~4 ms of overshoot apiece, which a 250 ms budget cannot + /// afford. + done_event: Io.Event = .unset, + + fn acquire(w: *Watch) void { + while (!w.lock.tryLock()) std.atomic.spinLoopHint(); + } + + /// Worker, right after a spawn. A child spawned after `stop` is stopped at once. + pub fn publish(w: *Watch, id: ?std.process.Child.Id) void { + w.acquire(); + defer w.lock.unlock(); + w.child = id; + if (w.stopping) w.signal(); + } + + /// Worker, before it reaps the child or hands it to the consumer. + pub fn forget(w: *Watch) void { + w.acquire(); + defer w.lock.unlock(); + w.child = null; + } + + /// Boot thread: end the attempt now. + fn stop(w: *Watch) void { + w.acquire(); + defer w.lock.unlock(); + w.stopping = true; + w.signal(); + } + + /// End the child, not the worker. Both platforms can: POSIX has `SIGKILL`, + /// and on Windows `Child.Id` *is* the process handle, so the same + /// `NtTerminateProcess` `Child.kill` issues works there too. Neither waits + /// nor frees the `Child` — the worker still owns the reap — so teardown is + /// bounded by "the read sees end of stream", not by the 5 s probe plus the + /// 15 s handshake. The caller holds `lock`, so the handle cannot have been + /// reaped (and on Windows closed) underneath it. + fn signal(w: *Watch) void { + const id = w.child orelse return; + switch (@import("builtin").os.tag) { + .windows => _ = std.os.windows.ntdll.NtTerminateProcess(id, @fromBackingInt(1)), + else => std.posix.kill(id, .KILL) catch {}, + } + } + + /// Boot thread, at the join: publish `reg` as the merge target for an + /// attempt still running, or report that it already finished — then the + /// caller awaits and adopts the result itself. Write-once: it runs once per + /// attempt and the worker takes the target under this lock, so "exactly + /// once" is a property of the field, asserted rather than assumed. + fn handOff(w: *Watch, reg: *mcp.Registry) bool { + w.acquire(); + defer w.lock.unlock(); + if (w.done) return true; + std.debug.assert(w.late_merge == null); + w.late_merge = reg; + return false; + } + + /// What `settle` saw, in one critical section: the merge target the boot + /// thread installed, and whether a stop was already requested. A stop is + /// requested before the child is killed, so an attempt whose read returned + /// `McpClosed` because of that kill reads `stopped` here — the run is + /// ending, which is not the same thing as the companion failing (ADR 0339). + const Settled = struct { + target: ?*mcp.Registry = null, + stopped: bool = false, + }; + + /// Worker, last write: publish the result and claim a merge target the + /// boot thread installed while it was still running. Each attempt settles + /// once, so the outcome is consumed exactly once: here, or by `take` / + /// `stopAtExit` through the future. + fn settle(w: *Watch, io: Io) Settled { + w.acquire(); + const settled: Settled = .{ .target = w.late_merge, .stopped = w.stopping }; + w.done = true; + w.lock.unlock(); + w.done_event.set(io); // wakes the join's bounded wait + return settled; + } + + /// The outcome the worker published, under the same lock as `done`. + fn outcome(w: *Watch) LateOutcome { + w.acquire(); + defer w.lock.unlock(); + return w.late_state; + } + + /// Worker: publish what the handed-off attempt did. Same lock `done` uses, + /// so a reader that waits for `lateOutcome` to leave `.none` also sees the + /// registry in its final shape. + fn recordLate(w: *Watch, state: LateOutcome, err: ?anyerror) void { + w.acquire(); + defer w.lock.unlock(); + w.late_state = state; + w.late_err = err; + } + + fn finished(w: *Watch) bool { + w.acquire(); + defer w.lock.unlock(); + return w.done; + } + + fn handedOff(w: *Watch) bool { + w.acquire(); + defer w.lock.unlock(); + return w.late_merge != null; + } +}; + +/// Settings that only `Registry.init` reads. With any of them set the +/// prewarm could not match the registry, so it does not start. +const registry_env = [_][]const u8{ "GRAFF_MCP_PROBE", "GRAFF_MCP_EAGER", "GRAFF_MCP_HANDSHAKE_SECS", "GRAFF_MCP_PROBE_MS" }; + +/// How long `take` waits for the attempt before it leaves it running (ADR +/// 0339). The ACP `attach_budget_ms` precedent: long enough for the 50 ms +/// handshake a warm companion answers in, short enough that no first request +/// pays a silent companion's 5 s probe + 15 s handshake. Windows takes the +/// ACP figure too (the platform boots slower). +pub const default_budget_ms: u32 = if (@import("builtin").os.tag == .windows) 1_500 else 250; + +/// The knob for that budget. Unset, unparsable or `0` mean the default, and +/// anything above `budget_cap_ms` is clamped to it — a typo buys the cap, never +/// the unbounded join. +pub const budget_env = "GRAFF_MCP_COMPANION_BOOT_MS"; +pub const budget_cap_ms: u32 = 60_000; + +pub fn budgetMs(environ_map: anytype) u32 { + const raw = environ_map.get(budget_env) orelse return default_budget_ms; + const v = std.fmt.parseInt(u32, raw, 10) catch return default_budget_ms; + if (v == 0) return default_budget_ms; // 0 is "unset", not "wait forever" + return @min(v, budget_cap_ms); // above the cap is a bound, not the default +} + +/// The flag/env half of the gate: a lean one-shot that will build the empty +/// registry. Interactive and ACP sessions queue the companion instead. +pub fn wantsCompanion(flags: args.Flags, environ_map: anytype) bool { + if (flags.oneshot_prompt == null) return false; // the prompt is the positionals; subcommands have none + if (flags.is_subcommand or flags.worktree_flag != null) return false; + if (!(flags.effectiveLean() or environ_map.get("GRAFF_LEAN") != null)) return false; + for (registry_env) |k| if (environ_map.get(k) != null) return false; + return true; +} + +/// Called once credentials resolved and the cwd is final (after +/// `setupWorktreeAndBanner`). Picks the companion `connectCompanion` would +/// try first and starts it. The caller defers `discard`. +pub fn startCompanion(io: Io, gpa: Allocator, environ_map: anytype, flags: args.Flags) void { + if (!wantsCompanion(flags, environ_map)) return; + if (Io.Dir.cwd().access(io, ".mcp.json", .{})) |_| return else |_| {} // project servers: not the empty registry + const path_env = environ_map.get("PATH") orelse ""; + for (skills.companion_servers) |c| { + if (optedOut(io, c.server)) continue; + var buf: [1024]u8 = undefined; + if (@import("path_lookup.zig").resolve(io, path_env, c.bin, &buf) == null) continue; + startWithin(io, gpa, .{ .name = c.server, .command = c.bin, .args = &.{"--mcp"}, .home = @import("keys_cli.zig").homeEnv(environ_map) orelse "" }, budgetMs(environ_map)); + return; + } +} + +/// `skills.loadSkillSettings` has not run yet at prewarm time; read the same +/// `{"skills": {"": false}}` opt-out it will apply. +fn optedOut(io: Io, server: []const u8) bool { + var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena_state.deinit(); + const a = arena_state.allocator(); + const data = Io.Dir.cwd().readFileAlloc(io, @import("harness_policy.zig").settings_path, a, .limited(1 << 20)) catch return false; + return optedOutIn(a, data, server); +} + +/// Pub for `boot_prewarm_tests.zig` (the opt-out test); pure, no I/O. +pub fn optedOutIn(a: Allocator, data: []const u8, server: []const u8) bool { + const v = std.json.parseFromSliceLeaky(std.json.Value, a, data, .{ .allocate = .alloc_always }) catch return false; + if (v != .object) return false; + const section = v.object.get("skills") orelse return false; + if (section != .object) return false; + const entry = section.object.get(server) orelse return false; + return entry == .bool and !entry.bool; +} + +pub fn pending() bool { + return slot != null; +} + +/// Start one prewarm with the default join budget. +pub fn start(io: Io, gpa: Allocator, spec: Spec) void { + startWithin(io, gpa, spec, default_budget_ms); +} + +/// Start one prewarm, joining it for at most `budget_ms`. A second call, an +/// allocation failure or a pool with no thread to spare leaves the slot +/// empty: the consumer then runs inline. +pub fn startWithin(io: Io, gpa: Allocator, spec: Spec, budget_ms: u32) void { + if (slot != null) return; + var owned = std.heap.ArenaAllocator.init(gpa); + const copy = dupSpec(owned.allocator(), spec) catch { + owned.deinit(); + return; + }; + const watch = owned.allocator().create(Watch) catch { + owned.deinit(); + return; + }; + watch.* = .{}; + var s: Slot = .{ .future = undefined, .owned = owned, .spec = copy, .watch = watch, .budget_ms = budget_ms }; + s.cwd_len = cwdKey(io, &s.cwd); + // Never `io.async`: run inline it would serialize the boot again. + s.future = io.concurrent(connectTask, .{ gpa, io, copy, watch }) catch { + s.owned.deinit(); + return; + }; + slot = s; +} + +fn dupSpec(a: Allocator, spec: Spec) Allocator.Error!Spec { + var copy = spec; + copy.name = try a.dupe(u8, spec.name); + copy.command = try a.dupe(u8, spec.command); + copy.home = try a.dupe(u8, spec.home); + const list = try a.alloc([]const u8, spec.args.len); + for (spec.args, list) |src, *dst| dst.* = try a.dupe(u8, src); + copy.args = list; + return copy; +} + +fn cwdKey(io: Io, buf: *[std.fs.max_path_bytes]u8) usize { + return Io.Dir.cwd().realPath(io, buf) catch 0; +} + +/// The recorded cwd key `take` compares against. `boot_prewarm_tests.zig` sets +/// a different one to exercise the mismatch: a test cannot move the process +/// cwd under a live attempt without racing every other test. +pub fn testSetCwdKey(len: usize) void { + if (slot) |*s| s.cwd_len = len; +} + +/// The worker: `addServer`'s connect on a task-local registry (the pattern +/// `mcp_start.attempt` uses), one attempt, no retry, no failure record. +fn connectTask(gpa: Allocator, io: Io, spec: Spec, watch: *Watch) Joined { + var arena_state = std.heap.ArenaAllocator.init(gpa); + const outcome = connectInto(gpa, io, spec, watch, &arena_state) catch |err| { + arena_state.deinit(); + const settled = watch.settle(io); + if (settled.stopped) { + // Teardown ended this attempt because the run is ending: this + // `McpClosed` is the stop, so it is published as one and said to + // nobody. Reporting it was the bug this fixes (ADR 0339). + watch.recordLate(.stopped, null); + return .{ .err = err }; + } + // An error has nothing to merge, but a handed-off attempt still owes + // its failure to someone: the boot thread released the request on the + // promise that this would land, so a silent failure here is + // indistinguishable from a connect (ADR 0339). Record it, and say it + // on stderr — the only channel left once the answer is out. + if (settled.target != null) { + watch.recordLate(.failed, err); + std.debug.print("companion: {s} failed to connect after the boot budget ({t}); native tools only\n", .{ spec.name, err }); + } + return .{ .err = err }; + }; + watch.forget(); // the outcome owns the child now + if (watch.settle(io).target) |reg| { + // The join went over budget and handed this attempt to the live + // registry (ADR 0339). `adoptStarted` is the one merge point, so a + // server that connected meanwhile keeps its tools and this one is + // torn down (#505); the registry owns the outcome either way. + watch.recordLate(if (mcp_boot.adoptStarted(reg, outcome)) .merged else .duplicate, null); + return .{}; + } + return .{ .outcome = outcome }; +} + +fn connectInto(gpa: Allocator, io: Io, spec: Spec, watch: *Watch, arena_state: *std.heap.ArenaAllocator) !mcp_boot.StartOutcome { + const a = arena_state.allocator(); + var tmp: mcp.Registry = .{ + .gpa = gpa, + .io = io, + .home = spec.home, + .arena_state = std.heap.ArenaAllocator.init(gpa), + .stdio_probe = spec.stdio_probe, + .lazy_stdio = spec.lazy_stdio, + .show_diagnostics = spec.show_diagnostics, + .spawn_watch = watch, + }; + defer tmp.arena_state.deinit(); + // Same object, same key order as `Registry.addServer`: the cache key and + // the relaunch config are derived from it. + var cfg: std.json.ObjectMap = .empty; + try cfg.put(a, "command", .{ .string = try a.dupe(u8, spec.command) }); + var argv = std.json.Array.init(a); + for (spec.args) |arg| try argv.append(.{ .string = try a.dupe(u8, arg) }); + try cfg.put(a, "args", .{ .array = argv }); + var servers: std.ArrayList(*mcp_rpc.Server) = .empty; + var tools: std.ArrayList(mcp.Tool) = .empty; + try tmp.startServer(a, &servers, &tools, try a.dupe(u8, spec.name), cfg); + return .{ .server = servers.items[0], .tools = tools.items, .arena_state = arena_state.* }; +} + +/// `addServer(name, command, args)` for the consumer, served by the prewarm +/// when it ran this companion: one start either way. +pub fn connect(reg: *mcp.Registry, name: []const u8, command: []const u8, argv: []const []const u8) !Adopted { + if (take(reg, name)) |joined| return joined; + _ = try reg.addServer(name, command, argv); + return .connected; +} + +/// The consumer. Null: no attempt ran to a result for `name` (none started, +/// or discarded on a mismatch) — connect inline as before. +/// Otherwise `.connected` with the server merged into `reg`, or the error the +/// attempt ended with, which is the error `addServer` would have returned (the +/// pre-budget contract, `error.McpClosed` included; see `budgetMs`). A failed +/// attempt is not repeated: the serial path made one. +/// Over budget (ADR 0339) the attempt is neither adopted nor stopped: it keeps +/// running and merges into `reg` when it lands, so this returns `.late` — no +/// catalog yet, no inline second spawn, and nothing claiming a connect. +pub fn take(reg: *mcp.Registry, name: []const u8) ?anyerror!Adopted { + const s = if (slot) |*s| s else return null; + if (!std.mem.eql(u8, s.spec.name, name)) return null; + if (!matches(reg, s)) { + discard(reg.io); + return null; + } + if (!awaitWithin(s, reg.io) and !s.watch.handOff(reg)) return .late; + const joined = s.future.await(reg.io); + release(); + if (joined.err) |err| return err; + if (!mcp_boot.adoptStarted(reg, joined.outcome)) return error.McpServerAlreadyConnected; + return .connected; +} + +/// What the attempt did: `.none` while it is still running, then `.merged`, +/// `.duplicate`, `.failed`, or `.stopped` when the exit path ended it. +/// `boot_prewarm_tests` polls it — the late merge and the duplicate guard are +/// otherwise invisible (a dropped latecomer leaves no trace, and neither does +/// a missing merge). The exit path frees the slot, so it reads the same state +/// through `stopAtExit`'s return instead. +pub fn lateOutcome() LateOutcome { + const s = if (slot) |*s| s else return .none; + return s.watch.outcome(); +} + +/// The error a handed-off attempt ended with, when `lateOutcome` is `.failed`. +pub fn lateError() ?anyerror { + const s = if (slot) |*s| s else return null; + s.watch.acquire(); + defer s.watch.lock.unlock(); + return s.watch.late_err; +} + +/// Wait for the attempt's result, for at most `s.budget_ms`. True: it is on +/// the future now, so awaiting it does not block. False: still running (or the +/// wait was cancelled), and the caller hands it to the registry instead of +/// waiting. The worker's last write sets the event, so a 50 ms companion is +/// adopted at once and a silent one costs the budget, not the probe plus +/// handshake caps. +fn awaitWithin(s: *Slot, io: Io) bool { + if (s.watch.finished()) return true; + const budget: Io.Timeout = .{ .duration = .{ .raw = .fromMilliseconds(@intCast(s.budget_ms)), .clock = .awake } }; + s.watch.done_event.waitTimeout(io, budget) catch {}; // Timeout, or a cancelled wait + return s.watch.finished(); +} + +fn matches(reg: *const mcp.Registry, s: *const Slot) bool { + if (reg.stdio_probe != s.spec.stdio_probe or reg.lazy_stdio != s.spec.lazy_stdio) return false; + if (!std.mem.eql(u8, reg.home, s.spec.home)) return false; + var now: [std.fs.max_path_bytes]u8 = undefined; + const n = cwdKey(reg.io, &now); + return n > 0 and std.mem.eql(u8, now[0..n], s.cwd[0..s.cwd_len]); +} + +/// Stop, join and tear down a prewarm nobody adopted. No-op when the slot is +/// empty, so every exit path may call it — and no-op for an attempt `take` +/// handed to the live registry, which is still running on purpose (ADR 0339). +pub fn discard(io: Io) void { + const s = if (slot) |*s| s else return; + if (s.watch.handedOff()) return; + _ = stopJoin(io); +} + +/// Exit-path teardown: stop and join the attempt even when `take` handed it +/// to the live registry, so no worker outlives the registry or its `io` +/// (#325). `Registry.deinitAtExit` calls this before the registry goes away, +/// which is also what makes the worker's late merge safe; the one-shot's own +/// `std.process.exit` paths (`oneshot.zig`, which skip every `defer`) call it +/// too. The join is bounded because `stop` ends the child on both platforms: +/// a silent companion costs the kill plus a reap, not its 5 s probe and 15 s +/// handshake. Returns what the attempt did when the stop ended it: `.stopped` +/// is the quiet case, `.failed` a companion that had already failed on its own +/// (ADR 0339). The slot and its watch are freed here, so this is where that +/// outcome is read — `lateOutcome` has nothing left to read afterwards. +pub fn stopAtExit(io: Io) LateOutcome { + return stopJoin(io); +} + +fn stopJoin(io: Io) LateOutcome { + const s = if (slot) |*s| s else return .none; + s.watch.stop(); + var joined = s.future.await(io); + const ended = s.watch.outcome(); // before `release` frees the watch + release(); + if (joined.outcome.server) |server| mcp_rpc.deinitServer(server, io, .init(io, mcp_teardown.teardown_grace)); + if (joined.outcome.arena_state) |*ta| ta.deinit(); + return ended; +} + +fn release() void { + if (slot) |*s| s.owned.deinit(); + slot = null; +} + +const testing = std.testing; + +// The fixtures, the join-budget cases and the late-merge cases live in +// boot_prewarm_tests.zig, pulled in here so `zig build test` reaches them +// (`src/main.zig` references this module). Split out to stay inside the +// 600-line ceiling after ADR 0339 added the budget. +test { + _ = @import("boot_prewarm_tests.zig"); +} + +test "boot prewarm: early-exit and interactive invocations start nothing" { + var env = std.process.Environ.Map.init(testing.allocator); + defer env.deinit(); + try testing.expect(!wantsCompanion(.{ .help_flag = true }, &env)); + try testing.expect(!wantsCompanion(.{ .version_flag = true }, &env)); + try testing.expect(!wantsCompanion(.{}, &env)); // REPL: ADR 0230 queues it + // What args.parse builds for `graff -p hi`: the prompt is the positionals. + var words: [1][]const u8 = .{"hi"}; + const oneshot: args.Flags = .{ .print_flag = true, .positionals = .fromOwnedSlice(&words), .oneshot_prompt = "hi" }; + try testing.expect(wantsCompanion(oneshot, &env)); + var no_lean = oneshot; + no_lean.no_lean_flag = true; + try testing.expect(!wantsCompanion(no_lean, &env)); + var worktree = oneshot; + worktree.worktree_flag = "w"; + try testing.expect(!wantsCompanion(worktree, &env)); + var title: [2][]const u8 = .{ "title", "hi" }; + try testing.expect(!wantsCompanion(.{ .positionals = .fromOwnedSlice(&title), .is_subcommand = true }, &env)); + var probe = std.process.Environ.Map.init(testing.allocator); + defer probe.deinit(); + try probe.put("GRAFF_MCP_EAGER", "1"); + try testing.expect(!wantsCompanion(oneshot, &probe)); + try testing.expect(!pending()); +} diff --git a/src/boot_prewarm_tests.zig b/src/boot_prewarm_tests.zig new file mode 100644 index 00000000..8799e887 --- /dev/null +++ b/src/boot_prewarm_tests.zig @@ -0,0 +1,461 @@ +//! Fixtures and tests for `boot_prewarm.zig`, split out so that module stays +//! inside the 600-line ceiling (ADR 0339 added the join budget there), pulled +//! in by its trailing `test { _ = @import("boot_prewarm_tests.zig"); }`. +//! +//! Everything here uses the module's public surface: `start` / `startWithin`, +//! `take` (directly and through `connect`), `discard`, `stopAtExit`, `pending`, +//! `budgetMs`, and `testSetCwdKey` for the one case a test cannot stage by +//! moving the process cwd. + +const std = @import("std"); +const Io = std.Io; +const Allocator = std.mem.Allocator; +const testing = std.testing; + +const args = @import("args.zig"); +const mcp = @import("mcp.zig"); +const bp = @import("boot_prewarm.zig"); + +const start = bp.start; +const startWithin = bp.startWithin; +const take = bp.take; +const connect = bp.connect; +const discard = bp.discard; +const stopAtExit = bp.stopAtExit; +const pending = bp.pending; +const budgetMs = bp.budgetMs; +const wantsCompanion = bp.wantsCompanion; +const default_budget_ms = bp.default_budget_ms; +const budget_env = bp.budget_env; +const Spec = bp.Spec; + +/// A legacy stdio MCP server in /bin/sh, as in mcp_restart.zig's fixture. +const fixture_script = + \\while read -r l; do + \\ id=$(printf '%s' "$l" | sed -n 's/^{"jsonrpc":"2.0","id":\([0-9]*\),.*/\1/p') + \\ [ -z "$id" ] && continue + \\ case "$l" in + \\ *'"method":"initialize"'*) printf '{"jsonrpc":"2.0","id":%s,"result":{"protocolVersion":"2025-06-18","capabilities":{"tools":{}},"serverInfo":{"name":"f","version":"1"}}}\n' "$id" ;; + \\ *'"method":"tools/list"'*) printf '{"jsonrpc":"2.0","id":%s,"result":{"tools":[{"name":"search","description":"Search","inputSchema":{"type":"object","properties":{"q":{"type":"string"}},"required":["q"]}},{"name":"read","description":"Read","inputSchema":{"type":"object"},"annotations":{"readOnlyHint":true}}]}}\n' "$id" ;; + \\ *) printf '{"jsonrpc":"2.0","id":%s,"error":{"code":-32601,"message":"no"}}\n' "$id" ;; + \\ esac + \\done +; + +fn fixtureSpec(name: []const u8, argv: []const []const u8) Spec { + return .{ .name = name, .command = "/bin/sh", .args = argv, .stdio_probe = false, .lazy_stdio = false, .show_diagnostics = false }; +} + +const fixture_argv = [_][]const u8{ "-c", fixture_script }; + +fn testRegistry() mcp.Registry { + var reg = mcp.Registry.empty(testing.allocator, testing.io); + reg.stdio_probe = false; + reg.lazy_stdio = false; + return reg; +} + +fn toolsJson(a: Allocator, reg: *mcp.Registry) ![]const u8 { + var out: std.Io.Writer.Allocating = .init(a); + for (reg.tools) |t| { + try out.writer.print("{s}|{s}|{s}|{d}|{any}|", .{ t.qualified_name, t.serverName(), t.description, t.server_index, t.read_only }); + try std.json.Stringify.value(t.input_schema, .{}, &out.writer); + try out.writer.writeByte('\n'); + } + for (reg.servers) |s| try out.writer.print("server {s} {s}\n", .{ s.name, s.protocol_version }); + return out.written(); +} + +test "boot prewarm: the adopted companion matches the inline addServer catalog byte for byte" { + if (@import("builtin").os.tag == .windows) return error.SkipZigTest; // /bin/sh + var arena_state = std.heap.ArenaAllocator.init(testing.allocator); + defer arena_state.deinit(); + const a = arena_state.allocator(); + + var inline_reg = testRegistry(); + defer inline_reg.deinit(); + _ = try inline_reg.addServer("codedbpro", "/bin/sh", &.{ "-c", fixture_script }); + + var warm_reg = testRegistry(); + defer warm_reg.deinit(); + start(testing.io, testing.allocator, fixtureSpec("codedbpro", &fixture_argv)); + try testing.expect(pending()); + try testing.expect(take(&warm_reg, "other") == null); // another name leaves the slot alone + const adopted = try (take(&warm_reg, "codedbpro") orelse return error.TestExpectedPrewarm); + try testing.expectEqual(bp.Adopted.connected, adopted); + try testing.expect(!pending()); + try testing.expectEqual(@as(usize, 2), warm_reg.tools.len); + try testing.expectEqualStrings(try toolsJson(a, &inline_reg), try toolsJson(a, &warm_reg)); +} + +test "boot prewarm: a registry with other settings is not adopted" { + if (@import("builtin").os.tag == .windows) return error.SkipZigTest; + var reg = testRegistry(); + defer reg.deinit(); + reg.stdio_probe = true; // what GRAFF_MCP_PROBE would change + start(testing.io, testing.allocator, fixtureSpec("codedbpro", &fixture_argv)); + try testing.expect(take(®, "codedbpro") == null); + try testing.expect(!pending()); + try testing.expectEqual(@as(usize, 0), reg.tools.len); +} + +/// A scratch directory with a spawn log the fixtures append their pid to. +const SpawnLog = struct { + tmp: testing.TmpDir, + path: []u8, + + fn init() !SpawnLog { + var tmp = testing.tmpDir(.{}); + errdefer tmp.cleanup(); + const dir = try tmp.dir.realPathFileAlloc(testing.io, ".", testing.allocator); + defer testing.allocator.free(dir); + return .{ .tmp = tmp, .path = try std.fmt.allocPrint(testing.allocator, "{s}/spawns", .{dir}) }; + } + + fn deinit(l: *SpawnLog) void { + testing.allocator.free(l.path); + l.tmp.cleanup(); + } + + fn pids(l: *const SpawnLog, buf: []std.posix.pid_t) []std.posix.pid_t { + var raw: [512]u8 = undefined; + const data = l.tmp.dir.readFile(testing.io, "spawns", &raw) catch return buf[0..0]; + var n: usize = 0; + var it = std.mem.tokenizeAny(u8, data, " \n"); + while (it.next()) |w| : (n += 1) { + if (n == buf.len) break; + buf[n] = std.fmt.parseInt(std.posix.pid_t, w, 10) catch return buf[0..n]; + } + return buf[0..n]; + } +}; + +fn processAlive(pid: std.posix.pid_t) bool { + std.posix.kill(pid, @fromBackingInt(@intCast(0))) catch |err| return err != error.ProcessNotFound; + return true; +} + +/// `sh -c